From d5b2167d91e4b15c3b90b2ce35774eae5835f816 Mon Sep 17 00:00:00 2001 From: Andy Juniper Date: Sun, 30 Jul 2017 12:24:05 +0100 Subject: [PATCH 1/9] Initial support for Bluetooth --- CMakeLists.txt | 37 +- examples/simpleble.cpp | 119 + include/firmbase.h | 23 +- include/firmble.h | 160 + include/firmio.h | 1 + src/firmbase.cpp | 94 +- src/firmble.cpp | 959 ++++ vendor/libblepp-master.patch | 57 + vendor/libblepp-master/.gitignore | 17 + vendor/libblepp-master/ATT.txt | 186 + vendor/libblepp-master/COPYING | 54 + vendor/libblepp-master/Makefile.in | 175 + vendor/libblepp-master/Notes.txt | 115 + vendor/libblepp-master/README | 32 + vendor/libblepp-master/att_gatt.h | 41 + vendor/libblepp-master/blelogger.cc | 96 + vendor/libblepp-master/blepp/att.h | 323 ++ vendor/libblepp-master/blepp/att_pdu.h | 355 ++ vendor/libblepp-master/blepp/bledevice.h | 67 + .../libblepp-master/blepp/blestatemachine.h | 348 ++ vendor/libblepp-master/blepp/float.h | 32 + vendor/libblepp-master/blepp/gap.h | 31 + vendor/libblepp-master/blepp/lescan.h | 217 + vendor/libblepp-master/blepp/logging.h | 107 + .../libblepp-master/blepp/pretty_printers.h | 48 + vendor/libblepp-master/blepp/uuid.h | 140 + vendor/libblepp-master/blepp/xtoa.h | 38 + vendor/libblepp-master/bluetooth.cc | 294 + vendor/libblepp-master/configure | 4858 +++++++++++++++++ vendor/libblepp-master/configure.ac | 111 + vendor/libblepp-master/cxxgplot.h | 159 + vendor/libblepp-master/get_attrs.sh | 11 + vendor/libblepp-master/hex2ascii.awk | 31 + vendor/libblepp-master/lescan.cc | 133 + vendor/libblepp-master/lescan_simple.cc | 10 + vendor/libblepp-master/libblepp.pc.in | 8 + .../m4/ax_cxx_compile_stdcxx_14.m4 | 173 + .../libblepp-master/primary_service_names.cc | 32 + vendor/libblepp-master/pstreams/pstream.h | 2095 +++++++ vendor/libblepp-master/src/att.cc | 1181 ++++ vendor/libblepp-master/src/att_pdu.cc | 85 + vendor/libblepp-master/src/bledevice.cc | 260 + vendor/libblepp-master/src/blestatemachine.cc | 836 +++ vendor/libblepp-master/src/float.cc | 22 + vendor/libblepp-master/src/lescan.cc | 701 +++ vendor/libblepp-master/src/logging.cc | 28 + vendor/libblepp-master/src/pretty_printers.cc | 110 + vendor/libblepp-master/src/uuid.cc | 244 + vendor/libblepp-master/temperature.cc | 104 + vendor/libblepp-master/tests/test_scan.cc | 109 + 50 files changed, 15433 insertions(+), 34 deletions(-) create mode 100644 examples/simpleble.cpp create mode 100644 include/firmble.h create mode 100644 src/firmble.cpp create mode 100644 vendor/libblepp-master.patch create mode 100644 vendor/libblepp-master/.gitignore create mode 100644 vendor/libblepp-master/ATT.txt create mode 100644 vendor/libblepp-master/COPYING create mode 100644 vendor/libblepp-master/Makefile.in create mode 100644 vendor/libblepp-master/Notes.txt create mode 100644 vendor/libblepp-master/README create mode 100644 vendor/libblepp-master/att_gatt.h create mode 100644 vendor/libblepp-master/blelogger.cc create mode 100644 vendor/libblepp-master/blepp/att.h create mode 100644 vendor/libblepp-master/blepp/att_pdu.h create mode 100644 vendor/libblepp-master/blepp/bledevice.h create mode 100644 vendor/libblepp-master/blepp/blestatemachine.h create mode 100644 vendor/libblepp-master/blepp/float.h create mode 100644 vendor/libblepp-master/blepp/gap.h create mode 100644 vendor/libblepp-master/blepp/lescan.h create mode 100644 vendor/libblepp-master/blepp/logging.h create mode 100644 vendor/libblepp-master/blepp/pretty_printers.h create mode 100644 vendor/libblepp-master/blepp/uuid.h create mode 100644 vendor/libblepp-master/blepp/xtoa.h create mode 100644 vendor/libblepp-master/bluetooth.cc create mode 100755 vendor/libblepp-master/configure create mode 100644 vendor/libblepp-master/configure.ac create mode 100644 vendor/libblepp-master/cxxgplot.h create mode 100644 vendor/libblepp-master/get_attrs.sh create mode 100644 vendor/libblepp-master/hex2ascii.awk create mode 100644 vendor/libblepp-master/lescan.cc create mode 100644 vendor/libblepp-master/lescan_simple.cc create mode 100644 vendor/libblepp-master/libblepp.pc.in create mode 100644 vendor/libblepp-master/m4/ax_cxx_compile_stdcxx_14.m4 create mode 100644 vendor/libblepp-master/primary_service_names.cc create mode 100644 vendor/libblepp-master/pstreams/pstream.h create mode 100644 vendor/libblepp-master/src/att.cc create mode 100644 vendor/libblepp-master/src/att_pdu.cc create mode 100644 vendor/libblepp-master/src/bledevice.cc create mode 100644 vendor/libblepp-master/src/blestatemachine.cc create mode 100644 vendor/libblepp-master/src/float.cc create mode 100644 vendor/libblepp-master/src/lescan.cc create mode 100644 vendor/libblepp-master/src/logging.cc create mode 100644 vendor/libblepp-master/src/pretty_printers.cc create mode 100644 vendor/libblepp-master/src/uuid.cc create mode 100644 vendor/libblepp-master/temperature.cc create mode 100644 vendor/libblepp-master/tests/test_scan.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 06adf6f..cdbebdd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,24 @@ project(firmatacpp) set (CMAKE_CXX_STANDARD 11) option(FIRMATA_BUILD_EXAMPLES "Build firmata example programs" YES) +option(FIRMATA_WITH_BLUETOOTH "Enable Bluetooth support" YES) + +if (FIRMATA_WITH_BLUETOOTH) + include (ExternalProject) + + ExternalProject_Add(libblepp + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/libblepp-master + PATCH_COMMAND patch -p0 < ../libblepp-master.patch + CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/libblepp-master/configure --prefix= + BUILD_COMMAND ${MAKE}) + ExternalProject_Get_Property(libblepp install_dir) + set(FIRMATA_BLESRC src/firmble.cpp) + set(FIRMATA_BLEHDR include/firmble.h) +else() + set(FIRMATA_BLESRC) + set(FIRMATA_BLEHDR) +endif() + include (GenerateExportHeader) @@ -16,6 +34,10 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/vendor/serial/include ) +if (FIRMATA_WITH_BLUETOOTH) + include_directories( ${install_dir}/include) +endif() + set(FIRMATACPP_SOURCES src/firmbase.cpp src/firmi2c.cpp @@ -27,19 +49,30 @@ set(FIRMATACPP_INCLUDES include/firmata.h include/firmbase.h include/firmi2c.h - include/firmio.h + include/firmio.h include/firmserial.h ${CMAKE_CURRENT_BINARY_DIR}/firmatacpp_export.h ) -add_library(firmatacpp ${FIRMATACPP_SOURCES} ${FIRMATACPP_INCLUDES}) +SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3" ) + +add_library(firmatacpp ${FIRMATACPP_SOURCES} ${FIRMATA_BLESRC} ${FIRMATACPP_INCLUDES} ${FIRMATA_BLEHDR}) generate_export_header(firmatacpp) set_target_properties(firmatacpp PROPERTIES COMPILE_FLAGS -DLIBSHARED_AND_STATIC_STATIC_DEFINE) +link_directories( + ${install_dir}/lib +) + target_link_libraries(firmatacpp serial) if (FIRMATA_BUILD_EXAMPLES) add_executable(simple_example examples/simple.cpp) target_link_libraries(simple_example firmatacpp) + + if (FIRMATA_WITH_BLUETOOTH) + add_executable(simple_exampleble examples/simpleble.cpp) + target_link_libraries(simple_exampleble firmatacpp ble++) + endif() endif() diff --git a/examples/simpleble.cpp b/examples/simpleble.cpp new file mode 100644 index 0000000..14bb6ad --- /dev/null +++ b/examples/simpleble.cpp @@ -0,0 +1,119 @@ +#include +#include + +#include "firmata.h" +#include "firmble.h" + +#ifndef WIN32 +#include "unistd.h" +#endif + +bool stopping = false; + +void do_stop(int sig) +{ + std::cout << "Shutting down..." << std::endl; + stopping = true; +} + +/* + * Detect first bluetooth device with a StandardFirmata interface + * Read analog inputs A0 and A1 and digital pin 2 (eg, a Playstation analog stick + button) + * as well as I2C address 8 (eg, the slave_sender example that comes with Arduino IDE) + * and print to stdout + */ + +int main(int argc, const char* argv[]) +{ + signal(SIGINT, do_stop); + signal(SIGTERM, do_stop); + + std::vector ports = firmata::FirmBle::listPorts(3); + firmata::Firmata* f = NULL; + firmata::FirmBle* bleio; + + for (auto port : ports) { + std::cout << port.port << std::endl; + + if (f != NULL) { + delete f; + f = NULL; + } + + try { + bleio = new firmata::FirmBle(port.port.c_str()); +#ifndef WIN32 + //if (bleio->available()) { + f = new firmata::Firmata(bleio); + //} +#else + f = new firmata::Firmata(bleio); +#endif + } + catch(firmata::IOException e) { + std::cout << e.what() << std::endl; + } + catch(firmata::NotOpenException e) { + std::cout << e.what() << std::endl; + } + if (f != NULL && f->ready()) { + break; + } + } + if (f == NULL || !f->ready()) { + std::cout << "nothing there" <setSamplingInterval(100); + + std::cout << f->name << std::endl; + std::cout << f->major_version << std::endl; + std::cout << f->minor_version << std::endl; + + f->pinMode(2, MODE_INPUT); + + f->reportAnalog(0, 1); + f->reportAnalog(1, 1); + + f->reportDigital(0, 1); + //f->configI2C(0); + //f->reportI2C(8, FIRMATA_I2C_REGISTER_NOT_SPECIFIED, 6); + + while (true) { + if (stopping) + { + break; + } + f->parse(); + int a0 = f->analogRead("A0"); + int a1 = f->analogRead("A1"); + int pin2 = f->digitalRead(2); + //std::vector i2c = f->readI2C(8); + //std::string s = ""; + //for (auto byte = i2c.begin(); byte < i2c.end(); ++byte) { + //s += (char)*byte; + //} + + std::cout << a0 << ", " << a1 << ", " << pin2 << std::endl; + f->digitalWrite(13,1); + usleep(sleep_usecs); + f->digitalWrite(13,0); + usleep(sleep_usecs); + }; + + std::vector r; + r.push_back(FIRMATA_SYSTEM_RESET); + f->standardCommand(r); + delete f; + } + catch (firmata::IOException e) { + std::cout << e.what() << std::endl; + } + catch (firmata::NotOpenException e) { + std::cout << e.what() << std::endl; + } +} + diff --git a/include/firmbase.h b/include/firmbase.h index f789455..5a7f116 100644 --- a/include/firmbase.h +++ b/include/firmbase.h @@ -27,8 +27,8 @@ namespace firmata { void pinMode(uint8_t pin, uint8_t mode); void digitalWrite(uint8_t pin, uint8_t value); - void analogWrite(uint8_t pin, uint32_t value); - void analogWrite(const std::string& channel, uint32_t value); + void analogWrite(uint8_t pin, uint32_t value); // pin = digital pin + void analogWrite(const std::string& channel, uint32_t value); // pin = "AN" where N is analog pin uint8_t digitalRead(uint8_t pin); uint32_t analogRead(uint8_t pin); @@ -38,16 +38,25 @@ namespace firmata { void sysexCommand(uint8_t sysex_command); void sysexCommand(std::vector sysex_command); - void reportAnalog(uint8_t channel, uint8_t enable = 1); - void reportDigital(uint8_t port, uint8_t enable = 1); + void reportAnalog(uint8_t channel, uint8_t enable = 1); // pin = analog pin + void reportDigital(uint8_t port, uint8_t enable = 1); // port = port group + void reportDigitalPin(uint8_t pin, uint8_t enable = 1); void setSamplingInterval(uint32_t intervalms); + const uint8_t getNumPins() const { return m_numPins; } + const std::vector & getPinCaps(uint8_t pin) const { return pins[pin].supported_modes; } + const std::vector & getPinResolutions(uint8_t pin) const { return pins[pin].resolutions; } + uint8_t getPinCapResolution(uint8_t pin, uint8_t mode) const; + uint8_t getPinMode(uint8_t pin) { return pins[pin].mode; } + uint8_t getPinAnalogChannel(uint8_t pin) const { return pins[pin].analog_channel; } // Dpin -> Apin + uint8_t getPinFromAnalogChannel(uint8_t apin) const { return apins[apin]; } // Apin -> Dpin + protected: virtual bool handleSysex(uint8_t command, std::vector data); virtual bool handleString(std::string data); - bool awaitResponse(uint8_t command, uint32_t timeout = 1000); - bool awaitSysexResponse(uint8_t sysexCommand, uint32_t timeout = 1000); + bool awaitResponse(uint8_t command, uint32_t timeout = 1000 /* ms */ ); + bool awaitSysexResponse(uint8_t sysexCommand, uint32_t timeout = 1000 /* ms */ ); private: void initPins(); @@ -64,7 +73,9 @@ namespace firmata { FirmIO* m_firmIO; + uint8_t m_numPins; t_pin pins[128]; + uint8_t apins[128]; }; } diff --git a/include/firmble.h b/include/firmble.h new file mode 100644 index 0000000..dacc321 --- /dev/null +++ b/include/firmble.h @@ -0,0 +1,160 @@ +#ifndef __FIRMBLE_H_ +#define __FIRMBLE_H_ + +#include +#include +#include "firmio.h" +#include "blepp/blestatemachine.h" +#include "blepp/lescan.h" + +namespace firmata { + + typedef struct BlePortInfo { + std::string port; + std::string description; + std::string hardware_id; + } BlePortInfo; + + class FirmBle : public FirmIO { + public: + FirmBle(const std::string &port = ""); /* normal use */ + FirmBle(int maxScanTime); /* used for initiating a scan */ + virtual ~FirmBle(); + + ///////////////////////////////////////////////////////////// + // Firmata methods + + // firmata open connection + // this triggers the ble connect + virtual void open() override; + // firmata check if connection is open + virtual bool isOpen() override; + // firmata close + // this triggers ble disconnect + virtual void close() override; + // firmata queries how much data is queued + virtual size_t available() override; + // firmata read data + virtual std::vector read(size_t size = 1) override; + // firmata transmit data + virtual size_t write(std::vector bytes) override; + // firmata retrieve list of ports + static std::vector listPorts(int timeout=10 /*seconds*/, int maxDevices=0); + + private: + + ///////////////////////////////////////////////////////////// + // members etc. + + // state + enum ble_job { + st_idle, // idle + st_scan, // running scan + st_conn, // connecting + st_disc, // disconnecting + st_write, // send data + st_stop, // shutdown + }; + ble_job m_job = st_idle; + + // do we think we are connected? + bool m_connected = false; + + // are we busy doing something + bool m_active = false; + + // file descriptors for waking each side + int m_fdWakeBle = -1; + int m_fdWakeMain = -1; + int m_fdWakeMainRx = -1; + + // memory buffer for sending data from + uint8_t * m_tx_buff = nullptr; + // sets of bytes to be sent + std::queue< std::vector > m_tx_queue; + // access lock to transmit queue + std::mutex m_tx_lock; + + // received PDUs + // stored like this to make it easy to limit queue length + // without overwriting partial messages + std::queue m_rx_buf; + // easier to count bytes here than calculate on demand + volatile size_t m_rx_bytes = 0; + // max number of messages in receive queue + static size_t s_max_queued_messages; + // access lock to receive queue + std::mutex m_rx_lock; + // is anyone waiting to read from the rx queue? + volatile bool m_rx_reader_waiting = false; + + // BLE handles + BLEPP::BLEGATTStateMachine * m_gatt = nullptr; + BLEPP::Characteristic * m_tx = nullptr; + BLEPP::Characteristic * m_rx = nullptr; + + // scan stuff + BLEPP::HCIScanner * m_scanner = nullptr; + int mScanMaxTime = 10; + // list of "ports" (remote devices) that we will report + // to main + std::vector m_portList; + + // worker thread handle + pthread_t m_thread; + + // results - empty for OK, message otherwise + std::string m_result; + + // the port we have been asked to communicate with + std::string m_port; + + // connect callback + std::function m_scancallback; + + ///////////////////////////////////////////////////////////// + // ble methods + // called in context of worker thread + + // common constructor path + void initialise(); + + // scan results handler + void ble_handle_scan_result(); + // check remote characteristics during connect + void ble_connect_scan_result (); + // device connected + void ble_connected (); + // device reporting interval is now set up + void ble_connect_reporting_set (); + // device disconnected + // could happen any time + void ble_disconnected (BLEPP::BLEGATTStateMachine::Disconnect); + // all data written + void ble_write_done (); + // data received from device + void ble_rx(const BLEPP::PDUNotificationOrIndication & p); + void ble_rx2(const BLEPP::Characteristic &, const BLEPP::PDUNotificationOrIndication & p); + + ///////////////////////////////////////////////////////////// + // threading methods + + // main thread uses this to wake ble thread and wait for completion + void start_thread_and_wait(ble_job job, bool nothrow = false); + // ble thread sets flags as idle + void jobDone(); + // ble thread completes a job and wakes something waiting for receive + void wakeRx(); + // ble thread completes a job and wakes main + void wakeMain(); + // ble thread write helper + void do_write(); + // ble thread + static void * thread_main(void * b); + void ble_thread_main(); + }; + +} + +#endif + diff --git a/include/firmio.h b/include/firmio.h index 22ea840..2f67b34 100644 --- a/include/firmio.h +++ b/include/firmio.h @@ -15,6 +15,7 @@ namespace firmata { virtual size_t available() = 0; virtual std::vector read(size_t size = 1) = 0; virtual size_t write(std::vector bytes) = 0; + virtual ~FirmIO() {}; }; class IOException : public std::exception { diff --git a/src/firmbase.cpp b/src/firmbase.cpp index 4db3614..0ce7861 100644 --- a/src/firmbase.cpp +++ b/src/firmbase.cpp @@ -1,5 +1,7 @@ #include "firmbase.h" +#include +#include #include #include #include @@ -30,6 +32,8 @@ namespace firmata { void Base::init() { + // TODO each of these should check the return from + // await[Sysex]Response and throw if necessary reportFirmware(); initPins(); capabilityQuery(); @@ -50,6 +54,7 @@ namespace firmata { standardCommand({ FIRMATA_SET_DIGITAL_PIN, pin, value }); } + // pin is digital pin ID void Base::analogWrite(uint8_t pin, uint32_t value) { if (pin > 15 || value > FIRMATA_MAX) { @@ -64,6 +69,7 @@ namespace firmata { standardCommand({ analog_write_pin, lsb, msb }); } + // pin is digital pin ID void Base::analogWriteExtended(uint8_t pin, uint32_t value) { pins[pin].value = value; @@ -79,21 +85,22 @@ namespace firmata { sysexCommand(bytes); } + // arg is "AN" where N is analog pin ID void Base::analogWrite(const std::string& channel, uint32_t value) { if (channel[0] != 'A') return; - for (uint8_t pin = 0; pin < 127; pin++) { - if (pins[pin].analog_channel + '0' == channel[1]) { - pins[pin].value = value; - analogWrite(pin, value); - return; - } + uint8_t apin = std::stoul(channel.substr(1)); + uint8_t pin = apins[apin]; + if (pin < 128) { + pins[pin].value = value; + analogWrite(pin, value); + return; } } uint8_t Base::digitalRead(uint8_t pin) { - return pins[pin].value; + return pins[pin].value?1:0; } uint32_t Base::analogRead(uint8_t pin) @@ -101,17 +108,19 @@ namespace firmata { return pins[pin].value; } + // arg is "AN" where N is analog pin ID uint32_t Base::analogRead(const std::string& channel) { if (channel[0] != 'A') return 0; - for (uint8_t pin = 0; pin < 127; pin++) { - if (pins[pin].analog_channel + '0' == channel[1]) { - return pins[pin].value; - } + uint8_t apin = std::stoul(channel.substr(1)); + uint8_t pin = apins[apin]; + if (pin < 128) { + return pins[pin].value; } return 0; } + // arg is analog pin ID void Base::reportAnalog(uint8_t channel, uint8_t enable) { uint8_t report_channel = FIRMATA_REPORT_ANALOG | channel; @@ -124,6 +133,11 @@ namespace firmata { standardCommand({ report_port, enable }); } + void Base::reportDigitalPin(uint8_t pin, uint8_t enable) + { + reportDigital(pin>>3, enable); + } + void Base::setSamplingInterval(uint32_t intervalms) { @@ -186,11 +200,9 @@ namespace firmata { if (msb > 0x7F) continue; // Why do we sometimes get only 1 data byte? value = FIRMATA_COMBINE_LSB_MSB(lsb, msb); - for (int pin = 0; pin < 128; pin++) { - if (pins[pin].analog_channel == channel) { - pins[pin].value = value; - break; - } + uint8_t pin = apins[channel]; + if (pin < 128) { + pins[pin].value = value; } i += 2; completed_commands++; @@ -244,12 +256,17 @@ namespace firmata { std::vector sysex_buffer; for (i = i + 2; i < parse_buffer.size() && parse_buffer[i] != FIRMATA_END_SYSEX; i++) { // Copy sysex and skip to next command + if (parse_buffer[i] > 127) { + // bad character, drop what we have so far and go back to parsing new command + sysex_buffer.clear(); + break; + } sysex_buffer.push_back(parse_buffer[i]); } if (i == parse_buffer.size()) { interrupted_command = true; } - else { + else if (!sysex_buffer.empty()) { handleSysex(subcommand, sysex_buffer); completed_commands++; last_completed = (whole_command << 8) | subcommand; @@ -293,18 +310,18 @@ namespace firmata { pins[pin].resolutions = {}; } - pin = 0; + m_numPins = 0; for (uint8_t byte : data) { if (byte == 127) { - pin++; + m_numPins++; is_mode_byte = true; } else if (is_mode_byte) { - pins[pin].supported_modes.push_back(byte); + pins[m_numPins].supported_modes.push_back(byte); is_mode_byte = false; } else { - pins[pin].resolutions.push_back(byte); + pins[m_numPins].resolutions.push_back(byte); is_mode_byte = true; } } @@ -322,6 +339,7 @@ namespace firmata { case(FIRMATA_ANALOG_MAPPING_RESPONSE) : for (pin = 0; pin < data.size(); pin++) { pins[pin].analog_channel = data[pin]; + apins[data[pin]] = pin; } return true; @@ -350,8 +368,11 @@ namespace firmata { std::string Base::stringFromBytes(std::vector::iterator begin, std::vector::iterator end) { std::string s; - for (auto byte = begin; byte < end - 1; ++byte) { - s += (*byte) | (*(++byte) << 7); + //for (auto byte = begin; byte < end - 1; ++byte) { + //s += (*byte) | (*(++byte) << 7); + //} + for (auto byte = begin; byte < end; ++byte) { + s+=(*byte); } return s; } @@ -362,7 +383,8 @@ namespace firmata { std::chrono::time_point start, current; start = std::chrono::system_clock::now(); std::chrono::duration timeoutDuration(timeout * 10000), elapsed; + std::chrono::system_clock::period> elapsed; + std::chrono::milliseconds timeoutDuration(timeout); uint8_t first_nibble = FIRMATA_FIRST_NIBBLE(command); uint16_t result; @@ -385,11 +407,13 @@ namespace firmata { bool succeeded = true; std::chrono::time_point start, current; start = std::chrono::system_clock::now(); - std::chrono::duration timeoutDuration(timeout * 10000), elapsed; + std::chrono::duration elapsed; + std::chrono::milliseconds timeoutDuration(timeout); uint16_t result, result_sysex, result_command; do { + usleep(1000); current = std::chrono::system_clock::now(); elapsed = current - start; if (elapsed > timeoutDuration) { @@ -407,6 +431,9 @@ namespace firmata { void Base::initPins() { + // clear analog pin mappings + memset(apins, sizeof(apins), 128); + for (int i = 0; i < 128; i++) { pins[i].mode = 255; pins[i].analog_channel = 127; @@ -414,6 +441,7 @@ namespace firmata { pins[i].resolutions = {}; pins[i].value = 0; } + m_numPins = 0; } void Base::reportFirmware() { @@ -446,4 +474,18 @@ namespace firmata { } } } + uint8_t Base::getPinCapResolution(uint8_t pin, uint8_t mode) const { + std::vector::const_iterator pm = pins[pin].supported_modes.begin(); + std::vector::const_iterator pr = pins[pin].resolutions.begin(); + while (pm !=pins[pin].supported_modes.end()) + { + if (*pm == mode) + { + return *pr; + } + ++pm; + ++pr; + } + return 0; + } } diff --git a/src/firmble.cpp b/src/firmble.cpp new file mode 100644 index 0000000..ab73796 --- /dev/null +++ b/src/firmble.cpp @@ -0,0 +1,959 @@ +#include "firmble.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include //for UUID. FIXME mofo +#include + +#include + +using namespace std; +using namespace chrono; +using namespace BLEPP; + +#define DBG(__x...) \ + if (s_debug) { \ + std::ostringstream __s; \ + __s << "DBG:" << syscall(SYS_gettid) << ":" << __FILE__ ":" << __LINE__ << ":" << __FUNCTION__ << ":" << __x << std::endl; \ + std::cerr <<__s.str(); \ + } + +#define DBGPKT(__d, __l) \ + if (s_debug) { \ + std::ostringstream __s; \ + __s << "PKT:" << syscall(SYS_gettid) << ":" << __FILE__ ":" << __LINE__ << ":" << __FUNCTION__ << ":" << __l << ":" << hex << setw(2) ; \ + auto __p = __d; \ + size_t __n = __l; \ + while (__n > 0) { \ + __s << " " << (unsigned int)(*__p); \ + --__n; \ + ++__p; \ + } \ + __s << std::endl; \ + std::cerr <<__s.str(); \ + } + +namespace { + // debug integration + int s_debug = 0; + + // time to shut down + bool s_shutdown = false; + + // local methods + + // main thread waits for signal + void wait_complete(int fd) + { + // wait for the event completion signal to be raised + DBG("waiting for "<(b); + ble->ble_thread_main(); + DBG("exit "< lock(m_rx_lock); + DBG(m_rx_buf.size() << " entries"); + return m_rx_bytes; + } + + // firmata read data + std::vector FirmBle::read(size_t size) + { + std::vector bytes; + DBG("size "< lock(m_rx_lock); + DBG(m_rx_buf.size() << " entries"); + + if (!m_rx_buf.empty()) + { + // concatenate all available packets + while (!m_rx_buf.empty()) + { + BLEPP::PDUNotificationOrIndication & p = m_rx_buf.front(); + const uint8_t* d = p.value().first; + size_t n = p.value().second - p.value().first; + if (n > size) { + DBG("no space left "< 0) { + bytes.push_back(*d); + --n; + ++d; + } + m_rx_buf.pop(); + } + m_rx_bytes = 0; + } + } + DBG("prepared result"); + + pthread_yield(); + + DBG("returning "< bytes) + { + // check for not connected + if (!m_connected) { + DBG("not connected"); + throw firmata::NotOpenException(); + } + DBGPKT(bytes.begin(),bytes.size()); + { + std::lock_guard lock(m_tx_lock); + m_tx_queue.push(bytes); + } + DBG("waiting"); + start_thread_and_wait(st_write); + pthread_yield(); + DBG("waited"); + } + + // firmata retrieve list of ports + std::vector FirmBle::listPorts(int maxTime /*seconds*/, int maxDevices) + { + firmata::FirmBle * ble = new firmata::FirmBle(maxTime); + DBG("entry, ble "<start_thread_and_wait(st_scan); + DBG("waited, "<m_portList.size()<<" entries"); + + // all done + std::vector ret = ble->m_portList; + delete ble; + DBG("done"); + return ret; + } + + ////////////////////////////////////////////////////////////// + // + // response handlers + + // scan results handler + void FirmBle::ble_handle_scan_result() + { + DBG("entry "< ads = m_scanner->get_advertisements(); + + for(const auto& ad: ads) + { + // if device under consideration is connectable + DBG("device "<name, "" + })); + break; + } + } + } else { + DBG("not connectable"); + } + } + DBG("valid devices: "<connect_nonblocking(m_port); + DBG("started connect"); + } + } + else + { + // normal client request, all done + //DBG("done"); + //wakeMain(); + // wait for timeout to complete scan + } + } + + // check remote characteristics during connect + void FirmBle::ble_connect_scan_result () + { + DBG("entry"); + //pretty_print_tree(m_gatt); + + // look thru reported services + characteristics to find + // firmata characteristics + for(auto& service: m_gatt->primary_services) + { + DBG("service"); + for(auto& characteristic: service.characteristics) + { + DBG(" characteristic: "<cb_notify_or_indicate = std::bind(&firmata::FirmBle::ble_rx,this, std::placeholders::_1); + m_gatt->cb_notify_or_indicate = std::bind(&firmata::FirmBle::ble_rx2,this, std::placeholders::_1, std::placeholders::_2); + try + { + ble_connected(); + } + catch (...) + { + DBG("caught"); + m_result = "Cannot connect"; + wakeMain(); + } + } + DBG("done"); + }; + + // device connected + void FirmBle::ble_connected () + { + DBG("entry"); + // enable notify + m_rx->set_notify_and_indicate(true, false); + DBG("done set_notify"); + // then set reporting interval to something a little slower + // than is normally used on a serial link + m_gatt->cb_write_response = std::bind(&firmata::FirmBle::ble_connect_reporting_set,this); + static unsigned char set_reporting_interval[] = { 0xf0, 0x7a, 0, 8, 0xf7 }; + try + { + DBG("sending set reporting interval"); + m_tx->write_request(set_reporting_interval, 5); + } + catch (...) + { + DBG("caught"); + m_result = "Failed to set reporting interval"; + wakeMain(); + } + DBG("done"); + } + + // device reporting interval is now set up + void FirmBle::ble_connect_reporting_set () + { + DBG("entry"); + // all done + // reinstate the write done handler + m_gatt->cb_write_response = std::bind(&firmata::FirmBle::ble_write_done,this); + m_result = ""; + // wake the caller + m_connected = true; + wakeMain(); + DBG("done"); + } + + // device disconnected + // could happen any time + void FirmBle::ble_disconnected (BLEPP::BLEGATTStateMachine::Disconnect d) + { + DBG("entry "<(m_tx_buff)); + if (m_tx_buff) + { + free(m_tx_buff); + m_tx_buff = nullptr; + wakeMain(); + } + DBG("done"); + } + + // data received from device + void FirmBle::ble_rx(const PDUNotificationOrIndication & p) { + size_t n = p.value().second - p.value().first; + DBG("entry "< lock(m_rx_lock); + // limit queue length + if (m_rx_buf.size() > s_max_queued_messages) { + // too many queued messages, drop the oldest + BLEPP::PDUNotificationOrIndication & p2 = m_rx_buf.front(); + m_rx_bytes -= p2.value().second - p2.value().first; + m_rx_buf.pop(); + } + m_rx_buf.push(p); + m_rx_bytes += n; + DBG("queue now "<(&r), 8); + // wait for tx ack + DBG("waiting"); + wait_complete(m_fdWakeMain); + DBG("done"); + if ((nothrow == false) && (m_result.size())) { + DBG("error "< lock(m_rx_lock); + DBG("waiting "<(&r), 8); + DBG("done"); + } + } + // ble thread completes a job and wakes main + void FirmBle::wakeMain() + { + DBG("entry"); + // prepare the return value + uint64_t r = 1; + jobDone(); + // wake the caller + ::write(m_fdWakeMain, reinterpret_cast(&r), 8); + DBG("done"); + } + + // ble thread write helper + void FirmBle::do_write() + { + DBG("entry"); + int i=0; + { + size_t bufsiz = 256; + m_tx_buff = reinterpret_cast(malloc(bufsiz)); + std::lock_guard lock(m_tx_lock); + DBG(m_tx_queue.size()<<" entries to send"); + while (!m_tx_queue.empty()) + { + std::vector & r = m_tx_queue.front(); + DBG(r.size()<<" bytes in buffer"); + for(auto& b: r) + { + m_tx_buff[i++]=b; + if (i > bufsiz) + { + DBG("reallocating at bufsiz"); + bufsiz *= 2; + m_tx_buff = reinterpret_cast(realloc(m_tx_buff, bufsiz)); + } + } + DBG("now have "<(m_tx_buff)); + DBGPKT(m_tx_buff,i); + m_tx->write_request(m_tx_buff, i); + } + + // ble thread + void FirmBle::ble_thread_main() + { + DBG("entry"); + + fd_set write_set, read_set; + bool finished = false; + while (finished == false) + { + struct timeval tv; + int result; + do + { + FD_ZERO(&read_set); + FD_ZERO(&write_set); + int fd_max = -1; + + if (m_gatt) { + if (m_gatt->socket() != -1) + { + //Reads are always a possibility due to asynchronus notifications. + DBG("adding gatt socket "<socket()<<" to read"); + FD_SET(m_gatt->socket(), &read_set); + if (m_gatt->socket() > fd_max) { + fd_max = m_gatt->socket(); + } + + //Writes are usually available, so only check for them when the + //state machine wants to write. + if(m_gatt->wait_on_write()) { + DBG("adding gatt socket "<socket()<<" to write"); + FD_SET(m_gatt->socket(), &write_set); + } + } else { + DBG("no gatt socket"); + } + } + + if (!m_active) { + // add event fd only if idle + DBG("adding main fd "< fd_max) { fd_max = m_fdWakeBle; } + } + + if (m_scanner != nullptr) { + // add scanner fd if required + DBG("adding scanner fd "<get_fd()); + FD_SET(m_scanner->get_fd(), &read_set); + if (m_scanner->get_fd() > fd_max) { fd_max = m_scanner->get_fd(); } + } + + // use the timer to limit scan completion + if (m_job == st_scan) + { + // delay time was set up at scan initiation + } else { + // wait for max 10 sec + tv.tv_sec = 10; + tv.tv_usec = 0; + } + result = select(fd_max+1, &read_set, &write_set, nullptr, &tv); + if (result >= 0) + { + break; + } + DBG("trying select again after "<socket() != -1) { + if(FD_ISSET(m_gatt->socket(), &write_set)) { + DBG("gatt write"); + m_gatt->write_and_process_next(); + } + + if(FD_ISSET(m_gatt->socket(), &read_set)) { + DBG("gatt read"); + m_gatt->read_and_process_next(); + } + } else { + DBG("no gatt socket"); + } + } + + if((m_scanner != nullptr) && (FD_ISSET(m_scanner->get_fd(), &read_set))) { + DBG("scanner"); + ble_handle_scan_result(); + } + + if(FD_ISSET(m_fdWakeBle, &read_set)) + { + DBG("wake, job "<cb_disconnected = std::bind(&firmata::FirmBle::ble_disconnected,this,std::placeholders::_1); + m_gatt->cb_connected = std::bind(&firmata::FirmBle::ble_connected,this); + m_gatt->setup_standard_scan(m_scancallback); + DBG("m_gatt "<connect_nonblocking(m_port); + } + m_active = true; + DBG("done"); + } + catch (...) + { + DBG("caught"); + // any error -> disconnect + if (m_gatt) + { + try + { + DBG("closing"); + m_gatt->close(); + } + catch (...) + { + DBG("caught"); + } + m_active = false; + } + wakeMain(); + } + DBG("finished"); + break; + + case st_disc: // initiate disconnect + // stop any scanner that is running + if (m_scanner) + { + try + { + m_scanner->stop(); + DBG("stopped scanner"); + } + catch (...) + { + DBG("caught"); + } + delete m_scanner; + m_scanner = nullptr; + } + + if (m_gatt) + { + try + { + // TODO send reset or at least stop events + DBG("closing"); + if (m_gatt != nullptr) + { + m_gatt->close(); + } + } + catch (...) + { + DBG("caught"); + } + } + // disconnect appears instant + if ((m_scanner == nullptr) && (m_gatt == nullptr || m_gatt->socket() == -1)) + { + DBG("connection is now inactive"); + m_active = false; + wakeMain(); + } + DBG("done"); + break; + + case st_write: // send data + try + { + do_write(); + m_active = true; + } + catch (...) + { + DBG("caught"); + wakeMain(); + } + DBG("done"); + break; + + case st_stop: // all done + m_active = false; + if (m_scanner) + { + try + { + m_scanner->stop(); + DBG("stopped scanner"); + } + catch (...) + { + DBG("caught"); + } + delete m_scanner; + m_scanner = nullptr; + } + if (m_gatt) + { + try + { + m_gatt->close(); + DBG("closed gatt"); + } + catch (...) + { + DBG("caught"); + } + delete m_gatt; + m_gatt = nullptr; + } + if (m_tx_buff) + { + free(m_tx_buff); + m_tx_buff = nullptr; + } + finished = true; + DBG("done"); + wakeMain(); + break; + } + } + + } // end of main loop + } // end of thread main +} // end namespace + + + +#if 0 +//cout << "state "<cb_notify_or_indicate = notify_cb; + m_gatt.cb_notify_or_indicate = notify_cb2; + rx->set_notify_and_indicate(true, false); + } + break; + + case 2: // setting notify + if (m_gatt.is_idle()) { + cout << endl; + ++state; + } else { + break; + } + + case 3: // set reporting interval + { + unsigned char enable[] = { 0xf0, 0x7a, 0, 8, 0xf7 }; + tx->write_request(enable, 5); + } + ++state; + break; + + case 4: // setting reporting interval + if (m_gatt.is_idle()) { + cout << endl; + ++state; + } else { + break; + } + + case 5: // notify set + { + unsigned char enable[2] = { 0xc0, 0x01 }; + tx->write_request(enable, 2); + } + ++state; + break; + + case 6: // enabling reporting + if (m_gatt.is_idle()) { + cout << endl; + ++state; + } else { + break; + } + + case 7: // reporting enabled + if (tx == nullptr) { + cerr << "no tx characteristic found" << endl; + exit(1); + } + cout << endl; + ++state; +} +#endif diff --git a/vendor/libblepp-master.patch b/vendor/libblepp-master.patch new file mode 100644 index 0000000..5a5d058 --- /dev/null +++ b/vendor/libblepp-master.patch @@ -0,0 +1,57 @@ +--- ../libblepp-master.orig/Makefile.in 2017-03-06 16:13:49.000000000 +0000 ++++ Makefile.in 2017-07-29 21:22:54.740176669 +0100 +@@ -88,14 +88,14 @@ + install: install-so install-a install-hdr install-pkgconfig + + +-install-a: $(archive) ++install-a: $(archive) | $(if $(wildcard $(lib)),,$(lib)) + cp $(archive) $(lib) + +-install-so: $(soname) $(soname1) $(soname2) ++install-so: $(soname) $(soname1) $(soname2) | $(if $(wildcard $(lib)),,$(lib)) + cp $(soname) $(soname1) $(soname2) $(lib) + +-install-hdr: +- cp -r blepp $(hdr) ++install-hdr: | $(if $(wildcard $(hdr)),,$(hdr)) ++ cp -r $(srcdir)/blepp $(hdr) + + install-pkgconfig: + [ "$(pkgconfig)" = "" ] || mkdir -p $(DESTDIR)$(pkgconfig) +@@ -108,7 +108,7 @@ + + + #Every .cc file in the tests directory is a test +-TESTS=$(notdir $(basename $(wildcard tests/*.cc))) ++TESTS=$(notdir $(basename $(wildcard $(srcdir)/tests/*.cc))) + + + #Get the intermediate file names from the list of tests. +@@ -137,12 +137,12 @@ + + #Build a test executable from a test program. On compile error, + #create an executable which declares the error. +-tests/%.test: tests/%.cc $(LIBOBJS) ++tests/%.test: tests/%.cc $(LIBOBJS) | $(if $(wildcard tests),,tests) + $(CXX) $(CXXFLAGS) $^ -o $@ -I . $(LDFLAGS) $(LOADLIBES) || { echo "echo 'Compile error!' ; return 126" > $@ ; chmod +x $@; } + + #Run the program and either use it's output (it should just say OK) + #or a failure message +-tests/%.result_: tests/%.test ++tests/%.result_: tests/%.test | $(if $(wildcard tests),,tests) + $< > $@ 2>&1 ; \ + a=$$? ;\ + if [ $$a != 0 ]; \ +@@ -169,7 +169,11 @@ + + include .deps + ++$(LIBOBJS): $(foreach d,$(sort $(dir $(LIBOBJS))),$(if $(wildcard $d),,$d)) ++tests/results: $(if $(wildcard tests),,tests) + ++tests $(sort $(dir $(LIBOBJS))) $(lib) $(hdr): ++ mkdir -p $@ + + + diff --git a/vendor/libblepp-master/.gitignore b/vendor/libblepp-master/.gitignore new file mode 100644 index 0000000..a7a80d6 --- /dev/null +++ b/vendor/libblepp-master/.gitignore @@ -0,0 +1,17 @@ +*.sw? +*.o +core +bluez-tools/ +prog +lescan +temperature +Makefile +*.so.* +*.so +*.pc +config.log +config.status +autom4te.cache +.deps +tests/*.result* +tests/*.test diff --git a/vendor/libblepp-master/ATT.txt b/vendor/libblepp-master/ATT.txt new file mode 100644 index 0000000..e6de889 --- /dev/null +++ b/vendor/libblepp-master/ATT.txt @@ -0,0 +1,186 @@ +Haskell Notation +---------------- + +I've used Haskell style notation. Functions, dictionaries and arrays are +essentially similar in that both map an input to an output, i.e. A -> B. +Tuples are indicated with "," and "()". Returned lists or arrays with []. +Alternatives are indicated with |. For arguments, The type is written first, and +the name (if applicable) follows after a "." . + + +Attributes +---------- + +The device contains an array of attributes. The index of tha attributes in known +as the handle. The attributes themselves consist of a "type" and a "value". The +type is a type code and is represented as a UUID. UUIDs are either 16 or 128 +bits long. 16 bit UUIDs are converted to proper 128 bit UUID by setting the +remaining 112 bits to some fixed values. The purpose of 16 bit UUIDs is to save +on bandwidth. + +Every attribute must have a type. The value is just plain old data (a bunch of +bytes) and may be readable or writable[*] or neither. The read/write status of +an attribute is defined by a higher level protocol and there is no way of +querying this. + +[*] The data may be also indicatable or notifiable. In these cases, the +bluetooth device (the server) may send the attribute values back to the client +at any time without solicitation. + +So, in essence the server has an array of: +[ (Handle, Type, Data | Null)] + +Being an array, one can naturally index it using Handle. In some cases however +it is also possible to index it by the Type in some cases. + +There are various function for extracting information from the server: + +find_information: [(Handle, Type)] + +This gets a list of attributes back from the server as the handel and type. The +data can be read from an attribute in one of two ways: + +read: Handle->Data | Error + +which reads the data from a given handle. Alternatively, data can be read by the +Type: + +read_by_type: Type -> [(Handle | Data)] + +Since several attributes may share a type (and often do), read_by_type must be +able to return a of attributes. Since the type is known, all it has to give back +is the Handle and the data. + +Naturally, there exist commands for writing too. + + +There is also a concept of Grouping as well. A group is a contiguous set of +attributes (contiguous according to the handle). Groups can be read by their +type. Groups are delimited by attributes of the specified type. A sample set of +attributes, as [(Handle, Type, Data)] follows. Note that the Types and data are +Arbitrary. If the group type is specified to be 0xdead, then thr grouping +appears as: + +0001 dead some data \ +0002 2a00 xxxxx | First group +0003 5600 xxxxxxxx /_________________ +0004 dead more data \ +0005 1234 xxxxxxx | Second group +0006 4567 xxxxxxxx | +0007 1231 xxxxx /_________________ +0008 dead another datum \ Third group +0009 wtf / +EOF + +The command to read this is: + +read_by_group_type Type->[(Handle, Handle, Data)] + +where, the start and end handle along with the data for the start handle is +returned, so in this case + +read_by_group_type(dead) will return: + +0001 0003 "some data" +0005 0007 "more data" +0008 ffff "another datum" + +ffff being the highest possible handle number indicates that nothing can follow. + +It would appear that in the absence of efficiency concerns, one could replicate +all the functions by queryiing every attribute with find_information and then +reading whichever handles are necessary with read. + +Actually reading data +--------------------- + +The BLE packet length is a mere 23 bytes. Optionally both devices may be able to +lengthen it, but this is not normally supported. + +In practice each query can only be answered with a very limited amount of data. +Note that each of the functions above (except read) returns a list of handles. +In the protocol, each function actually takes a start and end handle as an +argument which limits which handles will be returned. In order to get a complete +list of things, one must keep setting the start handle to one plus the last +handle returned and reissuing the call. When no handles can be returned an error +message is sent back, indicating that no handles exist in the range. + +The read_by_type function is actually more like: + +read_by_type: (Type, Handle.first, Handle.last) -> [ (Handle, Data) ] | Error.no_attribute_in_range + + + + +The Generic Attribute Profile +----------------------------- + +The generic attribute (GATT) profile defines a standard set of attributes, +types and groups along with mechanisms for discovery. + +A GATT profile consists of a number of services. A service defines a set of +"characteristics". A characteristic pas properties (e.g. readable, writable), +a value and zero or more descriptors (e.g. some textual description). + +Primary services are groups of handles which have the name <> +aka 0x2800. Therefore + read_group_by_type(0x2800) +returns the list of services. Any handle falling in the the group belongs to +the service named by that group. The names are either ones specified by the SIG +or custom ones. + +Within each service there is a list of characteristics. Each characteristic +contains a group of handles. However, it is not possible to use +read_by_group_type on <> (aka 2803), since characteristic groups +are terminated either by the presence of the next characteristic or by the next +service. Recall that read_by_group_type insists that the delimiter must be the +type. + + +A characteristic consists of: + +* a characteristic definition (Type <>) + which includes the Type of the characteristic, the handle of the + characteristic value and some miscellaneous flags. + +* A characteristic value. Naturally, this has the Type of the characteristic. + The value may not actually be readable, or writable. For example the value + might only be pushed to the client via notifications. + +* Additional descriptors. The descriptors contain miscellaneous extra + information about the characteristic. The descriptors have a Type which + declares the semantic meaning of the descriptor. The meaning of the data is + naturally dependent on the Type. + + Common descriptors are: + + <> (2901) Some text describing the + characteristic. + + <> (2902) A write only attribute that is + written to enable and disable notifications and indications on thr + characteristic value. + + There are others too. + + + +The list of characteristics can be read by reading type <> aka 2803. + read_by_type 0x2803 +The return from this is for each characteristic: + + + +Property is a bit field indicating various properties, things like readable, +writable, notifyable, and so on. + +Two services must always be present: <> (aka 1800) and <> (aka 1801) + + +If a characteristic value is readable, it is indicated by the property. Also, +the value will have handle and type . It can be read by reading +the handle or reading by it's type. In other words and are +(nearly?) tautological. + + diff --git a/vendor/libblepp-master/COPYING b/vendor/libblepp-master/COPYING new file mode 100644 index 0000000..139aa9a --- /dev/null +++ b/vendor/libblepp-master/COPYING @@ -0,0 +1,54 @@ +This project has multiple authors and multiple licenses. Please +refer to the indivdial files for specific conditions. + +Copyright (c) 2013 Edward Rosten + +/* + * + * libattgatt - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + + +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + diff --git a/vendor/libblepp-master/Makefile.in b/vendor/libblepp-master/Makefile.in new file mode 100644 index 0000000..bc9ba1d --- /dev/null +++ b/vendor/libblepp-master/Makefile.in @@ -0,0 +1,175 @@ +#Standard boilerplate +prefix = @prefix@ +exec_prefix = @exec_prefix@ +mandir = @mandir@ +includedir = @includedir@ +datarootdir = @datarootdir@ +pkgconfig = @PKGCONFIG_LIBDIR@ +srcdir = @srcdir@ +libdir=@libdir@ +LOADLIBES = @LIBS@ + +vpath %.cc $(srcdir) + +ifneq "$(DESTDIR)" "" +DESTDIR+=/ +endif + +CXX=@CXX@ +LD=@CXX@ +CXXFLAGS=@CXXFLAGS@ -I$(srcdir) +LDFLAGS=@LDFLAGS@ + +hdr = $(DESTDIR)$(includedir)/ +lib = $(DESTDIR)$(libdir)/ + + +LIBOBJS=src/att.o src/uuid.o src/bledevice.o src/att_pdu.o src/pretty_printers.o src/blestatemachine.o src/float.o src/logging.o src/lescan.o + +PROGS=lescan blelogger bluetooth lescan_simple temperature + +.PHONY: all clean testclean install lib progs test doc install-so install-a install-hdr install-pkgconfig + +all: lib progs test doc + +lib: $(soname) $(archive) +progs:$(PROGS) + + +clean: testclean + rm -f $(PROGS) *.o src/*.o *.so.* *.so +testclean: + rm -f tests/*.result tests/*.test tests/*.result_ + + + +doc: + + +archive=libble++.a +soname=libble++.so +soname1=libble++.so.0 +soname2=libble++.so.0.5 +set_soname=-Wl,-soname,libble++.so.0 + +$(soname2): $(LIBOBJS) + $(LD) -shared -o $(soname2) $(LIBOBJS) $(LDFLAGS) $(LOADLIBES) + +$(soname1): $(soname2) + rm -f $(soname1) + ln -s $(soname2) $(soname1) + +$(soname): $(soname1) + rm -f $(soname) + ln -s $(soname1) $(soname) + +$(archive): $(LIBOBJS) + ar crvs $(archive) $(LIBOBJS) + ranlib $(archive) + +$(PROGS):$(soname) + +lescan: lescan.o + $(LD) -o $@ $< -L. -lble++ + + +lescan_simple: lescan_simple.o + $(LD) -o $@ $< -L. -lble++ + +temperature: temperature.o + $(LD) -o $@ $< -L. -lble++ + +blelogger: blelogger.o + $(LD) -o $@ $< -L. -lble++ + +bluetooth: bluetooth.o + $(LD) -o $@ $< -L. -lble++ + +install: install-so install-a install-hdr install-pkgconfig + + +install-a: $(archive) + cp $(archive) $(lib) + +install-so: $(soname) $(soname1) $(soname2) + cp $(soname) $(soname1) $(soname2) $(lib) + +install-hdr: + cp -r blepp $(hdr) + +install-pkgconfig: + [ "$(pkgconfig)" = "" ] || mkdir -p $(DESTDIR)$(pkgconfig) + [ "$(pkgconfig)" = "" ] || cp libblepp.pc $(DESTDIR)$(pkgconfig)/ + + + +docs: + doxygen + + +#Every .cc file in the tests directory is a test +TESTS=$(notdir $(basename $(wildcard tests/*.cc))) + + +#Get the intermediate file names from the list of tests. +TEST_RESULT=$(TESTS:%=tests/%.result) + + +# Don't delete the intermediate files, since these can take a +# long time to regenerate +.PRECIOUS: tests/%.result_ tests/%.test + +test:tests/results + +#We don't want this file hanging around on failure since we +#want the build depend on it. If we leave it behing then typing make +#twice in a row will suceed, since make will find the file and not try +#to rebuild it. +.DELETE_ON_ERROR: tests/results + +tests/results:$(TEST_RESULT) + cat $(TEST_RESULT) > tests/results + @echo -------------- Test Results --------------- + @cat tests/results + @echo ------------------------------------------- + @ ! grep -qv OK tests/results + + +#Build a test executable from a test program. On compile error, +#create an executable which declares the error. +tests/%.test: tests/%.cc $(LIBOBJS) + $(CXX) $(CXXFLAGS) $^ -o $@ -I . $(LDFLAGS) $(LOADLIBES) || { echo "echo 'Compile error!' ; return 126" > $@ ; chmod +x $@; } + +#Run the program and either use it's output (it should just say OK) +#or a failure message +tests/%.result_: tests/%.test + $< > $@ 2>&1 ; \ + a=$$? ;\ + if [ $$a != 0 ]; \ + then \ + if [ $$a -ge 128 ] ; \ + then \ + echo Crash!! > $@ ; \ + elif [ $$a -ne 126 ] ;\ + then \ + echo Failed > $@ ; \ + fi;\ + else\ + echo OK >> $@;\ + fi + +tests/%.result: tests/%.result_ + echo $*: `tail -1 $<` > $@ + +#Get the C style dependencies working. Note we need to massage the test dependencies +#to make the filenames correct +.deps: + rm -f .deps .sourcefiles + find . -name "*.cc" | xargs -IQQQ $(CXX) $(CXXFLAGS) -MM -MG QQQ | sed -e'/test/s!\(.*\)\.o:!tests/\1.test:!' > .deps + +include .deps + + + + + diff --git a/vendor/libblepp-master/Notes.txt b/vendor/libblepp-master/Notes.txt new file mode 100644 index 0000000..a832d3e --- /dev/null +++ b/vendor/libblepp-master/Notes.txt @@ -0,0 +1,115 @@ +My adventures in bluetooth with the BLE112 devkit. + +Note, my machine is called "sheepfrog" http://en.wikipedia.org/wiki/Sheep_frog + +Get list of adapters: + +$bt-adapter -l +Available adapters: +sheepfrog-0 (88:9F:FA:EC:27:8F) +sheepfrog-1 (00:02:72:3E:A5:07) + + +bt-adapter uses DBUS/GObject interface to bluez and is so far impenetrable. + +Not yet found libbluetooth C API call which does this. Kernel call exists, but not C API? + + +Find device: + +$bt-adapter -a sheepfrog-1 -d +Searching... + +[3C:2D:B7:85:50:2A] + Name: DKBLE112 thermometer + Alias: DKBLE112 thermometer + Address: 3C:2D:B7:85:50:2A + +(bt-adapter:31979): GLib-GObject-CRITICAL **: g_value_get_string: assertion `G_VALUE_HOLDS_STRING (value)' failed + Icon: (null) + Class: 0x0 + LegacyPairing: 0 + Paired: 0 + RSSI: -68 + +[7C:E9:D3:E4:3F:7C] + Name: LAWRENCE-THINK + Alias: LAWRENCE-THINK + Address: 7C:E9:D3:E4:3F:7C + Icon: computer + Class: 0x3e010c + LegacyPairing: 0 + Paired: 0 + RSSI: -88 + +Done + + +Or, alternatively, use hcitool: + +hcitool -i hci1 scan + +does not work (why?). Whereas: + +$ sudo hcitool lescan +LE Scan ... +3C:2D:B7:85:50:2A (unknown) +3C:2D:B7:85:50:2A DKBLE112 thermometer + + +For some reason only lescan picks up BLE devices. Also, lescan knows which +device to use (presumably because only one of my adapters supports BLE, so it +skips over the first one??). Also for some reason, root is needed to initiate LE +scan. + + +Now to connect: +(I for interactive mode). Anything before > is the prompt. # are my comments + +$ gatttool -b 3C:2D:B7:85:50:2A -I +[ ][3C:2D:B7:85:50:2A][LE]> connect +[CON][3C:2D:B7:85:50:2A][LE]> +# From here: +# http://stackoverflow.com/questions/15657007/bluetooth-low-energy-listening-for-notifications-indications-in-linux +# Then type char-read-uuid 2902. You should get a list of all CCC (Client +# Characteristic Configuration) attributes on the device +# see also http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml +# +[CON][3C:2D:B7:85:50:2A][LE]> char-read-uuid 2902 +[CON][3C:2D:B7:85:50:2A][LE]> +handle: 0x0012 value: 00 00 +[CON][3C:2D:B7:85:50:2A][LE]> +#Switch on indications... +[CON][3C:2D:B7:85:50:2A][LE]> char-write-cmd 12 0200 +Indication handle = 0x0010 value: 00 2f 01 00 ff +Indication handle = 0x0010 value: 00 2f 01 00 ff +Indication handle = 0x0010 value: 00 2f 01 00 ff +Indication handle = 0x0010 value: 00 31 01 00 ff +# 2f 01, 31 01 is temperature in degrees C / 10 in little endian order. i.e. +# x2f + xff*x1 = d303 i.e. 30.3 degrees C. + + + +Ah ha! +https://www.bluetooth.org/en-us/specification/assigned-numbers-overview/generic-attribute-profile +Magic number 2902 is the "client characteristic specification" + + +More docs: +http://developer.bluetooth.org/TechnologyOverview/Pages/BLE.aspx + +So, it seems that Generic Attribute Profile (GATT) is the way of communicating +with BLE devices. Or at least it's a standard way of doing it. Presumably one +could use lower layers, but that's making life hard. I won't try. Actually, +apparently GATT and ATT are mandatory in BLE. + +Documents about the generic attribute profile are here: + +http://developer.bluetooth.org/TechnologyOverview/Pages/GATT.aspx + + + + + + + diff --git a/vendor/libblepp-master/README b/vendor/libblepp-master/README new file mode 100644 index 0000000..22d0c8e --- /dev/null +++ b/vendor/libblepp-master/README @@ -0,0 +1,32 @@ +libble++ +--------- + +Implementation of Bluetooth Low Energy functions in modern C++, without +the BlueZ DBUS API. + +Includes: +* Scanning for bluetooth packets + +* Implmentation of the GATT profile and ATT protocol + +* Lots of comments, complete with references to to the specific part og + the Bluetooth 4.0 standard. + +* Example programs + +Design: + +Clean, modern C++ with callbacks. Feed it lambdas (or whatever you like) +to perform an event happens. Access provided to the raw socket FD, so +you can select(), poll() or use blocking IO. + + + +The example programs are: + +* lescan_simple: Simplest possible program for scanning for devices. Only 2 non boilerplate lines. + +* lescan: A "proper" scanning program that cleans up properly. It's got the same 2 lines of BLE related code and a bit of pretty standard unix for dealing with non blocking I/O and signals. + +* temperature: A program for logging temperature values from a device providing a standard temperature characteristic. Very short to indicate the usave, but not much error checking. + diff --git a/vendor/libblepp-master/att_gatt.h b/vendor/libblepp-master/att_gatt.h new file mode 100644 index 0000000..1ab3c2e --- /dev/null +++ b/vendor/libblepp-master/att_gatt.h @@ -0,0 +1,41 @@ +/* + * + * libattgatt - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __INC_LIBATTGATT_PRETTY_PRINTERS_H +#define __INC_LIBATTGATT_PRETTY_PRINTERS_H + +#include "lib/uuid.h" +#include +#include +#include +std::string to_hex(const std::uint16_t& u); +std::string to_hex(const std::uint8_t& u); +std::string to_str(const std::uint8_t& u); +std::string to_str(const bt_uuid_t& uuid); +std::string to_hex(const std::uint8_t* d, int l); +std::string to_hex(pair d); +std::string to_hex(const std::vector& v); +std::string to_str(const std::uint8_t* d, int l); +std::string to_str(pair d); +std::string to_str(pair d); +std::string to_str(const std::vector& v); +#endif diff --git a/vendor/libblepp-master/blelogger.cc b/vendor/libblepp-master/blelogger.cc new file mode 100644 index 0000000..b01169b --- /dev/null +++ b/vendor/libblepp-master/blelogger.cc @@ -0,0 +1,96 @@ +/* + * + * libattgatt - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +#include +#include +#include +#include +#include +using namespace std; +using namespace chrono; +using namespace BLEPP; + +//////////////////////////////////////////////////////////////////////////////// +// +// This program demonstrates the use of the library +// +int main(int argc, char **argv) +{ + if(argc != 2 && argc != 3) + { + cerr << "Please supply address.\n"; + cerr << "Usage:\n"; + cerr << "prog address [nonblocking]\n"; + exit(1); + } + + log_level = Info; + + + BLEGATTStateMachine gatt; + + + std::function notify_cb = [&](const PDUNotificationOrIndication& n) + { + auto ms_since_epoch = duration_cast(system_clock::now().time_since_epoch()); + const uint8_t* d = n.value().first; + int emg = ((0+d[1] *256 + d[0])>>0) ; + + int volt = ((0+d[7] *256 + d[6])>>0) ; + double v=-1; + + if(volt != 0x8000) + v = volt / 1000.0; + + cout << setprecision(15) << ms_since_epoch.count()/1000. << " " << emg << " " << v << endl; + }; + + + std::function cb = [&gatt, ¬ify_cb](){ + pretty_print_tree(gatt); + + for(auto& service: gatt.primary_services) + for(auto& characteristic: service.characteristics) + if(characteristic.uuid == UUID("53f72b8c-ff27-4177-9eee-30ace844f8f2")) + { + characteristic.cb_notify_or_indicate = notify_cb; + characteristic.set_notify_and_indicate(true, false); + } + }; + + gatt.cb_disconnected = [](BLEGATTStateMachine::Disconnect d) + { + cerr << "Disconnect for reason " << BLEGATTStateMachine::get_disconnect_string(d) << endl; + exit(1); + }; + + + gatt.setup_standard_scan(cb); + + + //This is how to use the blocking interface. It is very simple. + gatt.connect_blocking(argv[1]); + for(;;) + gatt.read_and_process_next(); + +} diff --git a/vendor/libblepp-master/blepp/att.h b/vendor/libblepp-master/blepp/att.h new file mode 100644 index 0000000..e86d4ac --- /dev/null +++ b/vendor/libblepp-master/blepp/att.h @@ -0,0 +1,323 @@ +/* + * + * blepp - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +namespace BLEPP +{ + + /* New style defs */ +#define LE_ATT_CID 4 //Spec 4.0 G.5.2.2 +#define ATT_DEFAULT_MTU 23 //Spec 4.0 G.5.2.1 + +#define GATT_UUID_PRIMARY 0x2800 +#define GATT_CHARACTERISTIC 0x2803 +#define GATT_CLIENT_CHARACTERISTIC_CONFIGURATION 0x2902 +#define GATT_CHARACTERISTIC_FLAGS_BROADCAST 0x01 +#define GATT_CHARACTERISTIC_FLAGS_READ 0x02 +#define GATT_CHARACTERISTIC_FLAGS_WRITE_WITHOUT_RESPONSE 0x04 +#define GATT_CHARACTERISTIC_FLAGS_WRITE 0x08 +#define GATT_CHARACTERISTIC_FLAGS_NOTIFY 0x10 +#define GATT_CHARACTERISTIC_FLAGS_INDICATE 0x20 +#define GATT_CHARACTERISTIC_FLAGS_AUTHENTICATED_SIGNED_WRITES 0x40 +#define GATT_CHARACTERISTIC_FLAGS_EXTENDED_PROPERTIES 0x80 + + + /* Attribute Protocol Opcodes */ +#define ATT_OP_ERROR 0x01 +#define ATT_OP_MTU_REQ 0x02 +#define ATT_OP_MTU_RESP 0x03 +#define ATT_OP_FIND_INFO_REQ 0x04 +#define ATT_OP_FIND_INFO_RESP 0x05 +#define ATT_OP_FIND_BY_TYPE_REQ 0x06 +#define ATT_OP_FIND_BY_TYPE_RESP 0x07 +#define ATT_OP_READ_BY_TYPE_REQ 0x08 +#define ATT_OP_READ_BY_TYPE_RESP 0x09 +#define ATT_OP_READ_REQ 0x0A +#define ATT_OP_READ_RESP 0x0B +#define ATT_OP_READ_BLOB_REQ 0x0C +#define ATT_OP_READ_BLOB_RESP 0x0D +#define ATT_OP_READ_MULTI_REQ 0x0E +#define ATT_OP_READ_MULTI_RESP 0x0F +#define ATT_OP_READ_BY_GROUP_REQ 0x10 +#define ATT_OP_READ_BY_GROUP_RESP 0x11 +#define ATT_OP_WRITE_REQ 0x12 +#define ATT_OP_WRITE_RESP 0x13 +#define ATT_OP_WRITE_CMD 0x52 +#define ATT_OP_PREP_WRITE_REQ 0x16 +#define ATT_OP_PREP_WRITE_RESP 0x17 +#define ATT_OP_EXEC_WRITE_REQ 0x18 +#define ATT_OP_EXEC_WRITE_RESP 0x19 +#define ATT_OP_HANDLE_NOTIFY 0x1B +#define ATT_OP_HANDLE_IND 0x1D +#define ATT_OP_HANDLE_CNF 0x1E +#define ATT_OP_SIGNED_WRITE_CMD 0xD2 + + /* Error codes for Error response PDU */ +#define ATT_ECODE_INVALID_HANDLE 0x01 +#define ATT_ECODE_READ_NOT_PERM 0x02 +#define ATT_ECODE_WRITE_NOT_PERM 0x03 +#define ATT_ECODE_INVALID_PDU 0x04 +#define ATT_ECODE_AUTHENTICATION 0x05 +#define ATT_ECODE_REQ_NOT_SUPP 0x06 +#define ATT_ECODE_INVALID_OFFSET 0x07 +#define ATT_ECODE_AUTHORIZATION 0x08 +#define ATT_ECODE_PREP_QUEUE_FULL 0x09 +#define ATT_ECODE_ATTR_NOT_FOUND 0x0A +#define ATT_ECODE_ATTR_NOT_LONG 0x0B +#define ATT_ECODE_INSUFF_ENCR_KEY_SIZE 0x0C +#define ATT_ECODE_INVAL_ATTR_VALUE_LEN 0x0D +#define ATT_ECODE_UNLIKELY 0x0E +#define ATT_ECODE_INSUFF_ENC 0x0F +#define ATT_ECODE_UNSUPP_GRP_TYPE 0x10 +#define ATT_ECODE_INSUFF_RESOURCES 0x11 + /* Application error */ +#define ATT_ECODE_IO 0x80 +#define ATT_ECODE_TIMEOUT 0x81 +#define ATT_ECODE_ABORTED 0x82 + + /* Characteristic Property bit field */ +#define ATT_CHAR_PROPER_BROADCAST 0x01 +#define ATT_CHAR_PROPER_READ 0x02 +#define ATT_CHAR_PROPER_WRITE_WITHOUT_RESP 0x04 +#define ATT_CHAR_PROPER_WRITE 0x08 +#define ATT_CHAR_PROPER_NOTIFY 0x10 +#define ATT_CHAR_PROPER_INDICATE 0x20 +#define ATT_CHAR_PROPER_AUTH 0x40 +#define ATT_CHAR_PROPER_EXT_PROPER 0x80 + +#define ATT_MAX_VALUE_LEN 512 +#define ATT_DEFAULT_L2CAP_MTU 48 +#define ATT_DEFAULT_LE_MTU 23 + +#define ATT_CID 4 +#define ATT_PSM 31 + + /* Flags for Execute Write Request Operation */ +#define ATT_CANCEL_ALL_PREP_WRITES 0x00 +#define ATT_WRITE_ALL_PREP_WRITES 0x01 + + /* Find Information Response Formats */ +#define ATT_FIND_INFO_RESP_FMT_16BIT 0x01 +#define ATT_FIND_INFO_RESP_FMT_128BIT 0x02 + + struct att_data_list { + uint16_t num; + uint16_t len; + uint8_t **data; + }; + + struct att_range { + uint16_t start; + uint16_t end; + }; + + /* These functions do byte conversion */ + static inline uint8_t att_get_u8(const void *ptr) + { + const uint8_t *u8_ptr = (const uint8_t *) ptr; + return bt_get_unaligned(u8_ptr); + } + + static inline uint16_t att_get_u16(const void *ptr) + { + const uint16_t *u16_ptr = (const uint16_t*) ptr; + return btohs(bt_get_unaligned(u16_ptr)); + } + + static inline uint32_t att_get_u32(const void *ptr) + { + const uint32_t *u32_ptr = (const uint32_t*) ptr; + return btohl(bt_get_unaligned(u32_ptr)); + } + + static inline uint128_t att_get_u128(const void *ptr) + { + //it's an array and always little endian + const uint128_t *u128_ptr =(const uint128_t*) ptr; + return *u128_ptr; + } + + static inline void att_put_u8(uint8_t src, void *dst) + { + bt_put_unaligned(src, (uint8_t *) dst); + } + + static inline void att_put_u16(uint16_t src, void *dst) + { + bt_put_unaligned(htobs(src), (uint16_t *) dst); + } + + static inline void att_put_u32(uint32_t src, void *dst) + { + bt_put_unaligned(htobl(src), (uint32_t *) dst); + } + + static inline void att_put_u128(uint128_t src, void *dst) + { + //it's an array and always little endian + uint128_t *d128 = (uint128_t*)dst; + *d128 = src; + } + + static inline void att_put_uuid16(bt_uuid_t src, void *dst) + { + att_put_u16(src.value.u16, dst); + } + + static inline void att_put_uuid128(bt_uuid_t src, void *dst) + { + att_put_u128(src.value.u128, dst); + } + + static inline void att_put_uuid(bt_uuid_t src, void *dst) + { + if (src.type == BT_UUID16) + att_put_uuid16(src, dst); + else + att_put_uuid128(src, dst); + } + + static inline bt_uuid_t att_get_uuid16(const void *ptr) + { + bt_uuid_t uuid; + + bt_uuid16_create(&uuid, att_get_u16(ptr)); + + return uuid; + } + + static inline bt_uuid_t att_get_uuid128(const void *ptr) + { + bt_uuid_t uuid; + uint128_t value; + + value = att_get_u128(ptr); + bt_uuid128_create(&uuid, value); + + return uuid; + } + + struct att_data_list *att_data_list_alloc(uint16_t num, uint16_t len); + + + void att_data_list_free(struct att_data_list *list); + const char* att_op2str(uint8_t op); + const char *att_ecode2str(uint8_t status); + uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, + uint8_t *pdu, size_t len); + uint16_t dec_read_by_grp_req(const uint8_t *pdu, size_t len, uint16_t *start, + uint16_t *end, bt_uuid_t *uuid); + uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu, + size_t len); + uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, + const uint8_t *value, size_t vlen, uint8_t *pdu, + size_t len); + uint16_t dec_find_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start, + uint16_t *end, bt_uuid_t *uuid, uint8_t *value, size_t *vlen); + //uint16_t enc_find_by_type_resp(GSList *ranges, uint8_t *pdu, size_t len); + //GSList *dec_find_by_type_resp(const uint8_t *pdu, size_t len); + struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, size_t len); + uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, + uint8_t *pdu, size_t len); + uint16_t dec_read_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start, + uint16_t *end, bt_uuid_t *uuid); + uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu, + size_t len); + uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, size_t vlen, + uint8_t *pdu, size_t len); + uint16_t dec_write_cmd(const uint8_t *pdu, size_t len, uint16_t *handle, + uint8_t *value, size_t *vlen); + struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, size_t len); + uint16_t enc_write_req(uint16_t handle, const uint8_t *value, size_t vlen, + uint8_t *pdu, size_t len); + uint16_t dec_write_req(const uint8_t *pdu, size_t len, uint16_t *handle, + uint8_t *value, size_t *vlen); + uint16_t enc_write_resp(uint8_t *pdu, size_t len); + uint16_t dec_write_resp(const uint8_t *pdu, size_t len); + uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, size_t len); + uint16_t enc_read_blob_req(uint16_t handle, uint16_t offset, uint8_t *pdu, + size_t len); + uint16_t dec_read_req(const uint8_t *pdu, size_t len, uint16_t *handle); + uint16_t dec_read_blob_req(const uint8_t *pdu, size_t len, uint16_t *handle, + uint16_t *offset); + uint16_t enc_read_resp(uint8_t *value, size_t vlen, uint8_t *pdu, size_t len); + uint16_t enc_read_blob_resp(uint8_t *value, size_t vlen, uint16_t offset, + uint8_t *pdu, size_t len); + ssize_t dec_read_resp(const uint8_t *pdu, size_t len, uint8_t *value, + size_t vlen); + uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status, + uint8_t *pdu, size_t len); + uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, + size_t len); + uint16_t dec_find_info_req(const uint8_t *pdu, size_t len, uint16_t *start, + uint16_t *end); + uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list, + uint8_t *pdu, size_t len); + struct att_data_list *dec_find_info_resp(const uint8_t *pdu, size_t len, + uint8_t *format); + uint16_t enc_notification(uint16_t handle, uint8_t *value, size_t vlen, + uint8_t *pdu, size_t len); + uint16_t enc_indication(uint16_t handle, uint8_t *value, size_t vlen, + uint8_t *pdu, size_t len); + uint16_t dec_indication(const uint8_t *pdu, size_t len, uint16_t *handle, + uint8_t *value, size_t vlen); + uint16_t enc_confirmation(uint8_t *pdu, size_t len); + + uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, size_t len); + uint16_t dec_mtu_req(const uint8_t *pdu, size_t len, uint16_t *mtu); + uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, size_t len); + uint16_t dec_mtu_resp(const uint8_t *pdu, size_t len, uint16_t *mtu); + + uint16_t enc_prep_write_req(uint16_t handle, uint16_t offset, + const uint8_t *value, size_t vlen, + uint8_t *pdu, size_t len); + uint16_t dec_prep_write_resp(const uint8_t *pdu, size_t len, uint16_t *handle, + uint16_t *offset, uint8_t *value, + size_t *vlen); + uint16_t enc_exec_write_req(uint8_t flags, uint8_t *pdu, size_t len); + uint16_t dec_exec_write_resp(const uint8_t *pdu, size_t len); +} diff --git a/vendor/libblepp-master/blepp/att_pdu.h b/vendor/libblepp-master/blepp/att_pdu.h new file mode 100644 index 0000000..ea91467 --- /dev/null +++ b/vendor/libblepp-master/blepp/att_pdu.h @@ -0,0 +1,355 @@ +/* + * + * blepp - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +/* + This file contains classes to wrap ATT Protocol (Attribute Protocol) PDUs + (Protocol Data Units?) and present the data in a semantically meaningful + format. + + The format of the packets is covered in Core Spec 4.0 3.F.3.4 + + Logic errors (such as trying to construct a PDU packet class from the + wrong PDU data) come back as std::logic_error. Runtime errors, such as + invalid packets come back as exceptions derived from std::runtime_error. + +*/ + +#ifndef INCLUDE_BLUETOOTH_ATT_H_C51BA176654792D689D16398C9A4735A +#define INCLUDE_BLUETOOTH_ATT_H_C51BA176654792D689D16398C9A4735A + +#include +#include +#include + +#include +#include + +namespace BLEPP +{ + + /* Basic PDU response as in 3.F.3.3.1 */ + class PDUResponse + { + protected: + + template + void error(const std::string& s) const + { + LOG(Error, s); + throw C(s); + } + + void type_check(int target) const + { + if(target != type()) + error(std::string("Error converting PDUResponse to ") +att_op2str(target) + ". Type is " + att_op2str(type())); + } + + public: + + const uint8_t* data; //Pointer to the underlying data + int length; //Length of the underlying data + + //Utility function to return a uint8 at byte offset i; + uint8_t uint8(int i) const + { + assert(i >= 0 && i < length); + return data[i]; + } + + //Utility function to return a uint16 at byte offset i + //Note packets are little endian. + uint16_t uint16(int i) const + { + return uint8(i) | (uint8(i+1) << 8); + } + + PDUResponse(const uint8_t* d_, int l_) + :data(d_),length(l_) + { + } + + //Table 3.1: type field is the low 6 bits. + //The command flag is bit 6 and the authentication + //flag is bit 7. + + //Return the method type + uint8_t type() const + { + return uint8(0) & 63; + } + + bool is_command() const + { + return uint8(0) & 64; + } + + bool is_authenticated() const + { + return uint8(0) & 128; + } + }; + + /* Error packet response 3.F.3.4.1.1 */ + class PDUErrorResponse: public PDUResponse + { + public: + PDUErrorResponse(const PDUResponse& p_) + :PDUResponse(p_) + { + type_check(ATT_OP_ERROR); + } + + uint8_t request_opcode() const + { + return uint8(1); + } + + uint16_t handle() const + { + return uint16(2); + } + + uint8_t error_code() const + { + return uint8(4); + } + + const char* error_str() const + { + return att_ecode2str(error_code()); + } + }; + /* Response to read_req, 3.F.3.4.4.4 */ + class PDUReadResponse: public PDUResponse + { + public: + PDUReadResponse(const PDUResponse& p_) + :PDUResponse(p_) + { + type_check(ATT_OP_READ_RESP); + } + uint8_t request_opcode() const + { + return uint8(1); + } + + uint16_t handle() const + { + return uint16(2); + } + }; + + + + /* Response to read_by_type, 3.F.3.4.4.2 */ + class PDUReadByTypeResponse: public PDUResponse + { + public: + PDUReadByTypeResponse(const PDUResponse& p_) + :PDUResponse(p_) + { + type_check(ATT_OP_READ_BY_TYPE_RESP); + + if((length - 2) % element_size() != 0) + error("Invalid packet length for PDUReadByTypeResponse"); + } + + + //Size of each element in the response + int element_size() const + { + return uint8(1); + } + + //Elements consist of a handle and a value. + //This is the size of just the value. + int value_size() const + { + return uint8(1) -2; + } + + int num_elements() const + { + return (length - 1) / element_size(); + } + + uint16_t handle(int i) const + { + return uint16(i*element_size() + 2); + } + + //Return pointer span of the ith chunk of data + std::pair value(int i) const + { + const uint8_t* begin = data + i*element_size() + 4; + return std::make_pair(begin, begin + value_size()); + } + + //Utility function to return the ith element directly as a uint16. + uint16_t value_uint16(int i) const + { + if(value_size() != 2) + error("Wrong size for uint16 in PDUReadByTypeResponse"); + + return uint16(i*element_size()+4); + } + }; + + + /* Response to read_group_by_type, 3.F.3.4.4.10 */ + class PDUReadGroupByTypeResponse: public PDUResponse + { + public: + PDUReadGroupByTypeResponse(const PDUResponse& p_) + :PDUResponse(p_) + { + type_check(ATT_OP_READ_BY_GROUP_RESP); + + if((length - 2) % element_size() != 0) + error("Invalid packet length for PDUReadGroupByTypeResponse"); + + } + + int value_size() const + { + return uint8(1) -4; + } + + int element_size() const + { + return uint8(1); + } + + int num_elements() const + { + return (length - 2) / element_size(); + } + + uint16_t start_handle(int i) const + { + return uint16(i*element_size() + 2); + } + + uint16_t end_handle(int i) const + { + return uint16(i*element_size() + 4); + } + + std::pair value(int i) const + { + const uint8_t* begin = data + i*element_size() + 6; + return std::make_pair(begin, begin + value_size()); + } + + uint16_t value_uint16(int i) const + { + if(value_size() != 2) + error("Wrong size for uint16 in PDUReadGroupByTypeResponse"); + return uint16(i*element_size()+4); + } + + }; + + class PDUFindInformationResponse: public PDUResponse + { + public: + + PDUFindInformationResponse(const PDUResponse& p_) + :PDUResponse(p_) + { + type_check(ATT_OP_FIND_INFO_RESP); + if( (length-2) % element_size()) + error("Invalid packet length for PDUReadGroupByTypeResponse"); + } + + bool is_16_bit() const + { + //Table 3.8 + return uint8(1) == 1; + + }; + + int element_size() const + { + return 2 + (is_16_bit() ? 2 : 16); + } + + int num_elements() const + { + return (length - 2) / element_size(); + } + + uint16_t handle(int i) const + { + return uint16(2 + i * element_size()); + } + + bt_uuid_t uuid(int i) const + { + if(is_16_bit()) + return att_get_uuid16(data + 2 + 2 + i * element_size()); + else + return att_get_uuid128(data + 2 + 2 + i * element_size()); + } + }; + + class PDUNotificationOrIndication: public PDUResponse + { + public: + + PDUNotificationOrIndication(const PDUResponse& p_) + :PDUResponse(p_) + { + if(type() != ATT_OP_HANDLE_NOTIFY && type() != ATT_OP_HANDLE_IND) + error(std::string("Error converting PDUResponse to NotifyOrIndicate. Type is ") + att_op2str(type())); + } + + bool notification() const + { + return type() == ATT_OP_HANDLE_NOTIFY; + + }; + + int num_elements() const + { + return (length - 2); + } + + uint16_t handle() const + { + return uint16(1); + } + + //Return pointer span of the ith chunk of data + std::pair value() const + { + return std::make_pair(data + 3, data + length); + } + }; + + void pretty_print(const PDUResponse& pdu); +} + + +#endif diff --git a/vendor/libblepp-master/blepp/bledevice.h b/vendor/libblepp-master/blepp/bledevice.h new file mode 100644 index 0000000..82244c5 --- /dev/null +++ b/vendor/libblepp-master/blepp/bledevice.h @@ -0,0 +1,67 @@ +/* + * + * blepp - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __INC_LIBATTGATT_BLEDEVICE_H +#define __INC_LIBATTGATT_BLEDEVICE_H + +#include +#include +#include +#include + +namespace BLEPP +{ + + //Almost zero resource to represent the ATT protocol on a BLE + //device. This class does none of its own memory management, and will not generally allocate + //or do other nasty things. Oh no, it allocates a buffer! FIXME! + // + //Mostly what it can do is write ATT command packets (PDUs) and receive PDUs back. + struct BLEDevice + { + struct ReadError{}; + struct WriteError{}; + + const int& sock; + static const int buflen=ATT_DEFAULT_MTU; + std::vector buf; + + //template void test_fd_(int fd, int line); + void test_pdu(int len); + BLEDevice(const int& sock_); + + void send_read_request(std::uint16_t handle); + void send_read_by_type(const bt_uuid_t& uuid, std::uint16_t start = 0x0001, std::uint16_t end=0xffff); + void send_find_information(std::uint16_t start = 0x0001, std::uint16_t end=0xffff); + void send_read_group_by_type(const bt_uuid_t& uuid, std::uint16_t start = 0x0001, std::uint16_t end=0xffff); + void send_write_request(std::uint16_t handle, const std::uint8_t* data, int length); + void send_write_request(std::uint16_t handle, std::uint16_t data); + void send_handle_value_confirmation(); + void send_write_command(std::uint16_t handle, const std::uint8_t* data, int length); + void send_write_command(std::uint16_t handle, std::uint16_t data); + PDUResponse receive(std::uint8_t* buf, int max); + PDUResponse receive(std::vector& v); + }; + +} + +#endif diff --git a/vendor/libblepp-master/blepp/blestatemachine.h b/vendor/libblepp-master/blepp/blestatemachine.h new file mode 100644 index 0000000..cca28dc --- /dev/null +++ b/vendor/libblepp-master/blepp/blestatemachine.h @@ -0,0 +1,348 @@ +#ifndef __INC_LIBATTGATT_BLESTATEMACHINE_H +#define __INC_LIBATTGATT_BLESTATEMACHINE_H +/* + * + * blepp - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include + +#include +#include +#include + + +#include + +namespace BLEPP +{ + + ///Interpret a ReadByTypeResponse packet as a ReadCharacteristic packet + class GATTReadCharacteristic: public PDUReadByTypeResponse + { + public: + struct Characteristic + { + uint16_t handle; + uint8_t flags; + bt_uuid_t uuid; + }; + + GATTReadCharacteristic(const PDUResponse& p) + :PDUReadByTypeResponse(p) + { + if(value_size() != 5 && value_size() != 19) + throw std::runtime_error("Invalid packet size in GATTReadCharacteristic"); + } + + Characteristic characteristic(int i) const + { + Characteristic c; + c.handle = att_get_u16(value(i).first + 1); + c.flags = value(i).first[0]; + + if(value_size() == 5) + c.uuid= att_get_uuid16(value(i).first + 3); + else + c.uuid= att_get_uuid128(value(i).first + 3); + + return c; + } + }; + + + + ///Interpret a ReadByTypeResponse packet as a ReadCharacteristic packet + class GATTReadCCC: public PDUReadByTypeResponse + { + public: + + GATTReadCCC(const PDUResponse& p) + :PDUReadByTypeResponse(p) + { + if(value_size() != 2) + throw std::runtime_error("Invalid packet size in GATTReadCharacteristic"); + } + + uint16_t ccc(int i) const + { + return att_get_u16(value(i).first); + } + }; + + ///Interpret a read_group_by_type resoponde as a read service group response + class GATTReadServiceGroup: public PDUReadGroupByTypeResponse + { + public: + GATTReadServiceGroup(const PDUResponse& p) + :PDUReadGroupByTypeResponse(p) + { + if(value_size() != 2 && value_size() != 16) + { + LOG(Error, "UUID length" << value_size()); + error("Invalid UUID length in PDUReadGroupByTypeResponse"); + } + } + + bt_uuid_t uuid(int i) const + { + const uint8_t* begin = data + i*element_size() + 6; + + bt_uuid_t uuid; + if(value_size() == 2) + { + uuid.type = BT_UUID16; + uuid.value.u16 = att_get_u16(begin); + } + else + { + uuid.type = BT_UUID128; + uuid.value.u128 = att_get_u128(begin); + } + + return uuid; + } + }; + + class BLEGATTStateMachine; + + enum States + { + Disconnected, + Connecting, + Idle, + ReadingPrimaryService, + FindAllCharacteristics, + GetClientCharaceristicConfiguration, + AwaitingWriteResponse, + }; + + static const int Waiting=-1; + + + class UUID: public bt_uuid_t + { + public: + + explicit UUID(const uint16_t& u) + { + type = BT_UUID16; + value.u16 = u; + } + + UUID(){} + + UUID(const UUID&) = default; + + static UUID from(const bt_uuid_t& uuid) + { + UUID ret; + (bt_uuid_t&)ret = uuid; + + return ret; + } + + UUID(const std::string& uuid_str) + { + //FIXME: check errors! + bt_string_to_uuid(this, uuid_str.c_str()); + } + + bool operator==(const UUID& uuid) const + { + return bt_uuid_cmp(this, &uuid) == 0; + } + }; + + + struct Characteristic + { + private: + BLEGATTStateMachine* s; + + public: + + Characteristic(BLEGATTStateMachine* s_) + :s(s_) + {} + + void set_notify_and_indicate(bool , bool); + std::function cb_notify_or_indicate; + + void write_request(const uint8_t* data, int length); + void write_request(uint8_t data); + + //Flags indicating various properties + bool broadcast, read, write_without_response, write, notify, indicate, authenticated_write, extended; + + //UUID, i.e. name of what the characteristic represents semantically + UUID uuid; + + //Where the value can be read/written + uint16_t value_handle; + + //Where we write to configure, i.e. set notify and/or indicate + //0 means invalid. + uint16_t client_characteric_configuration_handle; + uint16_t ccc_last_known_value; + + uint16_t first_handle, last_handle; + }; + + struct StateMachineGoneBad: public std::runtime_error + { + StateMachineGoneBad(const std::string& err) + :std::runtime_error(err) + { + } + }; + + + struct ServiceInfo + { + std::string name, id; + UUID uuid; + }; + + struct PrimaryService + { + uint16_t start_handle; + uint16_t end_handle; + UUID uuid; + std::vector characteristics; + }; + + + const ServiceInfo* lookup_service_by_UUID(const UUID& uuid); + + class BLEGATTStateMachine + { + public: + + struct Disconnect + { + enum Reason{ + ConnectionFailed, + UnexpectedError, + UnexpectedResponse, + WriteError, + ReadError, + ConnectionClosed + } reason; + + static constexpr int NoErrorCode=1; // Any positive value + int error_code; + + Disconnect(Reason r, int e) + :reason(r), error_code(e) + { + } + }; + static const char* get_disconnect_string(Disconnect); + + private: + struct sockaddr_l2 addr; + + int sock = -1; + + + static void buggerall(); + static void buggerall2(Disconnect); + + BLEDevice dev; + + + States state = Disconnected; + int next_handle_to_read=-1; + int last_request=-1; + + std::vector buf; + + + struct PrimaryServiceInfo + { + std::string name, id; + UUID uuid; + }; + + void reset(); + void state_machine_write(); + void unexpected_error(const PDUErrorResponse&); + void fail(Disconnect); + + public: + + + std::vector primary_services; + + std::function cb_connected = buggerall; + std::function cb_disconnected = buggerall2; + std::function cb_services_read = buggerall; + std::function cb_notify = buggerall; + std::function cb_find_characteristics = buggerall; + std::function cb_get_client_characteristic_configuration = buggerall; + std::function cb_write_response = buggerall; + std::function cb_notify_or_indicate; + + + BLEGATTStateMachine(); + ~BLEGATTStateMachine(); + + + void connect_blocking(const std::string& addres); + void connect_nonblocking(const std::string& addres); + void connect(const std::string& addresa, bool blocking, bool pubaddr = true, std::string device = ""); + void close(); + + int socket(); + + bool wait_on_write(); + + bool is_idle() + { + return state == Idle; + } + + void send_write_request(uint16_t handle, const uint8_t* data, int length); + + void read_primary_services(); + void find_all_characteristics(); + void get_client_characteristic_configuration(); + void read_and_process_next(); + void write_and_process_next(); + void set_notify_and_indicate(Characteristic& c, bool notify, bool indicate); + + + void setup_standard_scan(std::function& cb); + }; + + + void pretty_print_tree(const BLEGATTStateMachine& s); + + + + class SocketAllocationFailed: public std::runtime_error { using runtime_error::runtime_error; }; + class SocketBindFailed: public std::runtime_error { using runtime_error::runtime_error; }; + class SocketGetSockOptFailed: public std::runtime_error { using runtime_error::runtime_error; }; + class SocketConnectFailed: public std::runtime_error { using runtime_error::runtime_error; }; +} +#endif diff --git a/vendor/libblepp-master/blepp/float.h b/vendor/libblepp-master/blepp/float.h new file mode 100644 index 0000000..3b89948 --- /dev/null +++ b/vendor/libblepp-master/blepp/float.h @@ -0,0 +1,32 @@ +/* + * + * blepp - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __INC_LIBATTGATT_FLOAT_H +#define __INC_LIBATTGATT_FLOAT_H + +#include +namespace BLEPP +{ + float bluetooth_float_to_IEEE754(const std::uint8_t* bytes); +} + +#endif diff --git a/vendor/libblepp-master/blepp/gap.h b/vendor/libblepp-master/blepp/gap.h new file mode 100644 index 0000000..85a07b6 --- /dev/null +++ b/vendor/libblepp-master/blepp/gap.h @@ -0,0 +1,31 @@ +#ifndef BLEPLUSPLUS_INC_GAP_H +#define BLEPLUSPLUS_INC_GAP_H + +namespace BLEPP +{ + namespace GAP + { + //From here: + //https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile + //incomplete list. + enum GAP + { + flags = 0x01, + incomplete_list_of_16_bit_UUIDs = 0x02, + complete_list_of_16_bit_UUIDs = 0x03, + incomplete_list_of_128_bit_UUIDs = 0x06, + complete_list_of_128_bit_UUIDs = 0x07, + shortened_local_name = 0x08, + complete_local_name = 0x09, + service_data_16_bit_UUID = 0x16, + manufacturer_data = 0xff + }; + + }; + + + +} + + +#endif diff --git a/vendor/libblepp-master/blepp/lescan.h b/vendor/libblepp-master/blepp/lescan.h new file mode 100644 index 0000000..e73731d --- /dev/null +++ b/vendor/libblepp-master/blepp/lescan.h @@ -0,0 +1,217 @@ + +/* + * + * blepp - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __INC_BLEPP_LESCAN_H +#define __INC_BLEPP_LESCAN_H + +#include +#include +#include +#include +#include +#include +#include +#include //for UUID. FIXME mofo +#include + +namespace BLEPP +{ + enum class LeAdvertisingEventType + { + ADV_IND = 0x00, //Connectable undirected advertising + //Broadcast; any device can connect or ask for more information + ADV_DIRECT_IND = 0x01, //Connectable Directed + //Targeted; a single known device that can only connect + ADV_SCAN_IND = 0x02, //Scannable Undirected + //Purely informative broadcast; devices can ask for more information + ADV_NONCONN_IND = 0x03, //Non-Connectable Undirected + //Purely informative broadcast; no device can connect or even ask for more information + SCAN_RSP = 0x04, //Result coming back after a scan request + }; + + //Is this the best design. I'm not especially convinced. + //It seems pretty wretched. + struct AdvertisingResponse + { + std::string address; + LeAdvertisingEventType type; + struct Name + { + std::string name; + bool complete; + }; + + struct Flags + { + bool LE_limited_discoverable=0; + bool LE_general_discoverable=0; + bool BR_EDR_unsupported=0; + bool simultaneous_LE_BR_controller=0; + bool simultaneous_LE_BR_host=0; + + std::vector flag_data; + Flags(std::vector&&); + }; + + std::vector UUIDs; + bool uuid_16_bit_complete=0; + bool uuid_32_bit_complete=0; + bool uuid_128_bit_complete=0; + + boost::optional local_name; + boost::optional flags; + + std::vector> manufacturer_specific_data; + std::vector> service_data; + std::vector> unparsed_data_with_types; + + }; + + /// Class for scanning for BLE devices + /// this must be run as root, because it requires getting packets from the HCI. + /// The HCI requires root since it has no permissions on setting filters, so + /// anyone with an open HCI device can sniff all data. + class HCIScanner + { + class FD + { + private: + int fd=-1; + + public: + operator int () const + { + return fd; + } + FD(int i) + :fd(i) + { + } + + FD()=default; + void set(int i) + { + fd = i; + } + + ~FD() + { + if(fd != -1) + close(fd); + } + }; + + + public: + + enum class ScanType + { + Passive = 0x00, + Active = 0x01, + }; + + enum class FilterDuplicates + { + Off, //Get all events + Hardware, //Rely on hardware filtering only. Lower power draw, but can actually send + //duplicates if the device's builtin list gets overwhelmed. + Software, //Get all events from the device and filter them by hand. + Both //The best and worst of both worlds. + }; + + ///Generic error exception class + class Error: public std::runtime_error + { + public: + Error(const std::string& why); + }; + + ///Thrown only if a read() is interrupted. Only bother + ///handling if you've got a non terminating exception handler + class Interrupted: public Error + { + using Error::Error; + }; + + + ///IO error of some sort. Probably fatal for any bluetooth + ///based system. Or might be that the dongle was unplugged. + class IOError: public Error + { + public: + IOError(const std::string& why, int errno_val); + }; + + ///HCI device spat out invalid data. + ///This is not good. Almost certainly fatal. + class HCIError: public Error + { + using Error::Error; + }; + + HCIScanner(); + HCIScanner(bool start); + HCIScanner(bool start, FilterDuplicates duplicates, ScanType, std::string device=""); + + + void start(); + void stop(); + + ///get the file descriptor. + ///Use with select(), poll() or whatever. + int get_fd() const; + + ~HCIScanner(); + + ///Blocking call. Use select() on the FD if you don't want to block. + ///This reads and parses the HCI packets. + std::vector get_advertisements(); + + ///Parse an HCI advertising packet. There's probably not much + ///reason to call this yourself. + static std::vector parse_packet(const std::vector& p); + + private: + struct FilterEntry + { + explicit FilterEntry(const AdvertisingResponse&); + const std::string mac_address; + int type; + bool operator<(const FilterEntry&) const; + }; + + bool hardware_filtering; + bool software_filtering; + ScanType scan_type; + + FD hci_fd; + bool running=0; + hci_filter old_filter; + + ///Read the HCI data, but don't parse it. + std::vector read_with_retry(); + std::set scanned_devices; + }; +} + +#endif diff --git a/vendor/libblepp-master/blepp/logging.h b/vendor/libblepp-master/blepp/logging.h new file mode 100644 index 0000000..7e642ea --- /dev/null +++ b/vendor/libblepp-master/blepp/logging.h @@ -0,0 +1,107 @@ +/* + * + * blepp - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __INC_LIBATTGATT_LOGGING_H +#define __INC_LIBATTGATT_LOGGING_H +#include +#include +#include +#include +#include +#include + +namespace BLEPP +{ + + enum LogLevels + { + Error, + Warning, + Info, + Debug, + Trace + }; + + static const char* log_types[] = + { + "error", + "warn ", + "info ", + "debug", + "trace" + }; +} +namespace BLEPP{ + + extern LogLevels log_level; + + template const T& log_no_uint8(const T& a) + { + return a; + } + inline int log_no_uint8(uint8_t a) + { + return a; + } + + inline std::ostream& log_line_header(LogLevels x, const char* function, const int line, const char* file) + { + std::clog << log_types[x] << " " << std::fixed << std::setprecision(6) << std::chrono::duration_cast>(std::chrono::system_clock::now().time_since_epoch()).count(); + if(log_level >= Debug) + std::clog << " " << function; + if(log_level >= Trace) + std::clog << " " << file << ":" << line; + std::clog << ": "; + return std::clog; + } + + + #define LOGVAR(Y, X) LOG(Y, #X << " = " << log_no_uint8(X)) + #define LOGVARHEX(Y, X) LOG(Y, #X << " = " << std::hex <= Trace) + log_line_header(Trace, who, where, file) << "entering" << std::endl; + } + + ~EnterThenLeave() + { + if(BLEPP::log_level >= Trace) + log_line_header(Trace, who, where, file) << "leaving" << std::endl; + } + + }; + + #define ENTER() EnterThenLeave log_enter_then_leave(__FUNCTION__, __LINE__, __FILE__); +} +#endif diff --git a/vendor/libblepp-master/blepp/pretty_printers.h b/vendor/libblepp-master/blepp/pretty_printers.h new file mode 100644 index 0000000..ee4d41c --- /dev/null +++ b/vendor/libblepp-master/blepp/pretty_printers.h @@ -0,0 +1,48 @@ +#ifndef __INC_LIBATTGATT_PRETTY_PRINTERS_H +#define __INC_LIBATTGATT_PRETTY_PRINTERS_H + +/* + * + * blepp - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#include +#include +#include +#include + +namespace BLEPP +{ + std::string to_hex(const std::uint16_t& u); + std::string to_hex(const std::uint8_t& u); + std::string to_str(const std::uint8_t& u); + std::string to_str(const bt_uuid_t& uuid); + std::string to_hex(const std::uint8_t* d, int l); + std::string to_hex(std::pair d); + std::string to_hex(const std::vector& v); + std::string to_str(const std::uint8_t* d, int l); + std::string to_str(std::pair d); + std::string to_str(std::pair d); + std::string to_str(const std::vector& v); +} + +#endif diff --git a/vendor/libblepp-master/blepp/uuid.h b/vendor/libblepp-master/blepp/uuid.h new file mode 100644 index 0000000..3dc5416 --- /dev/null +++ b/vendor/libblepp-master/blepp/uuid.h @@ -0,0 +1,140 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2011 Nokia Corporation + * Copyright (C) 2011 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __BLUETOOTH_UUID_H +#define __BLUETOOTH_UUID_H + +#include +#include + +namespace BLEPP +{ + #include + //#include + + #define GENERIC_AUDIO_UUID "00001203-0000-1000-8000-00805f9b34fb" + + #define HSP_HS_UUID "00001108-0000-1000-8000-00805f9b34fb" + #define HSP_AG_UUID "00001112-0000-1000-8000-00805f9b34fb" + + #define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" + #define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb" + + #define ADVANCED_AUDIO_UUID "0000110d-0000-1000-8000-00805f9b34fb" + + #define A2DP_SOURCE_UUID "0000110a-0000-1000-8000-00805f9b34fb" + #define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb" + + #define AVRCP_REMOTE_UUID "0000110e-0000-1000-8000-00805f9b34fb" + #define AVRCP_TARGET_UUID "0000110c-0000-1000-8000-00805f9b34fb" + + #define PANU_UUID "00001115-0000-1000-8000-00805f9b34fb" + #define NAP_UUID "00001116-0000-1000-8000-00805f9b34fb" + #define GN_UUID "00001117-0000-1000-8000-00805f9b34fb" + #define BNEP_SVC_UUID "0000000f-0000-1000-8000-00805f9b34fb" + + #define PNPID_UUID "00002a50-0000-1000-8000-00805f9b34fb" + #define DEVICE_INFORMATION_UUID "0000180a-0000-1000-8000-00805f9b34fb" + + #define GATT_UUID "00001801-0000-1000-8000-00805f9b34fb" + #define IMMEDIATE_ALERT_UUID "00001802-0000-1000-8000-00805f9b34fb" + #define LINK_LOSS_UUID "00001803-0000-1000-8000-00805f9b34fb" + #define TX_POWER_UUID "00001804-0000-1000-8000-00805f9b34fb" + + #define SAP_UUID "0000112D-0000-1000-8000-00805f9b34fb" + + #define HEART_RATE_UUID "0000180d-0000-1000-8000-00805f9b34fb" + #define HEART_RATE_MEASUREMENT_UUID "00002a37-0000-1000-8000-00805f9b34fb" + #define BODY_SENSOR_LOCATION_UUID "00002a38-0000-1000-8000-00805f9b34fb" + #define HEART_RATE_CONTROL_POINT_UUID "00002a39-0000-1000-8000-00805f9b34fb" + + #define HEALTH_THERMOMETER_UUID "00001809-0000-1000-8000-00805f9b34fb" + #define TEMPERATURE_MEASUREMENT_UUID "00002a1c-0000-1000-8000-00805f9b34fb" + #define TEMPERATURE_TYPE_UUID "00002a1d-0000-1000-8000-00805f9b34fb" + #define INTERMEDIATE_TEMPERATURE_UUID "00002a1e-0000-1000-8000-00805f9b34fb" + #define MEASUREMENT_INTERVAL_UUID "00002a21-0000-1000-8000-00805f9b34fb" + + #define CYCLING_SC_UUID "00001816-0000-1000-8000-00805f9b34fb" + #define CSC_MEASUREMENT_UUID "00002a5b-0000-1000-8000-00805f9b34fb" + #define CSC_FEATURE_UUID "00002a5c-0000-1000-8000-00805f9b34fb" + #define SENSOR_LOCATION_UUID "00002a5d-0000-1000-8000-00805f9b34fb" + #define SC_CONTROL_POINT_UUID "00002a55-0000-1000-8000-00805f9b34fb" + + #define RFCOMM_UUID_STR "00000003-0000-1000-8000-00805f9b34fb" + + #define HDP_UUID "00001400-0000-1000-8000-00805f9b34fb" + #define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805f9b34fb" + #define HDP_SINK_UUID "00001402-0000-1000-8000-00805f9b34fb" + + #define HSP_HS_UUID "00001108-0000-1000-8000-00805f9b34fb" + #define HID_UUID "00001124-0000-1000-8000-00805f9b34fb" + + #define DUN_GW_UUID "00001103-0000-1000-8000-00805f9b34fb" + + #define GAP_UUID "00001800-0000-1000-8000-00805f9b34fb" + #define PNP_UUID "00001200-0000-1000-8000-00805f9b34fb" + + #define SPP_UUID "00001101-0000-1000-8000-00805f9b34fb" + + #define OBEX_SYNC_UUID "00001104-0000-1000-8000-00805f9b34fb" + #define OBEX_OPP_UUID "00001105-0000-1000-8000-00805f9b34fb" + #define OBEX_FTP_UUID "00001106-0000-1000-8000-00805f9b34fb" + #define OBEX_PCE_UUID "0000112e-0000-1000-8000-00805f9b34fb" + #define OBEX_PSE_UUID "0000112f-0000-1000-8000-00805f9b34fb" + #define OBEX_PBAP_UUID "00001130-0000-1000-8000-00805f9b34fb" + #define OBEX_MAS_UUID "00001132-0000-1000-8000-00805f9b34fb" + #define OBEX_MNS_UUID "00001133-0000-1000-8000-00805f9b34fb" + #define OBEX_MAP_UUID "00001134-0000-1000-8000-00805f9b34fb" + + typedef enum { + BT_UUID_UNSPEC = 0, + BT_UUID16 = 16, + BT_UUID32 = 32, + BT_UUID128 = 128, + } bt_uuid_type_t; + typedef struct { + bt_uuid_type_t type; + union { + uint16_t u16; + uint32_t u32; + uint128_t u128; + } value; + } bt_uuid_t; + + int bt_uuid_strcmp(const void *a, const void *b); + + int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value); + int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value); + int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value); + + int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2); + void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst); + + #define MAX_LEN_UUID_STR 37 + + int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n); + int bt_string_to_uuid(bt_uuid_t *uuid, const char *string); + +} +#endif /* __BLUETOOTH_UUID_H */ diff --git a/vendor/libblepp-master/blepp/xtoa.h b/vendor/libblepp-master/blepp/xtoa.h new file mode 100644 index 0000000..7a9bd08 --- /dev/null +++ b/vendor/libblepp-master/blepp/xtoa.h @@ -0,0 +1,38 @@ +/* + * + * blepp - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +#ifndef INC_XTOA_H +#define INC_XTOA_H +#include + +namespace BLEPP +{ + template + std::string xtoa(const X& x) + { + std::ostringstream o; + o << x; + return o.str(); + } +} +#endif diff --git a/vendor/libblepp-master/bluetooth.cc b/vendor/libblepp-master/bluetooth.cc new file mode 100644 index 0000000..e23bc93 --- /dev/null +++ b/vendor/libblepp-master/bluetooth.cc @@ -0,0 +1,294 @@ +/* + * + * libattgatt - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include "cxxgplot.h" //lolzworthy plotting program +using namespace std; +using namespace BLEPP; + +void bin(uint8_t i) +{ + for(int b=7; b >= 0; b--) + cout << !!(i & (1<= 20) + i = 19-(i-20); + base[i + 2] = 'O'; + + return base + string(base.size(), '\b'); +} + + +double get_time_of_day() +{ + struct timeval tv; + gettimeofday(&tv,NULL); + return tv.tv_sec+tv.tv_usec * 1e-6; +} +//////////////////////////////////////////////////////////////////////////////// +// +// This program demonstrates the use of the library +// +int main(int argc, char **argv) +{ + if(argc != 2 && argc != 3) + { + cerr << "Please supply address.\n"; + cerr << "Usage:\n"; + cerr << "prog address [nonblocking]\n"; + exit(1); + } + + log_level = Info; + + + //This is the interface to the BLW protocol. + BLEGATTStateMachine gatt; + + + //This is a cheap and cheerful plotting system using gnuplot. + //Ignore this if you don't care about plotting. + cplot::Plotter plot; + plot.range = " [ ] [0:] "; + deque points; + + int count = -1; + double prev_time = 0; + float voltage=0; + + //////////////////////////////////////////////////////////////////////////////// + // + // This is important! This is an example of a callback which responds to + // notifications or indications. Currently, BLEGATTStateMachine responds + // automatically to indications. Maybe that will change. + // + //Function that reads an indication and formats it for plotting. + std::function notify_cb = [&](const PDUNotificationOrIndication& n) + { + if(count == -1) + { + prev_time = get_time_of_day(); + } + count++; + + if(count == 10) + { + double t = get_time_of_day(); + cout << 10 / (t-prev_time) << " packets per second\n"; + + prev_time = t; + count=0; + } + + + + //This particular device sends 16 bit integers. + //Extract them and both print them in binary and send them to the plotting program + const uint8_t* d = n.value().first; + for(int i=0; i < 7; i++) + { + int val = ((0+d[1 + 2*i] *256 + d[0 + 2*i])>>0) ; + //Format the points and send the results to the plotting program. + points.push_back(val); + if(points.size() > 300) + points.pop_front(); + } + + uint32_t seq = d[14] | (d[15]<<8) | (d[16]<<16) | (d[17]<<8); + int16_t bv = d[18] | (d[19] << 8); + + if(bv != -32768) + voltage = bv / 1000.0; + + //cout << "Hello: " << dec << setfill('0') << setw(6) << val << dec << " "; + //bin(d[1]); + //cout << " "; + //bin(d[0]); + + //cout << endl; + + + plot.newline("line lw 3 lt 1 title \"\""); + plot.addpts(points); + ostringstream os; + os << "set title \"Voltage: " << voltage << " Seq: " << seq << "\""; + plot.add_extra(os.str()); + + plot.draw(); + }; + + + //////////////////////////////////////////////////////////////////////////////// + // + // This is important! This is an example of a callback which is run when the + // client characteristic configuration is retreived. Essentially this is when + // all the most useful device information has been received and the device can + // now be used. + // + // At this point you need to search for things to activate. The code here activates + // notifications on a device I have. You will need to modify this! + // + // Search for the service and attribute and set up notifications and the appropriate callback. + bool enable=true; + std::function cb = [&gatt, ¬ify_cb, &enable](){ + + pretty_print_tree(gatt); + + for(auto& service: gatt.primary_services) + for(auto& characteristic: service.characteristics) + if(service.uuid == UUID("7309203e-349d-4c11-ac6b-baedd1819764") && characteristic.uuid == UUID("e5f49879-6ee1-479e-bfec-3d35e13d3b88")) + { + cout << "woooo\n"; + characteristic.cb_notify_or_indicate = notify_cb; + characteristic.set_notify_and_indicate(enable, false); + } + }; + + //////////////////////////////////////////////////////////////////////////////// + // + // This is somewhat important. Set up callback for disconnection + // + // All reasonable errors are handled by a disconnect. The BLE spec specifies that + // if the device sends invalid data, then the client must disconnect. + // + // Failure to connect also comes here. + gatt.cb_disconnected = [](BLEGATTStateMachine::Disconnect d) + { + cerr << "Disconnect for reason " << BLEGATTStateMachine::get_disconnect_string(d) << endl; + exit(1); + }; + + + //////////////////////////////////////////////////////////////////////////////// + // + // You almost always want to query the tree of things on the entire device + // So, there is a function to do this automatically. This is a helper which + // sets up all the callbacks necessary to automate the scanning. You could + // reduce connection times a little bit by only scanning for soma attributes. + gatt.setup_standard_scan(cb); + + + + //////////////////////////////////////////////////////////////////////////////// + // + // There are two modes, blocking and nonblocking. + // + // Blocking is useful for simple commandline programs which just log a bunch of + // data from a BLE device. + // + // Nonblocking is useful for everything else. + // + + // A few errors are handled by exceptions. std::runtime errors happen if nearly fatal + // but recoverable-with-effort errors happen, such as a failure in socket allocation. + // It is very unlikely you will encounter a runtime error. + // + // std::logic_error happens if you abuse the BLEGATTStateMachine. For example trying + // to issue a new instruction before the callback indicating the in progress one has + // finished has been called. These errors mean the program is incorrect. + try + { + if(argc >2 && argv[2] == string("nonblocking")) + { + + //This is how to use the blocking interface. It is very simple. + gatt.connect_blocking(argv[1]); + for(;;) + { + gatt.read_and_process_next(); + } + } + else + { + //Connect as a non blocking call + gatt.connect_nonblocking(argv[1]); + + + + //Example of how to use the state machine with select() + // + //This just demonstrates the capability and should be easily + //transferrable to poll(), epoll(), libevent and so on. + fd_set write_set, read_set; + + for(int i=0;;i++) + { + FD_ZERO(&read_set); + FD_ZERO(&write_set); + + //Reads are always a possibility due to asynchronus notifications. + FD_SET(gatt.socket(), &read_set); + + //Writes are usually available, so only check for them when the + //state machine wants to write. + if(gatt.wait_on_write()) + FD_SET(gatt.socket(), &write_set); + + + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 10000; + int result = select(gatt.socket() + 1, &read_set, &write_set, NULL, & tv); + + if(FD_ISSET(gatt.socket(), &write_set)) + gatt.write_and_process_next(); + + if(FD_ISSET(gatt.socket(), &read_set)) + gatt.read_and_process_next(); + + cout << throbber(i) << flush; +/* + if(i % 100 == 0 && gatt.is_idle()) + { + enable = !enable; + cb(); + }*/ + + } + } + } + catch(std::runtime_error e) + { + cerr << "Something's stopping bluetooth working: " << e.what() << endl; + } + catch(std::logic_error e) + { + cerr << "Oops, someone fouled up: " << e.what() << endl; + } + +} diff --git a/vendor/libblepp-master/configure b/vendor/libblepp-master/configure new file mode 100755 index 0000000..5d3f0f5 --- /dev/null +++ b/vendor/libblepp-master/configure @@ -0,0 +1,4858 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for libble++ version-0.5. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +# +# E. Rosten, 2016, the BlueZ contributors to 2016 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='libble++' +PACKAGE_TARNAME='libble--' +PACKAGE_VERSION='version-0.5' +PACKAGE_STRING='libble++ version-0.5' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='LTLIBOBJS +LIBOBJS +EGREP +GREP +CXXCPP +VERSION +PKGCONFIG_LIBDIR +SED +PKG_CONFIG +HAVE_CXX14 +OBJEXT +EXEEXT +ac_ct_CXX +CPPFLAGS +LDFLAGS +CXXFLAGS +CXX +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +' + ac_precious_vars='build_alias +host_alias +target_alias +CXX +CXXFLAGS +LDFLAGS +LIBS +CPPFLAGS +CCC +CXXCPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures libble++ version-0.5 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/libble--] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of libble++ version-0.5:";; + esac + cat <<\_ACEOF + +Some influential environment variables: + CXX C++ compiler command + CXXFLAGS C++ compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXXCPP C++ preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +libble++ configure version-0.5 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. + +E. Rosten, 2016, the BlueZ contributors to 2016 +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_cxx_try_cpp LINENO +# ------------------------ +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_cpp + +# ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES +# --------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_cxx_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_header_mongrel + +# ac_fn_cxx_try_run LINENO +# ------------------------ +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_cxx_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_run + +# ac_fn_cxx_check_header_compile LINENO HEADER VAR INCLUDES +# --------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_cxx_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_header_compile + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_link +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by libble++ $as_me version-0.5, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5 +$as_echo_n "checking whether the C++ compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C++ compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5 +$as_echo_n "checking for C++ compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C++ compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if ${ac_cv_cxx_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_14.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_14([ext|noext],[mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++14 +# standard; if necessary, add switches to CXXFLAGS to enable support. +# +# The first argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++14) or a strict conformance mode (e.g. +# -std=c++14). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The second argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline C++14 support is required and that the macro +# should error out if no mode with that support is found. If specified +# 'optional', then configuration proceeds regardless, after defining +# HAVE_CXX14 if and only if a supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2016 Edward Rosten +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 13 + + + + + + + +################################################################################ +# +# Useful macros +# + + + + + + + + +if test "$CXXFLAGS" == "-g -O2" +then + + + if test "" == "" + then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler flag -Wall works" >&5 +$as_echo_n "checking if compiler flag -Wall works... " >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking " >&5 +$as_echo_n "checking ... " >&6; } + fi + save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -Wall" + + + + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(){} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + cvd_conf_test=1 +else + cvd_conf_test=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + + + + if test $cvd_conf_test = 1 + then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ts_success=yes + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CXXFLAGS="$save_CXXFLAGS" + ts_success=no + fi + + + if test "" == "" + then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler flag -Wextra works" >&5 +$as_echo_n "checking if compiler flag -Wextra works... " >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking " >&5 +$as_echo_n "checking ... " >&6; } + fi + save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -Wextra" + + + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(){} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + cvd_conf_test=1 +else + cvd_conf_test=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + + + + if test $cvd_conf_test = 1 + then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ts_success=yes + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CXXFLAGS="$save_CXXFLAGS" + ts_success=no + fi + + + if test "" == "" + then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler flag -W works" >&5 +$as_echo_n "checking if compiler flag -W works... " >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking " >&5 +$as_echo_n "checking ... " >&6; } + fi + save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -W" + + + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(){} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + cvd_conf_test=1 +else + cvd_conf_test=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + + + + if test $cvd_conf_test = 1 + then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ts_success=yes + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CXXFLAGS="$save_CXXFLAGS" + ts_success=no + fi + + + if test "" == "" + then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler flag -O3 works" >&5 +$as_echo_n "checking if compiler flag -O3 works... " >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking " >&5 +$as_echo_n "checking ... " >&6; } + fi + save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -O3" + + + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(){} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + cvd_conf_test=1 +else + cvd_conf_test=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + + + + if test $cvd_conf_test = 1 + then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ts_success=yes + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CXXFLAGS="$save_CXXFLAGS" + ts_success=no + fi + + + if test "" == "" + then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler flag -ggdb works" >&5 +$as_echo_n "checking if compiler flag -ggdb works... " >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking " >&5 +$as_echo_n "checking ... " >&6; } + fi + save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -ggdb" + + + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(){} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + cvd_conf_test=1 +else + cvd_conf_test=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + + + + if test $cvd_conf_test = 1 + then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ts_success=yes + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CXXFLAGS="$save_CXXFLAGS" + ts_success=no + fi + +fi + + ax_cxx_compile_cxx14_required=true + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + ac_success=no + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++14 features by default" >&5 +$as_echo_n "checking whether $CXX supports C++14 features by default... " >&6; } +if ${ax_cv_cxx_compile_cxx14+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + struct Base { + virtual void f() {} + }; + struct Child : public Base { + virtual void f() override {} + }; + + typedef check> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check check_type; + check_type c; + check_type&& cr = static_cast(c); + + auto d = a; + auto l = [](){}; + // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] + struct use_l { use_l() { l(); } }; + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this + namespace test_template_alias_sfinae { + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { + func(0); + } + } + + // Check for C++14 attribute support + void noret [[noreturn]] () { throw 0; } + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ax_cv_cxx_compile_cxx14=yes +else + ax_cv_cxx_compile_cxx14=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx14" >&5 +$as_echo "$ax_cv_cxx_compile_cxx14" >&6; } + if test x$ax_cv_cxx_compile_cxx14 = xyes; then + ac_success=yes + fi + + if test x$ac_success = xno; then + for switch in -std=gnu++14 -std=gnu++1y; do + cachevar=`$as_echo "ax_cv_cxx_compile_cxx14_$switch" | $as_tr_sh` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++14 features with $switch" >&5 +$as_echo_n "checking whether $CXX supports C++14 features with $switch... " >&6; } +if eval \${$cachevar+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + struct Base { + virtual void f() {} + }; + struct Child : public Base { + virtual void f() override {} + }; + + typedef check> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check check_type; + check_type c; + check_type&& cr = static_cast(c); + + auto d = a; + auto l = [](){}; + // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] + struct use_l { use_l() { l(); } }; + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this + namespace test_template_alias_sfinae { + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { + func(0); + } + } + + // Check for C++14 attribute support + void noret [[noreturn]] () { throw 0; } + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval $cachevar=yes +else + eval $cachevar=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXXFLAGS="$ac_save_CXXFLAGS" +fi +eval ac_res=\$$cachevar + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi + + if test x$ac_success = xno; then + for switch in -std=c++14 -std=c++1y +std=c++14 "-h std=c++14"; do + cachevar=`$as_echo "ax_cv_cxx_compile_cxx14_$switch" | $as_tr_sh` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++14 features with $switch" >&5 +$as_echo_n "checking whether $CXX supports C++14 features with $switch... " >&6; } +if eval \${$cachevar+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + struct Base { + virtual void f() {} + }; + struct Child : public Base { + virtual void f() override {} + }; + + typedef check> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check check_type; + check_type c; + check_type&& cr = static_cast(c); + + auto d = a; + auto l = [](){}; + // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] + struct use_l { use_l() { l(); } }; + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this + namespace test_template_alias_sfinae { + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { + func(0); + } + } + + // Check for C++14 attribute support + void noret [[noreturn]] () { throw 0; } + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval $cachevar=yes +else + eval $cachevar=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXXFLAGS="$ac_save_CXXFLAGS" +fi +eval ac_res=\$$cachevar + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + if test x$ax_cxx_compile_cxx14_required = xtrue; then + if test x$ac_success = xno; then + as_fn_error $? "*** A compiler with support for C++14 language features is required." "$LINENO" 5 + fi + else + if test x$ac_success = xno; then + HAVE_CXX14=0 + { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++14 support was found" >&5 +$as_echo "$as_me: No compiler with C++14 support was found" >&6;} + else + HAVE_CXX14=1 + +$as_echo "#define HAVE_CXX14 1" >>confdefs.h + + fi + + + fi + + + +# +# Test for Package Config +# +# Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +if test "x$PKG_CONFIG" = "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find pkg-config, will not create pc file." >&5 +$as_echo "$as_me: WARNING: Could not find pkg-config, will not create pc file." >&2;} +else + # we need sed to find the pkg-config lib directory + # Extract the first word of "sed", so it can be a program name with args. +set dummy sed; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$SED"; then + ac_cv_prog_SED="$SED" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_SED="sed" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_SED" && ac_cv_prog_SED="as_fn_error $? "You Must install sed" "$LINENO" 5" +fi +fi +SED=$ac_cv_prog_SED +if test -n "$SED"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5 +$as_echo "$SED" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pkg-config library dir" >&5 +$as_echo_n "checking for pkg-config library dir... " >&6; } + PKGCONFIG_LIBDIR="`echo $PKG_CONFIG | $SED -e 's~.*/bin/pkg-config$~~'`${libdir}/pkgconfig" + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG_LIBDIR" >&5 +$as_echo "$PKGCONFIG_LIBDIR" >&6; } + + ac_config_files="$ac_config_files libblepp.pc" + + + # This will be put into the pc file + VERSION=version-0.5 + +fi + +a=1 +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if ${ac_cv_prog_CXXCPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_cxx_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +ac_fn_cxx_check_header_mongrel "$LINENO" "bluetooth/bluetooth.h" "ac_cv_header_bluetooth_bluetooth_h" "$ac_includes_default" +if test "x$ac_cv_header_bluetooth_bluetooth_h" = xyes; then : + +else + a=0 +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing hci_open_dev" >&5 +$as_echo_n "checking for library containing hci_open_dev... " >&6; } +if ${ac_cv_search_hci_open_dev+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char hci_open_dev (); +int +main () +{ +return hci_open_dev (); + ; + return 0; +} +_ACEOF +for ac_lib in '' bluetooth; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_search_hci_open_dev=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_hci_open_dev+:} false; then : + break +fi +done +if ${ac_cv_search_hci_open_dev+:} false; then : + +else + ac_cv_search_hci_open_dev=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_hci_open_dev" >&5 +$as_echo "$ac_cv_search_hci_open_dev" >&6; } +ac_res=$ac_cv_search_hci_open_dev +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +else + a=0 +fi + + +if test x$a == x0 +then + as_fn_error $? "bluez bluetooth missing" "$LINENO" 5 +fi + +ac_fn_cxx_check_header_mongrel "$LINENO" "boost/optional.hpp" "ac_cv_header_boost_optional_hpp" "$ac_includes_default" +if test "x$ac_cv_header_boost_optional_hpp" = xyes; then : + +else + as_fn_error $? "boost::optional missing" "$LINENO" 5 +fi + + + + + + + if test "" == "" + then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler flag -fPIC works" >&5 +$as_echo_n "checking if compiler flag -fPIC works... " >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking " >&5 +$as_echo_n "checking ... " >&6; } + fi + save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fPIC" + + + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(){} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + cvd_conf_test=1 +else + cvd_conf_test=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + + + + if test $cvd_conf_test = 1 + then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ts_success=yes + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CXXFLAGS="$save_CXXFLAGS" + ts_success=no + fi + + +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by libble++ $as_me version-0.5, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +libble++ config.status version-0.5 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "libblepp.pc") CONFIG_FILES="$CONFIG_FILES libblepp.pc" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + diff --git a/vendor/libblepp-master/configure.ac b/vendor/libblepp-master/configure.ac new file mode 100644 index 0000000..56907e9 --- /dev/null +++ b/vendor/libblepp-master/configure.ac @@ -0,0 +1,111 @@ +AC_INIT(libble++, version-0.5) +AC_COPYRIGHT([E. Rosten, 2016, the BlueZ contributors to 2016]) +AC_LANG(C++) +AC_PROG_CXX + + +m4_include([m4/ax_cxx_compile_stdcxx_14.m4]) + + +################################################################################ +# +# Useful macros +# + +dnl APPEND(var, value) +dnl This appends vale to a shell variable var +define(APPEND, [$1="$$1 $2"]) + + + +dnl TEST_AND_SET_CXXFLAG(flag, [program], [run]) +dnl +dnl This attempts to compile a and run program with a certain compiler flag. +dnl If no program is given, then the minimal C++ program is compiled, and +dnl this tests just the validity of the compiler flag. +dnl +define([TEST_AND_SET_CXXFLAG],[ + if test "$3" == "" + then + AC_MSG_CHECKING([if compiler flag $1 works]) + else + AC_MSG_CHECKING([$3]) + fi + save_CXXFLAGS="$CXXFLAGS" + APPEND(CXXFLAGS, [$1]) + + m4_if([$2],[],[pushdef(prog, [int main(){}])], [pushdef(prog, [$2])]) + + m4_if([$4],[run], + [AC_RUN_IFELSE([AC_LANG_SOURCE([prog])], [cvd_conf_test=1],[cvd_conf_test=0], [cvd_conf_test=0])], + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([prog])], [cvd_conf_test=1],[cvd_conf_test=0])] + ) + + + popdef([prog]) + + if test $cvd_conf_test = 1 + then + AC_MSG_RESULT(yes) + ts_success=yes + else + AC_MSG_RESULT(no) + CXXFLAGS="$save_CXXFLAGS" + ts_success=no + fi +]) + + +dnl Add flags, but only if the flags weren't specified. +if test "$CXXFLAGS" == "-g -O2" +then + + TEST_AND_SET_CXXFLAG(-Wall) + TEST_AND_SET_CXXFLAG(-Wextra) + TEST_AND_SET_CXXFLAG(-W) + TEST_AND_SET_CXXFLAG(-O3) + TEST_AND_SET_CXXFLAG(-ggdb) +fi + +AX_CXX_COMPILE_STDCXX_14 + + +# +# Test for Package Config +# +AC_PATH_PROG(PKG_CONFIG, pkg-config) +if test "x$PKG_CONFIG" = "x"; then + AC_MSG_WARN([Could not find pkg-config, will not create pc file.]) +else + # we need sed to find the pkg-config lib directory + AC_CHECK_PROG(SED,sed,sed,AC_MSG_ERROR([You Must install sed])) + AC_MSG_CHECKING([for pkg-config library dir]) + PKGCONFIG_LIBDIR="`echo $PKG_CONFIG | $SED -e 's~.*/bin/pkg-config$~~'`${libdir}/pkgconfig" + + AC_MSG_RESULT($PKGCONFIG_LIBDIR) + AC_SUBST(PKGCONFIG_LIBDIR) + AC_CONFIG_FILES([ libblepp.pc ]) + + # This will be put into the pc file + VERSION=AC_PACKAGE_VERSION() + AC_SUBST(VERSION) +fi + +a=1 +AC_CHECK_HEADER(bluetooth/bluetooth.h, [ ], [a=0]) +AC_SEARCH_LIBS(hci_open_dev, bluetooth, [ ], [a=0]) + +if test x$a == x0 +then + AC_ERROR([bluez bluetooth missing]) +fi + +AC_CHECK_HEADER(boost/optional.hpp, [ ], [AC_ERROR([boost::optional missing])]) + + + +TEST_AND_SET_CXXFLAG(-fPIC) +dnl TEST_AND_SET_CXXFLAG(-Werror) + +AC_OUTPUT(Makefile) + diff --git a/vendor/libblepp-master/cxxgplot.h b/vendor/libblepp-master/cxxgplot.h new file mode 100644 index 0000000..dc36419 --- /dev/null +++ b/vendor/libblepp-master/cxxgplot.h @@ -0,0 +1,159 @@ +#include "pstreams/pstream.h" +#include +#include +#include +#include + +//Super simple and stupid class for interactive +//plotting and visualisation from C++ using gnuplot +namespace cplot +{ + //A plot contains multiple axes + // A plot has a single location so axes are overlaid + // + //Axes contain multiple lines + + + class Plotter + { + //std::vector plots; + + std::vector plots, pdata, extra; + redi::opstream plot; + + public: + + std::string range; + + Plotter() + :plot("gnuplot") + { + plot << "set term x11 noraise\n"; + newline(""); + } + + + std::ostream& s() + { + return plot; + } + + void add_extra(const std::string& s) + { + extra.push_back(s); + } + + Plotter& newline(const std::string& ps) + { + plots.push_back(ps); + pdata.push_back(""); + return *this; + } + + template Plotter& addpt(const C& pt) + { + using std::isfinite; + std::ostringstream o; + + if(isfinite(pt)) + o << pt << std::endl; + else + skip(); + + pdata.back() += o.str(); + return *this; + } + + template Plotter& addpt(C p1, C p2) + { + using std::isfinite; + std::ostringstream o; + + if(isfinite(p1) && isfinite(p2)) + o << p1 << " " << p2 << std::endl; + else + skip(); + + pdata.back() += o.str(); + return *this; + } + + template Plotter& addpts(const D& pt) + { + using std::isfinite; + std::ostringstream o; + for(unsigned int i=0; i < pt.size(); i++) + if(isfinite(pt[i])) + o << pt[i] << std::endl; + else + skip(); + + pdata.back() += o.str(); + return *this; + } + + Plotter& skip() + { + pdata.back() += "\n"; + return *this; + } + + void draw() + { + using std::cerr; + using std::endl; + + bool data=0; + + //Check for data + std::vector have_data(plots.size()); + for(unsigned int i=0; i < plots.size(); i++) + for(unsigned int j=0; j < pdata[i].size(); j++) + if(!std::isspace(pdata[i][j])) + { + have_data[i] = 1; + data=1; + break; + } + + for(unsigned int i=0, first=1; i < plots.size(); i++) + if(have_data[i]) + { + if(first) + { + plot << "plot " << range << " \"-\""; + first=0; + } + else + { + plot << ", \"-\""; + } + + if(plots[i] != "") + { + plot << " with " << plots[i]; + } + } + + if(data) + plot << std::endl; + for(unsigned int i=0; i < plots.size(); i++) + if(have_data[i]) + { + plot << pdata[i] << "e\n"; + } + + if(data) + plot << std::flush; + + for(unsigned int i=0; i < extra.size(); i++) + plot << extra[i] << "\n"; + + + plots.clear(); + extra.clear(); + pdata.clear(); + newline(""); + } + }; +} diff --git a/vendor/libblepp-master/get_attrs.sh b/vendor/libblepp-master/get_attrs.sh new file mode 100644 index 0000000..a448ae5 --- /dev/null +++ b/vendor/libblepp-master/get_attrs.sh @@ -0,0 +1,11 @@ +mkdir attrs +cd attrs +mkdir services + +wget https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx + +awk -vFPAT='org.bluetooth.service.[a-z_]*' '{ + for(i=1; i <= NF; i++) + print $i + +}' ServicesHome.aspx | sed -e's!.*!wget -O services/&.xml https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=&.xml!' | parallel 50 diff --git a/vendor/libblepp-master/hex2ascii.awk b/vendor/libblepp-master/hex2ascii.awk new file mode 100644 index 0000000..c7c3b5f --- /dev/null +++ b/vendor/libblepp-master/hex2ascii.awk @@ -0,0 +1,31 @@ +BEGIN{ + for(i=0; i < 256; i++) + { + hex2c[sprintf("%02x", i)]=sprintf("%c", i) + hex2c[sprintf("%02X", i)]=sprintf("%c", i) + hex2c[sprintf("%x", i)]=sprintf("%c", i) + hex2c[sprintf("%X", i)]=sprintf("%c", i) + + hex2n[sprintf("%02x", i)]=sprintf("%i", i) + hex2n[sprintf("%02X", i)]=sprintf("%i", i) + hex2n[sprintf("%x", i)]=sprintf("%i", i) + hex2n[sprintf("%X", i)]=sprintf("%i", i) + } +} + +{ + for(i=1; i <= NF; i++) + if($i in hex2c) + printf("%s", hex2c[$i]) + else + printf("--%s--", $i) + + print "" + for(i=1; i <= NF; i++) + if($i in hex2c) + printf("%s ", hex2n[$i]) + else + printf("--%s-- ", $i) + + print "" +} diff --git a/vendor/libblepp-master/lescan.cc b/vendor/libblepp-master/lescan.cc new file mode 100644 index 0000000..5de0ae2 --- /dev/null +++ b/vendor/libblepp-master/lescan.cc @@ -0,0 +1,133 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include //for UUID. FIXME mofo +#include + +using namespace std; +using namespace BLEPP; + +void catch_function(int) +{ + cerr << "\nInterrupted!\n"; +} + +int main(int argc, char** argv) +{ + HCIScanner::ScanType type = HCIScanner::ScanType::Active; + HCIScanner::FilterDuplicates filter = HCIScanner::FilterDuplicates::Software; + int c; + string help = R"X(-[sHbdhp]: + -s software filtering of duplicates (default) + -H hardware filtering of duplicates + -b both hardware and software filtering + -d show duplicates (no filtering) + -h show this message + -p passive scan +)X"; + while((c=getopt(argc, argv, "sHbdhp")) != -1) + { + if(c == 'p') + type = HCIScanner::ScanType::Passive; + else if(c == 's') + filter = HCIScanner::FilterDuplicates::Software; + else if(c == 'H') + filter = HCIScanner::FilterDuplicates::Hardware; + else if(c == 'b') + filter = HCIScanner::FilterDuplicates::Both; + else if(c == 'd') + filter = HCIScanner::FilterDuplicates::Off; + else if(c == 'h') + { + cout << "Usage: " << argv[0] << " " << help; + return 0; + } + else + { + cerr << argv[0] << ": unknown option " << c << endl; + return 1; + } + } + + + log_level = LogLevels::Warning; + HCIScanner scanner(true, filter, type); + + //Catch the interrupt signal. If the scanner is not + //cleaned up properly, then it doesn't reset the HCI state. + signal(SIGINT, catch_function); + + //Something to print to demonstrate the timeout. + string throbber="/|\\-"; + + //hide cursor, to make the throbber look nicer. + cout << "[?25l" << flush; + + int i=0; + while (1) { + + + //Check to see if there's anything to read from the HCI + //and wait if there's not. + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 300000; + + fd_set fds; + FD_ZERO(&fds); + FD_SET(scanner.get_fd(), &fds); + int err = select(scanner.get_fd()+1, &fds, NULL, NULL, &timeout); + + //Interrupted, so quit and clean up properly. + if(err < 0 && errno == EINTR) + break; + + if(FD_ISSET(scanner.get_fd(), &fds)) + { + //Only read id there's something to read + vector ads = scanner.get_advertisements(); + + for(const auto& ad: ads) + { + cout << "Found device: " << ad.address << " "; + + if(ad.type == LeAdvertisingEventType::ADV_IND) + cout << "Connectable undirected" << endl; + else if(ad.type == LeAdvertisingEventType::ADV_DIRECT_IND) + cout << "Connectable directed" << endl; + else if(ad.type == LeAdvertisingEventType::ADV_SCAN_IND) + cout << "Scannable " << endl; + else if(ad.type == LeAdvertisingEventType::ADV_NONCONN_IND) + cout << "Non connectable" << endl; + else + cout << "Scan response" << endl; + for(const auto& uuid: ad.UUIDs) + cout << " Service: " << to_str(uuid) << endl; + if(ad.local_name) + cout << " Name: " << ad.local_name->name << endl; + } + } + else + cout << throbber[i%4] << "\b" << flush; + i++; + } + + //show cursor + cout << "[?25h" << flush; +} diff --git a/vendor/libblepp-master/lescan_simple.cc b/vendor/libblepp-master/lescan_simple.cc new file mode 100644 index 0000000..bf2f79d --- /dev/null +++ b/vendor/libblepp-master/lescan_simple.cc @@ -0,0 +1,10 @@ +#include + +int main() +{ + BLEPP::log_level = BLEPP::LogLevels::Info; + BLEPP::HCIScanner scanner; + while (1) { + std::vector ads = scanner.get_advertisements(); + } +} diff --git a/vendor/libblepp-master/libblepp.pc.in b/vendor/libblepp-master/libblepp.pc.in new file mode 100644 index 0000000..116c388 --- /dev/null +++ b/vendor/libblepp-master/libblepp.pc.in @@ -0,0 +1,8 @@ +prefix=@prefix@ +includedir=@includedir@ + +Name: libble++ +Description: Bluetooth LE interface for C++ +Version: @VERSION@ +Libs: @LIBS@ +Cflags: -I${includedir} diff --git a/vendor/libblepp-master/m4/ax_cxx_compile_stdcxx_14.m4 b/vendor/libblepp-master/m4/ax_cxx_compile_stdcxx_14.m4 new file mode 100644 index 0000000..8792fe1 --- /dev/null +++ b/vendor/libblepp-master/m4/ax_cxx_compile_stdcxx_14.m4 @@ -0,0 +1,173 @@ +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_14.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_14([ext|noext],[mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++14 +# standard; if necessary, add switches to CXXFLAGS to enable support. +# +# The first argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++14) or a strict conformance mode (e.g. +# -std=c++14). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The second argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline C++14 support is required and that the macro +# should error out if no mode with that support is found. If specified +# 'optional', then configuration proceeds regardless, after defining +# HAVE_CXX14 if and only if a supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2016 Edward Rosten +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 13 + +m4_define([_AX_CXX_COMPILE_STDCXX_14_testbody], [[ + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + struct Base { + virtual void f() {} + }; + struct Child : public Base { + virtual void f() override {} + }; + + typedef check> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check check_type; + check_type c; + check_type&& cr = static_cast(c); + + auto d = a; + auto l = [](){}; + // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] + struct use_l { use_l() { l(); } }; + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this + namespace test_template_alias_sfinae { + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { + func(0); + } + } + + // Check for C++14 attribute support + void noret [[noreturn]] () { throw 0; } +]]) + +AC_DEFUN([AX_CXX_COMPILE_STDCXX_14], [dnl + m4_if([$1], [], [], + [$1], [ext], [], + [$1], [noext], [], + [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_14])])dnl + m4_if([$2], [], [ax_cxx_compile_cxx14_required=true], + [$2], [mandatory], [ax_cxx_compile_cxx14_required=true], + [$2], [optional], [ax_cxx_compile_cxx14_required=false], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_14])]) + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++14 features by default, + ax_cv_cxx_compile_cxx14, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_14_testbody])], + [ax_cv_cxx_compile_cxx14=yes], + [ax_cv_cxx_compile_cxx14=no])]) + if test x$ax_cv_cxx_compile_cxx14 = xyes; then + ac_success=yes + fi + + m4_if([$1], [noext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=gnu++14 -std=gnu++1y; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx14_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++14 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_14_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + + m4_if([$1], [ext], [], [dnl + if test x$ac_success = xno; then + dnl HP's aCC needs +std=c++14 according to: + dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf + dnl Cray's crayCC needs "-h std=c++14" + for switch in -std=c++14 -std=c++1y +std=c++14 "-h std=c++14"; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx14_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++14 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_14_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx14_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++14 language features is required.]) + fi + else + if test x$ac_success = xno; then + HAVE_CXX14=0 + AC_MSG_NOTICE([No compiler with C++14 support was found]) + else + HAVE_CXX14=1 + AC_DEFINE(HAVE_CXX14,1, + [define if the compiler supports basic C++14 syntax]) + fi + + AC_SUBST(HAVE_CXX14) + fi +]) diff --git a/vendor/libblepp-master/primary_service_names.cc b/vendor/libblepp-master/primary_service_names.cc new file mode 100644 index 0000000..170df9e --- /dev/null +++ b/vendor/libblepp-master/primary_service_names.cc @@ -0,0 +1,32 @@ + + + + + + +"Alert Notification Service", "org.bluetooth.service.alert_notification", 0x1811 +"Battery Service", "org.bluetooth.service.battery_service", 0x180F +"Blood Pressure", "org.bluetooth.service.blood_pressure", 0x1810 +"Body Composition", "org.bluetooth.service.body_composition", 0x181B +"Bond Management", "org.bluetooth.service.bond_management", 0x181E +"Current Time Service", "org.bluetooth.service.current_time", 0x1805 +"Cycling Power", "org.bluetooth.service.cycling_power", 0x1818 +"Cycling Speed and Cadence", "org.bluetooth.service.cycling_speed_and_cadence", 0x1816 +"Device Information", "org.bluetooth.service.device_information", 0x180A +"Generic Access", "org.bluetooth.service.generic_access", 0x1800 +"Generic Attribute", "org.bluetooth.service.generic_attribute", 0x1801 +"Glucose", "org.bluetooth.service.glucose", 0x1808 +"Health Thermometer", "org.bluetooth.service.health_thermometer", 0x1809 +"Heart Rate", "org.bluetooth.service.heart_rate", 0x180D +"Human Interface Device", "org.bluetooth.service.human_interface_device", 0x1812 +"Immediate Alert", "org.bluetooth.service.immediate_alert", 0x1802 +"Link Loss", "org.bluetooth.service.link_loss", 0x1803 +"Location and Navigation", "org.bluetooth.service.location_and_navigation", 0x1819 +"Next DST Change Service", "org.bluetooth.service.next_dst_change", 0x1807 +"Phone Alert Status Service", "org.bluetooth.service.phone_alert_status", 0x180E +"Reference Time Update Service", "org.bluetooth.service.reference_time_update", 0x1806 +"Running Speed and Cadence", "org.bluetooth.service.running_speed_and_cadence", 0x1814 +"Scan Parameters", "org.bluetooth.service.scan_parameters", 0x1813 +"Tx Power", "org.bluetooth.service.tx_power", 0x1804 +"User Data", "org.bluetooth.service.user_data", 0x181C +"Weight Scale", "org.bluetooth.service.weight_scale", 0x181D diff --git a/vendor/libblepp-master/pstreams/pstream.h b/vendor/libblepp-master/pstreams/pstream.h new file mode 100644 index 0000000..c0a1f96 --- /dev/null +++ b/vendor/libblepp-master/pstreams/pstream.h @@ -0,0 +1,2095 @@ +/* $Id: pstream.h,v 1.112 2010/03/20 14:50:47 redi Exp $ +PStreams - POSIX Process I/O for C++ +Copyright (C) 2001,2002,2003,2004,2005,2006,2007,2008 Jonathan Wakely + +This file is part of PStreams. + +PStreams is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +PStreams is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . +*/ + +/** + * @file pstream.h + * @brief Declares all PStreams classes. + * @author Jonathan Wakely + * + * Defines classes redi::ipstream, redi::opstream, redi::pstream + * and redi::rpstream. + */ + +#ifndef REDI_PSTREAM_H_SEEN +#define REDI_PSTREAM_H_SEEN + +#include +#include +#include +#include +#include +#include +#include // for min() +#include // for errno +#include // for size_t +#include // for exit() +#include // for pid_t +#include // for waitpid() +#include // for ioctl() and FIONREAD +#if defined(__sun) +# include // for FIONREAD on Solaris 2.5 +#endif +#include // for pipe() fork() exec() and filedes functions +#include // for kill() +#include // for fcntl() +#if REDI_EVISCERATE_PSTREAMS +# include // for FILE, fdopen() +#endif + + +/// The library version. +#define PSTREAMS_VERSION 0x0070 // 0.7.0 + +/** + * @namespace redi + * @brief All PStreams classes are declared in namespace redi. + * + * Like the standard iostreams, PStreams is a set of class templates, + * taking a character type and traits type. As with the standard streams + * they are most likely to be used with @c char and the default + * traits type, so typedefs for this most common case are provided. + * + * The @c pstream_common class template is not intended to be used directly, + * it is used internally to provide the common functionality for the + * other stream classes. + */ +namespace redi +{ + /// Common base class providing constants and typenames. + struct pstreams + { + /// Type used to specify how to connect to the process. + typedef std::ios_base::openmode pmode; + + /// Type used to hold the arguments for a command. + typedef std::vector argv_type; + + /// Type used for file descriptors. + typedef int fd_type; + + static const pmode pstdin = std::ios_base::out; ///< Write to stdin + static const pmode pstdout = std::ios_base::in; ///< Read from stdout + static const pmode pstderr = std::ios_base::app; ///< Read from stderr + + protected: + enum { bufsz = 32 }; ///< Size of pstreambuf buffers. + enum { pbsz = 2 }; ///< Number of putback characters kept. + }; + + /// Class template for stream buffer. + template > + class basic_pstreambuf + : public std::basic_streambuf + , public pstreams + { + public: + // Type definitions for dependent types + typedef CharT char_type; + typedef Traits traits_type; + typedef typename traits_type::int_type int_type; + typedef typename traits_type::off_type off_type; + typedef typename traits_type::pos_type pos_type; + /** @deprecated use pstreams::fd_type instead. */ + typedef fd_type fd_t; + + /// Default constructor. + basic_pstreambuf(); + + /// Constructor that initialises the buffer with @a command. + basic_pstreambuf(const std::string& command, pmode mode); + + /// Constructor that initialises the buffer with @a file and @a argv. + basic_pstreambuf( const std::string& file, + const argv_type& argv, + pmode mode ); + + /// Destructor. + ~basic_pstreambuf(); + + /// Initialise the stream buffer with @a command. + basic_pstreambuf* + open(const std::string& command, pmode mode); + + /// Initialise the stream buffer with @a file and @a argv. + basic_pstreambuf* + open(const std::string& file, const argv_type& argv, pmode mode); + + /// Close the stream buffer and wait for the process to exit. + basic_pstreambuf* + close(); + + /// Send a signal to the process. + basic_pstreambuf* + kill(int signal = SIGTERM); + + /// Close the pipe connected to the process' stdin. + void + peof(); + + /// Change active input source. + bool + read_err(bool readerr = true); + + /// Report whether the stream buffer has been initialised. + bool + is_open() const; + + /// Report whether the process has exited. + bool + exited(); + +#if REDI_EVISCERATE_PSTREAMS + /// Obtain FILE pointers for each of the process' standard streams. + std::size_t + fopen(FILE*& in, FILE*& out, FILE*& err); +#endif + + /// Return the exit status of the process. + int + status() const; + + /// Return the error number (errno) for the most recent failed operation. + int + error() const; + + protected: + /// Transfer characters to the pipe when character buffer overflows. + int_type + overflow(int_type c); + + /// Transfer characters from the pipe when the character buffer is empty. + int_type + underflow(); + + /// Make a character available to be returned by the next extraction. + int_type + pbackfail(int_type c = traits_type::eof()); + + /// Write any buffered characters to the stream. + int + sync(); + + /// Insert multiple characters into the pipe. + std::streamsize + xsputn(const char_type* s, std::streamsize n); + + /// Insert a sequence of characters into the pipe. + std::streamsize + write(const char_type* s, std::streamsize n); + + /// Extract a sequence of characters from the pipe. + std::streamsize + read(char_type* s, std::streamsize n); + + /// Report how many characters can be read from active input without blocking. + std::streamsize + showmanyc(); + + protected: + /// Enumerated type to indicate whether stdout or stderr is to be read. + enum buf_read_src { rsrc_out = 0, rsrc_err = 1 }; + + /// Initialise pipes and fork process. + pid_t + fork(pmode mode); + + /// Wait for the child process to exit. + int + wait(bool nohang = false); + + /// Return the file descriptor for the output pipe. + fd_type& + wpipe(); + + /// Return the file descriptor for the active input pipe. + fd_type& + rpipe(); + + /// Return the file descriptor for the specified input pipe. + fd_type& + rpipe(buf_read_src which); + + void + create_buffers(pmode mode); + + void + destroy_buffers(pmode mode); + + /// Writes buffered characters to the process' stdin pipe. + bool + empty_buffer(); + + bool + fill_buffer(bool non_blocking = false); + + /// Return the active input buffer. + char_type* + rbuffer(); + + buf_read_src + switch_read_buffer(buf_read_src); + + private: + basic_pstreambuf(const basic_pstreambuf&); + basic_pstreambuf& operator=(const basic_pstreambuf&); + + void + init_rbuffers(); + + pid_t ppid_; // pid of process + fd_type wpipe_; // pipe used to write to process' stdin + fd_type rpipe_[2]; // two pipes to read from, stdout and stderr + char_type* wbuffer_; + char_type* rbuffer_[2]; + char_type* rbufstate_[3]; + /// Index into rpipe_[] to indicate active source for read operations. + buf_read_src rsrc_; + int status_; // hold exit status of child process + int error_; // hold errno if fork() or exec() fails + }; + + /// Class template for common base class. + template > + class pstream_common + : virtual public std::basic_ios + , virtual public pstreams + { + protected: + typedef basic_pstreambuf streambuf_type; + + typedef pstreams::pmode pmode; + typedef pstreams::argv_type argv_type; + + /// Default constructor. + pstream_common(); + + /// Constructor that initialises the stream by starting a process. + pstream_common(const std::string& command, pmode mode); + + /// Constructor that initialises the stream by starting a process. + pstream_common(const std::string& file, const argv_type& argv, pmode mode); + + /// Pure virtual destructor. + virtual + ~pstream_common() = 0; + + /// Start a process. + void + do_open(const std::string& command, pmode mode); + + /// Start a process. + void + do_open(const std::string& file, const argv_type& argv, pmode mode); + + public: + /// Close the pipe. + void + close(); + + /// Report whether the stream's buffer has been initialised. + bool + is_open() const; + + /// Return the command used to initialise the stream. + const std::string& + command() const; + + /// Return a pointer to the stream buffer. + streambuf_type* + rdbuf() const; + +#if REDI_EVISCERATE_PSTREAMS + /// Obtain FILE pointers for each of the process' standard streams. + std::size_t + fopen(FILE*& in, FILE*& out, FILE*& err); +#endif + + protected: + std::string command_; ///< The command used to start the process. + streambuf_type buf_; ///< The stream buffer. + }; + + + /** + * @class basic_ipstream + * @brief Class template for Input PStreams. + * + * Reading from an ipstream reads the command's standard output and/or + * standard error (depending on how the ipstream is opened) + * and the command's standard input is the same as that of the process + * that created the object, unless altered by the command itself. + */ + + template > + class basic_ipstream + : public std::basic_istream + , public pstream_common + , virtual public pstreams + { + typedef std::basic_istream istream_type; + typedef pstream_common pbase_type; + + using pbase_type::buf_; // declare name in this scope + + pmode readable(pmode mode) + { + if (!(mode & (pstdout|pstderr))) + mode |= pstdout; + return mode; + } + + public: + /// Type used to specify how to connect to the process. + typedef typename pbase_type::pmode pmode; + + /// Type used to hold the arguments for a command. + typedef typename pbase_type::argv_type argv_type; + + /// Default constructor, creates an uninitialised stream. + basic_ipstream() + : istream_type(NULL), pbase_type() + { } + + /** + * @brief Constructor that initialises the stream by starting a process. + * + * Initialises the stream buffer by calling do_open() with the supplied + * arguments. + * + * @param command a string containing a shell command. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, pmode) + */ + basic_ipstream(const std::string& command, pmode mode = pstdout) + : istream_type(NULL), pbase_type(command, readable(mode)) + { } + + /** + * @brief Constructor that initialises the stream by starting a process. + * + * Initialises the stream buffer by calling do_open() with the supplied + * arguments. + * + * @param file a string containing the pathname of a program to execute. + * @param argv a vector of argument strings passed to the new program. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, const argv_type&, pmode) + */ + basic_ipstream( const std::string& file, + const argv_type& argv, + pmode mode = pstdout ) + : istream_type(NULL), pbase_type(file, argv, readable(mode)) + { } + + /** + * @brief Destructor. + * + * Closes the stream and waits for the child to exit. + */ + ~basic_ipstream() + { } + + /** + * @brief Start a process. + * + * Calls do_open( @a %command , @a mode|pstdout ). + * + * @param command a string containing a shell command. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, pmode) + */ + void + open(const std::string& command, pmode mode = pstdout) + { + this->do_open(command, readable(mode)); + } + + /** + * @brief Start a process. + * + * Calls do_open( @a file , @a argv , @a mode|pstdout ). + * + * @param file a string containing the pathname of a program to execute. + * @param argv a vector of argument strings passed to the new program. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, const argv_type&, pmode) + */ + void + open( const std::string& file, + const argv_type& argv, + pmode mode = pstdout ) + { + this->do_open(file, argv, readable(mode)); + } + + /** + * @brief Set streambuf to read from process' @c stdout. + * @return @c *this + */ + basic_ipstream& + out() + { + this->buf_.read_err(false); + return *this; + } + + /** + * @brief Set streambuf to read from process' @c stderr. + * @return @c *this + */ + basic_ipstream& + err() + { + this->buf_.read_err(true); + return *this; + } + }; + + + /** + * @class basic_opstream + * @brief Class template for Output PStreams. + * + * Writing to an open opstream writes to the standard input of the command; + * the command's standard output is the same as that of the process that + * created the pstream object, unless altered by the command itself. + */ + + template > + class basic_opstream + : public std::basic_ostream + , public pstream_common + , virtual public pstreams + { + typedef std::basic_ostream ostream_type; + typedef pstream_common pbase_type; + + using pbase_type::buf_; // declare name in this scope + + public: + /// Type used to specify how to connect to the process. + typedef typename pbase_type::pmode pmode; + + /// Type used to hold the arguments for a command. + typedef typename pbase_type::argv_type argv_type; + + /// Default constructor, creates an uninitialised stream. + basic_opstream() + : ostream_type(NULL), pbase_type() + { } + + /** + * @brief Constructor that initialises the stream by starting a process. + * + * Initialises the stream buffer by calling do_open() with the supplied + * arguments. + * + * @param command a string containing a shell command. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, pmode) + */ + basic_opstream(const std::string& command, pmode mode = pstdin) + : ostream_type(NULL), pbase_type(command, mode|pstdin) + { } + + /** + * @brief Constructor that initialises the stream by starting a process. + * + * Initialises the stream buffer by calling do_open() with the supplied + * arguments. + * + * @param file a string containing the pathname of a program to execute. + * @param argv a vector of argument strings passed to the new program. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, const argv_type&, pmode) + */ + basic_opstream( const std::string& file, + const argv_type& argv, + pmode mode = pstdin ) + : ostream_type(NULL), pbase_type(file, argv, mode|pstdin) + { } + + /** + * @brief Destructor + * + * Closes the stream and waits for the child to exit. + */ + ~basic_opstream() { } + + /** + * @brief Start a process. + * + * Calls do_open( @a %command , @a mode|pstdin ). + * + * @param command a string containing a shell command. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, pmode) + */ + void + open(const std::string& command, pmode mode = pstdin) + { + this->do_open(command, mode|pstdin); + } + + /** + * @brief Start a process. + * + * Calls do_open( @a file , @a argv , @a mode|pstdin ). + * + * @param file a string containing the pathname of a program to execute. + * @param argv a vector of argument strings passed to the new program. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, const argv_type&, pmode) + */ + void + open( const std::string& file, + const argv_type& argv, + pmode mode = pstdin) + { + this->do_open(file, argv, mode|pstdin); + } + }; + + + /** + * @class basic_pstream + * @brief Class template for Bidirectional PStreams. + * + * Writing to a pstream opened with @c pmode @c pstdin writes to the + * standard input of the command. + * Reading from a pstream opened with @c pmode @c pstdout and/or @c pstderr + * reads the command's standard output and/or standard error. + * Any of the process' @c stdin, @c stdout or @c stderr that is not + * connected to the pstream (as specified by the @c pmode) + * will be the same as the process that created the pstream object, + * unless altered by the command itself. + */ + template > + class basic_pstream + : public std::basic_iostream + , public pstream_common + , virtual public pstreams + { + typedef std::basic_iostream iostream_type; + typedef pstream_common pbase_type; + + using pbase_type::buf_; // declare name in this scope + + public: + /// Type used to specify how to connect to the process. + typedef typename pbase_type::pmode pmode; + + /// Type used to hold the arguments for a command. + typedef typename pbase_type::argv_type argv_type; + + /// Default constructor, creates an uninitialised stream. + basic_pstream() + : iostream_type(NULL), pbase_type() + { } + + /** + * @brief Constructor that initialises the stream by starting a process. + * + * Initialises the stream buffer by calling do_open() with the supplied + * arguments. + * + * @param command a string containing a shell command. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, pmode) + */ + basic_pstream(const std::string& command, pmode mode = pstdout|pstdin) + : iostream_type(NULL), pbase_type(command, mode) + { } + + /** + * @brief Constructor that initialises the stream by starting a process. + * + * Initialises the stream buffer by calling do_open() with the supplied + * arguments. + * + * @param file a string containing the pathname of a program to execute. + * @param argv a vector of argument strings passed to the new program. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, const argv_type&, pmode) + */ + basic_pstream( const std::string& file, + const argv_type& argv, + pmode mode = pstdout|pstdin ) + : iostream_type(NULL), pbase_type(file, argv, mode) + { } + + /** + * @brief Destructor + * + * Closes the stream and waits for the child to exit. + */ + ~basic_pstream() { } + + /** + * @brief Start a process. + * + * Calls do_open( @a %command , @a mode ). + * + * @param command a string containing a shell command. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, pmode) + */ + void + open(const std::string& command, pmode mode = pstdout|pstdin) + { + this->do_open(command, mode); + } + + /** + * @brief Start a process. + * + * Calls do_open( @a file , @a argv , @a mode ). + * + * @param file a string containing the pathname of a program to execute. + * @param argv a vector of argument strings passed to the new program. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, const argv_type&, pmode) + */ + void + open( const std::string& file, + const argv_type& argv, + pmode mode = pstdout|pstdin ) + { + this->do_open(file, argv, mode); + } + + /** + * @brief Set streambuf to read from process' @c stdout. + * @return @c *this + */ + basic_pstream& + out() + { + this->buf_.read_err(false); + return *this; + } + + /** + * @brief Set streambuf to read from process' @c stderr. + * @return @c *this + */ + basic_pstream& + err() + { + this->buf_.read_err(true); + return *this; + } + }; + + + /** + * @class basic_rpstream + * @brief template for Restricted PStreams. + * + * Writing to an rpstream opened with @c pmode @c pstdin writes to the + * standard input of the command. + * It is not possible to read directly from an rpstream object, to use + * an rpstream as in istream you must call either basic_rpstream::out() + * or basic_rpstream::err(). This is to prevent accidental reads from + * the wrong input source. If the rpstream was not opened with @c pmode + * @c pstderr then the class cannot read the process' @c stderr, and + * basic_rpstream::err() will return an istream that reads from the + * process' @c stdout, and vice versa. + * Reading from an rpstream opened with @c pmode @c pstdout and/or + * @c pstderr reads the command's standard output and/or standard error. + * Any of the process' @c stdin, @c stdout or @c stderr that is not + * connected to the pstream (as specified by the @c pmode) + * will be the same as the process that created the pstream object, + * unless altered by the command itself. + */ + + template > + class basic_rpstream + : public std::basic_ostream + , private std::basic_istream + , private pstream_common + , virtual public pstreams + { + typedef std::basic_ostream ostream_type; + typedef std::basic_istream istream_type; + typedef pstream_common pbase_type; + + using pbase_type::buf_; // declare name in this scope + + public: + /// Type used to specify how to connect to the process. + typedef typename pbase_type::pmode pmode; + + /// Type used to hold the arguments for a command. + typedef typename pbase_type::argv_type argv_type; + + /// Default constructor, creates an uninitialised stream. + basic_rpstream() + : ostream_type(NULL), istream_type(NULL), pbase_type() + { } + + /** + * @brief Constructor that initialises the stream by starting a process. + * + * Initialises the stream buffer by calling do_open() with the supplied + * arguments. + * + * @param command a string containing a shell command. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, pmode) + */ + basic_rpstream(const std::string& command, pmode mode = pstdout|pstdin) + : ostream_type(NULL) , istream_type(NULL) , pbase_type(command, mode) + { } + + /** + * @brief Constructor that initialises the stream by starting a process. + * + * Initialises the stream buffer by calling do_open() with the supplied + * arguments. + * + * @param file a string containing the pathname of a program to execute. + * @param argv a vector of argument strings passed to the new program. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, const argv_type&, pmode) + */ + basic_rpstream( const std::string& file, + const argv_type& argv, + pmode mode = pstdout|pstdin ) + : ostream_type(NULL), istream_type(NULL), pbase_type(file, argv, mode) + { } + + /// Destructor + ~basic_rpstream() { } + + /** + * @brief Start a process. + * + * Calls do_open( @a %command , @a mode ). + * + * @param command a string containing a shell command. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, pmode) + */ + void + open(const std::string& command, pmode mode = pstdout|pstdin) + { + this->do_open(command, mode); + } + + /** + * @brief Start a process. + * + * Calls do_open( @a file , @a argv , @a mode ). + * + * @param file a string containing the pathname of a program to execute. + * @param argv a vector of argument strings passed to the new program. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, const argv_type&, pmode) + */ + void + open( const std::string& file, + const argv_type& argv, + pmode mode = pstdout|pstdin ) + { + this->do_open(file, argv, mode); + } + + /** + * @brief Obtain a reference to the istream that reads + * the process' @c stdout. + * @return @c *this + */ + istream_type& + out() + { + this->buf_.read_err(false); + return *this; + } + + /** + * @brief Obtain a reference to the istream that reads + * the process' @c stderr. + * @return @c *this + */ + istream_type& + err() + { + this->buf_.read_err(true); + return *this; + } + }; + + + /// Type definition for common template specialisation. + typedef basic_pstreambuf pstreambuf; + /// Type definition for common template specialisation. + typedef basic_ipstream ipstream; + /// Type definition for common template specialisation. + typedef basic_opstream opstream; + /// Type definition for common template specialisation. + typedef basic_pstream pstream; + /// Type definition for common template specialisation. + typedef basic_rpstream rpstream; + + + /** + * When inserted into an output pstream the manipulator calls + * basic_pstreambuf::peof() to close the output pipe, + * causing the child process to receive the end-of-file indicator + * on subsequent reads from its @c stdin stream. + * + * @brief Manipulator to close the pipe connected to the process' stdin. + * @param s An output PStream class. + * @return The stream object the manipulator was invoked on. + * @see basic_pstreambuf::peof() + * @relates basic_opstream basic_pstream basic_rpstream + */ + template + inline std::basic_ostream& + peof(std::basic_ostream& s) + { + typedef basic_pstreambuf pstreambuf; + if (pstreambuf* p = dynamic_cast(s.rdbuf())) + p->peof(); + return s; + } + + + /* + * member definitions for pstreambuf + */ + + + /** + * @class basic_pstreambuf + * Provides underlying streambuf functionality for the PStreams classes. + */ + + /** Creates an uninitialised stream buffer. */ + template + inline + basic_pstreambuf::basic_pstreambuf() + : ppid_(-1) // initialise to -1 to indicate no process run yet. + , wpipe_(-1) + , wbuffer_(NULL) + , rsrc_(rsrc_out) + , status_(-1) + , error_(0) + { + init_rbuffers(); + } + + /** + * Initialises the stream buffer by calling open() with the supplied + * arguments. + * + * @param command a string containing a shell command. + * @param mode the I/O mode to use when opening the pipe. + * @see open() + */ + template + inline + basic_pstreambuf::basic_pstreambuf(const std::string& command, pmode mode) + : ppid_(-1) // initialise to -1 to indicate no process run yet. + , wpipe_(-1) + , wbuffer_(NULL) + , rsrc_(rsrc_out) + , status_(-1) + , error_(0) + { + init_rbuffers(); + open(command, mode); + } + + /** + * Initialises the stream buffer by calling open() with the supplied + * arguments. + * + * @param file a string containing the name of a program to execute. + * @param argv a vector of argument strings passsed to the new program. + * @param mode the I/O mode to use when opening the pipe. + * @see open() + */ + template + inline + basic_pstreambuf::basic_pstreambuf( const std::string& file, + const argv_type& argv, + pmode mode ) + : ppid_(-1) // initialise to -1 to indicate no process run yet. + , wpipe_(-1) + , wbuffer_(NULL) + , rsrc_(rsrc_out) + , status_(-1) + , error_(0) + { + init_rbuffers(); + open(file, argv, mode); + } + + /** + * Closes the stream by calling close(). + * @see close() + */ + template + inline + basic_pstreambuf::~basic_pstreambuf() + { + close(); + } + + /** + * Starts a new process by passing @a command to the shell (/bin/sh) + * and opens pipes to the process with the specified @a mode. + * + * If @a mode contains @c pstdout the initial read source will be + * the child process' stdout, otherwise if @a mode contains @c pstderr + * the initial read source will be the child's stderr. + * + * Will duplicate the actions of the shell in searching for an + * executable file if the specified file name does not contain a slash (/) + * character. + * + * @warning + * There is no way to tell whether the shell command succeeded, this + * function will always succeed unless resource limits (such as + * memory usage, or number of processes or open files) are exceeded. + * This means is_open() will return true even if @a command cannot + * be executed. + * Use pstreambuf::open(const std::string&, const argv_type&, pmode) + * if you need to know whether the command failed to execute. + * + * @param command a string containing a shell command. + * @param mode a bitwise OR of one or more of @c out, @c in, @c err. + * @return NULL if the shell could not be started or the + * pipes could not be opened, @c this otherwise. + * @see execl(3) + */ + template + basic_pstreambuf* + basic_pstreambuf::open(const std::string& command, pmode mode) + { + const char * shell_path = "/bin/sh"; +#if 0 + const std::string argv[] = { "sh", "-c", command }; + return this->open(shell_path, argv_type(argv, argv+3), mode); +#else + basic_pstreambuf* ret = NULL; + + if (!is_open()) + { + switch(fork(mode)) + { + case 0 : + // this is the new process, exec command + ::execl(shell_path, "sh", "-c", command.c_str(), (char*)NULL); + + // can only reach this point if exec() failed + + // parent can get exit code from waitpid() + ::_exit(errno); + // using std::exit() would make static dtors run twice + + case -1 : + // couldn't fork, error already handled in pstreambuf::fork() + break; + + default : + // this is the parent process + // activate buffers + create_buffers(mode); + ret = this; + } + } + return ret; +#endif + } + + /** + * @brief Helper function to close a file descriptor. + * + * Inspects @a fd and calls close(3) if it has a non-negative value. + * + * @param fd a file descriptor. + * @relates basic_pstreambuf + */ + inline void + close_fd(pstreams::fd_type& fd) + { + if (fd >= 0 && ::close(fd) == 0) + fd = -1; + } + + /** + * @brief Helper function to close an array of file descriptors. + * + * Calls @c close_fd() on each member of the array. + * The length of the array is determined automatically by + * template argument deduction to avoid errors. + * + * @param fds an array of file descriptors. + * @relates basic_pstreambuf + */ + template + inline void + close_fd_array(pstreams::fd_type (&fds)[N]) + { + for (std::size_t i = 0; i < N; ++i) + close_fd(fds[i]); + } + + /** + * Starts a new process by executing @a file with the arguments in + * @a argv and opens pipes to the process with the specified @a mode. + * + * By convention @c argv[0] should be the file name of the file being + * executed. + * + * If @a mode contains @c pstdout the initial read source will be + * the child process' stdout, otherwise if @a mode contains @c pstderr + * the initial read source will be the child's stderr. + * + * Will duplicate the actions of the shell in searching for an + * executable file if the specified file name does not contain a slash (/) + * character. + * + * Iff @a file is successfully executed then is_open() will return true. + * Otherwise, pstreambuf::error() can be used to obtain the value of + * @c errno that was set by execvp(3) in the child process. + * + * The exit status of the new process will be returned by + * pstreambuf::status() after pstreambuf::exited() returns true. + * + * @param file a string containing the pathname of a program to execute. + * @param argv a vector of argument strings passed to the new program. + * @param mode a bitwise OR of one or more of @c out, @c in and @c err. + * @return NULL if a pipe could not be opened or if the program could + * not be executed, @c this otherwise. + * @see execvp(3) + */ + template + basic_pstreambuf* + basic_pstreambuf::open( const std::string& file, + const argv_type& argv, + pmode mode ) + { + basic_pstreambuf* ret = NULL; + + if (!is_open()) + { + // constants for read/write ends of pipe + enum { RD, WR }; + + // open another pipe and set close-on-exec + fd_type ck_exec[] = { -1, -1 }; + if (-1 == ::pipe(ck_exec) + || -1 == ::fcntl(ck_exec[RD], F_SETFD, FD_CLOEXEC) + || -1 == ::fcntl(ck_exec[WR], F_SETFD, FD_CLOEXEC)) + { + error_ = errno; + close_fd_array(ck_exec); + } + else + { + switch(fork(mode)) + { + case 0 : + // this is the new process, exec command + { + char** arg_v = new char*[argv.size()+1]; + for (std::size_t i = 0; i < argv.size(); ++i) + { + const std::string& src = argv[i]; + char*& dest = arg_v[i]; + dest = new char[src.size()+1]; + dest[ src.copy(dest, src.size()) ] = '\0'; + } + arg_v[argv.size()] = NULL; + + ::execvp(file.c_str(), arg_v); + + // can only reach this point if exec() failed + + // parent can get error code from ck_exec pipe + error_ = errno; + + ::write(ck_exec[WR], &error_, sizeof(error_)); + ::close(ck_exec[WR]); + ::close(ck_exec[RD]); + + ::_exit(error_); + // using std::exit() would make static dtors run twice + } + + case -1 : + // couldn't fork, error already handled in pstreambuf::fork() + close_fd_array(ck_exec); + break; + + default : + // this is the parent process + + // check child called exec() successfully + ::close(ck_exec[WR]); + switch (::read(ck_exec[RD], &error_, sizeof(error_))) + { + case 0: + // activate buffers + create_buffers(mode); + ret = this; + break; + case -1: + error_ = errno; + break; + default: + // error_ contains error code from child + // call wait() to clean up and set ppid_ to 0 + this->wait(); + break; + } + ::close(ck_exec[RD]); + } + } + } + return ret; + } + + /** + * Creates pipes as specified by @a mode and calls @c fork() to create + * a new process. If the fork is successful the parent process stores + * the child's PID and the opened pipes and the child process replaces + * its standard streams with the opened pipes. + * + * If an error occurs the error code will be set to one of the possible + * errors for @c pipe() or @c fork(). + * See your system's documentation for these error codes. + * + * @param mode an OR of pmodes specifying which of the child's + * standard streams to connect to. + * @return On success the PID of the child is returned in the parent's + * context and zero is returned in the child's context. + * On error -1 is returned and the error code is set appropriately. + */ + template + pid_t + basic_pstreambuf::fork(pmode mode) + { + pid_t pid = -1; + + // Three pairs of file descriptors, for pipes connected to the + // process' stdin, stdout and stderr + // (stored in a single array so close_fd_array() can close all at once) + fd_type fd[] = { -1, -1, -1, -1, -1, -1 }; + fd_type* const pin = fd; + fd_type* const pout = fd+2; + fd_type* const perr = fd+4; + + // constants for read/write ends of pipe + enum { RD, WR }; + + // N.B. + // For the pstreambuf pin is an output stream and + // pout and perr are input streams. + + if (!error_ && mode&pstdin && ::pipe(pin)) + error_ = errno; + + if (!error_ && mode&pstdout && ::pipe(pout)) + error_ = errno; + + if (!error_ && mode&pstderr && ::pipe(perr)) + error_ = errno; + + if (!error_) + { + pid = ::fork(); + switch (pid) + { + case 0 : + { + // this is the new process + + // for each open pipe close one end and redirect the + // respective standard stream to the other end + + if (*pin >= 0) + { + ::close(pin[WR]); + ::dup2(pin[RD], STDIN_FILENO); + ::close(pin[RD]); + } + if (*pout >= 0) + { + ::close(pout[RD]); + ::dup2(pout[WR], STDOUT_FILENO); + ::close(pout[WR]); + } + if (*perr >= 0) + { + ::close(perr[RD]); + ::dup2(perr[WR], STDERR_FILENO); + ::close(perr[WR]); + } + break; + } + case -1 : + { + // couldn't fork for some reason + error_ = errno; + // close any open pipes + close_fd_array(fd); + break; + } + default : + { + // this is the parent process, store process' pid + ppid_ = pid; + + // store one end of open pipes and close other end + if (*pin >= 0) + { + wpipe_ = pin[WR]; + ::close(pin[RD]); + } + if (*pout >= 0) + { + rpipe_[rsrc_out] = pout[RD]; + ::close(pout[WR]); + } + if (*perr >= 0) + { + rpipe_[rsrc_err] = perr[RD]; + ::close(perr[WR]); + } + } + } + } + else + { + // close any pipes we opened before failure + close_fd_array(fd); + } + return pid; + } + + /** + * Closes all pipes and calls wait() to wait for the process to finish. + * If an error occurs the error code will be set to one of the possible + * errors for @c waitpid(). + * See your system's documentation for these errors. + * + * @return @c this on successful close or @c NULL if there is no + * process to close or if an error occurs. + */ + template + basic_pstreambuf* + basic_pstreambuf::close() + { + const bool running = is_open(); + + sync(); // this might call wait() and reap the child process + + // rather than trying to work out whether or not we need to clean up + // just do it anyway, all cleanup functions are safe to call twice. + + destroy_buffers(pstdin|pstdout|pstderr); + + // close pipes before wait() so child gets EOF/SIGPIPE + close_fd(wpipe_); + close_fd_array(rpipe_); + + do + { + error_ = 0; + } while (wait() == -1 && error() == EINTR); + + return running ? this : NULL; + } + + /** + * Called on construction to initialise the arrays used for reading. + */ + template + inline void + basic_pstreambuf::init_rbuffers() + { + rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1; + rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL; + rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL; + } + + template + void + basic_pstreambuf::create_buffers(pmode mode) + { + if (mode & pstdin) + { + delete[] wbuffer_; + wbuffer_ = new char_type[bufsz]; + this->setp(wbuffer_, wbuffer_ + bufsz); + } + if (mode & pstdout) + { + delete[] rbuffer_[rsrc_out]; + rbuffer_[rsrc_out] = new char_type[bufsz]; + rsrc_ = rsrc_out; + this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz, + rbuffer_[rsrc_out] + pbsz); + } + if (mode & pstderr) + { + delete[] rbuffer_[rsrc_err]; + rbuffer_[rsrc_err] = new char_type[bufsz]; + if (!(mode & pstdout)) + { + rsrc_ = rsrc_err; + this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz, + rbuffer_[rsrc_err] + pbsz); + } + } + } + + template + void + basic_pstreambuf::destroy_buffers(pmode mode) + { + if (mode & pstdin) + { + this->setp(NULL, NULL); + delete[] wbuffer_; + wbuffer_ = NULL; + } + if (mode & pstdout) + { + if (rsrc_ == rsrc_out) + this->setg(NULL, NULL, NULL); + delete[] rbuffer_[rsrc_out]; + rbuffer_[rsrc_out] = NULL; + } + if (mode & pstderr) + { + if (rsrc_ == rsrc_err) + this->setg(NULL, NULL, NULL); + delete[] rbuffer_[rsrc_err]; + rbuffer_[rsrc_err] = NULL; + } + } + + template + typename basic_pstreambuf::buf_read_src + basic_pstreambuf::switch_read_buffer(buf_read_src src) + { + if (rsrc_ != src) + { + char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()}; + this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]); + for (std::size_t i = 0; i < 3; ++i) + rbufstate_[i] = tmpbufstate[i]; + rsrc_ = src; + } + return rsrc_; + } + + /** + * Suspends execution and waits for the associated process to exit, or + * until a signal is delivered whose action is to terminate the current + * process or to call a signal handling function. If the process has + * already exited (i.e. it is a "zombie" process) then wait() returns + * immediately. Waiting for the child process causes all its system + * resources to be freed. + * + * error() will return EINTR if wait() is interrupted by a signal. + * + * @param nohang true to return immediately if the process has not exited. + * @return 1 if the process has exited and wait() has not yet been called. + * 0 if @a nohang is true and the process has not exited yet. + * -1 if no process has been started or if an error occurs, + * in which case the error can be found using error(). + */ + template + int + basic_pstreambuf::wait(bool nohang) + { + int exited = -1; + if (is_open()) + { + int status; + switch(::waitpid(ppid_, &status, nohang ? WNOHANG : 0)) + { + case 0 : + // nohang was true and process has not exited + exited = 0; + break; + case -1 : + error_ = errno; + break; + default : + // process has exited + ppid_ = 0; + status_ = status; + exited = 1; + // Close wpipe, would get SIGPIPE if we used it. + destroy_buffers(pstdin); + close_fd(wpipe_); + // Must free read buffers and pipes on destruction + // or next call to open()/close() + break; + } + } + return exited; + } + + /** + * Sends the specified signal to the process. A signal can be used to + * terminate a child process that would not exit otherwise. + * + * If an error occurs the error code will be set to one of the possible + * errors for @c kill(). See your system's documentation for these errors. + * + * @param signal A signal to send to the child process. + * @return @c this or @c NULL if @c kill() fails. + */ + template + inline basic_pstreambuf* + basic_pstreambuf::kill(int signal) + { + basic_pstreambuf* ret = NULL; + if (is_open()) + { + if (::kill(ppid_, signal)) + error_ = errno; + else + { +#if 0 + // TODO call exited() to check for exit and clean up? leave to user? + if (signal==SIGTERM || signal==SIGKILL) + this->exited(); +#endif + ret = this; + } + } + return ret; + } + + /** + * This function can call pstreambuf::wait() and so may change the + * object's state if the child process has already exited. + * + * @return True if the associated process has exited, false otherwise. + * @see basic_pstreambuf::wait() + */ + template + inline bool + basic_pstreambuf::exited() + { + return ppid_ == 0 || wait(true)==1; + } + + + /** + * @return The exit status of the child process, or -1 if wait() + * has not yet been called to wait for the child to exit. + * @see basic_pstreambuf::wait() + */ + template + inline int + basic_pstreambuf::status() const + { + return status_; + } + + /** + * @return The error code of the most recently failed operation, or zero. + */ + template + inline int + basic_pstreambuf::error() const + { + return error_; + } + + /** + * Closes the output pipe, causing the child process to receive the + * end-of-file indicator on subsequent reads from its @c stdin stream. + */ + template + inline void + basic_pstreambuf::peof() + { + sync(); + destroy_buffers(pstdin); + close_fd(wpipe_); + } + + /** + * Unlike pstreambuf::exited(), this function will not call wait() and + * so will not change the object's state. This means that once a child + * process is executed successfully this function will continue to + * return true even after the process exits (until wait() is called.) + * + * @return true if a previous call to open() succeeded and wait() has + * not been called and determined that the process has exited, + * false otherwise. + */ + template + inline bool + basic_pstreambuf::is_open() const + { + return ppid_ > 0; + } + + /** + * Toggle the stream used for reading. If @a readerr is @c true then the + * process' @c stderr output will be used for subsequent extractions, if + * @a readerr is false the the process' stdout will be used. + * @param readerr @c true to read @c stderr, @c false to read @c stdout. + * @return @c true if the requested stream is open and will be used for + * subsequent extractions, @c false otherwise. + */ + template + inline bool + basic_pstreambuf::read_err(bool readerr) + { + buf_read_src src = readerr ? rsrc_err : rsrc_out; + if (rpipe_[src]>=0) + { + switch_read_buffer(src); + return true; + } + return false; + } + + /** + * Called when the internal character buffer is not present or is full, + * to transfer the buffer contents to the pipe. + * + * @param c a character to be written to the pipe. + * @return @c traits_type::eof() if an error occurs, otherwise if @a c + * is not equal to @c traits_type::eof() it will be buffered and + * a value other than @c traits_type::eof() returned to indicate + * success. + */ + template + typename basic_pstreambuf::int_type + basic_pstreambuf::overflow(int_type c) + { + if (!empty_buffer()) + return traits_type::eof(); + else if (!traits_type::eq_int_type(c, traits_type::eof())) + return this->sputc(c); + else + return traits_type::not_eof(c); + } + + + template + int + basic_pstreambuf::sync() + { + return !exited() && empty_buffer() ? 0 : -1; + } + + /** + * @param s character buffer. + * @param n buffer length. + * @return the number of characters written. + */ + template + std::streamsize + basic_pstreambuf::xsputn(const char_type* s, std::streamsize n) + { + if (n < this->epptr() - this->pptr()) + { + traits_type::copy(this->pptr(), s, n); + this->pbump(n); + return n; + } + else + { + for (std::streamsize i = 0; i < n; ++i) + { + if (traits_type::eq_int_type(this->sputc(s[i]), traits_type::eof())) + return i; + } + return n; + } + } + + /** + * @return true if the buffer was emptied, false otherwise. + */ + template + bool + basic_pstreambuf::empty_buffer() + { + const std::streamsize count = this->pptr() - this->pbase(); + if (count > 0) + { + const std::streamsize written = this->write(this->wbuffer_, count); + if (written > 0) + { + if (const std::streamsize unwritten = count - written) + traits_type::move(this->pbase(), this->pbase()+written, unwritten); + this->pbump(-written); + return true; + } + } + return false; + } + + /** + * Called when the internal character buffer is is empty, to re-fill it + * from the pipe. + * + * @return The first available character in the buffer, + * or @c traits_type::eof() in case of failure. + */ + template + typename basic_pstreambuf::int_type + basic_pstreambuf::underflow() + { + if (this->gptr() < this->egptr() || fill_buffer()) + return traits_type::to_int_type(*this->gptr()); + else + return traits_type::eof(); + } + + /** + * Attempts to make @a c available as the next character to be read by + * @c sgetc(). + * + * @param c a character to make available for extraction. + * @return @a c if the character can be made available, + * @c traits_type::eof() otherwise. + */ + template + typename basic_pstreambuf::int_type + basic_pstreambuf::pbackfail(int_type c) + { + if (this->gptr() != this->eback()) + { + this->gbump(-1); + if (!traits_type::eq_int_type(c, traits_type::eof())) + *this->gptr() = traits_type::to_char_type(c); + return traits_type::not_eof(c); + } + else + return traits_type::eof(); + } + + template + std::streamsize + basic_pstreambuf::showmanyc() + { + int avail = 0; + if (sizeof(char_type) == 1) + avail = fill_buffer(true) ? this->egptr() - this->gptr() : -1; +#ifdef FIONREAD + else + { + if (::ioctl(rpipe(), FIONREAD, &avail) == -1) + avail = -1; + else if (avail) + avail /= sizeof(char_type); + } +#endif + return std::streamsize(avail); + } + + /** + * @return true if the buffer was filled, false otherwise. + */ + template + bool + basic_pstreambuf::fill_buffer(bool non_blocking) + { + const std::streamsize pb1 = this->gptr() - this->eback(); + const std::streamsize pb2 = pbsz; + const std::streamsize npb = std::min(pb1, pb2); + + char_type* const rbuf = rbuffer(); + + traits_type::move(rbuf + pbsz - npb, this->gptr() - npb, npb); + + std::streamsize rc = -1; + + if (non_blocking) + { + const int flags = ::fcntl(rpipe(), F_GETFL); + if (flags != -1) + { + const bool blocking = !(flags & O_NONBLOCK); + if (blocking) + ::fcntl(rpipe(), F_SETFL, flags | O_NONBLOCK); // set non-blocking + + error_ = 0; + rc = read(rbuf + pbsz, bufsz - pbsz); + + if (rc == -1 && error_ == EAGAIN) // nothing available + rc = 0; + else if (rc == 0) // EOF + rc = -1; + + if (blocking) + ::fcntl(rpipe(), F_SETFL, flags); // restore + } + } + else + rc = read(rbuf + pbsz, bufsz - pbsz); + + if (rc > 0 || (rc == 0 && non_blocking)) + { + this->setg( rbuf + pbsz - npb, + rbuf + pbsz, + rbuf + pbsz + rc ); + return true; + } + else + { + this->setg(NULL, NULL, NULL); + return false; + } + } + + /** + * Writes up to @a n characters to the pipe from the buffer @a s. + * + * @param s character buffer. + * @param n buffer length. + * @return the number of characters written. + */ + template + inline std::streamsize + basic_pstreambuf::write(const char_type* s, std::streamsize n) + { + std::streamsize nwritten = 0; + if (wpipe() >= 0) + { + nwritten = ::write(wpipe(), s, n * sizeof(char_type)); + if (nwritten == -1) + error_ = errno; + else + nwritten /= sizeof(char_type); + } + return nwritten; + } + + /** + * Reads up to @a n characters from the pipe to the buffer @a s. + * + * @param s character buffer. + * @param n buffer length. + * @return the number of characters read. + */ + template + inline std::streamsize + basic_pstreambuf::read(char_type* s, std::streamsize n) + { + std::streamsize nread = 0; + if (rpipe() >= 0) + { + nread = ::read(rpipe(), s, n * sizeof(char_type)); + if (nread == -1) + error_ = errno; + else + nread /= sizeof(char_type); + } + return nread; + } + + /** @return a reference to the output file descriptor */ + template + inline typename basic_pstreambuf::fd_type& + basic_pstreambuf::wpipe() + { + return wpipe_; + } + + /** @return a reference to the active input file descriptor */ + template + inline typename basic_pstreambuf::fd_type& + basic_pstreambuf::rpipe() + { + return rpipe_[rsrc_]; + } + + /** @return a reference to the specified input file descriptor */ + template + inline typename basic_pstreambuf::fd_type& + basic_pstreambuf::rpipe(buf_read_src which) + { + return rpipe_[which]; + } + + /** @return a pointer to the start of the active input buffer area. */ + template + inline typename basic_pstreambuf::char_type* + basic_pstreambuf::rbuffer() + { + return rbuffer_[rsrc_]; + } + + + /* + * member definitions for pstream_common + */ + + /** + * @class pstream_common + * Abstract Base Class providing common functionality for basic_ipstream, + * basic_opstream and basic_pstream. + * pstream_common manages the basic_pstreambuf stream buffer that is used + * by the derived classes to initialise an iostream class. + */ + + /** Creates an uninitialised stream. */ + template + inline + pstream_common::pstream_common() + : std::basic_ios(NULL) + , command_() + , buf_() + { + this->init(&buf_); + } + + /** + * Initialises the stream buffer by calling + * do_open( @a command , @a mode ) + * + * @param command a string containing a shell command. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, pmode) + */ + template + inline + pstream_common::pstream_common(const std::string& command, pmode mode) + : std::basic_ios(NULL) + , command_(command) + , buf_() + { + this->init(&buf_); + do_open(command, mode); + } + + /** + * Initialises the stream buffer by calling + * do_open( @a file , @a argv , @a mode ) + * + * @param file a string containing the pathname of a program to execute. + * @param argv a vector of argument strings passed to the new program. + * @param mode the I/O mode to use when opening the pipe. + * @see do_open(const std::string&, const argv_type&, pmode) + */ + template + inline + pstream_common::pstream_common( const std::string& file, + const argv_type& argv, + pmode mode ) + : std::basic_ios(NULL) + , command_(file) + , buf_() + { + this->init(&buf_); + do_open(file, argv, mode); + } + + /** + * This is a pure virtual function to make @c pstream_common abstract. + * Because it is the destructor it will be called by derived classes + * and so must be defined. It is also protected, to discourage use of + * the PStreams classes through pointers or references to the base class. + * + * @sa If defining a pure virtual seems odd you should read + * http://www.gotw.ca/gotw/031.htm (and the rest of the site as well!) + */ + template + inline + pstream_common::~pstream_common() + { + } + + /** + * Calls rdbuf()->open( @a command , @a mode ) + * and sets @c failbit on error. + * + * @param command a string containing a shell command. + * @param mode the I/O mode to use when opening the pipe. + * @see basic_pstreambuf::open(const std::string&, pmode) + */ + template + inline void + pstream_common::do_open(const std::string& command, pmode mode) + { + if (!buf_.open((command_=command), mode)) + this->setstate(std::ios_base::failbit); + } + + /** + * Calls rdbuf()->open( @a file, @a argv, @a mode ) + * and sets @c failbit on error. + * + * @param file a string containing the pathname of a program to execute. + * @param argv a vector of argument strings passed to the new program. + * @param mode the I/O mode to use when opening the pipe. + * @see basic_pstreambuf::open(const std::string&, const argv_type&, pmode) + */ + template + inline void + pstream_common::do_open( const std::string& file, + const argv_type& argv, + pmode mode ) + { + if (!buf_.open((command_=file), argv, mode)) + this->setstate(std::ios_base::failbit); + } + + /** Calls rdbuf->close() and sets @c failbit on error. */ + template + inline void + pstream_common::close() + { + if (!buf_.close()) + this->setstate(std::ios_base::failbit); + } + + /** + * @return rdbuf()->is_open(). + * @see basic_pstreambuf::is_open() + */ + template + inline bool + pstream_common::is_open() const + { + return buf_.is_open(); + } + + /** @return a string containing the command used to initialise the stream. */ + template + inline const std::string& + pstream_common::command() const + { + return command_; + } + + /** @return a pointer to the private stream buffer member. */ + // TODO document behaviour if buffer replaced. + template + inline typename pstream_common::streambuf_type* + pstream_common::rdbuf() const + { + return const_cast(&buf_); + } + + +#if REDI_EVISCERATE_PSTREAMS + /** + * @def REDI_EVISCERATE_PSTREAMS + * If this macro has a non-zero value then certain internals of the + * @c basic_pstreambuf template class are exposed. In general this is + * a Bad Thing, as the internal implementation is largely undocumented + * and may be subject to change at any time, so this feature is only + * provided because it might make PStreams useful in situations where + * it is necessary to do Bad Things. + */ + + /** + * @warning This function exposes the internals of the stream buffer and + * should be used with caution. It is the caller's responsibility + * to flush streams etc. in order to clear any buffered data. + * The POSIX.1 function fdopen(3) is used to obtain the + * @c FILE pointers from the streambuf's private file descriptor + * members so consult your system's documentation for + * fdopen(3). + * + * @param in A FILE* that will refer to the process' stdin. + * @param out A FILE* that will refer to the process' stdout. + * @param err A FILE* that will refer to the process' stderr. + * @return An OR of zero or more of @c pstdin, @c pstdout, @c pstderr. + * + * For each open stream shared with the child process a @c FILE* is + * obtained and assigned to the corresponding parameter. For closed + * streams @c NULL is assigned to the parameter. + * The return value can be tested to see which parameters should be + * @c !NULL by masking with the corresponding @c pmode value. + * + * @see fdopen(3) + */ + template + std::size_t + basic_pstreambuf::fopen(FILE*& in, FILE*& out, FILE*& err) + { + in = out = err = NULL; + std::size_t open_files = 0; + if (wpipe() > -1) + { + if ((in = ::fdopen(wpipe(), "w"))) + { + open_files |= pstdin; + } + } + if (rpipe(rsrc_out) > -1) + { + if ((out = ::fdopen(rpipe(rsrc_out), "r"))) + { + open_files |= pstdout; + } + } + if (rpipe(rsrc_err) > -1) + { + if ((err = ::fdopen(rpipe(rsrc_err), "r"))) + { + open_files |= pstderr; + } + } + return open_files; + } + + /** + * @warning This function exposes the internals of the stream buffer and + * should be used with caution. + * + * @param in A FILE* that will refer to the process' stdin. + * @param out A FILE* that will refer to the process' stdout. + * @param err A FILE* that will refer to the process' stderr. + * @return A bitwise-or of zero or more of @c pstdin, @c pstdout, @c pstderr. + * @see basic_pstreambuf::fopen() + */ + template + inline std::size_t + pstream_common::fopen(FILE*& fin, FILE*& fout, FILE*& ferr) + { + return buf_.fopen(fin, fout, ferr); + } + +#endif // REDI_EVISCERATE_PSTREAMS + + +} // namespace redi + +/** + * @mainpage PStreams Reference + * @htmlinclude mainpage.html + */ + +#endif // REDI_PSTREAM_H_SEEN + +// vim: ts=2 sw=2 expandtab + diff --git a/vendor/libblepp-master/src/att.cc b/vendor/libblepp-master/src/att.cc new file mode 100644 index 0000000..dfc6165 --- /dev/null +++ b/vendor/libblepp-master/src/att.cc @@ -0,0 +1,1181 @@ +/* + Copyright (c) 2013 Edward Rosten + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include + +#include + +#include +#include + +namespace BLEPP +{ + + #define MIN(A, B) (((A)<(B))?(A):(B)) + const char *att_ecode2str(uint8_t status) + { + switch (status) { + case ATT_ECODE_INVALID_HANDLE: + return "Invalid handle"; + case ATT_ECODE_READ_NOT_PERM: + return "Attribute can't be read"; + case ATT_ECODE_WRITE_NOT_PERM: + return "Attribute can't be written"; + case ATT_ECODE_INVALID_PDU: + return "Attribute PDU was invalid"; + case ATT_ECODE_AUTHENTICATION: + return "Attribute requires authentication before read/write"; + case ATT_ECODE_REQ_NOT_SUPP: + return "Server doesn't support the request received"; + case ATT_ECODE_INVALID_OFFSET: + return "Offset past the end of the attribute"; + case ATT_ECODE_AUTHORIZATION: + return "Attribute requires authorization before read/write"; + case ATT_ECODE_PREP_QUEUE_FULL: + return "Too many prepare writes have been queued"; + case ATT_ECODE_ATTR_NOT_FOUND: + return "No attribute found within the given range"; + case ATT_ECODE_ATTR_NOT_LONG: + return "Attribute can't be read/written using Read Blob Req"; + case ATT_ECODE_INSUFF_ENCR_KEY_SIZE: + return "Encryption Key Size is insufficient"; + case ATT_ECODE_INVAL_ATTR_VALUE_LEN: + return "Attribute value length is invalid"; + case ATT_ECODE_UNLIKELY: + return "Request attribute has encountered an unlikely error"; + case ATT_ECODE_INSUFF_ENC: + return "Encryption required before read/write"; + case ATT_ECODE_UNSUPP_GRP_TYPE: + return "Attribute type is not a supported grouping attribute"; + case ATT_ECODE_INSUFF_RESOURCES: + return "Insufficient Resources to complete the request"; + case ATT_ECODE_IO: + return "Internal application error: I/O"; + case ATT_ECODE_TIMEOUT: + return "A timeout occured"; + case ATT_ECODE_ABORTED: + return "The operation was aborted"; + default: + return "Unexpected error code"; + } + } + + + const char* att_op2str(uint8_t op) + { + switch(op) + { + case ATT_OP_ERROR: + return "Error"; + case ATT_OP_MTU_REQ: + return "MTU Request"; + case ATT_OP_MTU_RESP: + return "MTU Response"; + case ATT_OP_FIND_INFO_REQ: + return "Find Info Request"; + case ATT_OP_FIND_INFO_RESP: + return "Find Info Response"; + case ATT_OP_FIND_BY_TYPE_REQ: + return "Find By Type Request"; + case ATT_OP_FIND_BY_TYPE_RESP: + return "Find By Type Response"; + case ATT_OP_READ_BY_TYPE_REQ: + return "Read By Type Request"; + case ATT_OP_READ_BY_TYPE_RESP: + return "Read By Type Response"; + case ATT_OP_READ_REQ: + return "Read Request"; + case ATT_OP_READ_RESP: + return "Read Response"; + case ATT_OP_READ_BLOB_REQ: + return "Read Blob Request"; + case ATT_OP_READ_BLOB_RESP: + return "Read Blob Response"; + case ATT_OP_READ_MULTI_REQ: + return "Read Multi Request"; + case ATT_OP_READ_MULTI_RESP: + return "Read Multi Resources"; + case ATT_OP_READ_BY_GROUP_REQ: + return "Read By Group Request"; + case ATT_OP_READ_BY_GROUP_RESP: + return "Read By Group Response"; + case ATT_OP_WRITE_REQ: + return "Write Request"; + case ATT_OP_WRITE_RESP: + return "Write Request Response"; + case ATT_OP_WRITE_CMD: + return "Write Command"; + case ATT_OP_HANDLE_NOTIFY: + return "Notify"; + case ATT_OP_HANDLE_IND: + return "Indicate"; + case ATT_OP_PREP_WRITE_REQ: + case ATT_OP_PREP_WRITE_RESP: + case ATT_OP_EXEC_WRITE_REQ: + case ATT_OP_EXEC_WRITE_RESP: + case ATT_OP_HANDLE_CNF: + case ATT_OP_SIGNED_WRITE_CMD: + return "haha fill me in :)"; + + default: + return "Unnkown opcode"; + }; + } + + + /* + void att_data_list_free(struct att_data_list *list) + { + if (list == NULL) + return; + + if (list->data) { + int i; + for (i = 0; i < list->num; i++) + g_free(list->data[i]); + } + + g_free(list->data); + g_free(list); + } + */ + /* + struct att_data_list *att_data_list_alloc(uint16_t num, uint16_t len) + { + struct att_data_list *list; + int i; + + if (len > UINT8_MAX) + return NULL; + + list = g_new0(struct att_data_list, 1); + list->len = len; + list->num = num; + + list->data = g_malloc0(sizeof(uint8_t *) * num); + + for (i = 0; i < num; i++) + list->data[i] = g_malloc0(sizeof(uint8_t) * len); + + return list; + } + */ + + uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, + uint8_t *pdu, size_t len) + { + uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end); + uint16_t length; + + if (!uuid) + return 0; + + if (uuid->type == BT_UUID16) + length = 2; + else if (uuid->type == BT_UUID128) + length = 16; + else + return 0; + + if (len < min_len + length) + return 0; + + pdu[0] = ATT_OP_READ_BY_GROUP_REQ; + att_put_u16(start, &pdu[1]); + att_put_u16(end, &pdu[3]); + + att_put_uuid(*uuid, &pdu[5]); + + return min_len + length; + } + /* + uint16_t dec_read_by_grp_req(const uint8_t *pdu, size_t len, uint16_t *start, + uint16_t *end, bt_uuid_t *uuid) + { + const size_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end); + + if (pdu == NULL) + return 0; + + if (start == NULL || end == NULL || uuid == NULL) + return 0; + + if (pdu[0] != ATT_OP_READ_BY_GROUP_REQ) + return 0; + + if (len < min_len + 2) + return 0; + + *start = att_get_u16(&pdu[1]); + *end = att_get_u16(&pdu[3]); + if (len == min_len + 2) + *uuid = att_get_uuid16(&pdu[5]); + else + *uuid = att_get_uuid128(&pdu[5]); + + return len; + } + + uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu, + size_t len) + { + int i; + uint16_t w; + uint8_t *ptr; + + if (list == NULL) + return 0; + + if (len < list->len + sizeof(uint8_t) * 2) + return 0; + + pdu[0] = ATT_OP_READ_BY_GROUP_RESP; + pdu[1] = list->len; + + ptr = &pdu[2]; + + for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) { + memcpy(ptr, list->data[i], list->len); + ptr += list->len; + w += list->len; + } + + return w; + } + + struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, size_t len) + { + struct att_data_list *list; + const uint8_t *ptr; + uint16_t elen, num; + int i; + + if (pdu[0] != ATT_OP_READ_BY_GROUP_RESP) + return NULL; + + elen = pdu[1]; + num = (len - 2) / elen; + list = att_data_list_alloc(num, elen); + if (list == NULL) + return NULL; + + ptr = &pdu[2]; + + for (i = 0; i < num; i++) { + memcpy(list->data[i], ptr, list->len); + ptr += list->len; + } + + return list; + } + */ + uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, + const uint8_t *value, size_t vlen, + uint8_t *pdu, size_t len) + { + uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end) + + sizeof(uint16_t); + + if (pdu == NULL) + return 0; + + if (!uuid) + return 0; + + if (uuid->type != BT_UUID16) + return 0; + + if (len < min_len) + return 0; + + if (vlen > len - min_len) + vlen = len - min_len; + + pdu[0] = ATT_OP_FIND_BY_TYPE_REQ; + att_put_u16(start, &pdu[1]); + att_put_u16(end, &pdu[3]); + att_put_uuid16(*uuid, &pdu[5]); + + if (vlen > 0) { + memcpy(&pdu[7], value, vlen); + return min_len + vlen; + } + + return min_len; + } + + uint16_t dec_find_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start, + uint16_t *end, bt_uuid_t *uuid, + uint8_t *value, size_t *vlen) + { + size_t valuelen; + uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + + sizeof(*end) + sizeof(uint16_t); + + if (pdu == NULL) + return 0; + + if (len < min_len) + return 0; + + if (pdu[0] != ATT_OP_FIND_BY_TYPE_REQ) + return 0; + + /* First requested handle number */ + if (start) + *start = att_get_u16(&pdu[1]); + + /* Last requested handle number */ + if (end) + *end = att_get_u16(&pdu[3]); + + /* Always UUID16 */ + if (uuid) + *uuid = att_get_uuid16(&pdu[5]); + + valuelen = len - min_len; + + /* Attribute value to find */ + if (valuelen > 0 && value) + memcpy(value, pdu + min_len, valuelen); + + if (vlen) + *vlen = valuelen; + + return len; + } + + /* + uint16_t enc_find_by_type_resp(GSList *matches, uint8_t *pdu, size_t len) + { + GSList *l; + uint16_t offset; + + if (pdu == NULL || len < 5) + return 0; + + pdu[0] = ATT_OP_FIND_BY_TYPE_RESP; + + for (l = matches, offset = 1; + l && len >= (offset + sizeof(uint16_t) * 2); + l = l->next, offset += sizeof(uint16_t) * 2) { + struct att_range *range = l->data; + + att_put_u16(range->start, &pdu[offset]); + att_put_u16(range->end, &pdu[offset + 2]); + } + + return offset; + }*/ + + /* + GSList *dec_find_by_type_resp(const uint8_t *pdu, size_t len) + { + struct att_range *range; + GSList *matches; + off_t offset; + + if (pdu == NULL || len < 5) + return NULL; + + if (pdu[0] != ATT_OP_FIND_BY_TYPE_RESP) + return NULL; + + for (offset = 1, matches = NULL; + len >= (offset + sizeof(uint16_t) * 2); + offset += sizeof(uint16_t) * 2) { + range = g_new0(struct att_range, 1); + range->start = att_get_u16(&pdu[offset]); + range->end = att_get_u16(&pdu[offset + 2]); + + matches = g_slist_append(matches, range); + } + + return matches; + }*/ + + uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, + uint8_t *pdu, size_t len) + { + uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end); + uint16_t length; + + if (!uuid) + return 0; + + if (uuid->type == BT_UUID16) + length = 2; + else if (uuid->type == BT_UUID128) + length = 16; + else + return 0; + + if (len < min_len + length) + return 0; + + pdu[0] = ATT_OP_READ_BY_TYPE_REQ; + att_put_u16(start, &pdu[1]); + att_put_u16(end, &pdu[3]); + + att_put_uuid(*uuid, &pdu[5]); + + return min_len + length; + } + + uint16_t dec_read_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start, + uint16_t *end, bt_uuid_t *uuid) + { + const size_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end); + + if (pdu == NULL) + return 0; + + if (start == NULL || end == NULL || uuid == NULL) + return 0; + + if (len < min_len + 2) + return 0; + + if (pdu[0] != ATT_OP_READ_BY_TYPE_REQ) + return 0; + + *start = att_get_u16(&pdu[1]); + *end = att_get_u16(&pdu[3]); + + if (len == min_len + 2) + *uuid = att_get_uuid16(&pdu[5]); + else + *uuid = att_get_uuid128(&pdu[5]); + + return len; + } + /* + uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu, + size_t len) + { + uint8_t *ptr; + size_t i, w, l; + + if (list == NULL) + return 0; + + if (pdu == NULL) + return 0; + + l = MIN(len - 2, list->len); + + pdu[0] = ATT_OP_READ_BY_TYPE_RESP; + pdu[1] = l; + ptr = &pdu[2]; + + for (i = 0, w = 2; i < list->num && w + l <= len; i++) { + memcpy(ptr, list->data[i], l); + ptr += l; + w += l; + } + + return w; + }*/ + /* + struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, size_t len) + { + struct att_data_list *list; + const uint8_t *ptr; + uint16_t elen, num; + int i; + + if (pdu[0] != ATT_OP_READ_BY_TYPE_RESP) + return NULL; + + elen = pdu[1]; + num = (len - 2) / elen; + list = att_data_list_alloc(num, elen); + if (list == NULL) + return NULL; + + ptr = &pdu[2]; + + for (i = 0; i < num; i++) { + memcpy(list->data[i], ptr, list->len); + ptr += list->len; + } + + return list; + } + */ + uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, size_t vlen, + uint8_t *pdu, size_t len) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle); + + if (pdu == NULL) + return 0; + + if (len < min_len) + return 0; + + if (vlen > len - min_len) + vlen = len - min_len; + + pdu[0] = ATT_OP_WRITE_CMD; + att_put_u16(handle, &pdu[1]); + + if (vlen > 0) { + memcpy(&pdu[3], value, vlen); + return min_len + vlen; + } + + return min_len; + } + + uint16_t dec_write_cmd(const uint8_t *pdu, size_t len, uint16_t *handle, + uint8_t *value, size_t *vlen) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle); + + if (pdu == NULL) + return 0; + + if (value == NULL || vlen == NULL || handle == NULL) + return 0; + + if (len < min_len) + return 0; + + if (pdu[0] != ATT_OP_WRITE_CMD) + return 0; + + *handle = att_get_u16(&pdu[1]); + memcpy(value, pdu + min_len, len - min_len); + *vlen = len - min_len; + + return len; + } + + uint16_t enc_write_req(uint16_t handle, const uint8_t *value, size_t vlen, + uint8_t *pdu, size_t len) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle); + + if (pdu == NULL) + return 0; + + if (len < min_len) + return 0; + + if (vlen > len - min_len) + vlen = len - min_len; + + pdu[0] = ATT_OP_WRITE_REQ; + att_put_u16(handle, &pdu[1]); + + if (vlen > 0) { + memcpy(&pdu[3], value, vlen); + return min_len + vlen; + } + + return min_len; + } + + uint16_t dec_write_req(const uint8_t *pdu, size_t len, uint16_t *handle, + uint8_t *value, size_t *vlen) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle); + + if (pdu == NULL) + return 0; + + if (value == NULL || vlen == NULL || handle == NULL) + return 0; + + if (len < min_len) + return 0; + + if (pdu[0] != ATT_OP_WRITE_REQ) + return 0; + + *handle = att_get_u16(&pdu[1]); + *vlen = len - min_len; + if (*vlen > 0) + memcpy(value, pdu + min_len, *vlen); + + return len; + } + + uint16_t enc_write_resp(uint8_t *pdu, size_t len) + { + if (pdu == NULL) + return 0; + + pdu[0] = ATT_OP_WRITE_RESP; + + return sizeof(pdu[0]); + } + + uint16_t dec_write_resp(const uint8_t *pdu, size_t len) + { + if (pdu == NULL) + return 0; + + if (pdu[0] != ATT_OP_WRITE_RESP) + return 0; + + return len; + } + + uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, size_t len) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle); + + if (pdu == NULL) + return 0; + + if (len < min_len) + return 0; + + pdu[0] = ATT_OP_READ_REQ; + att_put_u16(handle, &pdu[1]); + + return min_len; + } + + uint16_t enc_read_blob_req(uint16_t handle, uint16_t offset, uint8_t *pdu, + size_t len) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle) + + sizeof(offset); + + if (pdu == NULL) + return 0; + + if (len < min_len) + return 0; + + pdu[0] = ATT_OP_READ_BLOB_REQ; + att_put_u16(handle, &pdu[1]); + att_put_u16(offset, &pdu[3]); + + return min_len; + } + + uint16_t dec_read_req(const uint8_t *pdu, size_t len, uint16_t *handle) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle); + + if (pdu == NULL) + return 0; + + if (handle == NULL) + return 0; + + if (len < min_len) + return 0; + + if (pdu[0] != ATT_OP_READ_REQ) + return 0; + + *handle = att_get_u16(&pdu[1]); + + return min_len; + } + + uint16_t dec_read_blob_req(const uint8_t *pdu, size_t len, uint16_t *handle, + uint16_t *offset) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle) + + sizeof(*offset); + + if (pdu == NULL) + return 0; + + if (handle == NULL) + return 0; + + if (offset == NULL) + return 0; + + if (len < min_len) + return 0; + + if (pdu[0] != ATT_OP_READ_BLOB_REQ) + return 0; + + *handle = att_get_u16(&pdu[1]); + *offset = att_get_u16(&pdu[3]); + + return min_len; + } + + uint16_t enc_read_resp(uint8_t *value, size_t vlen, uint8_t *pdu, size_t len) + { + if (pdu == NULL) + return 0; + + /* If the attribute value length is longer than the allowed PDU size, + * send only the octets that fit on the PDU. The remaining octets can + * be requested using the Read Blob Request. */ + if (vlen > len - 1) + vlen = len - 1; + + pdu[0] = ATT_OP_READ_RESP; + + memcpy(pdu + 1, value, vlen); + + return vlen + 1; + } + + uint16_t enc_read_blob_resp(uint8_t *value, size_t vlen, uint16_t offset, + uint8_t *pdu, size_t len) + { + if (pdu == NULL) + return 0; + + vlen -= offset; + if (vlen > len - 1) + vlen = len - 1; + + pdu[0] = ATT_OP_READ_BLOB_RESP; + + memcpy(pdu + 1, &value[offset], vlen); + + return vlen + 1; + } + + ssize_t dec_read_resp(const uint8_t *pdu, size_t len, uint8_t *value, size_t vlen) + { + if (pdu == NULL) + return -EINVAL; + + if (value == NULL) + return -EINVAL; + + if (pdu[0] != ATT_OP_READ_RESP) + return -EINVAL; + + if (vlen < (len - 1)) + return -ENOBUFS; + + memcpy(value, pdu + 1, len - 1); + + return len - 1; + } + + uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status, + uint8_t *pdu, size_t len) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(opcode) + + sizeof(handle) + sizeof(status); + uint16_t u16; + + if (len < min_len) + return 0; + + u16 = htobs(handle); + pdu[0] = ATT_OP_ERROR; + pdu[1] = opcode; + memcpy(&pdu[2], &u16, sizeof(u16)); + pdu[4] = status; + + return min_len; + } + + uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, size_t len) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end); + + if (pdu == NULL) + return 0; + + if (len < min_len) + return 0; + + pdu[0] = ATT_OP_FIND_INFO_REQ; + att_put_u16(start, &pdu[1]); + att_put_u16(end, &pdu[3]); + + return min_len; + } + + uint16_t dec_find_info_req(const uint8_t *pdu, size_t len, uint16_t *start, + uint16_t *end) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end); + + if (pdu == NULL) + return 0; + + if (len < min_len) + return 0; + + if (start == NULL || end == NULL) + return 0; + + if (pdu[0] != ATT_OP_FIND_INFO_REQ) + return 0; + + *start = att_get_u16(&pdu[1]); + *end = att_get_u16(&pdu[3]); + + return min_len; + } + /* + uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list, + uint8_t *pdu, size_t len) + { + uint8_t *ptr; + size_t i, w; + + if (pdu == NULL) + return 0; + + if (list == NULL) + return 0; + + if (len < list->len + sizeof(uint8_t) * 2) + return 0; + + pdu[0] = ATT_OP_FIND_INFO_RESP; + pdu[1] = format; + ptr = (void *) &pdu[2]; + + for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) { + memcpy(ptr, list->data[i], list->len); + ptr += list->len; + w += list->len; + } + + return w; + } + + struct att_data_list *dec_find_info_resp(const uint8_t *pdu, size_t len, + uint8_t *format) + { + struct att_data_list *list; + uint8_t *ptr; + uint16_t elen, num; + int i; + + if (pdu == NULL) + return 0; + + if (format == NULL) + return 0; + + if (pdu[0] != ATT_OP_FIND_INFO_RESP) + return 0; + + *format = pdu[1]; + elen = sizeof(pdu[0]) + sizeof(*format); + if (*format == 0x01) + elen += 2; + else if (*format == 0x02) + elen += 16; + + num = (len - 2) / elen; + + ptr = (void *) &pdu[2]; + + list = att_data_list_alloc(num, elen); + if (list == NULL) + return NULL; + + for (i = 0; i < num; i++) { + memcpy(list->data[i], ptr, list->len); + ptr += list->len; + } + + return list; + }*/ + + uint16_t enc_notification(uint16_t handle, uint8_t *value, size_t vlen, + uint8_t *pdu, size_t len) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t); + + if (pdu == NULL) + return 0; + + if (len < (vlen + min_len)) + return 0; + + pdu[0] = ATT_OP_HANDLE_NOTIFY; + att_put_u16(handle, &pdu[1]); + memcpy(&pdu[3], value, vlen); + + return vlen + min_len; + } + + uint16_t enc_indication(uint16_t handle, uint8_t *value, size_t vlen, + uint8_t *pdu, size_t len) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t); + + if (pdu == NULL) + return 0; + + if (len < (vlen + min_len)) + return 0; + + pdu[0] = ATT_OP_HANDLE_IND; + att_put_u16(handle, &pdu[1]); + memcpy(&pdu[3], value, vlen); + + return vlen + min_len; + } + + uint16_t dec_indication(const uint8_t *pdu, size_t len, uint16_t *handle, + uint8_t *value, size_t vlen) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t); + uint16_t dlen; + + if (pdu == NULL) + return 0; + + if (pdu[0] != ATT_OP_HANDLE_IND) + return 0; + + if (len < min_len) + return 0; + + dlen = MIN(len - min_len, vlen); + + if (handle) + *handle = att_get_u16(&pdu[1]); + + memcpy(value, &pdu[3], dlen); + + return dlen; + } + + uint16_t enc_confirmation(uint8_t *pdu, size_t len) + { + const uint16_t min_len = sizeof(pdu[0]); + + if (pdu == NULL) + return 0; + + if (len < min_len) + return 0; + + pdu[0] = ATT_OP_HANDLE_CNF; + + return min_len; + } + + uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, size_t len) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu); + + if (pdu == NULL) + return 0; + + if (len < min_len) + return 0; + + pdu[0] = ATT_OP_MTU_REQ; + att_put_u16(mtu, &pdu[1]); + + return min_len; + } + + uint16_t dec_mtu_req(const uint8_t *pdu, size_t len, uint16_t *mtu) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu); + + if (pdu == NULL) + return 0; + + if (mtu == NULL) + return 0; + + if (len < min_len) + return 0; + + if (pdu[0] != ATT_OP_MTU_REQ) + return 0; + + *mtu = att_get_u16(&pdu[1]); + + return min_len; + } + + uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, size_t len) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu); + + if (pdu == NULL) + return 0; + + if (len < min_len) + return 0; + + pdu[0] = ATT_OP_MTU_RESP; + att_put_u16(mtu, &pdu[1]); + + return min_len; + } + + uint16_t dec_mtu_resp(const uint8_t *pdu, size_t len, uint16_t *mtu) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu); + + if (pdu == NULL) + return 0; + + if (mtu == NULL) + return 0; + + if (len < min_len) + return 0; + + if (pdu[0] != ATT_OP_MTU_RESP) + return 0; + + *mtu = att_get_u16(&pdu[1]); + + return min_len; + } + + uint16_t enc_prep_write_req(uint16_t handle, uint16_t offset, + const uint8_t *value, size_t vlen, uint8_t *pdu, size_t len) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle) + + sizeof(offset); + + if (pdu == NULL) + return 0; + + if (len < min_len) + return 0; + + if (vlen > len - min_len) + vlen = len - min_len; + + pdu[0] = ATT_OP_PREP_WRITE_REQ; + att_put_u16(handle, &pdu[1]); + att_put_u16(offset, &pdu[3]); + + if (vlen > 0) { + memcpy(&pdu[5], value, vlen); + return min_len + vlen; + } + + return min_len; + } + + uint16_t dec_prep_write_resp(const uint8_t *pdu, size_t len, uint16_t *handle, + uint16_t *offset, uint8_t *value, size_t *vlen) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle) + + sizeof(*offset); + + if (pdu == NULL) + return 0; + + if (handle == NULL || offset == NULL || value == NULL || vlen == NULL) + return 0; + + if (len < min_len) + return 0; + + if (pdu[0] != ATT_OP_PREP_WRITE_REQ) + return 0; + + *handle = att_get_u16(&pdu[1]); + *offset = att_get_u16(&pdu[3]); + *vlen = len - min_len; + if (*vlen > 0) + memcpy(value, pdu + min_len, *vlen); + + return len; + } + + uint16_t enc_exec_write_req(uint8_t flags, uint8_t *pdu, size_t len) + { + const uint16_t min_len = sizeof(pdu[0]) + sizeof(flags); + + if (pdu == NULL) + return 0; + + if (len < min_len) + return 0; + + if (flags > 1) + return 0; + + pdu[0] = ATT_OP_EXEC_WRITE_REQ; + pdu[1] = flags; + + return min_len; + } + + uint16_t dec_exec_write_resp(const uint8_t *pdu, size_t len) + { + const uint16_t min_len = sizeof(pdu[0]); + + if (pdu == NULL) + return 0; + + if (len < min_len) + return 0; + + if (pdu[0] != ATT_OP_EXEC_WRITE_RESP) + return 0; + + return len; + } + +} diff --git a/vendor/libblepp-master/src/att_pdu.cc b/vendor/libblepp-master/src/att_pdu.cc new file mode 100644 index 0000000..799045e --- /dev/null +++ b/vendor/libblepp-master/src/att_pdu.cc @@ -0,0 +1,85 @@ +/* + * + * blepp - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include + +using namespace std; + + +void BLEPP::pretty_print(const PDUResponse& pdu) +{ + if(log_level >= Debug) + { + cerr << "debug: ---PDU packet ---\n"; + cerr << "debug: " << to_hex(pdu.data, pdu.length) << endl; + cerr << "debug: " << to_str(pdu.data, pdu.length) << endl; + cerr << "debug: Packet type: " << to_hex(pdu.type()) << " " << att_op2str(pdu.type()) << endl; + + if(pdu.type() == ATT_OP_ERROR) + cerr << "debug: " << PDUErrorResponse(pdu).error_str() << " in response to " << att_op2str(PDUErrorResponse(pdu).request_opcode()) << " on handle " + to_hex(PDUErrorResponse(pdu).handle()) << endl; + else if(pdu.type() == ATT_OP_READ_BY_TYPE_RESP) + { + PDUReadByTypeResponse p(pdu); + + cerr << "debug: elements = " << p.num_elements() << endl; + cerr << "debug: value size = " << p.value_size() << endl; + + for(int i=0; i < p.num_elements(); i++) + { + cerr << "debug: " << to_hex(p.handle(i)) << " "; + if(p.value_size() != 2) + cerr << "-->" << to_str(p.value(i)) << "<--" << endl; + else + cerr << to_hex(p.value_uint16(i)) << endl; + } + + } + else if(pdu.type() == ATT_OP_READ_BY_GROUP_RESP) + { + PDUReadGroupByTypeResponse p(pdu); + cerr << "debug: elements = " << p.num_elements() << endl; + cerr << "debug: value size = " << p.value_size() << endl; + + for(int i=0; i < p.num_elements(); i++) + cerr << "debug: " << "[ " << to_hex(p.start_handle(i)) << ", " << to_hex(p.end_handle(i)) << ") :" << to_str(p.value(i)) << endl; + } + else if(pdu.type() == ATT_OP_WRITE_RESP) + { + } + else if(pdu.type() == ATT_OP_HANDLE_NOTIFY || pdu.type() == ATT_OP_HANDLE_IND) + { + PDUNotificationOrIndication p(pdu); + cerr << "debug: handle = " << p.handle() << endl; + cerr << "debug: data = " << to_hex(p.value().first, p.value().second - p.value().first) << endl; + cerr << "debug: data = " << to_str(p.value().first, p.value().second - p.value().first) << endl; + + } + else + cerr << "debug: --no pretty printer available--\n"; + + cerr << "debug:\n"; + } +}; + + diff --git a/vendor/libblepp-master/src/bledevice.cc b/vendor/libblepp-master/src/bledevice.cc new file mode 100644 index 0000000..dfdb920 --- /dev/null +++ b/vendor/libblepp-master/src/bledevice.cc @@ -0,0 +1,260 @@ +/* + * + * blepp - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "blepp/bledevice.h" +#include "blepp/logging.h" +#include "blepp/att_pdu.h" + + +#include +#include + +#include + +#include + +using namespace std; + +namespace BLEPP +{ + + template const C& haxx(const C& X) + { + return X; + } + + inline int haxx(uint8_t X) + { + return X; + } + + #define test(X, Y) test_fd_(X, __LINE__) + #define TEST(X, S, B, L) call(X(),S, B, L) + + template void test_fd_(int fd, int line) + { + if(fd < 0) + { + LOG(Info, "Error on line " << line << "( " << __FILE__ << "): " <(write(sock, buf, len), line); + } + + + void call(const Read&, int sock, uint8_t* buf, size_t len, int line) + { + test_fd_(read(sock, buf, len), line); + } + + void BLEDevice::send_read_request(uint16_t handle) + { + int len = enc_read_req(handle, buf.data(), buf.size()); + test_pdu(len); + int ret = write(sock, buf.data(), len); + test(ret, Write); + } + + void BLEDevice::send_read_by_type(const bt_uuid_t& uuid, uint16_t start, uint16_t end) + { + int len = enc_read_by_type_req(start, end, const_cast(&uuid), buf.data(), buf.size()); + test_pdu(len); + int ret = write(sock, buf.data(), len); + test(ret, Write); + } + + void BLEDevice::send_find_information(uint16_t start, uint16_t end) + { + int len = enc_find_info_req(start, end, buf.data(), buf.size()); + test_pdu(len); + int ret = write(sock, buf.data(), len); + test(ret, Write); + } + + void BLEDevice::send_read_group_by_type(const bt_uuid_t& uuid, uint16_t start, uint16_t end) + { + int len = enc_read_by_grp_req(start, end, const_cast(&uuid), buf.data(), buf.size()); + test_pdu(len); + int ret = write(sock, buf.data(), len); + test(ret, Write); + } + + void BLEDevice::send_write_request(uint16_t handle, const uint8_t* data, int length) + { + int len = enc_write_req(handle, data, length, buf.data(), buf.size()); + test_pdu(len); + int ret = write(sock, buf.data(), len); + test(ret, Write); + } + + void BLEDevice::send_write_request(uint16_t handle, uint16_t data) + { + const uint8_t buf[2] = { (uint8_t)(data & 0xff), (uint8_t)((data & 0xff00) >> 8)}; + send_write_request(handle, buf, 2); + } + + void BLEDevice::send_handle_value_confirmation() + { + int len = enc_confirmation(buf.data(), buf.size()); + test_pdu(len); + int ret = write(sock, buf.data(), len); + test(ret, Write); + } + + void BLEDevice::send_write_command(uint16_t handle, const uint8_t* data, int length) + { + int len = enc_write_cmd(handle, data, length, buf.data(), buf.size()); + test_pdu(len); + int ret = write(sock, buf.data(), len); + test(ret, Write); + } + + void BLEDevice::send_write_command(uint16_t handle, uint16_t data) + { + const uint8_t buf[2] = { (uint8_t)(data & 0xff), (uint8_t)((data & 0xff00) >> 8)}; + send_write_command(handle, buf, 2); + } + + + PDUResponse BLEDevice::receive(uint8_t* buf, int max) + { + int len = read(sock, buf, max); + test(len, Read); + pretty_print(PDUResponse(buf, len)); + return PDUResponse(buf, len); + } + + PDUResponse BLEDevice::receive(vector& v) + { + return receive(v.data(), v.size()); + } + + + + + BLEDevice::BLEDevice(const int& sock_) + :sock(sock_) + { + /* + //Allocate socket and create endpoint. + sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + test(sock); + + //////////////////////////////////////// + //Bind the socket + //I believe that l2 is for an l2cap socket. These are kind of like + //UDP in that they have port numbers and are packet oriented. + struct sockaddr_l2 addr; + + bdaddr_t source_address = {{0,0,0,0,0,0}}; //i.e. the adapter. Note, 0, corresponds to BDADDR_ANY + //However BDADDR_ANY uses a nonstandard C hack and does not compile + //under C++. So, set it manually. + //So, a sockaddr_l2 has the family (obviously) + //a PSM (wtf?) + // Protocol Service Multiplexer (WTF?) + //an address (of course) + //a CID (wtf) + // Channel ID (i.e. port number?) + //and an address type (wtf) + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + + addr.l2_psm = 0; + addr.l2_cid = htobs(LE_ATT_CID); + + + bacpy(&addr.l2_bdaddr, &source_address); + + //Address type: Low Energy public + addr.l2_bdaddr_type=BDADDR_LE_PUBLIC; + + //Bind socket. This associates it with a particular adapter. + //We chose ANY as the source address, so packets will go out of + //whichever adapter necessary. + int ret = bind(sock, (sockaddr*)&addr, sizeof(addr)); + test(ret); + + + //////////////////////////////////////// + + //Need to do l2cap_set here + l2cap_options options; + unsigned int len = sizeof(options); + memset(&options, 0, len); + + //Get the options with a minor bit of cargo culting. + //SOL_L2CAP seems to mean that is should operate at the L2CAP level of the stack + //L2CAP_OPTIONS who knows? + ret = getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &options, &len); + test(ret); + + LOGVAR(options.omtu); + LOGVAR(options.imtu); + LOGVAR(options.flush_to); + LOGVAR(options.mode); + LOGVAR(options.fcs); + LOGVAR(options.max_tx); + LOGVAR(options.txwin_size); + + + + //Can also use bacpy to copy addresses about + str2ba(address.c_str(), &addr.l2_bdaddr); + ret = connect(sock, (sockaddr*)&addr, sizeof(addr)); + test(ret); + + + //And this seems to work up to here. + + //Get the options with a minor bit of cargo culting. + //SOL_L2CAP seems to mean that is should operate at the L2CAP level of the stack + //L2CAP_OPTIONS who knows? + ret = getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &options, &len); + test(ret); + + LOGVAR(options.omtu); + LOGVAR(options.imtu); + LOGVAR(options.flush_to); + LOGVAR(options.mode); + LOGVAR(options.fcs); + LOGVAR(options.max_tx); + LOGVAR(options.txwin_size); + */ + buf.resize(ATT_DEFAULT_MTU); + } + +} diff --git a/vendor/libblepp-master/src/blestatemachine.cc b/vendor/libblepp-master/src/blestatemachine.cc new file mode 100644 index 0000000..340d89f --- /dev/null +++ b/vendor/libblepp-master/src/blestatemachine.cc @@ -0,0 +1,836 @@ +/* + * + * blepp - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "blepp/bledevice.h" +#include "blepp/logging.h" +#include "blepp/att_pdu.h" +#include "blepp/pretty_printers.h" +#include "blepp/blestatemachine.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include +using namespace std; + + + +#define log_fd(X) log_fd_(X, __LINE__, __FILE__) + +namespace BLEPP +{ + + namespace { + int log_fd_(int fd, int line, const char* file) + { + if(fd < 0) + { + LOG(Error, "Error on line: " << line << " (" << file << "): " << strerror(errno)); + } + else + LOG(Info, "Socket success: " << line << " (" << file << ")"); + + return fd; + } + } + + const char* BLEGATTStateMachine::get_disconnect_string(Disconnect d) + { + switch(d.reason) + { + case Disconnect::ConnectionFailed: return "Connection failed."; + case Disconnect::UnexpectedError: return "Unexpected Error."; + case Disconnect::UnexpectedResponse: return "Unexpected Response."; + case Disconnect::WriteError: return "Write Error."; + case Disconnect::ReadError: return "Read Error."; + case Disconnect::ConnectionClosed: return "Connection Closed."; + default: return "Unknown reason."; + } + } + + + + const ServiceInfo* lookup_service_by_UUID(const UUID& uuid) + { + static vector vec; + + if(vec.size() == 0) + { + auto add = [](const char* n, const char* i, uint16_t u) + { + ServiceInfo s; + s.name=n; + s.id = i; + s.uuid = UUID(u); + vec.push_back(s); + }; + + add( "Alert Notification Service", "org.bluetooth.service.alert_notification", 0x1811); + add( "Battery Service", "org.bluetooth.service.battery_service", 0x180F); + add( "Blood Pressure", "org.bluetooth.service.blood_pressure", 0x1810); + add( "Body Composition", "org.bluetooth.service.body_composition", 0x181B); + add( "Bond Management", "org.bluetooth.service.bond_management", 0x181E); + add( "Current Time Service", "org.bluetooth.service.current_time", 0x1805); + add( "Cycling Power", "org.bluetooth.service.cycling_power", 0x1818); + add( "Cycling Speed and Cadence", "org.bluetooth.service.cycling_speed_and_cadence", 0x1816); + add( "Device Information", "org.bluetooth.service.device_information", 0x180A); + add( "Generic Access", "org.bluetooth.service.generic_access", 0x1800); + add( "Generic Attribute", "org.bluetooth.service.generic_attribute", 0x1801); + add( "Glucose", "org.bluetooth.service.glucose", 0x1808); + add( "Health Thermometer", "org.bluetooth.service.health_thermometer", 0x1809); + add( "Heart Rate", "org.bluetooth.service.heart_rate", 0x180D); + add( "Human Interface Device", "org.bluetooth.service.human_interface_device", 0x1812); + add( "Immediate Alert", "org.bluetooth.service.immediate_alert", 0x1802); + add( "Link Loss", "org.bluetooth.service.link_loss", 0x1803); + add( "Location and Navigation", "org.bluetooth.service.location_and_navigation", 0x1819); + add( "Next DST Change Service", "org.bluetooth.service.next_dst_change", 0x1807); + add( "Phone Alert Status Service", "org.bluetooth.service.phone_alert_status", 0x180E); + add( "Reference Time Update Service", "org.bluetooth.service.reference_time_update", 0x1806); + add( "Running Speed and Cadence", "org.bluetooth.service.running_speed_and_cadence", 0x1814); + add( "Scan Parameters", "org.bluetooth.service.scan_parameters", 0x1813); + add( "Tx Power", "org.bluetooth.service.tx_power", 0x1804); + add( "User Data", "org.bluetooth.service.user_data", 0x181C); + add( "Weight Scale", "org.bluetooth.service.weight_scale", 0x181D); + } + + auto f = find_if(vec.begin(), vec.end(), [&](const ServiceInfo& s) + { + return s.uuid == uuid; + }); + + if(f == vec.end()) + return 0; + else + return &*f; + } + + + void BLEGATTStateMachine::buggerall() + { + } + + void BLEGATTStateMachine::buggerall2(Disconnect) + { + } + + + void BLEGATTStateMachine::close() + { + reset(); + + state = Disconnected; + next_handle_to_read=-1; + last_request=-1; + + if(sock != -1) + log_fd(::close(sock)); + sock = -1; + } + + + int log_l2cap_options(int sock) + { + //Read and log the socket setup. + + l2cap_options options; + unsigned int len = sizeof(options); + memset(&options, 0, len); + + //Get the options with a minor bit of cargo culting. + //SOL_L2CAP seems to mean that is should operate at the L2CAP level of the stack + //L2CAP_OPTIONS who knows? + if(log_fd(getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &options, &len)) == -1) + return -1; + + LOGVAR(Info,options.omtu); + LOGVAR(Info,options.imtu); + LOGVAR(Info,options.flush_to); + LOGVAR(Info,options.mode); + LOGVAR(Info,options.fcs); + LOGVAR(Info,options.max_tx); + LOGVAR(Info,options.txwin_size); + + return 0; + } + + BLEGATTStateMachine::~BLEGATTStateMachine() + { + ENTER(); + close(); + } + + BLEGATTStateMachine::BLEGATTStateMachine() + :dev(sock) + { + ENTER(); + close(); + buf.resize(128); + } + + void BLEGATTStateMachine::connect_blocking(const string& address) + { + connect(address, true); + } + + + void BLEGATTStateMachine::connect_nonblocking(const string& address) + { + connect(address, false); + } + + void BLEGATTStateMachine::connect(const string& address, bool blocking, bool pubaddr, string device) + { + ENTER(); + + //The constructor sets up the socket. Unless something is badly broken, + //then we should succeed. Therefore errors are an exception. + + //Allocate socket and create endpoint. + //Make socket nonblocking so connect() doesn't hang. + + if(blocking) + sock = log_fd(::socket(PF_BLUETOOTH, SOCK_SEQPACKET , BTPROTO_L2CAP)); + else + sock = log_fd(::socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK , BTPROTO_L2CAP)); + + if(sock == -1) + throw SocketAllocationFailed(strerror(errno)); + + //////////////////////////////////////// + //Bind the socket + //I believe that l2 is for an l2cap socket. These are kind of like + //UDP in that they have port numbers and are packet oriented. + //However they are also ordered and reliable. + //So, a sockaddr_l2 has the family (obviously) + //a PSM (wtf?) + // Protocol Service Multiplexer (WTF?) + //an address (of course) + //a CID(Channel ID) - See bluetooth 4.2 core spec for more info + // Section 2.1 CHANNEL IDENTIFIERS ATTRIBUTE PROTOCOL + //and an address type + // See bluetooth 4.2 core spec for more info, section 15.1.1 + // Device will either have a registered "public" address, or a private "random" one that meets certain criteria + //Holy cargo cult, Batman! + + + sockaddr_l2 sba; + memset(&sba, 0, sizeof(sba)); + if (device == "") sba.l2_bdaddr={{0,0,0,0,0,0}}; //use default adapter + + else { + bdaddr_t btsrc_addr; + int dev_id = hci_devid(device.c_str()); //obtain device id from HCI device name + LOG(Debug, "dev_id = " << dev_id); + if (dev_id < 0) { + throw SocketConnectFailed("Error obtaining HCI device ID"); + } + hci_devba(dev_id, &btsrc_addr); + bacpy(&sba.l2_bdaddr,&btsrc_addr); //lifted from bluez example, populate src sockaddr with address of desired device + } + + + + + sba.l2_family=AF_BLUETOOTH; + sba.l2_cid = htobs(LE_ATT_CID); + sba.l2_bdaddr_type = BDADDR_LE_PUBLIC; + log_fd(bind(sock, (sockaddr*)&sba , sizeof(sba))); + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + addr.l2_psm = 0; + addr.l2_cid = htobs(LE_ATT_CID); + + + //Address type: Low Energy PUBLIC or RANDOM + if (pubaddr) addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; + else addr.l2_bdaddr_type = BDADDR_LE_RANDOM; + + if(log_l2cap_options(sock) == -1) + { + reset(); + throw SocketGetSockOptFailed(strerror(errno)); + } + //Construct an address from the address string + + + + + + //Can also use bacpy to copy addresses about + int rr = str2ba(address.c_str(), &addr.l2_bdaddr); + LOG(Debug, "address = " << address); + LOG(Debug, "str2ba = " << rr); + int ret = log_fd(::connect(sock, (sockaddr*)&addr, sizeof(addr))); + + + + if(ret == 0) + { + state = Idle; + + if(log_l2cap_options(sock) == -1) + { + reset(); + throw SocketGetSockOptFailed(strerror(errno)); + } + + cb_connected(); + } + else if(errno == EINPROGRESS) + { + //This "error" means the connection is happening and + //we should come back later after select() returns. + state = Connecting; + } + else if(errno == ENETUNREACH || errno == EHOSTUNREACH) + { + close(); + cb_disconnected(Disconnect(Disconnect::Reason::ConnectionFailed, errno)); + } + else + { + reset(); + throw SocketConnectFailed(strerror(errno)); + } + } + + + + int BLEGATTStateMachine::socket() + { + return sock; + } + + void BLEGATTStateMachine::reset() + { + state = Idle; + next_handle_to_read=-1; + last_request=-1; + } + + + + + void BLEGATTStateMachine::state_machine_write() + { + try + { + if(state == ReadingPrimaryService) + { + last_request = ATT_OP_READ_BY_GROUP_REQ; + dev.send_read_group_by_type(UUID(GATT_UUID_PRIMARY), next_handle_to_read, 0xffff); + } + else if(state == FindAllCharacteristics) + { + last_request = ATT_OP_READ_BY_TYPE_REQ; + dev.send_read_by_type(UUID(GATT_CHARACTERISTIC), next_handle_to_read, 0xffff); + } + else if(state == GetClientCharaceristicConfiguration) + { + last_request = ATT_OP_READ_BY_TYPE_REQ; + dev.send_read_by_type(UUID(GATT_CLIENT_CHARACTERISTIC_CONFIGURATION), next_handle_to_read, 0xffff); + } + else if(state == AwaitingWriteResponse) + { + last_request = ATT_OP_WRITE_REQ; + //data already sent + } + } + catch(BLEDevice::WriteError) + { + fail(Disconnect(Disconnect::Reason::WriteError, errno)); + } + + } + + + + //////////////////////////////////////////////////////////////////////////////// + // + // Commands to move machine into other states explicitly + // + + void BLEGATTStateMachine::read_primary_services() + { + if(state != Idle) + throw logic_error("Error trying to issue command mid state"); + state = ReadingPrimaryService; + next_handle_to_read=1; + state_machine_write(); + } + + void BLEGATTStateMachine::find_all_characteristics() + { + if(state != Idle) + throw logic_error("Error trying to issue command mid state"); + state = FindAllCharacteristics; + next_handle_to_read=1; + state_machine_write(); + } + + void BLEGATTStateMachine::get_client_characteristic_configuration() + { + if(state != Idle) + throw logic_error("Error trying to issue command mid state"); + state = GetClientCharaceristicConfiguration; + next_handle_to_read=1; + state_machine_write(); + } + + void BLEGATTStateMachine::set_notify_and_indicate(Characteristic& c, bool notify, bool indicate) + { + LOG(Trace, "BLEGATTStateMachine::enable_indications(Characteristic&)"); + + if(state != Idle) + throw logic_error("Error trying to issue command mid state"); + + if(!c.indicate && indicate) + throw logic_error("Error: this is not indicateable"); + if(!c.notify && notify) + throw logic_error("Error: this is not notifiable"); + + //FIXME: check for CCC + c.ccc_last_known_value = notify | (indicate << 1); + + + try{ + dev.send_write_command(c.client_characteric_configuration_handle, c.ccc_last_known_value); + } + catch(BLEDevice::WriteError) + { + fail(Disconnect(Disconnect::Reason::WriteError, errno)); + } + } + + + bool BLEGATTStateMachine::wait_on_write() + { + if(state == Connecting) + return true; + else + return false; + } + + void BLEGATTStateMachine::fail(Disconnect d) + { + close(); + cb_disconnected(d); + } + + void BLEGATTStateMachine::unexpected_error(const PDUErrorResponse& r) + { + PDUErrorResponse err(r); + string msg = string("Received unexpected error:") + att_ecode2str(err.error_code()); + LOG(Error, msg); + fail(Disconnect(Disconnect::Reason::UnexpectedError, Disconnect::NoErrorCode)); + } + //////////////////////////////////////////////////////////////////////////////// + // + // The state machine itself! + void BLEGATTStateMachine::write_and_process_next() + { + ENTER(); + try + { + LOG(Debug, "State is: " << state); + if(state == Connecting) + { + int errval=-7; + socklen_t len; + len = sizeof(errval); + //Check the status of the socket + log_fd(getsockopt(sock, SOL_SOCKET, SO_ERROR, &errval, &len)); + + LOG(Info, "errval = " << strerror(errval)); + + if(errval == 0) + { + //Connected, so go to the idle state + reset(); + cb_connected(); + } + else + { + close(); + cb_disconnected(Disconnect(Disconnect::Reason::ConnectionFailed, errval)); + } + + } + else + { + LOG(Error, "Not implemented!"); + } + } + catch(BLEDevice::WriteError) + { + fail(Disconnect(Disconnect::Reason::WriteError, errno)); + } + catch(BLEDevice::ReadError) + { + fail(Disconnect(Disconnect::Reason::ReadError, errno)); + } + } + + void BLEGATTStateMachine::read_and_process_next() + { + ENTER(); + //This is always an error + if(state == Connecting) + throw logic_error("Trying to read socket while connecting"); + + + if(state == Disconnected) + { + //This is just possible. Imagine select() returning both read and write. + //The write is processed first and fails, causing a disconnect. + //The program then issues a call to read without checking for errors. + //The result is harmless and unlikely, so log a warning. + LOG(Warning, "Trying to read_and_process_next while disconnected"); + return; + } + + try + { + PDUResponse r = dev.receive(buf); + + if(r.type() == ATT_OP_HANDLE_NOTIFY || r.type() == ATT_OP_HANDLE_IND) + { + PDUNotificationOrIndication n(r); + //Find the correct characteristic + for(auto& s:primary_services) + if(n.handle() > s.start_handle && n.handle() <= s.end_handle) + for(auto& c:s.characteristics) + if(n.handle() == c.value_handle) + { + if(c.cb_notify_or_indicate) + c.cb_notify_or_indicate(n); + else if(cb_notify_or_indicate) + cb_notify_or_indicate(c, n); + else + LOG(Warning, "Notify arrived, but no callback set\n"); + } + + //Respond to indications after the callback has run + if(!n.notification()) + dev.send_handle_value_confirmation(); + } + else if(r.type() == ATT_OP_ERROR && PDUErrorResponse(r).request_opcode() != last_request) + { + PDUErrorResponse err(r); + + std::string msg = string("Unexpected opcode in error. Expected ") + att_op2str(last_request) + " got " + att_op2str(err.request_opcode()); + LOG(Error, msg); + fail(Disconnect(Disconnect::Reason::UnexpectedError, Disconnect::NoErrorCode)); + } + else if(r.type() != ATT_OP_ERROR && r.type() != last_request + 1) + { + string msg = string("Unexpected response. Expected ") + att_op2str(last_request+1) + " got " + att_op2str(r.type()); + LOG(Error, msg); + fail(Disconnect(Disconnect::Reason::UnexpectedResponse, Disconnect::NoErrorCode)); + } + else + { + if(state == ReadingPrimaryService) + { + if(r.type() == ATT_OP_ERROR) + { + if(PDUErrorResponse(r).error_code() == ATT_ECODE_ATTR_NOT_FOUND) + { + //Maybe ? Indicates that the last one has been read. + cb_services_read(); + reset(); + } + else + unexpected_error(r); + } + else + { + GATTReadServiceGroup g(r); + + for(int i=0; i < g.num_elements(); i++) + { + struct PrimaryService service; + service.start_handle = g.start_handle(i); + service.end_handle = g.end_handle(i); + service.uuid = UUID::from(g.uuid(i)); + primary_services.push_back(service); + } + + + if(primary_services.back().end_handle == 0xffff) + { + reset(); + cb_services_read(); + } + else + { + next_handle_to_read = primary_services.back().end_handle+1; + state_machine_write(); + } + } + } + else if(state == FindAllCharacteristics) + { + if(r.type() == ATT_OP_ERROR) + { + if(PDUErrorResponse(r).error_code() == ATT_ECODE_ATTR_NOT_FOUND) + { + //Maybe ? Indicates that the last one has been read. + reset(); + cb_find_characteristics(); + } + else + unexpected_error(r); + } + else + { + GATTReadCharacteristic rc(r); + + for(int i=0; i < rc.num_elements(); i++) + { + uint16_t handle = rc.handle(i); + GATTReadCharacteristic::Characteristic ch = rc.characteristic(i); + + LOG(Debug, "Found characteristic handle: " << to_hex(handle)); + + //Search for the correct service. + for(unsigned int s=0; s < primary_services.size(); s++) + { + if(handle > primary_services[s].start_handle && handle <= primary_services[s].end_handle) + { + LOG(Debug, " handle belongs to service " << s); + Characteristic c(this); + + + c.broadcast= ch.flags & GATT_CHARACTERISTIC_FLAGS_BROADCAST; + c.read = ch.flags & GATT_CHARACTERISTIC_FLAGS_READ; + c.write_without_response= ch.flags & GATT_CHARACTERISTIC_FLAGS_WRITE_WITHOUT_RESPONSE; + c.write = ch.flags & GATT_CHARACTERISTIC_FLAGS_WRITE; + c.notify = ch.flags & GATT_CHARACTERISTIC_FLAGS_NOTIFY; + c.indicate = ch.flags & GATT_CHARACTERISTIC_FLAGS_INDICATE; + c.authenticated_write = ch.flags & GATT_CHARACTERISTIC_FLAGS_AUTHENTICATED_SIGNED_WRITES; + c.extended = ch.flags & GATT_CHARACTERISTIC_FLAGS_EXTENDED_PROPERTIES; + c.uuid = UUID::from(ch.uuid); + c.value_handle = ch.handle; + c.client_characteric_configuration_handle = 0; + c.first_handle = handle; + + //Initially mark the end as the start of the current service + c.last_handle = primary_services[s].end_handle; + + //Terminate the previous characteristic + if(!primary_services[s].characteristics.empty()) + primary_services[s].characteristics.back().last_handle = handle-1; + + primary_services[s].characteristics.push_back(c); + + + + } + } + + next_handle_to_read = handle+1; + } + LOG(Debug, "Reading " << to_hex((uint16_t)next_handle_to_read) << " next"); + state_machine_write(); + } + } + else if(state == GetClientCharaceristicConfiguration) + { + if(r.type() == ATT_OP_ERROR) + { + if(PDUErrorResponse(r).error_code() == ATT_ECODE_ATTR_NOT_FOUND) + { + //Maybe ? Indicates that the last one has been read. + reset(); + cb_get_client_characteristic_configuration(); + } + else + unexpected_error(r); + } + else + { + GATTReadCCC rc(r); + + for(int i=0; i < rc.num_elements(); i++) + { + uint16_t handle = rc.handle(i); + next_handle_to_read = handle + 1; + LOG(Debug, "Handle: " << to_hex(rc.handle(i)) << " ccc: " << to_hex(rc.ccc(i))); + + + //Find the correct place + for(auto& s:primary_services) + if(handle > s.start_handle && handle <= s.end_handle) + for(auto& c:s.characteristics) + if(handle > c.first_handle && handle <= c.last_handle) + { + c.client_characteric_configuration_handle = rc.handle(i); + c.ccc_last_known_value = rc.ccc(i); + } + + } + state_machine_write(); + } + } + else if(state == AwaitingWriteResponse) + { + + if(r.type() == ATT_OP_ERROR) + unexpected_error(r); + else + { + reset(); + cb_write_response(); + } + } + } + } + catch(BLEDevice::WriteError) + { + fail(Disconnect(Disconnect::WriteError, errno)); + } + catch(BLEDevice::ReadError) + { + fail(Disconnect(Disconnect::ReadError, errno)); + } + } + + + void BLEGATTStateMachine::send_write_request(uint16_t handle, const uint8_t* data, int length) + { + if(state != Idle) + throw logic_error("Error trying to issue command mid state"); + dev.send_write_request(handle, data, length); + state = AwaitingWriteResponse; + state_machine_write(); + } + + void Characteristic::write_request(const uint8_t*data, int length) + { + s->send_write_request(value_handle, data, length); + } + + + void Characteristic::write_request(const uint8_t data) + { + s->send_write_request(value_handle, &data, 1); + } + + void Characteristic::set_notify_and_indicate(bool notify, bool indicate) + { + LOG(Trace, "Characteristic::enable_indications()"); + s->set_notify_and_indicate(*this, notify, indicate); + } + + + void pretty_print_tree(const BLEGATTStateMachine& s) + { + + cout << "Primary services:\n"; + for(auto& service: s.primary_services) + { + cout << "Start: " << to_hex(service.start_handle); + cout << " End: " << to_hex(service.end_handle); + cout << " UUID: " << to_str(service.uuid) << endl; + const ServiceInfo* s = lookup_service_by_UUID(UUID::from(service.uuid)); + if(s) + cout << " " << s->id << ": " << s->name << endl; + else + cout << " Unknown\n"; + + + for(auto& characteristic: service.characteristics) + { + cout << " Characteristic: " << to_str(characteristic.uuid) << endl; + cout << " Start: " << to_hex(characteristic.first_handle) << " End: " << to_hex(characteristic.last_handle) << endl; + + cout << " Flags: "; + if(characteristic.broadcast) + cout << "Broadcast "; + if(characteristic.read) + cout << "Read "; + if(characteristic.write_without_response) + cout << "Write (without response) "; + if(characteristic.write) + cout << "Write "; + if(characteristic.notify) + cout << "Notify "; + if(characteristic.indicate) + cout << "Indicate "; + if(characteristic.authenticated_write) + cout << "Authenticated signed writes "; + if(characteristic.extended) + cout << "Extended properties "; + cout << endl; + + cout << " Value at handle: " << characteristic.value_handle << endl; + + if(characteristic.client_characteric_configuration_handle != 0) + cout << " CCC: (" << to_hex(characteristic.client_characteric_configuration_handle) << ") " << to_hex(characteristic.ccc_last_known_value) << endl; + + cout << endl; + + } + + cout << endl; + } + } + + + //Handy utility function to do the sort of thing you'd normally do. + void BLEGATTStateMachine::setup_standard_scan(std::function& cb) + { + ENTER(); + + primary_services.clear(); + + cb_services_read = [this]() + { + this->find_all_characteristics(); + }; + + + cb_find_characteristics = [this]() + { + this->get_client_characteristic_configuration(); + }; + + cb_get_client_characteristic_configuration = [&cb]() + { + cb(); + }; + + cb_connected = [this]() + { + read_primary_services(); + }; + } + +} diff --git a/vendor/libblepp-master/src/float.cc b/vendor/libblepp-master/src/float.cc new file mode 100644 index 0000000..753d386 --- /dev/null +++ b/vendor/libblepp-master/src/float.cc @@ -0,0 +1,22 @@ +#include +#include + +using namespace std; + +namespace BLEPP +{ + + float bluetooth_float_to_IEEE754(const uint8_t* bytes) + { + int exponent = (int8_t)bytes[3]; + + int mantissa = (bytes[0]) | (bytes[1] << 8) | (bytes[2] << 16); + + if(mantissa > 0x080000) + mantissa = - (0x100000-mantissa); + + + return mantissa * pow(10, exponent); + + } +} diff --git a/vendor/libblepp-master/src/lescan.cc b/vendor/libblepp-master/src/lescan.cc new file mode 100644 index 0000000..e9310e5 --- /dev/null +++ b/vendor/libblepp-master/src/lescan.cc @@ -0,0 +1,701 @@ +#include "blepp/lescan.h" +#include "blepp/pretty_printers.h" +#include "blepp/gap.h" + +#include +#include +#include +#include +#include + +using namespace std; + +namespace BLEPP +{ + class Span + { + private: + const uint8_t* begin_; + const uint8_t* end_; + + public: + Span(const std::vector& d) + :begin_(d.data()),end_(begin_ + d.size()) + { + } + + Span(const Span&) = default; + + Span pop_front(size_t length) + { + if(length > size()) + throw std::out_of_range(""); + + Span s = *this; + s.end_ = begin_ + length; + + begin_ += length; + return s; + } + const uint8_t* begin() const + { + return begin_; + } + const uint8_t* end() const + { + return end_; + } + + const uint8_t& operator[](const size_t i) const + { + if(i >= size()) + throw std::out_of_range(""); + return begin_[i]; + } + + bool empty() const + { + return size()==0; + } + + size_t size() const + { + return end_ - begin_; + } + + const uint8_t* data() const + { + return begin_; + } + + const uint8_t& pop_front() + { + if(begin_ == end_) + throw std::out_of_range(""); + + begin_++; + return *(begin_-1); + } + }; + + AdvertisingResponse::Flags::Flags(vector&& s) + :flag_data(s) + { + //Remove the type field + flag_data.erase(flag_data.begin()); + if(!flag_data.empty()) + { + //See 4.0/4.C.18.1 + LE_limited_discoverable = flag_data[0] & (1<<0); + LE_general_discoverable = flag_data[0] & (1<<1); + BR_EDR_unsupported = flag_data[0] & (1<<2); + simultaneous_LE_BR_controller = flag_data[0] & (1<<3); + simultaneous_LE_BR_host = flag_data[0] & (1<<4); + } + } + + string to_hex(const Span& s) + { + return to_hex(s.data(), s.size()); + } + + HCIScanner::Error::Error(const string& why) + :std::runtime_error(why) + { + LOG(LogLevels::Error, why); + } + + HCIScanner::IOError::IOError(const string& why, int errno_val) + :Error(why + ": " + strerror(errno_val)) + { + } + + HCIScanner::HCIScanner(bool start_scan) + :HCIScanner(start_scan, FilterDuplicates::Both, ScanType::Active) + { + } + + + HCIScanner::HCIScanner(bool start_scan, FilterDuplicates filtering, ScanType st, string device) + { + if(filtering == FilterDuplicates::Hardware || filtering == FilterDuplicates::Both) + hardware_filtering = true; + else + hardware_filtering = false; + + if(filtering == FilterDuplicates::Software || filtering == FilterDuplicates::Both) + software_filtering = true; + else + software_filtering = false; + + scan_type=st; + + int dev_id = 0; + if (device == "") { + //Get a route to any(?) BTLE adapter (?) + dev_id = hci_get_route(NULL); + } + else { + dev_id = hci_devid(device.c_str()); + } + if (dev_id < 0) { + throw HCIError("Error obtaining HCI device ID"); + } + + //Open the device + //FIXME check errors + hci_fd.set(hci_open_dev(dev_id)); + + if(start_scan) + start(); + } + + HCIScanner::HCIScanner() + :HCIScanner(true) + { + + } + + void HCIScanner::start() + { + ENTER(); + if(running) + { + LOG(Trace, "Scanner is already running"); + return; + } + + //Cadged from the hcitool sources. No idea what + //these mean + uint16_t interval = htobs(0x0010); + uint16_t window = htobs(0x0010); + + //Address for the adapter (I think). Use a public address. + //other option is random. Works either way it seems. + uint8_t own_type = LE_PUBLIC_ADDRESS; + + //Don't use a whitelist (?) + uint8_t filter_policy = 0x00; + + + //The 10,000 thing seems to be some sort of retry logic timeout + //thing. Number of miliseconds, but there are multiple tries + //where it gets reduced by 10ms each time. It's a bit odd. + int err = hci_le_set_scan_parameters(hci_fd, static_cast(scan_type), interval, window, + own_type, filter_policy, 10000); + if(err < 0) + { + if(errno != EIO) + throw IOError("Setting scan parameters", errno); + else + { + //If the BLE device is already set to scanning, then we get an IO error. So + //try turning it off and trying again. This bad state would happen, if, to pick + //like a *totally* hypothetical example, the program segged-out during scanning + //and so never cleaned up properly. + LOG(LogLevels::Warning, "Received I/O error while setting scan parameters."); + LOG(LogLevels::Warning, "Switching off HCI scanner"); + err = hci_le_set_scan_enable(hci_fd, 0x00, 0x00, 10000); + if(err < 0) + throw IOError("Error disabling scan:", errno); + + + err = hci_le_set_scan_parameters(hci_fd, static_cast(scan_type), interval, window, own_type, filter_policy, 10000); + if(err < 0) + throw IOError("Error disabling scan:", errno); + else + LOG(LogLevels::Warning, "Setting scan parameters worked this time."); + + + } + } + + LOG(LogLevels::Info, "Starting scanner"); + scanned_devices.clear(); + + //Removal of duplicates done on the adapter itself + uint8_t filter_dup = hardware_filtering?0x01:0x00; + + + //Set up the filters. + socklen_t olen = sizeof(old_filter); + if (getsockopt(hci_fd, SOL_HCI, HCI_FILTER, &old_filter, &olen) < 0) + throw IOError("Getting HCI filter socket options", errno); + + + //Magic incantations to get scan events + struct hci_filter nf; + hci_filter_clear(&nf); + hci_filter_set_ptype(HCI_EVENT_PKT, &nf); + hci_filter_set_event(EVT_LE_META_EVENT, &nf); + if (setsockopt(hci_fd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) + throw IOError("Setting HCI filter socket options", errno); + + + //device disable/enable duplictes ???? + err = hci_le_set_scan_enable(hci_fd, 0x01, filter_dup, 10000); + if(err < 0) + throw IOError("Enabling scan", errno); + + running=true; + } + + void HCIScanner::stop() + { + ENTER(); + if(!running) + { + return; + } + + LOG(LogLevels::Info, "Cleaning up HCI scanner"); + int err = hci_le_set_scan_enable(hci_fd, 0x00, 0x00, 10000); + + if(err < 0) + throw IOError("Error disabling scan:", errno); + + err = setsockopt(hci_fd, SOL_HCI, HCI_FILTER, &old_filter, sizeof(old_filter)); + + if(err < 0) + throw IOError("Error resetting HCI socket:", errno); + + running = false; + } + + int HCIScanner::get_fd() const + { + return hci_fd; + } + + + HCIScanner::~HCIScanner() + { + try + { + stop(); + } + catch(IOError) + { + } + } + + HCIScanner::FilterEntry::FilterEntry(const AdvertisingResponse& a) + :mac_address(a.address),type(static_cast(a.type)) + {} + + bool HCIScanner::FilterEntry::operator<(const FilterEntry& f) const + { + //Simple lexi-sorting + if(mac_address < f.mac_address) + return true; + else if(mac_address == f.mac_address) + return type < f.type; + else + return false; + } + + vector HCIScanner::read_with_retry() + { + int len; + std::vector buf(HCI_MAX_EVENT_SIZE); + + + while((len = read(hci_fd, buf.data(), buf.size())) < 0) + { + if(errno == EAGAIN) + continue; + else if(errno == EINTR) + throw Interrupted("interrupted reading HCI packet"); + else + throw IOError("reading HCI packet", errno); + } + + buf.resize(len); + return buf; + } + + vector HCIScanner::get_advertisements() + { + vector adverts = parse_packet(read_with_retry()); + + if(software_filtering) + { + vector filtered; + + for(const auto& a: adverts) + { + auto r = scanned_devices.insert(FilterEntry(a)); + + if(r.second) + filtered.emplace_back(move(a)); + else + LOG(Debug, "Entry " << a.address << " " << static_cast(a.type) << " found already"); + } + + return filtered; + } + else + return adverts; + } + + /* + Hello comment-reader! + + This is a class for dealing with device scanning. The scans are done + using the HCI (Host Controller Interface). Interstingly, the HCI is + well specified even down to the transport layer (RS232 syle, USB, + SDIO and some sort of SLIP based serial). The HCI sometimes unpacks + and aggregates PDUs (the data part of packets) before sending them + for some reason, so you need to look in the HCI part of the spec, + not the PDU part of the spec. + + The HCI is also semi-autonomous, and can be instructed to do things like + sctive scanning (where it queries and reports additional information, + typically the device name) and filtering of duplicated advertising + events. This is great for low power draw because the host CPU doesn't need + to wake up to do menial or unimportant things. + + Also, the HCI of course gives you everything! The kernel contains no + permissioned control over filtering which means anything with permissions + to open the HCI can also get all data packets in both directions and + therefore sniff everything. As a result, scanning normally has to be + activated by root only. + + + The general HCI event format is (Bluetooth 4.0 Vol 2, Part E, 5.4.4) + + + Note that the HCI unpacks some of the bitfields in the advertising + PDU and presents them as whole bytes. + + Packet type is not part of the HCI command. In USB the type is + determined by the endpoint address. In all the serial protocols the + packet type is 1 byte at the beginning where + + Command = 0x01 Event = 0x04 + + See, e.g. 4.0/4/A.2 + + Linux seems to use these. + + And the LE events are all = 0x3E (HCI_LE_META_EVT) as per + 4.0/2/E.7.7.65 + And the format of is: + + + + And we're interested in advertising events, where + = 0x02 (as per 4.0/2/E.7.7.65.2) + + And the format of in this case is + + + + Where is + +
+
+ + + + + is an advertising packet and that's specified + all over the place. 4.0/3/C.8 for example. The advertising packets + are of the format: + + + ... + + + Now, the meaning of type, and the valid data are not defined in the main + spec, but in "Supplement to the Bluetooth Core Specification" version 4, + referred to here as S4. Except that defines only the name of the types + not their numeric code for some reason. Those are on the web. + https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile + + + Some datatypes are not valid in advertising packets and some are also not + valid in LE applications. Apart from a small selection, many of the types + are rare to the point of nonexistence. I ignore them because I've got nothing + that generates tham and I wouldn't know what to do with them anyway. Feel free + to fix or ping me if you need them :) + + The ones generally of interest are: + <> + <> + <> + <> + <> + <> + <> + <> + <> + + Personal experience suggest UUIDs and flags are almost always present. + Names are often present. iBeacons use manufacturer specific data whereas + Eddystone beacons use service data. I've used neither. I've not personally + seen or heard of any of the other types, including 32 bit UUIDs. + + There are also some moderately sensible restrictions. A device SHALL NOT + report bot incomplete and complete lists of the same things in the same + packet S4/1.1.1. Furthermore an ommitted UUID specification is equivalent + to a incomplete list with no elements. + + + + Returns 1 on success, 0 on failure - such as an inability + to handle the packet, not an error. + + Return code can probably be ignored because + it will call lambdas on specific packets anyway. + + TODO: replace some errors with throw. + such as the HCI device spewing crap. + + */ + + vector parse_event_packet(Span packet); + vector parse_le_meta_event(Span packet); + vector parse_le_meta_event_advertisement(Span packet); + + vector HCIScanner::parse_packet(const vector& p) + { + Span packet(p); + LOG(Debug, to_hex(p)); + + if(packet.size() < 1) + { + LOG(LogLevels::Error, "Empty packet received"); + return {}; + } + + uint8_t packet_id = packet.pop_front(); + + + if(packet_id == HCI_EVENT_PKT) + { + LOG(Debug, "Event packet received"); + return parse_event_packet(packet); + } + else + { + LOG(LogLevels::Error, "Unknown HCI packet received"); + throw HCIError("Unknown HCI packet received"); + } + } + + vector parse_event_packet(Span packet) + { + if(packet.size() < 2) + throw HCIScanner::HCIError("Truncated event packet"); + + uint8_t event_code = packet.pop_front(); + uint8_t length = packet.pop_front(); + + + if(packet.size() != length) + throw HCIScanner::HCIError("Bad packet length"); + + if(event_code == EVT_LE_META_EVENT) + { + LOG(Info, "event_code = 0x" << hex << (int)event_code << ": Meta event" << dec); + LOGVAR(Info, length); + + return parse_le_meta_event(packet); + } + else + { + LOG(Info, "event_code = 0x" << hex << (int)event_code << dec); + LOGVAR(Info, length); + throw HCIScanner::HCIError("Unexpected HCI event packet"); + } + } + + + vector parse_le_meta_event(Span packet) + { + uint8_t subevent_code = packet.pop_front(); + + if(subevent_code == 0x02) // see big blob of comments above + { + LOG(Info, "subevent_code = 0x02: LE Advertising Report Event"); + return parse_le_meta_event_advertisement(packet); + } + else + { + LOGVAR(Info, subevent_code); + return {}; + } + } + + vector parse_le_meta_event_advertisement(Span packet) + { + vector ret; + + uint8_t num_reports = packet.pop_front(); + LOGVAR(Info, num_reports); + + for(int i=0; i < num_reports; i++) + { + LeAdvertisingEventType event_type = static_cast(packet.pop_front()); + + if(event_type == LeAdvertisingEventType::ADV_IND) + LOG(Info, "event_type = 0x00 ADV_IND, Connectable undirected advertising"); + else if(event_type == LeAdvertisingEventType::ADV_DIRECT_IND) + LOG(Info, "event_type = 0x01 ADV_DIRECT_IND, Connectable directed advertising"); + else if(event_type == LeAdvertisingEventType::ADV_SCAN_IND) + LOG(Info, "event_type = 0x02 ADV_SCAN_IND, Scannable undirected advertising"); + else if(event_type == LeAdvertisingEventType::ADV_NONCONN_IND) + LOG(Info, "event_type = 0x03 ADV_NONCONN_IND, Non connectable undirected advertising"); + else if(event_type == LeAdvertisingEventType::SCAN_RSP) + LOG(Info, "event_type = 0x04 SCAN_RSP, Scan response"); + else + LOG(Warning, "event_type = 0x" << hex << (int)event_type << dec << ", unknown"); + + uint8_t address_type = packet.pop_front(); + + if(address_type == 0) + LOG(Info, "Address type = 0: Public device address"); + else if(address_type == 1) + LOG(Info, "Address type = 0: Random device address"); + else + LOG(Info, "Address type = 0x" << to_hex(address_type) << ": unknown"); + + + string address; + for(int j=0; j < 6; j++) + { + ostringstream s; + s << hex << setw(2) << setfill('0') << (int) packet.pop_front(); + if(j != 0) + s << ":"; + + address = s.str() + address; + } + + + LOGVAR(Info, address); + + uint8_t length = packet.pop_front(); + LOGVAR(Info, length); + + + Span data = packet.pop_front(length); + + LOG(Debug, "Data = " << to_hex(data)); + + int8_t rssi = packet.pop_front(); + + if(rssi == 127) + LOG(Info, "RSSI = 127: unavailable"); + else if(rssi <= 20) + LOG(Info, "RSSI = " << (int) rssi << " dBm"); + else + LOG(Info, "RSSI = " << to_hex((uint8_t)rssi) << " unknown"); + + try{ + AdvertisingResponse rsp; + rsp.address = address; + rsp.type = event_type; + + while(data.size() > 0) + { + LOGVAR(Debug, data.size()); + LOG(Debug, "Packet = " << to_hex(data)); + //Format is length, type, crap + int length = data.pop_front(); + + LOGVAR(Debug, length); + + Span chunk = data.pop_front(length); + uint8_t type = chunk[0]; + LOGVAR(Debug, type); + + if(type == GAP::flags) + { + rsp.flags = AdvertisingResponse::Flags({chunk.begin(), chunk.end()}); + + LOG(Info, "Flags = " << to_hex(rsp.flags->flag_data)); + + if(rsp.flags->LE_limited_discoverable) + LOG(Info, " LE limited discoverable"); + + if(rsp.flags->LE_general_discoverable) + LOG(Info, " LE general discoverable"); + + if(rsp.flags->BR_EDR_unsupported) + LOG(Info, " BR/EDR unsupported"); + + if(rsp.flags->simultaneous_LE_BR_host) + LOG(Info, " simultaneous LE BR host"); + + if(rsp.flags->simultaneous_LE_BR_controller) + LOG(Info, " simultaneous LE BR controller"); + } + else if(type == GAP::incomplete_list_of_16_bit_UUIDs || type == GAP::complete_list_of_16_bit_UUIDs) + { + rsp.uuid_16_bit_complete = (type == GAP::complete_list_of_16_bit_UUIDs); + chunk.pop_front(); //remove the type field + + while(!chunk.empty()) + { + uint16_t u = chunk.pop_front() + chunk.pop_front()*256; + rsp.UUIDs.push_back(UUID(u)); + } + } + else if(type == GAP::incomplete_list_of_128_bit_UUIDs || type == GAP::complete_list_of_128_bit_UUIDs) + { + rsp.uuid_128_bit_complete = (type == GAP::complete_list_of_128_bit_UUIDs); + chunk.pop_front(); //remove the type field + + while(!chunk.empty()) + rsp.UUIDs.push_back(UUID::from(att_get_uuid128(chunk.pop_front(16).data()))); + } + else if(type == GAP::shortened_local_name || type == GAP::complete_local_name) + { + chunk.pop_front(); + AdvertisingResponse::Name n; + n.complete = type==GAP::complete_local_name; + n.name = string(chunk.begin(), chunk.end()); + rsp.local_name = n; + + LOG(Info, "Name (" << (n.complete?"complete":"incomplete") << "): " << n.name); + } + else if(type == GAP::manufacturer_data) + { + chunk.pop_front(); + rsp.manufacturer_specific_data.push_back({chunk.begin(), chunk.end()}); + LOG(Info, "Manufacturer data: " << to_hex(chunk)); + } + else + { + rsp.unparsed_data_with_types.push_back({chunk.begin(), chunk.end()}); + + LOG(Info, "Unparsed chunk " << to_hex(chunk)); + } + } + + if(rsp.UUIDs.size() > 0) + { + LOG(Info, "UUIDs (128 bit " << (rsp.uuid_128_bit_complete?"complete":"incomplete") + << ", 16 bit " << (rsp.uuid_16_bit_complete?"complete":"incomplete") << " ):"); + + for(const auto& uuid: rsp.UUIDs) + LOG(Info, " " << to_str(uuid)); + } + + ret.push_back(rsp); + + + } + catch(out_of_range r) + { + LOG(LogLevels::Error, "Corrupted data sent by device " << address); + } + } + + return ret; + } + + +} diff --git a/vendor/libblepp-master/src/logging.cc b/vendor/libblepp-master/src/logging.cc new file mode 100644 index 0000000..871578a --- /dev/null +++ b/vendor/libblepp-master/src/logging.cc @@ -0,0 +1,28 @@ +/* + * + * blepp - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "blepp/logging.h" + +namespace BLEPP +{ + LogLevels log_level; +} + diff --git a/vendor/libblepp-master/src/pretty_printers.cc b/vendor/libblepp-master/src/pretty_printers.cc new file mode 100644 index 0000000..0fc85d6 --- /dev/null +++ b/vendor/libblepp-master/src/pretty_printers.cc @@ -0,0 +1,110 @@ +/* + * + * blepp - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include + +#include +#include +using namespace std; + +namespace BLEPP +{ + + std::string to_hex(const std::uint16_t& u) + { + stringstream os; + os << setw(4) << setfill('0') << hex << u; + return os.str(); + } + + std::string to_hex(const std::uint8_t& u) + { + stringstream os; + os << setw(2) << setfill('0') << hex << (int)u; + return os.str(); + } + + std::string to_str(const std::uint8_t& u) + { + if(u < 32 || u > 126) + return "\\x" + to_hex(u); + else + { + char buf[] = {(char)u, 0}; + return buf; + } + } + + std::string to_str(const bt_uuid_t& uuid) + { + //8 4 4 4 12 + if(uuid.type == BT_UUID16) + return to_hex(uuid.value.u16); + else if(uuid.type == BT_UUID128) + { + char s[] = "xoxoxoxo-xoxo-xoxo-xoxo-xoxoxoxoxoxo"; + bt_uuid_to_string(&uuid, s, sizeof(s)); + return s; + } + else + return "uuid.wtf"; + + } + + std::string to_hex(const std::uint8_t* d, int l) + { + stringstream os; + for(int i=0; i < l; i++) + os << to_hex(d[i]) << " "; + return os.str(); + } + std::string to_hex(pair d) + { + return to_hex(d.first, d.second); + } + + std::string to_hex(const vector& v) + { + return to_hex(v.data(), v.size()); + } + + std::string to_str(const std::uint8_t* d, int l) + { + stringstream os; + for(int i=0; i < l; i++) + os << to_str(d[i]); + return os.str(); + } + std::string to_str(pair d) + { + return to_str(d.first, d.second); + } + std::string to_str(pair d) + { + return to_str(d.first, d.second - d.first); + } + + std::string to_str(const vector& v) + { + return to_str(v.data(), v.size()); + } + +} diff --git a/vendor/libblepp-master/src/uuid.cc b/vendor/libblepp-master/src/uuid.cc new file mode 100644 index 0000000..3d3fd43 --- /dev/null +++ b/vendor/libblepp-master/src/uuid.cc @@ -0,0 +1,244 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2011 Nokia Corporation + * Copyright (C) 2011 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +namespace BLEPP +{ + + //Always store full UUIDs as little endian, since they come over + //the wire that way. + // + //Also, see Bluetooth 4.0, Part B, Section 2.5.1 + static uint128_t bluetooth_base_uuid = { + .data = { 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }; + + //12 = 96/8 + #define BASE_UUID_OFFSET 12 + + static void bt_uint32_to_uuid128(uint32_t src, bt_uuid_t *dst) + { + dst->value.u128 = bluetooth_base_uuid; + dst->type = BT_UUID128; + + for(int i=0; i < 4; i++) + dst->value.u128.data[BASE_UUID_OFFSET+i] = (src>>8*i) & 0xff; + } + + void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst) + { + switch (src->type) { + case BT_UUID128: + *dst = *src; + break; + case BT_UUID32: + bt_uint32_to_uuid128(src->value.u32, dst); + break; + case BT_UUID16: + bt_uint32_to_uuid128(src->value.u16, dst); + break; + default: + break; + } + } + + static int bt_uuid128_cmp(const bt_uuid_t *u1, const bt_uuid_t *u2) + { + return memcmp(&u1->value.u128, &u2->value.u128, sizeof(uint128_t)); + } + + int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value) + { + memset(btuuid, 0, sizeof(bt_uuid_t)); + btuuid->type = BT_UUID16; + btuuid->value.u16 = value; + + return 0; + } + + int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value) + { + memset(btuuid, 0, sizeof(bt_uuid_t)); + btuuid->type = BT_UUID32; + btuuid->value.u32 = value; + + return 0; + } + + int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value) + { + memset(btuuid, 0, sizeof(bt_uuid_t)); + btuuid->type = BT_UUID128; + btuuid->value.u128 = value; + + return 0; + } + + int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2) + { + bt_uuid_t u1, u2; + + bt_uuid_to_uuid128(uuid1, &u1); + bt_uuid_to_uuid128(uuid2, &u2); + + return bt_uuid128_cmp(&u1, &u2); + } + + + static uint16_t u16_from_le(const uint8_t* data) + { + return data[0] + (data[1]<<8); + } + + /* + * convert the UUID to string, copying a maximum of n characters. + */ + int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n) + { + if (!uuid) { + snprintf(str, n, "NULL"); + return -EINVAL; + } + + switch (uuid->type) { + case BT_UUID16: + snprintf(str, n, "%.4x", uuid->value.u16); + break; + case BT_UUID32: + snprintf(str, n, "%.8x", uuid->value.u32); + break; + case BT_UUID128: + snprintf(str, n, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", + u16_from_le(uuid->value.u128.data + 14), + u16_from_le(uuid->value.u128.data + 12), + u16_from_le(uuid->value.u128.data + 10), + u16_from_le(uuid->value.u128.data + 8), + u16_from_le(uuid->value.u128.data + 6), + u16_from_le(uuid->value.u128.data + 4), + u16_from_le(uuid->value.u128.data + 2), + u16_from_le(uuid->value.u128.data + 0)); + + break; + default: + snprintf(str, n, "Type of UUID (%x) unknown.", uuid->type); + return -EINVAL; /* Enum type of UUID not set */ + } + + return 0; + } + + static inline int is_uuid128(const char *string) + { + return (strlen(string) == 36 && + string[8] == '-' && + string[13] == '-' && + string[18] == '-' && + string[23] == '-'); + } + + static inline int is_uuid32(const char *string) + { + return (strlen(string) == 8 || strlen(string) == 10); + } + + static inline int is_uuid16(const char *string) + { + return (strlen(string) == 4 || strlen(string) == 6); + } + + static int bt_string_to_uuid16(bt_uuid_t *uuid, const char *string) + { + uint16_t u16; + char *endptr = NULL; + + u16 = strtol(string, &endptr, 16); + if (endptr && *endptr == '\0') { + bt_uuid16_create(uuid, u16); + return 0; + } + + return -EINVAL; + } + + static int bt_string_to_uuid32(bt_uuid_t *uuid, const char *string) + { + uint32_t u32; + char *endptr = NULL; + + u32 = strtol(string, &endptr, 16); + if (endptr && *endptr == '\0') { + bt_uuid32_create(uuid, u32); + return 0; + } + + return -EINVAL; + } + + + static int bt_string_to_uuid128(bt_uuid_t *uuid, const char *string) + { + unsigned int data[16]; + + if(sscanf(string, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + &data[15], &data[14], &data[13], &data[12], + &data[11], &data[10], &data[ 9], &data[ 8], + &data[ 7], &data[ 6], &data[ 5], &data[ 4], + &data[ 3], &data[ 2], &data[ 1], &data[ 0]) != 16) + return -EINVAL; + + uuid->type = BT_UUID128; + + for(int i=0; i < 16; i++) + uuid->value.u128.data[i] = data[i]; + return 0; + } + + int bt_string_to_uuid(bt_uuid_t *uuid, const char *string) + { + if (is_uuid128(string)) + return bt_string_to_uuid128(uuid, string); + else if (is_uuid32(string)) + return bt_string_to_uuid32(uuid, string); + else if (is_uuid16(string)) + return bt_string_to_uuid16(uuid, string); + + return -EINVAL; + } + + int bt_uuid_strcmp(const void *a, const void *b) + { + return strcasecmp(static_cast(a), static_cast(b)); + } + +} diff --git a/vendor/libblepp-master/temperature.cc b/vendor/libblepp-master/temperature.cc new file mode 100644 index 0000000..06a12aa --- /dev/null +++ b/vendor/libblepp-master/temperature.cc @@ -0,0 +1,104 @@ +/* + * + * libble++ - Implementation of the Generic ATTribute Protocol + * + * Copyright (C) 2013, 2014 Edward Rosten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +#include +#include +#include +#include //BLE uses the obscure IEEE11073 decimal exponent floating point values +#include +#include +using namespace std; +using namespace chrono; +using namespace BLEPP; + +int main(int argc, char **argv) +{ + if(argc != 2) + { + cerr << "Please supply address.\n"; + cerr << "Usage:\n"; + cerr << "prog "; + exit(1); + } + + log_level = Error; + + //This class does all of the GATT interactions for you. + //It's a callback based interface, so you need to provide + //callbacks to make it do anything useful. Don't worry: this is + //a library, not a "framework", so it won't steal your main loop. + //In other examples, I show you how to get and use the file descriptor, so + //you will only make calls into BLEGATTStateMachine when there's data + //to process. + BLEGATTStateMachine gatt; + + //This function will be called when a push notification arrives from the device. + //Not much sanity/error checking here, just for clarity. + //Basically, extract the float and log it along with the time. + std::function notify_cb = [&](const PDUNotificationOrIndication& n) + { + auto ms_since_epoch = duration_cast(system_clock::now().time_since_epoch()); + float temp = bluetooth_float_to_IEEE754(n.value().first+1); + + cout << setprecision(15) << ms_since_epoch.count()/1000. << " " << setprecision(5) << temp << endl; + }; + + //This is called when a complete scan of the device is done, giving + //all services and characteristics. This one simply searches for the + //standardised "temperature" characteristic (aggressively cheating and not + //bothering to check if the service is correct) and sets up the device to + //send us notifications. + // + //This will simply sit there happily connected in blissful ignorance if there's + //no temperature characteristic. + std::function found_services_and_characteristics_cb = [&gatt, ¬ify_cb](){ + for(auto& service: gatt.primary_services) + for(auto& characteristic: service.characteristics) + if(characteristic.uuid == UUID("2a1c")) + { + characteristic.cb_notify_or_indicate = notify_cb; + characteristic.set_notify_and_indicate(true, false); + } + }; + + //This is the simplest way of using a bluetooth device. If you call this + //helper function, it will put everything in place to do a complete scan for + //services and characteristics when you connect. If you want to save a small amount + //of time on a connect and avoid the complete scan (you are allowed to cache this + //information in certain cases), then you can provide your own callbacks. + gatt.setup_standard_scan(found_services_and_characteristics_cb); + + //I think this one is reasonably clear? + gatt.cb_disconnected = [](BLEGATTStateMachine::Disconnect d) + { + cerr << "Disconnect for reason " << BLEGATTStateMachine::get_disconnect_string(d) << endl; + exit(1); + }; + + //This is how to use the blocking interface. It is very simple. You provide the main + //loop and just hammer on the state machine struct. + gatt.connect_blocking(argv[1]); + for(;;) + gatt.read_and_process_next(); + +} diff --git a/vendor/libblepp-master/tests/test_scan.cc b/vendor/libblepp-master/tests/test_scan.cc new file mode 100644 index 0000000..79cd7de --- /dev/null +++ b/vendor/libblepp-master/tests/test_scan.cc @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include +#include + + +using namespace BLEPP; +using namespace std; + +#define check(X) do{\ +if(!(X))\ +{\ + cerr << "Test failed on line " << __LINE__ << ": " << #X << endl;\ + exit(1);\ +}}while(0) + +vector to_data(const string& ss) +{ + istringstream s(ss); + + //Format is > 04 3E ... + + string tmp; + s >> tmp; + s>>hex; + + vector ret; + + for(;;) + { + int x; + s >> x; + if(s.fail()) + { + return ret; + } + else + ret.push_back(x); + } + +} + +int main() +{ + log_level = LogLevels::Trace; +/* +HCI sniffer - Bluetooth packet analyzer ver 2.5 +device: hci0 snap_len: 1500 filter: 0xffffffffffffffff +< 01 0B 20 07 01 10 00 10 00 00 00 +> 04 0E 04 01 0B 20 00 +< 01 0C 20 02 01 01 +> 04 0E 04 01 0C 20 00 +> 04 3E 0C 02 01 04 01 0B 57 16 21 76 7C 00 C1 +< 01 0C 20 02 00 01 +> 04 0E 04 01 0C 20 00 +*/ + + AdvertisingResponse r = HCIScanner::parse_packet(to_data("> 04 3E 21 02 01 00 00 1B EE B5 80 07 00 15 02 01 06 11 06 64 97 81 D1 ED BA 6B AC 11 4C 9D 34 3E 20 09 73 BC")).back(); + check(r.UUIDs[0] == UUID("7309203e-349d-4c11-ac6b-baedd1819764")); + check(r.UUIDs.size() == 1); + check(r.service_data.empty()); + check(r.manufacturer_specific_data.empty()); + check(r.unparsed_data_with_types.empty()); + check(!r.local_name); + check(!r.uuid_16_bit_complete); + check(!r.uuid_32_bit_complete); + check(!r.uuid_128_bit_complete); + check(!r.flags->LE_limited_discoverable); + check(r.flags); + check(!r.flags->LE_limited_discoverable); + check(r.flags->LE_general_discoverable); + check(r.flags->BR_EDR_unsupported); + check(!r.flags->simultaneous_LE_BR_controller); + check(!r.flags->simultaneous_LE_BR_host); + + + r = HCIScanner::parse_packet(to_data("> 04 3E 24 02 01 04 00 1B EE B5 80 07 00 18 17 09 44 79 6E 6F 66 69 74 20 49 6E 63 20 44 4F 54 53 20 78 78 78 78 31 BE")).back(); + check(r.UUIDs.size() == 0); + check(r.service_data.empty()); + check(r.manufacturer_specific_data.empty()); + check(r.unparsed_data_with_types.empty()); + check(r.local_name); + check(r.local_name->complete); + check(r.local_name->name == "Dynofit Inc DOTS xxxx1"); + check(!r.uuid_16_bit_complete); + check(!r.uuid_32_bit_complete); + check(!r.uuid_128_bit_complete); + check(!r.flags); + + r = HCIScanner::parse_packet(to_data("> 04 3E 17 02 01 00 01 0B 57 16 21 76 7C 0B 02 01 1A 07 FF 4C 00 10 02 0A 00 BC")).back(); + vector vendor_data_1 = {0x4c, 0x00, 0x10, 0x02, 0x0a, 0x00}; + check(r.UUIDs.size() == 0); + check(r.service_data.empty()); + check(r.manufacturer_specific_data.size() == 1); + check(r.manufacturer_specific_data[0].size() == 6); + check(equal(vendor_data_1.begin(), vendor_data_1.end(), r.manufacturer_specific_data[0].begin())); + check(r.unparsed_data_with_types.empty()); + check(!r.local_name); + check(r.flags); + check(!r.flags->LE_limited_discoverable); + check(r.flags->LE_general_discoverable); + check(!r.flags->BR_EDR_unsupported); + check(r.flags->simultaneous_LE_BR_controller); + check(r.flags->simultaneous_LE_BR_host); + +} From c2965d7a9d8bb035e111f4a23779097019d4e997 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 4 Sep 2017 22:59:31 +0100 Subject: [PATCH 2/9] remove hard coded copy of libblepp in prep for using git submodule --- vendor/libblepp-master/.gitignore | 17 - vendor/libblepp-master/ATT.txt | 186 - vendor/libblepp-master/COPYING | 54 - vendor/libblepp-master/Makefile.in | 175 - vendor/libblepp-master/Notes.txt | 115 - vendor/libblepp-master/README | 32 - vendor/libblepp-master/att_gatt.h | 41 - vendor/libblepp-master/blelogger.cc | 96 - vendor/libblepp-master/blepp/att.h | 323 -- vendor/libblepp-master/blepp/att_pdu.h | 355 -- vendor/libblepp-master/blepp/bledevice.h | 67 - .../libblepp-master/blepp/blestatemachine.h | 348 -- vendor/libblepp-master/blepp/float.h | 32 - vendor/libblepp-master/blepp/gap.h | 31 - vendor/libblepp-master/blepp/lescan.h | 217 - vendor/libblepp-master/blepp/logging.h | 107 - .../libblepp-master/blepp/pretty_printers.h | 48 - vendor/libblepp-master/blepp/uuid.h | 140 - vendor/libblepp-master/blepp/xtoa.h | 38 - vendor/libblepp-master/bluetooth.cc | 294 - vendor/libblepp-master/configure | 4858 ----------------- vendor/libblepp-master/configure.ac | 111 - vendor/libblepp-master/cxxgplot.h | 159 - vendor/libblepp-master/get_attrs.sh | 11 - vendor/libblepp-master/hex2ascii.awk | 31 - vendor/libblepp-master/lescan.cc | 133 - vendor/libblepp-master/lescan_simple.cc | 10 - vendor/libblepp-master/libblepp.pc.in | 8 - .../m4/ax_cxx_compile_stdcxx_14.m4 | 173 - .../libblepp-master/primary_service_names.cc | 32 - vendor/libblepp-master/pstreams/pstream.h | 2095 ------- vendor/libblepp-master/src/att.cc | 1181 ---- vendor/libblepp-master/src/att_pdu.cc | 85 - vendor/libblepp-master/src/bledevice.cc | 260 - vendor/libblepp-master/src/blestatemachine.cc | 836 --- vendor/libblepp-master/src/float.cc | 22 - vendor/libblepp-master/src/lescan.cc | 701 --- vendor/libblepp-master/src/logging.cc | 28 - vendor/libblepp-master/src/pretty_printers.cc | 110 - vendor/libblepp-master/src/uuid.cc | 244 - vendor/libblepp-master/temperature.cc | 104 - vendor/libblepp-master/tests/test_scan.cc | 109 - 42 files changed, 14017 deletions(-) delete mode 100644 vendor/libblepp-master/.gitignore delete mode 100644 vendor/libblepp-master/ATT.txt delete mode 100644 vendor/libblepp-master/COPYING delete mode 100644 vendor/libblepp-master/Makefile.in delete mode 100644 vendor/libblepp-master/Notes.txt delete mode 100644 vendor/libblepp-master/README delete mode 100644 vendor/libblepp-master/att_gatt.h delete mode 100644 vendor/libblepp-master/blelogger.cc delete mode 100644 vendor/libblepp-master/blepp/att.h delete mode 100644 vendor/libblepp-master/blepp/att_pdu.h delete mode 100644 vendor/libblepp-master/blepp/bledevice.h delete mode 100644 vendor/libblepp-master/blepp/blestatemachine.h delete mode 100644 vendor/libblepp-master/blepp/float.h delete mode 100644 vendor/libblepp-master/blepp/gap.h delete mode 100644 vendor/libblepp-master/blepp/lescan.h delete mode 100644 vendor/libblepp-master/blepp/logging.h delete mode 100644 vendor/libblepp-master/blepp/pretty_printers.h delete mode 100644 vendor/libblepp-master/blepp/uuid.h delete mode 100644 vendor/libblepp-master/blepp/xtoa.h delete mode 100644 vendor/libblepp-master/bluetooth.cc delete mode 100755 vendor/libblepp-master/configure delete mode 100644 vendor/libblepp-master/configure.ac delete mode 100644 vendor/libblepp-master/cxxgplot.h delete mode 100644 vendor/libblepp-master/get_attrs.sh delete mode 100644 vendor/libblepp-master/hex2ascii.awk delete mode 100644 vendor/libblepp-master/lescan.cc delete mode 100644 vendor/libblepp-master/lescan_simple.cc delete mode 100644 vendor/libblepp-master/libblepp.pc.in delete mode 100644 vendor/libblepp-master/m4/ax_cxx_compile_stdcxx_14.m4 delete mode 100644 vendor/libblepp-master/primary_service_names.cc delete mode 100644 vendor/libblepp-master/pstreams/pstream.h delete mode 100644 vendor/libblepp-master/src/att.cc delete mode 100644 vendor/libblepp-master/src/att_pdu.cc delete mode 100644 vendor/libblepp-master/src/bledevice.cc delete mode 100644 vendor/libblepp-master/src/blestatemachine.cc delete mode 100644 vendor/libblepp-master/src/float.cc delete mode 100644 vendor/libblepp-master/src/lescan.cc delete mode 100644 vendor/libblepp-master/src/logging.cc delete mode 100644 vendor/libblepp-master/src/pretty_printers.cc delete mode 100644 vendor/libblepp-master/src/uuid.cc delete mode 100644 vendor/libblepp-master/temperature.cc delete mode 100644 vendor/libblepp-master/tests/test_scan.cc diff --git a/vendor/libblepp-master/.gitignore b/vendor/libblepp-master/.gitignore deleted file mode 100644 index a7a80d6..0000000 --- a/vendor/libblepp-master/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -*.sw? -*.o -core -bluez-tools/ -prog -lescan -temperature -Makefile -*.so.* -*.so -*.pc -config.log -config.status -autom4te.cache -.deps -tests/*.result* -tests/*.test diff --git a/vendor/libblepp-master/ATT.txt b/vendor/libblepp-master/ATT.txt deleted file mode 100644 index e6de889..0000000 --- a/vendor/libblepp-master/ATT.txt +++ /dev/null @@ -1,186 +0,0 @@ -Haskell Notation ----------------- - -I've used Haskell style notation. Functions, dictionaries and arrays are -essentially similar in that both map an input to an output, i.e. A -> B. -Tuples are indicated with "," and "()". Returned lists or arrays with []. -Alternatives are indicated with |. For arguments, The type is written first, and -the name (if applicable) follows after a "." . - - -Attributes ----------- - -The device contains an array of attributes. The index of tha attributes in known -as the handle. The attributes themselves consist of a "type" and a "value". The -type is a type code and is represented as a UUID. UUIDs are either 16 or 128 -bits long. 16 bit UUIDs are converted to proper 128 bit UUID by setting the -remaining 112 bits to some fixed values. The purpose of 16 bit UUIDs is to save -on bandwidth. - -Every attribute must have a type. The value is just plain old data (a bunch of -bytes) and may be readable or writable[*] or neither. The read/write status of -an attribute is defined by a higher level protocol and there is no way of -querying this. - -[*] The data may be also indicatable or notifiable. In these cases, the -bluetooth device (the server) may send the attribute values back to the client -at any time without solicitation. - -So, in essence the server has an array of: -[ (Handle, Type, Data | Null)] - -Being an array, one can naturally index it using Handle. In some cases however -it is also possible to index it by the Type in some cases. - -There are various function for extracting information from the server: - -find_information: [(Handle, Type)] - -This gets a list of attributes back from the server as the handel and type. The -data can be read from an attribute in one of two ways: - -read: Handle->Data | Error - -which reads the data from a given handle. Alternatively, data can be read by the -Type: - -read_by_type: Type -> [(Handle | Data)] - -Since several attributes may share a type (and often do), read_by_type must be -able to return a of attributes. Since the type is known, all it has to give back -is the Handle and the data. - -Naturally, there exist commands for writing too. - - -There is also a concept of Grouping as well. A group is a contiguous set of -attributes (contiguous according to the handle). Groups can be read by their -type. Groups are delimited by attributes of the specified type. A sample set of -attributes, as [(Handle, Type, Data)] follows. Note that the Types and data are -Arbitrary. If the group type is specified to be 0xdead, then thr grouping -appears as: - -0001 dead some data \ -0002 2a00 xxxxx | First group -0003 5600 xxxxxxxx /_________________ -0004 dead more data \ -0005 1234 xxxxxxx | Second group -0006 4567 xxxxxxxx | -0007 1231 xxxxx /_________________ -0008 dead another datum \ Third group -0009 wtf / -EOF - -The command to read this is: - -read_by_group_type Type->[(Handle, Handle, Data)] - -where, the start and end handle along with the data for the start handle is -returned, so in this case - -read_by_group_type(dead) will return: - -0001 0003 "some data" -0005 0007 "more data" -0008 ffff "another datum" - -ffff being the highest possible handle number indicates that nothing can follow. - -It would appear that in the absence of efficiency concerns, one could replicate -all the functions by queryiing every attribute with find_information and then -reading whichever handles are necessary with read. - -Actually reading data ---------------------- - -The BLE packet length is a mere 23 bytes. Optionally both devices may be able to -lengthen it, but this is not normally supported. - -In practice each query can only be answered with a very limited amount of data. -Note that each of the functions above (except read) returns a list of handles. -In the protocol, each function actually takes a start and end handle as an -argument which limits which handles will be returned. In order to get a complete -list of things, one must keep setting the start handle to one plus the last -handle returned and reissuing the call. When no handles can be returned an error -message is sent back, indicating that no handles exist in the range. - -The read_by_type function is actually more like: - -read_by_type: (Type, Handle.first, Handle.last) -> [ (Handle, Data) ] | Error.no_attribute_in_range - - - - -The Generic Attribute Profile ------------------------------ - -The generic attribute (GATT) profile defines a standard set of attributes, -types and groups along with mechanisms for discovery. - -A GATT profile consists of a number of services. A service defines a set of -"characteristics". A characteristic pas properties (e.g. readable, writable), -a value and zero or more descriptors (e.g. some textual description). - -Primary services are groups of handles which have the name <> -aka 0x2800. Therefore - read_group_by_type(0x2800) -returns the list of services. Any handle falling in the the group belongs to -the service named by that group. The names are either ones specified by the SIG -or custom ones. - -Within each service there is a list of characteristics. Each characteristic -contains a group of handles. However, it is not possible to use -read_by_group_type on <> (aka 2803), since characteristic groups -are terminated either by the presence of the next characteristic or by the next -service. Recall that read_by_group_type insists that the delimiter must be the -type. - - -A characteristic consists of: - -* a characteristic definition (Type <>) - which includes the Type of the characteristic, the handle of the - characteristic value and some miscellaneous flags. - -* A characteristic value. Naturally, this has the Type of the characteristic. - The value may not actually be readable, or writable. For example the value - might only be pushed to the client via notifications. - -* Additional descriptors. The descriptors contain miscellaneous extra - information about the characteristic. The descriptors have a Type which - declares the semantic meaning of the descriptor. The meaning of the data is - naturally dependent on the Type. - - Common descriptors are: - - <> (2901) Some text describing the - characteristic. - - <> (2902) A write only attribute that is - written to enable and disable notifications and indications on thr - characteristic value. - - There are others too. - - - -The list of characteristics can be read by reading type <> aka 2803. - read_by_type 0x2803 -The return from this is for each characteristic: - - - -Property is a bit field indicating various properties, things like readable, -writable, notifyable, and so on. - -Two services must always be present: <> (aka 1800) and <> (aka 1801) - - -If a characteristic value is readable, it is indicated by the property. Also, -the value will have handle and type . It can be read by reading -the handle or reading by it's type. In other words and are -(nearly?) tautological. - - diff --git a/vendor/libblepp-master/COPYING b/vendor/libblepp-master/COPYING deleted file mode 100644 index 139aa9a..0000000 --- a/vendor/libblepp-master/COPYING +++ /dev/null @@ -1,54 +0,0 @@ -This project has multiple authors and multiple licenses. Please -refer to the indivdial files for specific conditions. - -Copyright (c) 2013 Edward Rosten - -/* - * - * libattgatt - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - - - -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2010 Marcel Holtmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - - diff --git a/vendor/libblepp-master/Makefile.in b/vendor/libblepp-master/Makefile.in deleted file mode 100644 index bc9ba1d..0000000 --- a/vendor/libblepp-master/Makefile.in +++ /dev/null @@ -1,175 +0,0 @@ -#Standard boilerplate -prefix = @prefix@ -exec_prefix = @exec_prefix@ -mandir = @mandir@ -includedir = @includedir@ -datarootdir = @datarootdir@ -pkgconfig = @PKGCONFIG_LIBDIR@ -srcdir = @srcdir@ -libdir=@libdir@ -LOADLIBES = @LIBS@ - -vpath %.cc $(srcdir) - -ifneq "$(DESTDIR)" "" -DESTDIR+=/ -endif - -CXX=@CXX@ -LD=@CXX@ -CXXFLAGS=@CXXFLAGS@ -I$(srcdir) -LDFLAGS=@LDFLAGS@ - -hdr = $(DESTDIR)$(includedir)/ -lib = $(DESTDIR)$(libdir)/ - - -LIBOBJS=src/att.o src/uuid.o src/bledevice.o src/att_pdu.o src/pretty_printers.o src/blestatemachine.o src/float.o src/logging.o src/lescan.o - -PROGS=lescan blelogger bluetooth lescan_simple temperature - -.PHONY: all clean testclean install lib progs test doc install-so install-a install-hdr install-pkgconfig - -all: lib progs test doc - -lib: $(soname) $(archive) -progs:$(PROGS) - - -clean: testclean - rm -f $(PROGS) *.o src/*.o *.so.* *.so -testclean: - rm -f tests/*.result tests/*.test tests/*.result_ - - - -doc: - - -archive=libble++.a -soname=libble++.so -soname1=libble++.so.0 -soname2=libble++.so.0.5 -set_soname=-Wl,-soname,libble++.so.0 - -$(soname2): $(LIBOBJS) - $(LD) -shared -o $(soname2) $(LIBOBJS) $(LDFLAGS) $(LOADLIBES) - -$(soname1): $(soname2) - rm -f $(soname1) - ln -s $(soname2) $(soname1) - -$(soname): $(soname1) - rm -f $(soname) - ln -s $(soname1) $(soname) - -$(archive): $(LIBOBJS) - ar crvs $(archive) $(LIBOBJS) - ranlib $(archive) - -$(PROGS):$(soname) - -lescan: lescan.o - $(LD) -o $@ $< -L. -lble++ - - -lescan_simple: lescan_simple.o - $(LD) -o $@ $< -L. -lble++ - -temperature: temperature.o - $(LD) -o $@ $< -L. -lble++ - -blelogger: blelogger.o - $(LD) -o $@ $< -L. -lble++ - -bluetooth: bluetooth.o - $(LD) -o $@ $< -L. -lble++ - -install: install-so install-a install-hdr install-pkgconfig - - -install-a: $(archive) - cp $(archive) $(lib) - -install-so: $(soname) $(soname1) $(soname2) - cp $(soname) $(soname1) $(soname2) $(lib) - -install-hdr: - cp -r blepp $(hdr) - -install-pkgconfig: - [ "$(pkgconfig)" = "" ] || mkdir -p $(DESTDIR)$(pkgconfig) - [ "$(pkgconfig)" = "" ] || cp libblepp.pc $(DESTDIR)$(pkgconfig)/ - - - -docs: - doxygen - - -#Every .cc file in the tests directory is a test -TESTS=$(notdir $(basename $(wildcard tests/*.cc))) - - -#Get the intermediate file names from the list of tests. -TEST_RESULT=$(TESTS:%=tests/%.result) - - -# Don't delete the intermediate files, since these can take a -# long time to regenerate -.PRECIOUS: tests/%.result_ tests/%.test - -test:tests/results - -#We don't want this file hanging around on failure since we -#want the build depend on it. If we leave it behing then typing make -#twice in a row will suceed, since make will find the file and not try -#to rebuild it. -.DELETE_ON_ERROR: tests/results - -tests/results:$(TEST_RESULT) - cat $(TEST_RESULT) > tests/results - @echo -------------- Test Results --------------- - @cat tests/results - @echo ------------------------------------------- - @ ! grep -qv OK tests/results - - -#Build a test executable from a test program. On compile error, -#create an executable which declares the error. -tests/%.test: tests/%.cc $(LIBOBJS) - $(CXX) $(CXXFLAGS) $^ -o $@ -I . $(LDFLAGS) $(LOADLIBES) || { echo "echo 'Compile error!' ; return 126" > $@ ; chmod +x $@; } - -#Run the program and either use it's output (it should just say OK) -#or a failure message -tests/%.result_: tests/%.test - $< > $@ 2>&1 ; \ - a=$$? ;\ - if [ $$a != 0 ]; \ - then \ - if [ $$a -ge 128 ] ; \ - then \ - echo Crash!! > $@ ; \ - elif [ $$a -ne 126 ] ;\ - then \ - echo Failed > $@ ; \ - fi;\ - else\ - echo OK >> $@;\ - fi - -tests/%.result: tests/%.result_ - echo $*: `tail -1 $<` > $@ - -#Get the C style dependencies working. Note we need to massage the test dependencies -#to make the filenames correct -.deps: - rm -f .deps .sourcefiles - find . -name "*.cc" | xargs -IQQQ $(CXX) $(CXXFLAGS) -MM -MG QQQ | sed -e'/test/s!\(.*\)\.o:!tests/\1.test:!' > .deps - -include .deps - - - - - diff --git a/vendor/libblepp-master/Notes.txt b/vendor/libblepp-master/Notes.txt deleted file mode 100644 index a832d3e..0000000 --- a/vendor/libblepp-master/Notes.txt +++ /dev/null @@ -1,115 +0,0 @@ -My adventures in bluetooth with the BLE112 devkit. - -Note, my machine is called "sheepfrog" http://en.wikipedia.org/wiki/Sheep_frog - -Get list of adapters: - -$bt-adapter -l -Available adapters: -sheepfrog-0 (88:9F:FA:EC:27:8F) -sheepfrog-1 (00:02:72:3E:A5:07) - - -bt-adapter uses DBUS/GObject interface to bluez and is so far impenetrable. - -Not yet found libbluetooth C API call which does this. Kernel call exists, but not C API? - - -Find device: - -$bt-adapter -a sheepfrog-1 -d -Searching... - -[3C:2D:B7:85:50:2A] - Name: DKBLE112 thermometer - Alias: DKBLE112 thermometer - Address: 3C:2D:B7:85:50:2A - -(bt-adapter:31979): GLib-GObject-CRITICAL **: g_value_get_string: assertion `G_VALUE_HOLDS_STRING (value)' failed - Icon: (null) - Class: 0x0 - LegacyPairing: 0 - Paired: 0 - RSSI: -68 - -[7C:E9:D3:E4:3F:7C] - Name: LAWRENCE-THINK - Alias: LAWRENCE-THINK - Address: 7C:E9:D3:E4:3F:7C - Icon: computer - Class: 0x3e010c - LegacyPairing: 0 - Paired: 0 - RSSI: -88 - -Done - - -Or, alternatively, use hcitool: - -hcitool -i hci1 scan - -does not work (why?). Whereas: - -$ sudo hcitool lescan -LE Scan ... -3C:2D:B7:85:50:2A (unknown) -3C:2D:B7:85:50:2A DKBLE112 thermometer - - -For some reason only lescan picks up BLE devices. Also, lescan knows which -device to use (presumably because only one of my adapters supports BLE, so it -skips over the first one??). Also for some reason, root is needed to initiate LE -scan. - - -Now to connect: -(I for interactive mode). Anything before > is the prompt. # are my comments - -$ gatttool -b 3C:2D:B7:85:50:2A -I -[ ][3C:2D:B7:85:50:2A][LE]> connect -[CON][3C:2D:B7:85:50:2A][LE]> -# From here: -# http://stackoverflow.com/questions/15657007/bluetooth-low-energy-listening-for-notifications-indications-in-linux -# Then type char-read-uuid 2902. You should get a list of all CCC (Client -# Characteristic Configuration) attributes on the device -# see also http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml -# -[CON][3C:2D:B7:85:50:2A][LE]> char-read-uuid 2902 -[CON][3C:2D:B7:85:50:2A][LE]> -handle: 0x0012 value: 00 00 -[CON][3C:2D:B7:85:50:2A][LE]> -#Switch on indications... -[CON][3C:2D:B7:85:50:2A][LE]> char-write-cmd 12 0200 -Indication handle = 0x0010 value: 00 2f 01 00 ff -Indication handle = 0x0010 value: 00 2f 01 00 ff -Indication handle = 0x0010 value: 00 2f 01 00 ff -Indication handle = 0x0010 value: 00 31 01 00 ff -# 2f 01, 31 01 is temperature in degrees C / 10 in little endian order. i.e. -# x2f + xff*x1 = d303 i.e. 30.3 degrees C. - - - -Ah ha! -https://www.bluetooth.org/en-us/specification/assigned-numbers-overview/generic-attribute-profile -Magic number 2902 is the "client characteristic specification" - - -More docs: -http://developer.bluetooth.org/TechnologyOverview/Pages/BLE.aspx - -So, it seems that Generic Attribute Profile (GATT) is the way of communicating -with BLE devices. Or at least it's a standard way of doing it. Presumably one -could use lower layers, but that's making life hard. I won't try. Actually, -apparently GATT and ATT are mandatory in BLE. - -Documents about the generic attribute profile are here: - -http://developer.bluetooth.org/TechnologyOverview/Pages/GATT.aspx - - - - - - - diff --git a/vendor/libblepp-master/README b/vendor/libblepp-master/README deleted file mode 100644 index 22d0c8e..0000000 --- a/vendor/libblepp-master/README +++ /dev/null @@ -1,32 +0,0 @@ -libble++ ---------- - -Implementation of Bluetooth Low Energy functions in modern C++, without -the BlueZ DBUS API. - -Includes: -* Scanning for bluetooth packets - -* Implmentation of the GATT profile and ATT protocol - -* Lots of comments, complete with references to to the specific part og - the Bluetooth 4.0 standard. - -* Example programs - -Design: - -Clean, modern C++ with callbacks. Feed it lambdas (or whatever you like) -to perform an event happens. Access provided to the raw socket FD, so -you can select(), poll() or use blocking IO. - - - -The example programs are: - -* lescan_simple: Simplest possible program for scanning for devices. Only 2 non boilerplate lines. - -* lescan: A "proper" scanning program that cleans up properly. It's got the same 2 lines of BLE related code and a bit of pretty standard unix for dealing with non blocking I/O and signals. - -* temperature: A program for logging temperature values from a device providing a standard temperature characteristic. Very short to indicate the usave, but not much error checking. - diff --git a/vendor/libblepp-master/att_gatt.h b/vendor/libblepp-master/att_gatt.h deleted file mode 100644 index 1ab3c2e..0000000 --- a/vendor/libblepp-master/att_gatt.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * - * libattgatt - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __INC_LIBATTGATT_PRETTY_PRINTERS_H -#define __INC_LIBATTGATT_PRETTY_PRINTERS_H - -#include "lib/uuid.h" -#include -#include -#include -std::string to_hex(const std::uint16_t& u); -std::string to_hex(const std::uint8_t& u); -std::string to_str(const std::uint8_t& u); -std::string to_str(const bt_uuid_t& uuid); -std::string to_hex(const std::uint8_t* d, int l); -std::string to_hex(pair d); -std::string to_hex(const std::vector& v); -std::string to_str(const std::uint8_t* d, int l); -std::string to_str(pair d); -std::string to_str(pair d); -std::string to_str(const std::vector& v); -#endif diff --git a/vendor/libblepp-master/blelogger.cc b/vendor/libblepp-master/blelogger.cc deleted file mode 100644 index b01169b..0000000 --- a/vendor/libblepp-master/blelogger.cc +++ /dev/null @@ -1,96 +0,0 @@ -/* - * - * libattgatt - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - - -#include -#include -#include -#include -#include -using namespace std; -using namespace chrono; -using namespace BLEPP; - -//////////////////////////////////////////////////////////////////////////////// -// -// This program demonstrates the use of the library -// -int main(int argc, char **argv) -{ - if(argc != 2 && argc != 3) - { - cerr << "Please supply address.\n"; - cerr << "Usage:\n"; - cerr << "prog address [nonblocking]\n"; - exit(1); - } - - log_level = Info; - - - BLEGATTStateMachine gatt; - - - std::function notify_cb = [&](const PDUNotificationOrIndication& n) - { - auto ms_since_epoch = duration_cast(system_clock::now().time_since_epoch()); - const uint8_t* d = n.value().first; - int emg = ((0+d[1] *256 + d[0])>>0) ; - - int volt = ((0+d[7] *256 + d[6])>>0) ; - double v=-1; - - if(volt != 0x8000) - v = volt / 1000.0; - - cout << setprecision(15) << ms_since_epoch.count()/1000. << " " << emg << " " << v << endl; - }; - - - std::function cb = [&gatt, ¬ify_cb](){ - pretty_print_tree(gatt); - - for(auto& service: gatt.primary_services) - for(auto& characteristic: service.characteristics) - if(characteristic.uuid == UUID("53f72b8c-ff27-4177-9eee-30ace844f8f2")) - { - characteristic.cb_notify_or_indicate = notify_cb; - characteristic.set_notify_and_indicate(true, false); - } - }; - - gatt.cb_disconnected = [](BLEGATTStateMachine::Disconnect d) - { - cerr << "Disconnect for reason " << BLEGATTStateMachine::get_disconnect_string(d) << endl; - exit(1); - }; - - - gatt.setup_standard_scan(cb); - - - //This is how to use the blocking interface. It is very simple. - gatt.connect_blocking(argv[1]); - for(;;) - gatt.read_and_process_next(); - -} diff --git a/vendor/libblepp-master/blepp/att.h b/vendor/libblepp-master/blepp/att.h deleted file mode 100644 index e86d4ac..0000000 --- a/vendor/libblepp-master/blepp/att.h +++ /dev/null @@ -1,323 +0,0 @@ -/* - * - * blepp - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2010 Marcel Holtmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include - -namespace BLEPP -{ - - /* New style defs */ -#define LE_ATT_CID 4 //Spec 4.0 G.5.2.2 -#define ATT_DEFAULT_MTU 23 //Spec 4.0 G.5.2.1 - -#define GATT_UUID_PRIMARY 0x2800 -#define GATT_CHARACTERISTIC 0x2803 -#define GATT_CLIENT_CHARACTERISTIC_CONFIGURATION 0x2902 -#define GATT_CHARACTERISTIC_FLAGS_BROADCAST 0x01 -#define GATT_CHARACTERISTIC_FLAGS_READ 0x02 -#define GATT_CHARACTERISTIC_FLAGS_WRITE_WITHOUT_RESPONSE 0x04 -#define GATT_CHARACTERISTIC_FLAGS_WRITE 0x08 -#define GATT_CHARACTERISTIC_FLAGS_NOTIFY 0x10 -#define GATT_CHARACTERISTIC_FLAGS_INDICATE 0x20 -#define GATT_CHARACTERISTIC_FLAGS_AUTHENTICATED_SIGNED_WRITES 0x40 -#define GATT_CHARACTERISTIC_FLAGS_EXTENDED_PROPERTIES 0x80 - - - /* Attribute Protocol Opcodes */ -#define ATT_OP_ERROR 0x01 -#define ATT_OP_MTU_REQ 0x02 -#define ATT_OP_MTU_RESP 0x03 -#define ATT_OP_FIND_INFO_REQ 0x04 -#define ATT_OP_FIND_INFO_RESP 0x05 -#define ATT_OP_FIND_BY_TYPE_REQ 0x06 -#define ATT_OP_FIND_BY_TYPE_RESP 0x07 -#define ATT_OP_READ_BY_TYPE_REQ 0x08 -#define ATT_OP_READ_BY_TYPE_RESP 0x09 -#define ATT_OP_READ_REQ 0x0A -#define ATT_OP_READ_RESP 0x0B -#define ATT_OP_READ_BLOB_REQ 0x0C -#define ATT_OP_READ_BLOB_RESP 0x0D -#define ATT_OP_READ_MULTI_REQ 0x0E -#define ATT_OP_READ_MULTI_RESP 0x0F -#define ATT_OP_READ_BY_GROUP_REQ 0x10 -#define ATT_OP_READ_BY_GROUP_RESP 0x11 -#define ATT_OP_WRITE_REQ 0x12 -#define ATT_OP_WRITE_RESP 0x13 -#define ATT_OP_WRITE_CMD 0x52 -#define ATT_OP_PREP_WRITE_REQ 0x16 -#define ATT_OP_PREP_WRITE_RESP 0x17 -#define ATT_OP_EXEC_WRITE_REQ 0x18 -#define ATT_OP_EXEC_WRITE_RESP 0x19 -#define ATT_OP_HANDLE_NOTIFY 0x1B -#define ATT_OP_HANDLE_IND 0x1D -#define ATT_OP_HANDLE_CNF 0x1E -#define ATT_OP_SIGNED_WRITE_CMD 0xD2 - - /* Error codes for Error response PDU */ -#define ATT_ECODE_INVALID_HANDLE 0x01 -#define ATT_ECODE_READ_NOT_PERM 0x02 -#define ATT_ECODE_WRITE_NOT_PERM 0x03 -#define ATT_ECODE_INVALID_PDU 0x04 -#define ATT_ECODE_AUTHENTICATION 0x05 -#define ATT_ECODE_REQ_NOT_SUPP 0x06 -#define ATT_ECODE_INVALID_OFFSET 0x07 -#define ATT_ECODE_AUTHORIZATION 0x08 -#define ATT_ECODE_PREP_QUEUE_FULL 0x09 -#define ATT_ECODE_ATTR_NOT_FOUND 0x0A -#define ATT_ECODE_ATTR_NOT_LONG 0x0B -#define ATT_ECODE_INSUFF_ENCR_KEY_SIZE 0x0C -#define ATT_ECODE_INVAL_ATTR_VALUE_LEN 0x0D -#define ATT_ECODE_UNLIKELY 0x0E -#define ATT_ECODE_INSUFF_ENC 0x0F -#define ATT_ECODE_UNSUPP_GRP_TYPE 0x10 -#define ATT_ECODE_INSUFF_RESOURCES 0x11 - /* Application error */ -#define ATT_ECODE_IO 0x80 -#define ATT_ECODE_TIMEOUT 0x81 -#define ATT_ECODE_ABORTED 0x82 - - /* Characteristic Property bit field */ -#define ATT_CHAR_PROPER_BROADCAST 0x01 -#define ATT_CHAR_PROPER_READ 0x02 -#define ATT_CHAR_PROPER_WRITE_WITHOUT_RESP 0x04 -#define ATT_CHAR_PROPER_WRITE 0x08 -#define ATT_CHAR_PROPER_NOTIFY 0x10 -#define ATT_CHAR_PROPER_INDICATE 0x20 -#define ATT_CHAR_PROPER_AUTH 0x40 -#define ATT_CHAR_PROPER_EXT_PROPER 0x80 - -#define ATT_MAX_VALUE_LEN 512 -#define ATT_DEFAULT_L2CAP_MTU 48 -#define ATT_DEFAULT_LE_MTU 23 - -#define ATT_CID 4 -#define ATT_PSM 31 - - /* Flags for Execute Write Request Operation */ -#define ATT_CANCEL_ALL_PREP_WRITES 0x00 -#define ATT_WRITE_ALL_PREP_WRITES 0x01 - - /* Find Information Response Formats */ -#define ATT_FIND_INFO_RESP_FMT_16BIT 0x01 -#define ATT_FIND_INFO_RESP_FMT_128BIT 0x02 - - struct att_data_list { - uint16_t num; - uint16_t len; - uint8_t **data; - }; - - struct att_range { - uint16_t start; - uint16_t end; - }; - - /* These functions do byte conversion */ - static inline uint8_t att_get_u8(const void *ptr) - { - const uint8_t *u8_ptr = (const uint8_t *) ptr; - return bt_get_unaligned(u8_ptr); - } - - static inline uint16_t att_get_u16(const void *ptr) - { - const uint16_t *u16_ptr = (const uint16_t*) ptr; - return btohs(bt_get_unaligned(u16_ptr)); - } - - static inline uint32_t att_get_u32(const void *ptr) - { - const uint32_t *u32_ptr = (const uint32_t*) ptr; - return btohl(bt_get_unaligned(u32_ptr)); - } - - static inline uint128_t att_get_u128(const void *ptr) - { - //it's an array and always little endian - const uint128_t *u128_ptr =(const uint128_t*) ptr; - return *u128_ptr; - } - - static inline void att_put_u8(uint8_t src, void *dst) - { - bt_put_unaligned(src, (uint8_t *) dst); - } - - static inline void att_put_u16(uint16_t src, void *dst) - { - bt_put_unaligned(htobs(src), (uint16_t *) dst); - } - - static inline void att_put_u32(uint32_t src, void *dst) - { - bt_put_unaligned(htobl(src), (uint32_t *) dst); - } - - static inline void att_put_u128(uint128_t src, void *dst) - { - //it's an array and always little endian - uint128_t *d128 = (uint128_t*)dst; - *d128 = src; - } - - static inline void att_put_uuid16(bt_uuid_t src, void *dst) - { - att_put_u16(src.value.u16, dst); - } - - static inline void att_put_uuid128(bt_uuid_t src, void *dst) - { - att_put_u128(src.value.u128, dst); - } - - static inline void att_put_uuid(bt_uuid_t src, void *dst) - { - if (src.type == BT_UUID16) - att_put_uuid16(src, dst); - else - att_put_uuid128(src, dst); - } - - static inline bt_uuid_t att_get_uuid16(const void *ptr) - { - bt_uuid_t uuid; - - bt_uuid16_create(&uuid, att_get_u16(ptr)); - - return uuid; - } - - static inline bt_uuid_t att_get_uuid128(const void *ptr) - { - bt_uuid_t uuid; - uint128_t value; - - value = att_get_u128(ptr); - bt_uuid128_create(&uuid, value); - - return uuid; - } - - struct att_data_list *att_data_list_alloc(uint16_t num, uint16_t len); - - - void att_data_list_free(struct att_data_list *list); - const char* att_op2str(uint8_t op); - const char *att_ecode2str(uint8_t status); - uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, - uint8_t *pdu, size_t len); - uint16_t dec_read_by_grp_req(const uint8_t *pdu, size_t len, uint16_t *start, - uint16_t *end, bt_uuid_t *uuid); - uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu, - size_t len); - uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, - const uint8_t *value, size_t vlen, uint8_t *pdu, - size_t len); - uint16_t dec_find_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start, - uint16_t *end, bt_uuid_t *uuid, uint8_t *value, size_t *vlen); - //uint16_t enc_find_by_type_resp(GSList *ranges, uint8_t *pdu, size_t len); - //GSList *dec_find_by_type_resp(const uint8_t *pdu, size_t len); - struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, size_t len); - uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, - uint8_t *pdu, size_t len); - uint16_t dec_read_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start, - uint16_t *end, bt_uuid_t *uuid); - uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu, - size_t len); - uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, size_t vlen, - uint8_t *pdu, size_t len); - uint16_t dec_write_cmd(const uint8_t *pdu, size_t len, uint16_t *handle, - uint8_t *value, size_t *vlen); - struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, size_t len); - uint16_t enc_write_req(uint16_t handle, const uint8_t *value, size_t vlen, - uint8_t *pdu, size_t len); - uint16_t dec_write_req(const uint8_t *pdu, size_t len, uint16_t *handle, - uint8_t *value, size_t *vlen); - uint16_t enc_write_resp(uint8_t *pdu, size_t len); - uint16_t dec_write_resp(const uint8_t *pdu, size_t len); - uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, size_t len); - uint16_t enc_read_blob_req(uint16_t handle, uint16_t offset, uint8_t *pdu, - size_t len); - uint16_t dec_read_req(const uint8_t *pdu, size_t len, uint16_t *handle); - uint16_t dec_read_blob_req(const uint8_t *pdu, size_t len, uint16_t *handle, - uint16_t *offset); - uint16_t enc_read_resp(uint8_t *value, size_t vlen, uint8_t *pdu, size_t len); - uint16_t enc_read_blob_resp(uint8_t *value, size_t vlen, uint16_t offset, - uint8_t *pdu, size_t len); - ssize_t dec_read_resp(const uint8_t *pdu, size_t len, uint8_t *value, - size_t vlen); - uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status, - uint8_t *pdu, size_t len); - uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, - size_t len); - uint16_t dec_find_info_req(const uint8_t *pdu, size_t len, uint16_t *start, - uint16_t *end); - uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list, - uint8_t *pdu, size_t len); - struct att_data_list *dec_find_info_resp(const uint8_t *pdu, size_t len, - uint8_t *format); - uint16_t enc_notification(uint16_t handle, uint8_t *value, size_t vlen, - uint8_t *pdu, size_t len); - uint16_t enc_indication(uint16_t handle, uint8_t *value, size_t vlen, - uint8_t *pdu, size_t len); - uint16_t dec_indication(const uint8_t *pdu, size_t len, uint16_t *handle, - uint8_t *value, size_t vlen); - uint16_t enc_confirmation(uint8_t *pdu, size_t len); - - uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, size_t len); - uint16_t dec_mtu_req(const uint8_t *pdu, size_t len, uint16_t *mtu); - uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, size_t len); - uint16_t dec_mtu_resp(const uint8_t *pdu, size_t len, uint16_t *mtu); - - uint16_t enc_prep_write_req(uint16_t handle, uint16_t offset, - const uint8_t *value, size_t vlen, - uint8_t *pdu, size_t len); - uint16_t dec_prep_write_resp(const uint8_t *pdu, size_t len, uint16_t *handle, - uint16_t *offset, uint8_t *value, - size_t *vlen); - uint16_t enc_exec_write_req(uint8_t flags, uint8_t *pdu, size_t len); - uint16_t dec_exec_write_resp(const uint8_t *pdu, size_t len); -} diff --git a/vendor/libblepp-master/blepp/att_pdu.h b/vendor/libblepp-master/blepp/att_pdu.h deleted file mode 100644 index ea91467..0000000 --- a/vendor/libblepp-master/blepp/att_pdu.h +++ /dev/null @@ -1,355 +0,0 @@ -/* - * - * blepp - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - - -/* - This file contains classes to wrap ATT Protocol (Attribute Protocol) PDUs - (Protocol Data Units?) and present the data in a semantically meaningful - format. - - The format of the packets is covered in Core Spec 4.0 3.F.3.4 - - Logic errors (such as trying to construct a PDU packet class from the - wrong PDU data) come back as std::logic_error. Runtime errors, such as - invalid packets come back as exceptions derived from std::runtime_error. - -*/ - -#ifndef INCLUDE_BLUETOOTH_ATT_H_C51BA176654792D689D16398C9A4735A -#define INCLUDE_BLUETOOTH_ATT_H_C51BA176654792D689D16398C9A4735A - -#include -#include -#include - -#include -#include - -namespace BLEPP -{ - - /* Basic PDU response as in 3.F.3.3.1 */ - class PDUResponse - { - protected: - - template - void error(const std::string& s) const - { - LOG(Error, s); - throw C(s); - } - - void type_check(int target) const - { - if(target != type()) - error(std::string("Error converting PDUResponse to ") +att_op2str(target) + ". Type is " + att_op2str(type())); - } - - public: - - const uint8_t* data; //Pointer to the underlying data - int length; //Length of the underlying data - - //Utility function to return a uint8 at byte offset i; - uint8_t uint8(int i) const - { - assert(i >= 0 && i < length); - return data[i]; - } - - //Utility function to return a uint16 at byte offset i - //Note packets are little endian. - uint16_t uint16(int i) const - { - return uint8(i) | (uint8(i+1) << 8); - } - - PDUResponse(const uint8_t* d_, int l_) - :data(d_),length(l_) - { - } - - //Table 3.1: type field is the low 6 bits. - //The command flag is bit 6 and the authentication - //flag is bit 7. - - //Return the method type - uint8_t type() const - { - return uint8(0) & 63; - } - - bool is_command() const - { - return uint8(0) & 64; - } - - bool is_authenticated() const - { - return uint8(0) & 128; - } - }; - - /* Error packet response 3.F.3.4.1.1 */ - class PDUErrorResponse: public PDUResponse - { - public: - PDUErrorResponse(const PDUResponse& p_) - :PDUResponse(p_) - { - type_check(ATT_OP_ERROR); - } - - uint8_t request_opcode() const - { - return uint8(1); - } - - uint16_t handle() const - { - return uint16(2); - } - - uint8_t error_code() const - { - return uint8(4); - } - - const char* error_str() const - { - return att_ecode2str(error_code()); - } - }; - /* Response to read_req, 3.F.3.4.4.4 */ - class PDUReadResponse: public PDUResponse - { - public: - PDUReadResponse(const PDUResponse& p_) - :PDUResponse(p_) - { - type_check(ATT_OP_READ_RESP); - } - uint8_t request_opcode() const - { - return uint8(1); - } - - uint16_t handle() const - { - return uint16(2); - } - }; - - - - /* Response to read_by_type, 3.F.3.4.4.2 */ - class PDUReadByTypeResponse: public PDUResponse - { - public: - PDUReadByTypeResponse(const PDUResponse& p_) - :PDUResponse(p_) - { - type_check(ATT_OP_READ_BY_TYPE_RESP); - - if((length - 2) % element_size() != 0) - error("Invalid packet length for PDUReadByTypeResponse"); - } - - - //Size of each element in the response - int element_size() const - { - return uint8(1); - } - - //Elements consist of a handle and a value. - //This is the size of just the value. - int value_size() const - { - return uint8(1) -2; - } - - int num_elements() const - { - return (length - 1) / element_size(); - } - - uint16_t handle(int i) const - { - return uint16(i*element_size() + 2); - } - - //Return pointer span of the ith chunk of data - std::pair value(int i) const - { - const uint8_t* begin = data + i*element_size() + 4; - return std::make_pair(begin, begin + value_size()); - } - - //Utility function to return the ith element directly as a uint16. - uint16_t value_uint16(int i) const - { - if(value_size() != 2) - error("Wrong size for uint16 in PDUReadByTypeResponse"); - - return uint16(i*element_size()+4); - } - }; - - - /* Response to read_group_by_type, 3.F.3.4.4.10 */ - class PDUReadGroupByTypeResponse: public PDUResponse - { - public: - PDUReadGroupByTypeResponse(const PDUResponse& p_) - :PDUResponse(p_) - { - type_check(ATT_OP_READ_BY_GROUP_RESP); - - if((length - 2) % element_size() != 0) - error("Invalid packet length for PDUReadGroupByTypeResponse"); - - } - - int value_size() const - { - return uint8(1) -4; - } - - int element_size() const - { - return uint8(1); - } - - int num_elements() const - { - return (length - 2) / element_size(); - } - - uint16_t start_handle(int i) const - { - return uint16(i*element_size() + 2); - } - - uint16_t end_handle(int i) const - { - return uint16(i*element_size() + 4); - } - - std::pair value(int i) const - { - const uint8_t* begin = data + i*element_size() + 6; - return std::make_pair(begin, begin + value_size()); - } - - uint16_t value_uint16(int i) const - { - if(value_size() != 2) - error("Wrong size for uint16 in PDUReadGroupByTypeResponse"); - return uint16(i*element_size()+4); - } - - }; - - class PDUFindInformationResponse: public PDUResponse - { - public: - - PDUFindInformationResponse(const PDUResponse& p_) - :PDUResponse(p_) - { - type_check(ATT_OP_FIND_INFO_RESP); - if( (length-2) % element_size()) - error("Invalid packet length for PDUReadGroupByTypeResponse"); - } - - bool is_16_bit() const - { - //Table 3.8 - return uint8(1) == 1; - - }; - - int element_size() const - { - return 2 + (is_16_bit() ? 2 : 16); - } - - int num_elements() const - { - return (length - 2) / element_size(); - } - - uint16_t handle(int i) const - { - return uint16(2 + i * element_size()); - } - - bt_uuid_t uuid(int i) const - { - if(is_16_bit()) - return att_get_uuid16(data + 2 + 2 + i * element_size()); - else - return att_get_uuid128(data + 2 + 2 + i * element_size()); - } - }; - - class PDUNotificationOrIndication: public PDUResponse - { - public: - - PDUNotificationOrIndication(const PDUResponse& p_) - :PDUResponse(p_) - { - if(type() != ATT_OP_HANDLE_NOTIFY && type() != ATT_OP_HANDLE_IND) - error(std::string("Error converting PDUResponse to NotifyOrIndicate. Type is ") + att_op2str(type())); - } - - bool notification() const - { - return type() == ATT_OP_HANDLE_NOTIFY; - - }; - - int num_elements() const - { - return (length - 2); - } - - uint16_t handle() const - { - return uint16(1); - } - - //Return pointer span of the ith chunk of data - std::pair value() const - { - return std::make_pair(data + 3, data + length); - } - }; - - void pretty_print(const PDUResponse& pdu); -} - - -#endif diff --git a/vendor/libblepp-master/blepp/bledevice.h b/vendor/libblepp-master/blepp/bledevice.h deleted file mode 100644 index 82244c5..0000000 --- a/vendor/libblepp-master/blepp/bledevice.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * blepp - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __INC_LIBATTGATT_BLEDEVICE_H -#define __INC_LIBATTGATT_BLEDEVICE_H - -#include -#include -#include -#include - -namespace BLEPP -{ - - //Almost zero resource to represent the ATT protocol on a BLE - //device. This class does none of its own memory management, and will not generally allocate - //or do other nasty things. Oh no, it allocates a buffer! FIXME! - // - //Mostly what it can do is write ATT command packets (PDUs) and receive PDUs back. - struct BLEDevice - { - struct ReadError{}; - struct WriteError{}; - - const int& sock; - static const int buflen=ATT_DEFAULT_MTU; - std::vector buf; - - //template void test_fd_(int fd, int line); - void test_pdu(int len); - BLEDevice(const int& sock_); - - void send_read_request(std::uint16_t handle); - void send_read_by_type(const bt_uuid_t& uuid, std::uint16_t start = 0x0001, std::uint16_t end=0xffff); - void send_find_information(std::uint16_t start = 0x0001, std::uint16_t end=0xffff); - void send_read_group_by_type(const bt_uuid_t& uuid, std::uint16_t start = 0x0001, std::uint16_t end=0xffff); - void send_write_request(std::uint16_t handle, const std::uint8_t* data, int length); - void send_write_request(std::uint16_t handle, std::uint16_t data); - void send_handle_value_confirmation(); - void send_write_command(std::uint16_t handle, const std::uint8_t* data, int length); - void send_write_command(std::uint16_t handle, std::uint16_t data); - PDUResponse receive(std::uint8_t* buf, int max); - PDUResponse receive(std::vector& v); - }; - -} - -#endif diff --git a/vendor/libblepp-master/blepp/blestatemachine.h b/vendor/libblepp-master/blepp/blestatemachine.h deleted file mode 100644 index cca28dc..0000000 --- a/vendor/libblepp-master/blepp/blestatemachine.h +++ /dev/null @@ -1,348 +0,0 @@ -#ifndef __INC_LIBATTGATT_BLESTATEMACHINE_H -#define __INC_LIBATTGATT_BLESTATEMACHINE_H -/* - * - * blepp - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include - -#include -#include -#include - - -#include - -namespace BLEPP -{ - - ///Interpret a ReadByTypeResponse packet as a ReadCharacteristic packet - class GATTReadCharacteristic: public PDUReadByTypeResponse - { - public: - struct Characteristic - { - uint16_t handle; - uint8_t flags; - bt_uuid_t uuid; - }; - - GATTReadCharacteristic(const PDUResponse& p) - :PDUReadByTypeResponse(p) - { - if(value_size() != 5 && value_size() != 19) - throw std::runtime_error("Invalid packet size in GATTReadCharacteristic"); - } - - Characteristic characteristic(int i) const - { - Characteristic c; - c.handle = att_get_u16(value(i).first + 1); - c.flags = value(i).first[0]; - - if(value_size() == 5) - c.uuid= att_get_uuid16(value(i).first + 3); - else - c.uuid= att_get_uuid128(value(i).first + 3); - - return c; - } - }; - - - - ///Interpret a ReadByTypeResponse packet as a ReadCharacteristic packet - class GATTReadCCC: public PDUReadByTypeResponse - { - public: - - GATTReadCCC(const PDUResponse& p) - :PDUReadByTypeResponse(p) - { - if(value_size() != 2) - throw std::runtime_error("Invalid packet size in GATTReadCharacteristic"); - } - - uint16_t ccc(int i) const - { - return att_get_u16(value(i).first); - } - }; - - ///Interpret a read_group_by_type resoponde as a read service group response - class GATTReadServiceGroup: public PDUReadGroupByTypeResponse - { - public: - GATTReadServiceGroup(const PDUResponse& p) - :PDUReadGroupByTypeResponse(p) - { - if(value_size() != 2 && value_size() != 16) - { - LOG(Error, "UUID length" << value_size()); - error("Invalid UUID length in PDUReadGroupByTypeResponse"); - } - } - - bt_uuid_t uuid(int i) const - { - const uint8_t* begin = data + i*element_size() + 6; - - bt_uuid_t uuid; - if(value_size() == 2) - { - uuid.type = BT_UUID16; - uuid.value.u16 = att_get_u16(begin); - } - else - { - uuid.type = BT_UUID128; - uuid.value.u128 = att_get_u128(begin); - } - - return uuid; - } - }; - - class BLEGATTStateMachine; - - enum States - { - Disconnected, - Connecting, - Idle, - ReadingPrimaryService, - FindAllCharacteristics, - GetClientCharaceristicConfiguration, - AwaitingWriteResponse, - }; - - static const int Waiting=-1; - - - class UUID: public bt_uuid_t - { - public: - - explicit UUID(const uint16_t& u) - { - type = BT_UUID16; - value.u16 = u; - } - - UUID(){} - - UUID(const UUID&) = default; - - static UUID from(const bt_uuid_t& uuid) - { - UUID ret; - (bt_uuid_t&)ret = uuid; - - return ret; - } - - UUID(const std::string& uuid_str) - { - //FIXME: check errors! - bt_string_to_uuid(this, uuid_str.c_str()); - } - - bool operator==(const UUID& uuid) const - { - return bt_uuid_cmp(this, &uuid) == 0; - } - }; - - - struct Characteristic - { - private: - BLEGATTStateMachine* s; - - public: - - Characteristic(BLEGATTStateMachine* s_) - :s(s_) - {} - - void set_notify_and_indicate(bool , bool); - std::function cb_notify_or_indicate; - - void write_request(const uint8_t* data, int length); - void write_request(uint8_t data); - - //Flags indicating various properties - bool broadcast, read, write_without_response, write, notify, indicate, authenticated_write, extended; - - //UUID, i.e. name of what the characteristic represents semantically - UUID uuid; - - //Where the value can be read/written - uint16_t value_handle; - - //Where we write to configure, i.e. set notify and/or indicate - //0 means invalid. - uint16_t client_characteric_configuration_handle; - uint16_t ccc_last_known_value; - - uint16_t first_handle, last_handle; - }; - - struct StateMachineGoneBad: public std::runtime_error - { - StateMachineGoneBad(const std::string& err) - :std::runtime_error(err) - { - } - }; - - - struct ServiceInfo - { - std::string name, id; - UUID uuid; - }; - - struct PrimaryService - { - uint16_t start_handle; - uint16_t end_handle; - UUID uuid; - std::vector characteristics; - }; - - - const ServiceInfo* lookup_service_by_UUID(const UUID& uuid); - - class BLEGATTStateMachine - { - public: - - struct Disconnect - { - enum Reason{ - ConnectionFailed, - UnexpectedError, - UnexpectedResponse, - WriteError, - ReadError, - ConnectionClosed - } reason; - - static constexpr int NoErrorCode=1; // Any positive value - int error_code; - - Disconnect(Reason r, int e) - :reason(r), error_code(e) - { - } - }; - static const char* get_disconnect_string(Disconnect); - - private: - struct sockaddr_l2 addr; - - int sock = -1; - - - static void buggerall(); - static void buggerall2(Disconnect); - - BLEDevice dev; - - - States state = Disconnected; - int next_handle_to_read=-1; - int last_request=-1; - - std::vector buf; - - - struct PrimaryServiceInfo - { - std::string name, id; - UUID uuid; - }; - - void reset(); - void state_machine_write(); - void unexpected_error(const PDUErrorResponse&); - void fail(Disconnect); - - public: - - - std::vector primary_services; - - std::function cb_connected = buggerall; - std::function cb_disconnected = buggerall2; - std::function cb_services_read = buggerall; - std::function cb_notify = buggerall; - std::function cb_find_characteristics = buggerall; - std::function cb_get_client_characteristic_configuration = buggerall; - std::function cb_write_response = buggerall; - std::function cb_notify_or_indicate; - - - BLEGATTStateMachine(); - ~BLEGATTStateMachine(); - - - void connect_blocking(const std::string& addres); - void connect_nonblocking(const std::string& addres); - void connect(const std::string& addresa, bool blocking, bool pubaddr = true, std::string device = ""); - void close(); - - int socket(); - - bool wait_on_write(); - - bool is_idle() - { - return state == Idle; - } - - void send_write_request(uint16_t handle, const uint8_t* data, int length); - - void read_primary_services(); - void find_all_characteristics(); - void get_client_characteristic_configuration(); - void read_and_process_next(); - void write_and_process_next(); - void set_notify_and_indicate(Characteristic& c, bool notify, bool indicate); - - - void setup_standard_scan(std::function& cb); - }; - - - void pretty_print_tree(const BLEGATTStateMachine& s); - - - - class SocketAllocationFailed: public std::runtime_error { using runtime_error::runtime_error; }; - class SocketBindFailed: public std::runtime_error { using runtime_error::runtime_error; }; - class SocketGetSockOptFailed: public std::runtime_error { using runtime_error::runtime_error; }; - class SocketConnectFailed: public std::runtime_error { using runtime_error::runtime_error; }; -} -#endif diff --git a/vendor/libblepp-master/blepp/float.h b/vendor/libblepp-master/blepp/float.h deleted file mode 100644 index 3b89948..0000000 --- a/vendor/libblepp-master/blepp/float.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * - * blepp - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __INC_LIBATTGATT_FLOAT_H -#define __INC_LIBATTGATT_FLOAT_H - -#include -namespace BLEPP -{ - float bluetooth_float_to_IEEE754(const std::uint8_t* bytes); -} - -#endif diff --git a/vendor/libblepp-master/blepp/gap.h b/vendor/libblepp-master/blepp/gap.h deleted file mode 100644 index 85a07b6..0000000 --- a/vendor/libblepp-master/blepp/gap.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef BLEPLUSPLUS_INC_GAP_H -#define BLEPLUSPLUS_INC_GAP_H - -namespace BLEPP -{ - namespace GAP - { - //From here: - //https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile - //incomplete list. - enum GAP - { - flags = 0x01, - incomplete_list_of_16_bit_UUIDs = 0x02, - complete_list_of_16_bit_UUIDs = 0x03, - incomplete_list_of_128_bit_UUIDs = 0x06, - complete_list_of_128_bit_UUIDs = 0x07, - shortened_local_name = 0x08, - complete_local_name = 0x09, - service_data_16_bit_UUID = 0x16, - manufacturer_data = 0xff - }; - - }; - - - -} - - -#endif diff --git a/vendor/libblepp-master/blepp/lescan.h b/vendor/libblepp-master/blepp/lescan.h deleted file mode 100644 index e73731d..0000000 --- a/vendor/libblepp-master/blepp/lescan.h +++ /dev/null @@ -1,217 +0,0 @@ - -/* - * - * blepp - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __INC_BLEPP_LESCAN_H -#define __INC_BLEPP_LESCAN_H - -#include -#include -#include -#include -#include -#include -#include -#include //for UUID. FIXME mofo -#include - -namespace BLEPP -{ - enum class LeAdvertisingEventType - { - ADV_IND = 0x00, //Connectable undirected advertising - //Broadcast; any device can connect or ask for more information - ADV_DIRECT_IND = 0x01, //Connectable Directed - //Targeted; a single known device that can only connect - ADV_SCAN_IND = 0x02, //Scannable Undirected - //Purely informative broadcast; devices can ask for more information - ADV_NONCONN_IND = 0x03, //Non-Connectable Undirected - //Purely informative broadcast; no device can connect or even ask for more information - SCAN_RSP = 0x04, //Result coming back after a scan request - }; - - //Is this the best design. I'm not especially convinced. - //It seems pretty wretched. - struct AdvertisingResponse - { - std::string address; - LeAdvertisingEventType type; - struct Name - { - std::string name; - bool complete; - }; - - struct Flags - { - bool LE_limited_discoverable=0; - bool LE_general_discoverable=0; - bool BR_EDR_unsupported=0; - bool simultaneous_LE_BR_controller=0; - bool simultaneous_LE_BR_host=0; - - std::vector flag_data; - Flags(std::vector&&); - }; - - std::vector UUIDs; - bool uuid_16_bit_complete=0; - bool uuid_32_bit_complete=0; - bool uuid_128_bit_complete=0; - - boost::optional local_name; - boost::optional flags; - - std::vector> manufacturer_specific_data; - std::vector> service_data; - std::vector> unparsed_data_with_types; - - }; - - /// Class for scanning for BLE devices - /// this must be run as root, because it requires getting packets from the HCI. - /// The HCI requires root since it has no permissions on setting filters, so - /// anyone with an open HCI device can sniff all data. - class HCIScanner - { - class FD - { - private: - int fd=-1; - - public: - operator int () const - { - return fd; - } - FD(int i) - :fd(i) - { - } - - FD()=default; - void set(int i) - { - fd = i; - } - - ~FD() - { - if(fd != -1) - close(fd); - } - }; - - - public: - - enum class ScanType - { - Passive = 0x00, - Active = 0x01, - }; - - enum class FilterDuplicates - { - Off, //Get all events - Hardware, //Rely on hardware filtering only. Lower power draw, but can actually send - //duplicates if the device's builtin list gets overwhelmed. - Software, //Get all events from the device and filter them by hand. - Both //The best and worst of both worlds. - }; - - ///Generic error exception class - class Error: public std::runtime_error - { - public: - Error(const std::string& why); - }; - - ///Thrown only if a read() is interrupted. Only bother - ///handling if you've got a non terminating exception handler - class Interrupted: public Error - { - using Error::Error; - }; - - - ///IO error of some sort. Probably fatal for any bluetooth - ///based system. Or might be that the dongle was unplugged. - class IOError: public Error - { - public: - IOError(const std::string& why, int errno_val); - }; - - ///HCI device spat out invalid data. - ///This is not good. Almost certainly fatal. - class HCIError: public Error - { - using Error::Error; - }; - - HCIScanner(); - HCIScanner(bool start); - HCIScanner(bool start, FilterDuplicates duplicates, ScanType, std::string device=""); - - - void start(); - void stop(); - - ///get the file descriptor. - ///Use with select(), poll() or whatever. - int get_fd() const; - - ~HCIScanner(); - - ///Blocking call. Use select() on the FD if you don't want to block. - ///This reads and parses the HCI packets. - std::vector get_advertisements(); - - ///Parse an HCI advertising packet. There's probably not much - ///reason to call this yourself. - static std::vector parse_packet(const std::vector& p); - - private: - struct FilterEntry - { - explicit FilterEntry(const AdvertisingResponse&); - const std::string mac_address; - int type; - bool operator<(const FilterEntry&) const; - }; - - bool hardware_filtering; - bool software_filtering; - ScanType scan_type; - - FD hci_fd; - bool running=0; - hci_filter old_filter; - - ///Read the HCI data, but don't parse it. - std::vector read_with_retry(); - std::set scanned_devices; - }; -} - -#endif diff --git a/vendor/libblepp-master/blepp/logging.h b/vendor/libblepp-master/blepp/logging.h deleted file mode 100644 index 7e642ea..0000000 --- a/vendor/libblepp-master/blepp/logging.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * - * blepp - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __INC_LIBATTGATT_LOGGING_H -#define __INC_LIBATTGATT_LOGGING_H -#include -#include -#include -#include -#include -#include - -namespace BLEPP -{ - - enum LogLevels - { - Error, - Warning, - Info, - Debug, - Trace - }; - - static const char* log_types[] = - { - "error", - "warn ", - "info ", - "debug", - "trace" - }; -} -namespace BLEPP{ - - extern LogLevels log_level; - - template const T& log_no_uint8(const T& a) - { - return a; - } - inline int log_no_uint8(uint8_t a) - { - return a; - } - - inline std::ostream& log_line_header(LogLevels x, const char* function, const int line, const char* file) - { - std::clog << log_types[x] << " " << std::fixed << std::setprecision(6) << std::chrono::duration_cast>(std::chrono::system_clock::now().time_since_epoch()).count(); - if(log_level >= Debug) - std::clog << " " << function; - if(log_level >= Trace) - std::clog << " " << file << ":" << line; - std::clog << ": "; - return std::clog; - } - - - #define LOGVAR(Y, X) LOG(Y, #X << " = " << log_no_uint8(X)) - #define LOGVARHEX(Y, X) LOG(Y, #X << " = " << std::hex <= Trace) - log_line_header(Trace, who, where, file) << "entering" << std::endl; - } - - ~EnterThenLeave() - { - if(BLEPP::log_level >= Trace) - log_line_header(Trace, who, where, file) << "leaving" << std::endl; - } - - }; - - #define ENTER() EnterThenLeave log_enter_then_leave(__FUNCTION__, __LINE__, __FILE__); -} -#endif diff --git a/vendor/libblepp-master/blepp/pretty_printers.h b/vendor/libblepp-master/blepp/pretty_printers.h deleted file mode 100644 index ee4d41c..0000000 --- a/vendor/libblepp-master/blepp/pretty_printers.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef __INC_LIBATTGATT_PRETTY_PRINTERS_H -#define __INC_LIBATTGATT_PRETTY_PRINTERS_H - -/* - * - * blepp - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include - -#include -#include -#include -#include - -namespace BLEPP -{ - std::string to_hex(const std::uint16_t& u); - std::string to_hex(const std::uint8_t& u); - std::string to_str(const std::uint8_t& u); - std::string to_str(const bt_uuid_t& uuid); - std::string to_hex(const std::uint8_t* d, int l); - std::string to_hex(std::pair d); - std::string to_hex(const std::vector& v); - std::string to_str(const std::uint8_t* d, int l); - std::string to_str(std::pair d); - std::string to_str(std::pair d); - std::string to_str(const std::vector& v); -} - -#endif diff --git a/vendor/libblepp-master/blepp/uuid.h b/vendor/libblepp-master/blepp/uuid.h deleted file mode 100644 index 3dc5416..0000000 --- a/vendor/libblepp-master/blepp/uuid.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2011 Nokia Corporation - * Copyright (C) 2011 Marcel Holtmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __BLUETOOTH_UUID_H -#define __BLUETOOTH_UUID_H - -#include -#include - -namespace BLEPP -{ - #include - //#include - - #define GENERIC_AUDIO_UUID "00001203-0000-1000-8000-00805f9b34fb" - - #define HSP_HS_UUID "00001108-0000-1000-8000-00805f9b34fb" - #define HSP_AG_UUID "00001112-0000-1000-8000-00805f9b34fb" - - #define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" - #define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb" - - #define ADVANCED_AUDIO_UUID "0000110d-0000-1000-8000-00805f9b34fb" - - #define A2DP_SOURCE_UUID "0000110a-0000-1000-8000-00805f9b34fb" - #define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb" - - #define AVRCP_REMOTE_UUID "0000110e-0000-1000-8000-00805f9b34fb" - #define AVRCP_TARGET_UUID "0000110c-0000-1000-8000-00805f9b34fb" - - #define PANU_UUID "00001115-0000-1000-8000-00805f9b34fb" - #define NAP_UUID "00001116-0000-1000-8000-00805f9b34fb" - #define GN_UUID "00001117-0000-1000-8000-00805f9b34fb" - #define BNEP_SVC_UUID "0000000f-0000-1000-8000-00805f9b34fb" - - #define PNPID_UUID "00002a50-0000-1000-8000-00805f9b34fb" - #define DEVICE_INFORMATION_UUID "0000180a-0000-1000-8000-00805f9b34fb" - - #define GATT_UUID "00001801-0000-1000-8000-00805f9b34fb" - #define IMMEDIATE_ALERT_UUID "00001802-0000-1000-8000-00805f9b34fb" - #define LINK_LOSS_UUID "00001803-0000-1000-8000-00805f9b34fb" - #define TX_POWER_UUID "00001804-0000-1000-8000-00805f9b34fb" - - #define SAP_UUID "0000112D-0000-1000-8000-00805f9b34fb" - - #define HEART_RATE_UUID "0000180d-0000-1000-8000-00805f9b34fb" - #define HEART_RATE_MEASUREMENT_UUID "00002a37-0000-1000-8000-00805f9b34fb" - #define BODY_SENSOR_LOCATION_UUID "00002a38-0000-1000-8000-00805f9b34fb" - #define HEART_RATE_CONTROL_POINT_UUID "00002a39-0000-1000-8000-00805f9b34fb" - - #define HEALTH_THERMOMETER_UUID "00001809-0000-1000-8000-00805f9b34fb" - #define TEMPERATURE_MEASUREMENT_UUID "00002a1c-0000-1000-8000-00805f9b34fb" - #define TEMPERATURE_TYPE_UUID "00002a1d-0000-1000-8000-00805f9b34fb" - #define INTERMEDIATE_TEMPERATURE_UUID "00002a1e-0000-1000-8000-00805f9b34fb" - #define MEASUREMENT_INTERVAL_UUID "00002a21-0000-1000-8000-00805f9b34fb" - - #define CYCLING_SC_UUID "00001816-0000-1000-8000-00805f9b34fb" - #define CSC_MEASUREMENT_UUID "00002a5b-0000-1000-8000-00805f9b34fb" - #define CSC_FEATURE_UUID "00002a5c-0000-1000-8000-00805f9b34fb" - #define SENSOR_LOCATION_UUID "00002a5d-0000-1000-8000-00805f9b34fb" - #define SC_CONTROL_POINT_UUID "00002a55-0000-1000-8000-00805f9b34fb" - - #define RFCOMM_UUID_STR "00000003-0000-1000-8000-00805f9b34fb" - - #define HDP_UUID "00001400-0000-1000-8000-00805f9b34fb" - #define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805f9b34fb" - #define HDP_SINK_UUID "00001402-0000-1000-8000-00805f9b34fb" - - #define HSP_HS_UUID "00001108-0000-1000-8000-00805f9b34fb" - #define HID_UUID "00001124-0000-1000-8000-00805f9b34fb" - - #define DUN_GW_UUID "00001103-0000-1000-8000-00805f9b34fb" - - #define GAP_UUID "00001800-0000-1000-8000-00805f9b34fb" - #define PNP_UUID "00001200-0000-1000-8000-00805f9b34fb" - - #define SPP_UUID "00001101-0000-1000-8000-00805f9b34fb" - - #define OBEX_SYNC_UUID "00001104-0000-1000-8000-00805f9b34fb" - #define OBEX_OPP_UUID "00001105-0000-1000-8000-00805f9b34fb" - #define OBEX_FTP_UUID "00001106-0000-1000-8000-00805f9b34fb" - #define OBEX_PCE_UUID "0000112e-0000-1000-8000-00805f9b34fb" - #define OBEX_PSE_UUID "0000112f-0000-1000-8000-00805f9b34fb" - #define OBEX_PBAP_UUID "00001130-0000-1000-8000-00805f9b34fb" - #define OBEX_MAS_UUID "00001132-0000-1000-8000-00805f9b34fb" - #define OBEX_MNS_UUID "00001133-0000-1000-8000-00805f9b34fb" - #define OBEX_MAP_UUID "00001134-0000-1000-8000-00805f9b34fb" - - typedef enum { - BT_UUID_UNSPEC = 0, - BT_UUID16 = 16, - BT_UUID32 = 32, - BT_UUID128 = 128, - } bt_uuid_type_t; - typedef struct { - bt_uuid_type_t type; - union { - uint16_t u16; - uint32_t u32; - uint128_t u128; - } value; - } bt_uuid_t; - - int bt_uuid_strcmp(const void *a, const void *b); - - int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value); - int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value); - int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value); - - int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2); - void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst); - - #define MAX_LEN_UUID_STR 37 - - int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n); - int bt_string_to_uuid(bt_uuid_t *uuid, const char *string); - -} -#endif /* __BLUETOOTH_UUID_H */ diff --git a/vendor/libblepp-master/blepp/xtoa.h b/vendor/libblepp-master/blepp/xtoa.h deleted file mode 100644 index 7a9bd08..0000000 --- a/vendor/libblepp-master/blepp/xtoa.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * blepp - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - - -#ifndef INC_XTOA_H -#define INC_XTOA_H -#include - -namespace BLEPP -{ - template - std::string xtoa(const X& x) - { - std::ostringstream o; - o << x; - return o.str(); - } -} -#endif diff --git a/vendor/libblepp-master/bluetooth.cc b/vendor/libblepp-master/bluetooth.cc deleted file mode 100644 index e23bc93..0000000 --- a/vendor/libblepp-master/bluetooth.cc +++ /dev/null @@ -1,294 +0,0 @@ -/* - * - * libattgatt - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "cxxgplot.h" //lolzworthy plotting program -using namespace std; -using namespace BLEPP; - -void bin(uint8_t i) -{ - for(int b=7; b >= 0; b--) - cout << !!(i & (1<= 20) - i = 19-(i-20); - base[i + 2] = 'O'; - - return base + string(base.size(), '\b'); -} - - -double get_time_of_day() -{ - struct timeval tv; - gettimeofday(&tv,NULL); - return tv.tv_sec+tv.tv_usec * 1e-6; -} -//////////////////////////////////////////////////////////////////////////////// -// -// This program demonstrates the use of the library -// -int main(int argc, char **argv) -{ - if(argc != 2 && argc != 3) - { - cerr << "Please supply address.\n"; - cerr << "Usage:\n"; - cerr << "prog address [nonblocking]\n"; - exit(1); - } - - log_level = Info; - - - //This is the interface to the BLW protocol. - BLEGATTStateMachine gatt; - - - //This is a cheap and cheerful plotting system using gnuplot. - //Ignore this if you don't care about plotting. - cplot::Plotter plot; - plot.range = " [ ] [0:] "; - deque points; - - int count = -1; - double prev_time = 0; - float voltage=0; - - //////////////////////////////////////////////////////////////////////////////// - // - // This is important! This is an example of a callback which responds to - // notifications or indications. Currently, BLEGATTStateMachine responds - // automatically to indications. Maybe that will change. - // - //Function that reads an indication and formats it for plotting. - std::function notify_cb = [&](const PDUNotificationOrIndication& n) - { - if(count == -1) - { - prev_time = get_time_of_day(); - } - count++; - - if(count == 10) - { - double t = get_time_of_day(); - cout << 10 / (t-prev_time) << " packets per second\n"; - - prev_time = t; - count=0; - } - - - - //This particular device sends 16 bit integers. - //Extract them and both print them in binary and send them to the plotting program - const uint8_t* d = n.value().first; - for(int i=0; i < 7; i++) - { - int val = ((0+d[1 + 2*i] *256 + d[0 + 2*i])>>0) ; - //Format the points and send the results to the plotting program. - points.push_back(val); - if(points.size() > 300) - points.pop_front(); - } - - uint32_t seq = d[14] | (d[15]<<8) | (d[16]<<16) | (d[17]<<8); - int16_t bv = d[18] | (d[19] << 8); - - if(bv != -32768) - voltage = bv / 1000.0; - - //cout << "Hello: " << dec << setfill('0') << setw(6) << val << dec << " "; - //bin(d[1]); - //cout << " "; - //bin(d[0]); - - //cout << endl; - - - plot.newline("line lw 3 lt 1 title \"\""); - plot.addpts(points); - ostringstream os; - os << "set title \"Voltage: " << voltage << " Seq: " << seq << "\""; - plot.add_extra(os.str()); - - plot.draw(); - }; - - - //////////////////////////////////////////////////////////////////////////////// - // - // This is important! This is an example of a callback which is run when the - // client characteristic configuration is retreived. Essentially this is when - // all the most useful device information has been received and the device can - // now be used. - // - // At this point you need to search for things to activate. The code here activates - // notifications on a device I have. You will need to modify this! - // - // Search for the service and attribute and set up notifications and the appropriate callback. - bool enable=true; - std::function cb = [&gatt, ¬ify_cb, &enable](){ - - pretty_print_tree(gatt); - - for(auto& service: gatt.primary_services) - for(auto& characteristic: service.characteristics) - if(service.uuid == UUID("7309203e-349d-4c11-ac6b-baedd1819764") && characteristic.uuid == UUID("e5f49879-6ee1-479e-bfec-3d35e13d3b88")) - { - cout << "woooo\n"; - characteristic.cb_notify_or_indicate = notify_cb; - characteristic.set_notify_and_indicate(enable, false); - } - }; - - //////////////////////////////////////////////////////////////////////////////// - // - // This is somewhat important. Set up callback for disconnection - // - // All reasonable errors are handled by a disconnect. The BLE spec specifies that - // if the device sends invalid data, then the client must disconnect. - // - // Failure to connect also comes here. - gatt.cb_disconnected = [](BLEGATTStateMachine::Disconnect d) - { - cerr << "Disconnect for reason " << BLEGATTStateMachine::get_disconnect_string(d) << endl; - exit(1); - }; - - - //////////////////////////////////////////////////////////////////////////////// - // - // You almost always want to query the tree of things on the entire device - // So, there is a function to do this automatically. This is a helper which - // sets up all the callbacks necessary to automate the scanning. You could - // reduce connection times a little bit by only scanning for soma attributes. - gatt.setup_standard_scan(cb); - - - - //////////////////////////////////////////////////////////////////////////////// - // - // There are two modes, blocking and nonblocking. - // - // Blocking is useful for simple commandline programs which just log a bunch of - // data from a BLE device. - // - // Nonblocking is useful for everything else. - // - - // A few errors are handled by exceptions. std::runtime errors happen if nearly fatal - // but recoverable-with-effort errors happen, such as a failure in socket allocation. - // It is very unlikely you will encounter a runtime error. - // - // std::logic_error happens if you abuse the BLEGATTStateMachine. For example trying - // to issue a new instruction before the callback indicating the in progress one has - // finished has been called. These errors mean the program is incorrect. - try - { - if(argc >2 && argv[2] == string("nonblocking")) - { - - //This is how to use the blocking interface. It is very simple. - gatt.connect_blocking(argv[1]); - for(;;) - { - gatt.read_and_process_next(); - } - } - else - { - //Connect as a non blocking call - gatt.connect_nonblocking(argv[1]); - - - - //Example of how to use the state machine with select() - // - //This just demonstrates the capability and should be easily - //transferrable to poll(), epoll(), libevent and so on. - fd_set write_set, read_set; - - for(int i=0;;i++) - { - FD_ZERO(&read_set); - FD_ZERO(&write_set); - - //Reads are always a possibility due to asynchronus notifications. - FD_SET(gatt.socket(), &read_set); - - //Writes are usually available, so only check for them when the - //state machine wants to write. - if(gatt.wait_on_write()) - FD_SET(gatt.socket(), &write_set); - - - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 10000; - int result = select(gatt.socket() + 1, &read_set, &write_set, NULL, & tv); - - if(FD_ISSET(gatt.socket(), &write_set)) - gatt.write_and_process_next(); - - if(FD_ISSET(gatt.socket(), &read_set)) - gatt.read_and_process_next(); - - cout << throbber(i) << flush; -/* - if(i % 100 == 0 && gatt.is_idle()) - { - enable = !enable; - cb(); - }*/ - - } - } - } - catch(std::runtime_error e) - { - cerr << "Something's stopping bluetooth working: " << e.what() << endl; - } - catch(std::logic_error e) - { - cerr << "Oops, someone fouled up: " << e.what() << endl; - } - -} diff --git a/vendor/libblepp-master/configure b/vendor/libblepp-master/configure deleted file mode 100755 index 5d3f0f5..0000000 --- a/vendor/libblepp-master/configure +++ /dev/null @@ -1,4858 +0,0 @@ -#! /bin/sh -# Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for libble++ version-0.5. -# -# -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. -# -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. -# -# E. Rosten, 2016, the BlueZ contributors to 2016 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : - -else - exitcode=1; echo positional parameters were not saved. -fi -test x\$exitcode = x0 || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : - as_have_required=yes -else - as_have_required=no -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : - -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - as_found=: - case $as_dir in #( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : - CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : - break 2 -fi -fi - done;; - esac - as_found=false -done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } -IFS=$as_save_IFS - - - if test "x$CONFIG_SHELL" != x; then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." - else - $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, -$0: including any error possibly output before this -$0: message. Then install a modern shell, or manually run -$0: the script under such a shell if you do have one." - fi - exit 1 -fi -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_files= -ac_config_libobj_dir=. -LIBOBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='libble++' -PACKAGE_TARNAME='libble--' -PACKAGE_VERSION='version-0.5' -PACKAGE_STRING='libble++ version-0.5' -PACKAGE_BUGREPORT='' -PACKAGE_URL='' - -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif -#ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_subst_vars='LTLIBOBJS -LIBOBJS -EGREP -GREP -CXXCPP -VERSION -PKGCONFIG_LIBDIR -SED -PKG_CONFIG -HAVE_CXX14 -OBJEXT -EXEEXT -ac_ct_CXX -CPPFLAGS -LDFLAGS -CXXFLAGS -CXX -target_alias -host_alias -build_alias -LIBS -ECHO_T -ECHO_N -ECHO_C -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -' - ac_precious_vars='build_alias -host_alias -target_alias -CXX -CXXFLAGS -LDFLAGS -LIBS -CPPFLAGS -CCC -CXXCPP' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: `$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -\`configure' configures libble++ version-0.5 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/libble--] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of libble++ version-0.5:";; - esac - cat <<\_ACEOF - -Some influential environment variables: - CXX C++ compiler command - CXXFLAGS C++ compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - CXXCPP C++ preprocessor - -Use these variables to override the choices made by `configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to the package provider. -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -libble++ configure version-0.5 -generated by GNU Autoconf 2.69 - -Copyright (C) 2012 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. - -E. Rosten, 2016, the BlueZ contributors to 2016 -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -# ac_fn_cxx_try_compile LINENO -# ---------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_compile - -# ac_fn_cxx_try_cpp LINENO -# ------------------------ -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || - test ! -s conftest.err - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_cpp - -# ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES -# --------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_cxx_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_cxx_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_cxx_check_header_mongrel - -# ac_fn_cxx_try_run LINENO -# ------------------------ -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. -ac_fn_cxx_try_run () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : - ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=$ac_status -fi - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_run - -# ac_fn_cxx_check_header_compile LINENO HEADER VAR INCLUDES -# --------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_cxx_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_cxx_check_header_compile - -# ac_fn_cxx_try_link LINENO -# ------------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_link -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by libble++ $as_me version-0.5, which was -generated by GNU Autoconf 2.69. Invocation command line was - - $ $0 $@ - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Save into config.log some information that might help in debugging. - { - echo - - $as_echo "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - # The following way of writing the cache mishandles newlines in values, -( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" - ;; #( - *) - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) - echo - - $as_echo "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - - if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - $as_echo "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -$as_echo "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE -if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac -elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site -else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site -fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" -do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -if test -z "$CXX"; then - if test -n "$CCC"; then - CXX=$CCC - else - if test -n "$ac_tool_prefix"; then - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CXX=$ac_cv_prog_CXX -if test -n "$CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -$as_echo "$CXX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CXX" && break - done -fi -if test -z "$CXX"; then - ac_ct_CXX=$CXX - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CXX"; then - ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CXX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CXX=$ac_cv_prog_ac_ct_CXX -if test -n "$ac_ct_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 -$as_echo "$ac_ct_CXX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CXX" && break -done - - if test "x$ac_ct_CXX" = x; then - CXX="g++" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CXX=$ac_ct_CXX - fi -fi - - fi -fi -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5 -$as_echo_n "checking whether the C++ compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else - ac_file='' -fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "C++ compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5 -$as_echo_n "checking for C++ compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -FILE *f = fopen ("conftest.out", "w"); - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C++ compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out -ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 -$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } -if ${ac_cv_cxx_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 -$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GXX=yes -else - GXX= -fi -ac_test_CXXFLAGS=${CXXFLAGS+set} -ac_save_CXXFLAGS=$CXXFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 -$as_echo_n "checking whether $CXX accepts -g... " >&6; } -if ${ac_cv_prog_cxx_g+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_cxx_werror_flag=$ac_cxx_werror_flag - ac_cxx_werror_flag=yes - ac_cv_prog_cxx_g=no - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_cv_prog_cxx_g=yes -else - CXXFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - -else - ac_cxx_werror_flag=$ac_save_cxx_werror_flag - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_cv_prog_cxx_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_cxx_werror_flag=$ac_save_cxx_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 -$as_echo "$ac_cv_prog_cxx_g" >&6; } -if test "$ac_test_CXXFLAGS" = set; then - CXXFLAGS=$ac_save_CXXFLAGS -elif test $ac_cv_prog_cxx_g = yes; then - if test "$GXX" = yes; then - CXXFLAGS="-g -O2" - else - CXXFLAGS="-g" - fi -else - if test "$GXX" = yes; then - CXXFLAGS="-O2" - else - CXXFLAGS= - fi -fi -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - - -# ============================================================================ -# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_14.html -# ============================================================================ -# -# SYNOPSIS -# -# AX_CXX_COMPILE_STDCXX_14([ext|noext],[mandatory|optional]) -# -# DESCRIPTION -# -# Check for baseline language coverage in the compiler for the C++14 -# standard; if necessary, add switches to CXXFLAGS to enable support. -# -# The first argument, if specified, indicates whether you insist on an -# extended mode (e.g. -std=gnu++14) or a strict conformance mode (e.g. -# -std=c++14). If neither is specified, you get whatever works, with -# preference for an extended mode. -# -# The second argument, if specified 'mandatory' or if left unspecified, -# indicates that baseline C++14 support is required and that the macro -# should error out if no mode with that support is found. If specified -# 'optional', then configuration proceeds regardless, after defining -# HAVE_CXX14 if and only if a supporting mode is found. -# -# LICENSE -# -# Copyright (c) 2008 Benjamin Kosnik -# Copyright (c) 2012 Zack Weinberg -# Copyright (c) 2013 Roy Stogner -# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov -# Copyright (c) 2015 Paul Norman -# Copyright (c) 2016 Edward Rosten -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 13 - - - - - - - -################################################################################ -# -# Useful macros -# - - - - - - - - -if test "$CXXFLAGS" == "-g -O2" -then - - - if test "" == "" - then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler flag -Wall works" >&5 -$as_echo_n "checking if compiler flag -Wall works... " >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking " >&5 -$as_echo_n "checking ... " >&6; } - fi - save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS -Wall" - - - - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(){} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - cvd_conf_test=1 -else - cvd_conf_test=0 -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - - - - - if test $cvd_conf_test = 1 - then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - ts_success=yes - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CXXFLAGS="$save_CXXFLAGS" - ts_success=no - fi - - - if test "" == "" - then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler flag -Wextra works" >&5 -$as_echo_n "checking if compiler flag -Wextra works... " >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking " >&5 -$as_echo_n "checking ... " >&6; } - fi - save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS -Wextra" - - - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(){} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - cvd_conf_test=1 -else - cvd_conf_test=0 -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - - - - - if test $cvd_conf_test = 1 - then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - ts_success=yes - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CXXFLAGS="$save_CXXFLAGS" - ts_success=no - fi - - - if test "" == "" - then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler flag -W works" >&5 -$as_echo_n "checking if compiler flag -W works... " >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking " >&5 -$as_echo_n "checking ... " >&6; } - fi - save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS -W" - - - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(){} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - cvd_conf_test=1 -else - cvd_conf_test=0 -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - - - - - if test $cvd_conf_test = 1 - then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - ts_success=yes - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CXXFLAGS="$save_CXXFLAGS" - ts_success=no - fi - - - if test "" == "" - then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler flag -O3 works" >&5 -$as_echo_n "checking if compiler flag -O3 works... " >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking " >&5 -$as_echo_n "checking ... " >&6; } - fi - save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS -O3" - - - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(){} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - cvd_conf_test=1 -else - cvd_conf_test=0 -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - - - - - if test $cvd_conf_test = 1 - then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - ts_success=yes - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CXXFLAGS="$save_CXXFLAGS" - ts_success=no - fi - - - if test "" == "" - then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler flag -ggdb works" >&5 -$as_echo_n "checking if compiler flag -ggdb works... " >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking " >&5 -$as_echo_n "checking ... " >&6; } - fi - save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS -ggdb" - - - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(){} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - cvd_conf_test=1 -else - cvd_conf_test=0 -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - - - - - if test $cvd_conf_test = 1 - then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - ts_success=yes - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CXXFLAGS="$save_CXXFLAGS" - ts_success=no - fi - -fi - - ax_cxx_compile_cxx14_required=true - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - ac_success=no - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++14 features by default" >&5 -$as_echo_n "checking whether $CXX supports C++14 features by default... " >&6; } -if ${ax_cv_cxx_compile_cxx14+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - template - struct check - { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); - }; - - struct Base { - virtual void f() {} - }; - struct Child : public Base { - virtual void f() override {} - }; - - typedef check> right_angle_brackets; - - int a; - decltype(a) b; - - typedef check check_type; - check_type c; - check_type&& cr = static_cast(c); - - auto d = a; - auto l = [](){}; - // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] - struct use_l { use_l() { l(); } }; - - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this - namespace test_template_alias_sfinae { - struct foo {}; - - template - using member = typename T::member_type; - - template - void func(...) {} - - template - void func(member*) {} - - void test(); - - void test() { - func(0); - } - } - - // Check for C++14 attribute support - void noret [[noreturn]] () { throw 0; } - -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ax_cv_cxx_compile_cxx14=yes -else - ax_cv_cxx_compile_cxx14=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx14" >&5 -$as_echo "$ax_cv_cxx_compile_cxx14" >&6; } - if test x$ax_cv_cxx_compile_cxx14 = xyes; then - ac_success=yes - fi - - if test x$ac_success = xno; then - for switch in -std=gnu++14 -std=gnu++1y; do - cachevar=`$as_echo "ax_cv_cxx_compile_cxx14_$switch" | $as_tr_sh` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++14 features with $switch" >&5 -$as_echo_n "checking whether $CXX supports C++14 features with $switch... " >&6; } -if eval \${$cachevar+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - template - struct check - { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); - }; - - struct Base { - virtual void f() {} - }; - struct Child : public Base { - virtual void f() override {} - }; - - typedef check> right_angle_brackets; - - int a; - decltype(a) b; - - typedef check check_type; - check_type c; - check_type&& cr = static_cast(c); - - auto d = a; - auto l = [](){}; - // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] - struct use_l { use_l() { l(); } }; - - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this - namespace test_template_alias_sfinae { - struct foo {}; - - template - using member = typename T::member_type; - - template - void func(...) {} - - template - void func(member*) {} - - void test(); - - void test() { - func(0); - } - } - - // Check for C++14 attribute support - void noret [[noreturn]] () { throw 0; } - -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - eval $cachevar=yes -else - eval $cachevar=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CXXFLAGS="$ac_save_CXXFLAGS" -fi -eval ac_res=\$$cachevar - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" - ac_success=yes - break - fi - done - fi - - if test x$ac_success = xno; then - for switch in -std=c++14 -std=c++1y +std=c++14 "-h std=c++14"; do - cachevar=`$as_echo "ax_cv_cxx_compile_cxx14_$switch" | $as_tr_sh` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++14 features with $switch" >&5 -$as_echo_n "checking whether $CXX supports C++14 features with $switch... " >&6; } -if eval \${$cachevar+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - template - struct check - { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); - }; - - struct Base { - virtual void f() {} - }; - struct Child : public Base { - virtual void f() override {} - }; - - typedef check> right_angle_brackets; - - int a; - decltype(a) b; - - typedef check check_type; - check_type c; - check_type&& cr = static_cast(c); - - auto d = a; - auto l = [](){}; - // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] - struct use_l { use_l() { l(); } }; - - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this - namespace test_template_alias_sfinae { - struct foo {}; - - template - using member = typename T::member_type; - - template - void func(...) {} - - template - void func(member*) {} - - void test(); - - void test() { - func(0); - } - } - - // Check for C++14 attribute support - void noret [[noreturn]] () { throw 0; } - -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - eval $cachevar=yes -else - eval $cachevar=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CXXFLAGS="$ac_save_CXXFLAGS" -fi -eval ac_res=\$$cachevar - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" - ac_success=yes - break - fi - done - fi - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - if test x$ax_cxx_compile_cxx14_required = xtrue; then - if test x$ac_success = xno; then - as_fn_error $? "*** A compiler with support for C++14 language features is required." "$LINENO" 5 - fi - else - if test x$ac_success = xno; then - HAVE_CXX14=0 - { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++14 support was found" >&5 -$as_echo "$as_me: No compiler with C++14 support was found" >&6;} - else - HAVE_CXX14=1 - -$as_echo "#define HAVE_CXX14 1" >>confdefs.h - - fi - - - fi - - - -# -# Test for Package Config -# -# Extract the first word of "pkg-config", so it can be a program name with args. -set dummy pkg-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_PKG_CONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac -fi -PKG_CONFIG=$ac_cv_path_PKG_CONFIG -if test -n "$PKG_CONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -$as_echo "$PKG_CONFIG" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -if test "x$PKG_CONFIG" = "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find pkg-config, will not create pc file." >&5 -$as_echo "$as_me: WARNING: Could not find pkg-config, will not create pc file." >&2;} -else - # we need sed to find the pkg-config lib directory - # Extract the first word of "sed", so it can be a program name with args. -set dummy sed; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_SED+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$SED"; then - ac_cv_prog_SED="$SED" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_SED="sed" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_prog_SED" && ac_cv_prog_SED="as_fn_error $? "You Must install sed" "$LINENO" 5" -fi -fi -SED=$ac_cv_prog_SED -if test -n "$SED"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5 -$as_echo "$SED" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pkg-config library dir" >&5 -$as_echo_n "checking for pkg-config library dir... " >&6; } - PKGCONFIG_LIBDIR="`echo $PKG_CONFIG | $SED -e 's~.*/bin/pkg-config$~~'`${libdir}/pkgconfig" - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG_LIBDIR" >&5 -$as_echo "$PKGCONFIG_LIBDIR" >&6; } - - ac_config_files="$ac_config_files libblepp.pc" - - - # This will be put into the pc file - VERSION=version-0.5 - -fi - -a=1 -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 -$as_echo_n "checking how to run the C++ preprocessor... " >&6; } -if test -z "$CXXCPP"; then - if ${ac_cv_prog_CXXCPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CXXCPP needs to be expanded - for CXXCPP in "$CXX -E" "/lib/cpp" - do - ac_preproc_ok=false -for ac_cxx_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_cxx_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_cxx_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - - done - ac_cv_prog_CXXCPP=$CXXCPP - -fi - CXXCPP=$ac_cv_prog_CXXCPP -else - ac_cv_prog_CXXCPP=$CXXCPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 -$as_echo "$CXXCPP" >&6; } -ac_preproc_ok=false -for ac_cxx_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_cxx_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_cxx_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } -fi - -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_cxx_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "#define STDC_HEADERS 1" >>confdefs.h - -fi - -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_cxx_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - -ac_fn_cxx_check_header_mongrel "$LINENO" "bluetooth/bluetooth.h" "ac_cv_header_bluetooth_bluetooth_h" "$ac_includes_default" -if test "x$ac_cv_header_bluetooth_bluetooth_h" = xyes; then : - -else - a=0 -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing hci_open_dev" >&5 -$as_echo_n "checking for library containing hci_open_dev... " >&6; } -if ${ac_cv_search_hci_open_dev+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char hci_open_dev (); -int -main () -{ -return hci_open_dev (); - ; - return 0; -} -_ACEOF -for ac_lib in '' bluetooth; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_cxx_try_link "$LINENO"; then : - ac_cv_search_hci_open_dev=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_hci_open_dev+:} false; then : - break -fi -done -if ${ac_cv_search_hci_open_dev+:} false; then : - -else - ac_cv_search_hci_open_dev=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_hci_open_dev" >&5 -$as_echo "$ac_cv_search_hci_open_dev" >&6; } -ac_res=$ac_cv_search_hci_open_dev -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -else - a=0 -fi - - -if test x$a == x0 -then - as_fn_error $? "bluez bluetooth missing" "$LINENO" 5 -fi - -ac_fn_cxx_check_header_mongrel "$LINENO" "boost/optional.hpp" "ac_cv_header_boost_optional_hpp" "$ac_includes_default" -if test "x$ac_cv_header_boost_optional_hpp" = xyes; then : - -else - as_fn_error $? "boost::optional missing" "$LINENO" 5 -fi - - - - - - - if test "" == "" - then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler flag -fPIC works" >&5 -$as_echo_n "checking if compiler flag -fPIC works... " >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking " >&5 -$as_echo_n "checking ... " >&6; } - fi - save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS -fPIC" - - - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(){} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - cvd_conf_test=1 -else - cvd_conf_test=0 -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - - - - - if test $cvd_conf_test = 1 - then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - ts_success=yes - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CXXFLAGS="$save_CXXFLAGS" - ts_success=no - fi - - -ac_config_files="$ac_config_files Makefile" - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -# Transform confdefs.h into DEFS. -# Protect against shell expansion while executing Makefile rules. -# Protect against Makefile macro expansion. -# -# If the first sed substitution is executed (which looks for macros that -# take arguments), then branch to the quote section. Otherwise, -# look for a macro that doesn't take arguments. -ac_script=' -:mline -/\\$/{ - N - s,\\\n,, - b mline -} -t clear -:clear -s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g -t quote -s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g -t quote -b any -:quote -s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g -s/\[/\\&/g -s/\]/\\&/g -s/\$/$$/g -H -:any -${ - g - s/^\n// - s/\n/ /g - p -} -' -DEFS=`sed -n "$ac_script" confdefs.h` - - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - - -: "${CONFIG_STATUS=./config.status}" -ac_write_fail=0 -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -exec 6>&1 -## ----------------------------------- ## -## Main body of $CONFIG_STATUS script. ## -## ----------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by libble++ $as_me version-0.5, which was -generated by GNU Autoconf 2.69. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - - - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - -Configuration files: -$config_files - -Report bugs to the package provider." - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" -ac_cs_version="\\ -libble++ config.status version-0.5 -configured by $0, generated by GNU Autoconf 2.69, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2012 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -test -n "\$AWK" || AWK=awk -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h | --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - $as_echo "$ac_log" -} >&5 - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "libblepp.pc") CONFIG_FILES="$CONFIG_FILES libblepp.pc" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >$CONFIG_STATUS || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - - -eval set X " :F $CONFIG_FILES " -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when `$srcdir' = `.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - - - - esac - -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_files=$ac_clean_files_save - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - - diff --git a/vendor/libblepp-master/configure.ac b/vendor/libblepp-master/configure.ac deleted file mode 100644 index 56907e9..0000000 --- a/vendor/libblepp-master/configure.ac +++ /dev/null @@ -1,111 +0,0 @@ -AC_INIT(libble++, version-0.5) -AC_COPYRIGHT([E. Rosten, 2016, the BlueZ contributors to 2016]) -AC_LANG(C++) -AC_PROG_CXX - - -m4_include([m4/ax_cxx_compile_stdcxx_14.m4]) - - -################################################################################ -# -# Useful macros -# - -dnl APPEND(var, value) -dnl This appends vale to a shell variable var -define(APPEND, [$1="$$1 $2"]) - - - -dnl TEST_AND_SET_CXXFLAG(flag, [program], [run]) -dnl -dnl This attempts to compile a and run program with a certain compiler flag. -dnl If no program is given, then the minimal C++ program is compiled, and -dnl this tests just the validity of the compiler flag. -dnl -define([TEST_AND_SET_CXXFLAG],[ - if test "$3" == "" - then - AC_MSG_CHECKING([if compiler flag $1 works]) - else - AC_MSG_CHECKING([$3]) - fi - save_CXXFLAGS="$CXXFLAGS" - APPEND(CXXFLAGS, [$1]) - - m4_if([$2],[],[pushdef(prog, [int main(){}])], [pushdef(prog, [$2])]) - - m4_if([$4],[run], - [AC_RUN_IFELSE([AC_LANG_SOURCE([prog])], [cvd_conf_test=1],[cvd_conf_test=0], [cvd_conf_test=0])], - [AC_COMPILE_IFELSE([AC_LANG_SOURCE([prog])], [cvd_conf_test=1],[cvd_conf_test=0])] - ) - - - popdef([prog]) - - if test $cvd_conf_test = 1 - then - AC_MSG_RESULT(yes) - ts_success=yes - else - AC_MSG_RESULT(no) - CXXFLAGS="$save_CXXFLAGS" - ts_success=no - fi -]) - - -dnl Add flags, but only if the flags weren't specified. -if test "$CXXFLAGS" == "-g -O2" -then - - TEST_AND_SET_CXXFLAG(-Wall) - TEST_AND_SET_CXXFLAG(-Wextra) - TEST_AND_SET_CXXFLAG(-W) - TEST_AND_SET_CXXFLAG(-O3) - TEST_AND_SET_CXXFLAG(-ggdb) -fi - -AX_CXX_COMPILE_STDCXX_14 - - -# -# Test for Package Config -# -AC_PATH_PROG(PKG_CONFIG, pkg-config) -if test "x$PKG_CONFIG" = "x"; then - AC_MSG_WARN([Could not find pkg-config, will not create pc file.]) -else - # we need sed to find the pkg-config lib directory - AC_CHECK_PROG(SED,sed,sed,AC_MSG_ERROR([You Must install sed])) - AC_MSG_CHECKING([for pkg-config library dir]) - PKGCONFIG_LIBDIR="`echo $PKG_CONFIG | $SED -e 's~.*/bin/pkg-config$~~'`${libdir}/pkgconfig" - - AC_MSG_RESULT($PKGCONFIG_LIBDIR) - AC_SUBST(PKGCONFIG_LIBDIR) - AC_CONFIG_FILES([ libblepp.pc ]) - - # This will be put into the pc file - VERSION=AC_PACKAGE_VERSION() - AC_SUBST(VERSION) -fi - -a=1 -AC_CHECK_HEADER(bluetooth/bluetooth.h, [ ], [a=0]) -AC_SEARCH_LIBS(hci_open_dev, bluetooth, [ ], [a=0]) - -if test x$a == x0 -then - AC_ERROR([bluez bluetooth missing]) -fi - -AC_CHECK_HEADER(boost/optional.hpp, [ ], [AC_ERROR([boost::optional missing])]) - - - -TEST_AND_SET_CXXFLAG(-fPIC) -dnl TEST_AND_SET_CXXFLAG(-Werror) - -AC_OUTPUT(Makefile) - diff --git a/vendor/libblepp-master/cxxgplot.h b/vendor/libblepp-master/cxxgplot.h deleted file mode 100644 index dc36419..0000000 --- a/vendor/libblepp-master/cxxgplot.h +++ /dev/null @@ -1,159 +0,0 @@ -#include "pstreams/pstream.h" -#include -#include -#include -#include - -//Super simple and stupid class for interactive -//plotting and visualisation from C++ using gnuplot -namespace cplot -{ - //A plot contains multiple axes - // A plot has a single location so axes are overlaid - // - //Axes contain multiple lines - - - class Plotter - { - //std::vector plots; - - std::vector plots, pdata, extra; - redi::opstream plot; - - public: - - std::string range; - - Plotter() - :plot("gnuplot") - { - plot << "set term x11 noraise\n"; - newline(""); - } - - - std::ostream& s() - { - return plot; - } - - void add_extra(const std::string& s) - { - extra.push_back(s); - } - - Plotter& newline(const std::string& ps) - { - plots.push_back(ps); - pdata.push_back(""); - return *this; - } - - template Plotter& addpt(const C& pt) - { - using std::isfinite; - std::ostringstream o; - - if(isfinite(pt)) - o << pt << std::endl; - else - skip(); - - pdata.back() += o.str(); - return *this; - } - - template Plotter& addpt(C p1, C p2) - { - using std::isfinite; - std::ostringstream o; - - if(isfinite(p1) && isfinite(p2)) - o << p1 << " " << p2 << std::endl; - else - skip(); - - pdata.back() += o.str(); - return *this; - } - - template Plotter& addpts(const D& pt) - { - using std::isfinite; - std::ostringstream o; - for(unsigned int i=0; i < pt.size(); i++) - if(isfinite(pt[i])) - o << pt[i] << std::endl; - else - skip(); - - pdata.back() += o.str(); - return *this; - } - - Plotter& skip() - { - pdata.back() += "\n"; - return *this; - } - - void draw() - { - using std::cerr; - using std::endl; - - bool data=0; - - //Check for data - std::vector have_data(plots.size()); - for(unsigned int i=0; i < plots.size(); i++) - for(unsigned int j=0; j < pdata[i].size(); j++) - if(!std::isspace(pdata[i][j])) - { - have_data[i] = 1; - data=1; - break; - } - - for(unsigned int i=0, first=1; i < plots.size(); i++) - if(have_data[i]) - { - if(first) - { - plot << "plot " << range << " \"-\""; - first=0; - } - else - { - plot << ", \"-\""; - } - - if(plots[i] != "") - { - plot << " with " << plots[i]; - } - } - - if(data) - plot << std::endl; - for(unsigned int i=0; i < plots.size(); i++) - if(have_data[i]) - { - plot << pdata[i] << "e\n"; - } - - if(data) - plot << std::flush; - - for(unsigned int i=0; i < extra.size(); i++) - plot << extra[i] << "\n"; - - - plots.clear(); - extra.clear(); - pdata.clear(); - newline(""); - } - }; -} diff --git a/vendor/libblepp-master/get_attrs.sh b/vendor/libblepp-master/get_attrs.sh deleted file mode 100644 index a448ae5..0000000 --- a/vendor/libblepp-master/get_attrs.sh +++ /dev/null @@ -1,11 +0,0 @@ -mkdir attrs -cd attrs -mkdir services - -wget https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx - -awk -vFPAT='org.bluetooth.service.[a-z_]*' '{ - for(i=1; i <= NF; i++) - print $i - -}' ServicesHome.aspx | sed -e's!.*!wget -O services/&.xml https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=&.xml!' | parallel 50 diff --git a/vendor/libblepp-master/hex2ascii.awk b/vendor/libblepp-master/hex2ascii.awk deleted file mode 100644 index c7c3b5f..0000000 --- a/vendor/libblepp-master/hex2ascii.awk +++ /dev/null @@ -1,31 +0,0 @@ -BEGIN{ - for(i=0; i < 256; i++) - { - hex2c[sprintf("%02x", i)]=sprintf("%c", i) - hex2c[sprintf("%02X", i)]=sprintf("%c", i) - hex2c[sprintf("%x", i)]=sprintf("%c", i) - hex2c[sprintf("%X", i)]=sprintf("%c", i) - - hex2n[sprintf("%02x", i)]=sprintf("%i", i) - hex2n[sprintf("%02X", i)]=sprintf("%i", i) - hex2n[sprintf("%x", i)]=sprintf("%i", i) - hex2n[sprintf("%X", i)]=sprintf("%i", i) - } -} - -{ - for(i=1; i <= NF; i++) - if($i in hex2c) - printf("%s", hex2c[$i]) - else - printf("--%s--", $i) - - print "" - for(i=1; i <= NF; i++) - if($i in hex2c) - printf("%s ", hex2n[$i]) - else - printf("--%s-- ", $i) - - print "" -} diff --git a/vendor/libblepp-master/lescan.cc b/vendor/libblepp-master/lescan.cc deleted file mode 100644 index 5de0ae2..0000000 --- a/vendor/libblepp-master/lescan.cc +++ /dev/null @@ -1,133 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include //for UUID. FIXME mofo -#include - -using namespace std; -using namespace BLEPP; - -void catch_function(int) -{ - cerr << "\nInterrupted!\n"; -} - -int main(int argc, char** argv) -{ - HCIScanner::ScanType type = HCIScanner::ScanType::Active; - HCIScanner::FilterDuplicates filter = HCIScanner::FilterDuplicates::Software; - int c; - string help = R"X(-[sHbdhp]: - -s software filtering of duplicates (default) - -H hardware filtering of duplicates - -b both hardware and software filtering - -d show duplicates (no filtering) - -h show this message - -p passive scan -)X"; - while((c=getopt(argc, argv, "sHbdhp")) != -1) - { - if(c == 'p') - type = HCIScanner::ScanType::Passive; - else if(c == 's') - filter = HCIScanner::FilterDuplicates::Software; - else if(c == 'H') - filter = HCIScanner::FilterDuplicates::Hardware; - else if(c == 'b') - filter = HCIScanner::FilterDuplicates::Both; - else if(c == 'd') - filter = HCIScanner::FilterDuplicates::Off; - else if(c == 'h') - { - cout << "Usage: " << argv[0] << " " << help; - return 0; - } - else - { - cerr << argv[0] << ": unknown option " << c << endl; - return 1; - } - } - - - log_level = LogLevels::Warning; - HCIScanner scanner(true, filter, type); - - //Catch the interrupt signal. If the scanner is not - //cleaned up properly, then it doesn't reset the HCI state. - signal(SIGINT, catch_function); - - //Something to print to demonstrate the timeout. - string throbber="/|\\-"; - - //hide cursor, to make the throbber look nicer. - cout << "[?25l" << flush; - - int i=0; - while (1) { - - - //Check to see if there's anything to read from the HCI - //and wait if there's not. - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 300000; - - fd_set fds; - FD_ZERO(&fds); - FD_SET(scanner.get_fd(), &fds); - int err = select(scanner.get_fd()+1, &fds, NULL, NULL, &timeout); - - //Interrupted, so quit and clean up properly. - if(err < 0 && errno == EINTR) - break; - - if(FD_ISSET(scanner.get_fd(), &fds)) - { - //Only read id there's something to read - vector ads = scanner.get_advertisements(); - - for(const auto& ad: ads) - { - cout << "Found device: " << ad.address << " "; - - if(ad.type == LeAdvertisingEventType::ADV_IND) - cout << "Connectable undirected" << endl; - else if(ad.type == LeAdvertisingEventType::ADV_DIRECT_IND) - cout << "Connectable directed" << endl; - else if(ad.type == LeAdvertisingEventType::ADV_SCAN_IND) - cout << "Scannable " << endl; - else if(ad.type == LeAdvertisingEventType::ADV_NONCONN_IND) - cout << "Non connectable" << endl; - else - cout << "Scan response" << endl; - for(const auto& uuid: ad.UUIDs) - cout << " Service: " << to_str(uuid) << endl; - if(ad.local_name) - cout << " Name: " << ad.local_name->name << endl; - } - } - else - cout << throbber[i%4] << "\b" << flush; - i++; - } - - //show cursor - cout << "[?25h" << flush; -} diff --git a/vendor/libblepp-master/lescan_simple.cc b/vendor/libblepp-master/lescan_simple.cc deleted file mode 100644 index bf2f79d..0000000 --- a/vendor/libblepp-master/lescan_simple.cc +++ /dev/null @@ -1,10 +0,0 @@ -#include - -int main() -{ - BLEPP::log_level = BLEPP::LogLevels::Info; - BLEPP::HCIScanner scanner; - while (1) { - std::vector ads = scanner.get_advertisements(); - } -} diff --git a/vendor/libblepp-master/libblepp.pc.in b/vendor/libblepp-master/libblepp.pc.in deleted file mode 100644 index 116c388..0000000 --- a/vendor/libblepp-master/libblepp.pc.in +++ /dev/null @@ -1,8 +0,0 @@ -prefix=@prefix@ -includedir=@includedir@ - -Name: libble++ -Description: Bluetooth LE interface for C++ -Version: @VERSION@ -Libs: @LIBS@ -Cflags: -I${includedir} diff --git a/vendor/libblepp-master/m4/ax_cxx_compile_stdcxx_14.m4 b/vendor/libblepp-master/m4/ax_cxx_compile_stdcxx_14.m4 deleted file mode 100644 index 8792fe1..0000000 --- a/vendor/libblepp-master/m4/ax_cxx_compile_stdcxx_14.m4 +++ /dev/null @@ -1,173 +0,0 @@ -# ============================================================================ -# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_14.html -# ============================================================================ -# -# SYNOPSIS -# -# AX_CXX_COMPILE_STDCXX_14([ext|noext],[mandatory|optional]) -# -# DESCRIPTION -# -# Check for baseline language coverage in the compiler for the C++14 -# standard; if necessary, add switches to CXXFLAGS to enable support. -# -# The first argument, if specified, indicates whether you insist on an -# extended mode (e.g. -std=gnu++14) or a strict conformance mode (e.g. -# -std=c++14). If neither is specified, you get whatever works, with -# preference for an extended mode. -# -# The second argument, if specified 'mandatory' or if left unspecified, -# indicates that baseline C++14 support is required and that the macro -# should error out if no mode with that support is found. If specified -# 'optional', then configuration proceeds regardless, after defining -# HAVE_CXX14 if and only if a supporting mode is found. -# -# LICENSE -# -# Copyright (c) 2008 Benjamin Kosnik -# Copyright (c) 2012 Zack Weinberg -# Copyright (c) 2013 Roy Stogner -# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov -# Copyright (c) 2015 Paul Norman -# Copyright (c) 2016 Edward Rosten -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 13 - -m4_define([_AX_CXX_COMPILE_STDCXX_14_testbody], [[ - template - struct check - { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); - }; - - struct Base { - virtual void f() {} - }; - struct Child : public Base { - virtual void f() override {} - }; - - typedef check> right_angle_brackets; - - int a; - decltype(a) b; - - typedef check check_type; - check_type c; - check_type&& cr = static_cast(c); - - auto d = a; - auto l = [](){}; - // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] - struct use_l { use_l() { l(); } }; - - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this - namespace test_template_alias_sfinae { - struct foo {}; - - template - using member = typename T::member_type; - - template - void func(...) {} - - template - void func(member*) {} - - void test(); - - void test() { - func(0); - } - } - - // Check for C++14 attribute support - void noret [[noreturn]] () { throw 0; } -]]) - -AC_DEFUN([AX_CXX_COMPILE_STDCXX_14], [dnl - m4_if([$1], [], [], - [$1], [ext], [], - [$1], [noext], [], - [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_14])])dnl - m4_if([$2], [], [ax_cxx_compile_cxx14_required=true], - [$2], [mandatory], [ax_cxx_compile_cxx14_required=true], - [$2], [optional], [ax_cxx_compile_cxx14_required=false], - [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_14])]) - AC_LANG_PUSH([C++])dnl - ac_success=no - AC_CACHE_CHECK(whether $CXX supports C++14 features by default, - ax_cv_cxx_compile_cxx14, - [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_14_testbody])], - [ax_cv_cxx_compile_cxx14=yes], - [ax_cv_cxx_compile_cxx14=no])]) - if test x$ax_cv_cxx_compile_cxx14 = xyes; then - ac_success=yes - fi - - m4_if([$1], [noext], [], [dnl - if test x$ac_success = xno; then - for switch in -std=gnu++14 -std=gnu++1y; do - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx14_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++14 features with $switch, - $cachevar, - [ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_14_testbody])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXXFLAGS="$ac_save_CXXFLAGS"]) - if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" - ac_success=yes - break - fi - done - fi]) - - m4_if([$1], [ext], [], [dnl - if test x$ac_success = xno; then - dnl HP's aCC needs +std=c++14 according to: - dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf - dnl Cray's crayCC needs "-h std=c++14" - for switch in -std=c++14 -std=c++1y +std=c++14 "-h std=c++14"; do - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx14_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++14 features with $switch, - $cachevar, - [ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_14_testbody])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXXFLAGS="$ac_save_CXXFLAGS"]) - if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" - ac_success=yes - break - fi - done - fi]) - AC_LANG_POP([C++]) - if test x$ax_cxx_compile_cxx14_required = xtrue; then - if test x$ac_success = xno; then - AC_MSG_ERROR([*** A compiler with support for C++14 language features is required.]) - fi - else - if test x$ac_success = xno; then - HAVE_CXX14=0 - AC_MSG_NOTICE([No compiler with C++14 support was found]) - else - HAVE_CXX14=1 - AC_DEFINE(HAVE_CXX14,1, - [define if the compiler supports basic C++14 syntax]) - fi - - AC_SUBST(HAVE_CXX14) - fi -]) diff --git a/vendor/libblepp-master/primary_service_names.cc b/vendor/libblepp-master/primary_service_names.cc deleted file mode 100644 index 170df9e..0000000 --- a/vendor/libblepp-master/primary_service_names.cc +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - -"Alert Notification Service", "org.bluetooth.service.alert_notification", 0x1811 -"Battery Service", "org.bluetooth.service.battery_service", 0x180F -"Blood Pressure", "org.bluetooth.service.blood_pressure", 0x1810 -"Body Composition", "org.bluetooth.service.body_composition", 0x181B -"Bond Management", "org.bluetooth.service.bond_management", 0x181E -"Current Time Service", "org.bluetooth.service.current_time", 0x1805 -"Cycling Power", "org.bluetooth.service.cycling_power", 0x1818 -"Cycling Speed and Cadence", "org.bluetooth.service.cycling_speed_and_cadence", 0x1816 -"Device Information", "org.bluetooth.service.device_information", 0x180A -"Generic Access", "org.bluetooth.service.generic_access", 0x1800 -"Generic Attribute", "org.bluetooth.service.generic_attribute", 0x1801 -"Glucose", "org.bluetooth.service.glucose", 0x1808 -"Health Thermometer", "org.bluetooth.service.health_thermometer", 0x1809 -"Heart Rate", "org.bluetooth.service.heart_rate", 0x180D -"Human Interface Device", "org.bluetooth.service.human_interface_device", 0x1812 -"Immediate Alert", "org.bluetooth.service.immediate_alert", 0x1802 -"Link Loss", "org.bluetooth.service.link_loss", 0x1803 -"Location and Navigation", "org.bluetooth.service.location_and_navigation", 0x1819 -"Next DST Change Service", "org.bluetooth.service.next_dst_change", 0x1807 -"Phone Alert Status Service", "org.bluetooth.service.phone_alert_status", 0x180E -"Reference Time Update Service", "org.bluetooth.service.reference_time_update", 0x1806 -"Running Speed and Cadence", "org.bluetooth.service.running_speed_and_cadence", 0x1814 -"Scan Parameters", "org.bluetooth.service.scan_parameters", 0x1813 -"Tx Power", "org.bluetooth.service.tx_power", 0x1804 -"User Data", "org.bluetooth.service.user_data", 0x181C -"Weight Scale", "org.bluetooth.service.weight_scale", 0x181D diff --git a/vendor/libblepp-master/pstreams/pstream.h b/vendor/libblepp-master/pstreams/pstream.h deleted file mode 100644 index c0a1f96..0000000 --- a/vendor/libblepp-master/pstreams/pstream.h +++ /dev/null @@ -1,2095 +0,0 @@ -/* $Id: pstream.h,v 1.112 2010/03/20 14:50:47 redi Exp $ -PStreams - POSIX Process I/O for C++ -Copyright (C) 2001,2002,2003,2004,2005,2006,2007,2008 Jonathan Wakely - -This file is part of PStreams. - -PStreams is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or -(at your option) any later version. - -PStreams is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program. If not, see . -*/ - -/** - * @file pstream.h - * @brief Declares all PStreams classes. - * @author Jonathan Wakely - * - * Defines classes redi::ipstream, redi::opstream, redi::pstream - * and redi::rpstream. - */ - -#ifndef REDI_PSTREAM_H_SEEN -#define REDI_PSTREAM_H_SEEN - -#include -#include -#include -#include -#include -#include -#include // for min() -#include // for errno -#include // for size_t -#include // for exit() -#include // for pid_t -#include // for waitpid() -#include // for ioctl() and FIONREAD -#if defined(__sun) -# include // for FIONREAD on Solaris 2.5 -#endif -#include // for pipe() fork() exec() and filedes functions -#include // for kill() -#include // for fcntl() -#if REDI_EVISCERATE_PSTREAMS -# include // for FILE, fdopen() -#endif - - -/// The library version. -#define PSTREAMS_VERSION 0x0070 // 0.7.0 - -/** - * @namespace redi - * @brief All PStreams classes are declared in namespace redi. - * - * Like the standard iostreams, PStreams is a set of class templates, - * taking a character type and traits type. As with the standard streams - * they are most likely to be used with @c char and the default - * traits type, so typedefs for this most common case are provided. - * - * The @c pstream_common class template is not intended to be used directly, - * it is used internally to provide the common functionality for the - * other stream classes. - */ -namespace redi -{ - /// Common base class providing constants and typenames. - struct pstreams - { - /// Type used to specify how to connect to the process. - typedef std::ios_base::openmode pmode; - - /// Type used to hold the arguments for a command. - typedef std::vector argv_type; - - /// Type used for file descriptors. - typedef int fd_type; - - static const pmode pstdin = std::ios_base::out; ///< Write to stdin - static const pmode pstdout = std::ios_base::in; ///< Read from stdout - static const pmode pstderr = std::ios_base::app; ///< Read from stderr - - protected: - enum { bufsz = 32 }; ///< Size of pstreambuf buffers. - enum { pbsz = 2 }; ///< Number of putback characters kept. - }; - - /// Class template for stream buffer. - template > - class basic_pstreambuf - : public std::basic_streambuf - , public pstreams - { - public: - // Type definitions for dependent types - typedef CharT char_type; - typedef Traits traits_type; - typedef typename traits_type::int_type int_type; - typedef typename traits_type::off_type off_type; - typedef typename traits_type::pos_type pos_type; - /** @deprecated use pstreams::fd_type instead. */ - typedef fd_type fd_t; - - /// Default constructor. - basic_pstreambuf(); - - /// Constructor that initialises the buffer with @a command. - basic_pstreambuf(const std::string& command, pmode mode); - - /// Constructor that initialises the buffer with @a file and @a argv. - basic_pstreambuf( const std::string& file, - const argv_type& argv, - pmode mode ); - - /// Destructor. - ~basic_pstreambuf(); - - /// Initialise the stream buffer with @a command. - basic_pstreambuf* - open(const std::string& command, pmode mode); - - /// Initialise the stream buffer with @a file and @a argv. - basic_pstreambuf* - open(const std::string& file, const argv_type& argv, pmode mode); - - /// Close the stream buffer and wait for the process to exit. - basic_pstreambuf* - close(); - - /// Send a signal to the process. - basic_pstreambuf* - kill(int signal = SIGTERM); - - /// Close the pipe connected to the process' stdin. - void - peof(); - - /// Change active input source. - bool - read_err(bool readerr = true); - - /// Report whether the stream buffer has been initialised. - bool - is_open() const; - - /// Report whether the process has exited. - bool - exited(); - -#if REDI_EVISCERATE_PSTREAMS - /// Obtain FILE pointers for each of the process' standard streams. - std::size_t - fopen(FILE*& in, FILE*& out, FILE*& err); -#endif - - /// Return the exit status of the process. - int - status() const; - - /// Return the error number (errno) for the most recent failed operation. - int - error() const; - - protected: - /// Transfer characters to the pipe when character buffer overflows. - int_type - overflow(int_type c); - - /// Transfer characters from the pipe when the character buffer is empty. - int_type - underflow(); - - /// Make a character available to be returned by the next extraction. - int_type - pbackfail(int_type c = traits_type::eof()); - - /// Write any buffered characters to the stream. - int - sync(); - - /// Insert multiple characters into the pipe. - std::streamsize - xsputn(const char_type* s, std::streamsize n); - - /// Insert a sequence of characters into the pipe. - std::streamsize - write(const char_type* s, std::streamsize n); - - /// Extract a sequence of characters from the pipe. - std::streamsize - read(char_type* s, std::streamsize n); - - /// Report how many characters can be read from active input without blocking. - std::streamsize - showmanyc(); - - protected: - /// Enumerated type to indicate whether stdout or stderr is to be read. - enum buf_read_src { rsrc_out = 0, rsrc_err = 1 }; - - /// Initialise pipes and fork process. - pid_t - fork(pmode mode); - - /// Wait for the child process to exit. - int - wait(bool nohang = false); - - /// Return the file descriptor for the output pipe. - fd_type& - wpipe(); - - /// Return the file descriptor for the active input pipe. - fd_type& - rpipe(); - - /// Return the file descriptor for the specified input pipe. - fd_type& - rpipe(buf_read_src which); - - void - create_buffers(pmode mode); - - void - destroy_buffers(pmode mode); - - /// Writes buffered characters to the process' stdin pipe. - bool - empty_buffer(); - - bool - fill_buffer(bool non_blocking = false); - - /// Return the active input buffer. - char_type* - rbuffer(); - - buf_read_src - switch_read_buffer(buf_read_src); - - private: - basic_pstreambuf(const basic_pstreambuf&); - basic_pstreambuf& operator=(const basic_pstreambuf&); - - void - init_rbuffers(); - - pid_t ppid_; // pid of process - fd_type wpipe_; // pipe used to write to process' stdin - fd_type rpipe_[2]; // two pipes to read from, stdout and stderr - char_type* wbuffer_; - char_type* rbuffer_[2]; - char_type* rbufstate_[3]; - /// Index into rpipe_[] to indicate active source for read operations. - buf_read_src rsrc_; - int status_; // hold exit status of child process - int error_; // hold errno if fork() or exec() fails - }; - - /// Class template for common base class. - template > - class pstream_common - : virtual public std::basic_ios - , virtual public pstreams - { - protected: - typedef basic_pstreambuf streambuf_type; - - typedef pstreams::pmode pmode; - typedef pstreams::argv_type argv_type; - - /// Default constructor. - pstream_common(); - - /// Constructor that initialises the stream by starting a process. - pstream_common(const std::string& command, pmode mode); - - /// Constructor that initialises the stream by starting a process. - pstream_common(const std::string& file, const argv_type& argv, pmode mode); - - /// Pure virtual destructor. - virtual - ~pstream_common() = 0; - - /// Start a process. - void - do_open(const std::string& command, pmode mode); - - /// Start a process. - void - do_open(const std::string& file, const argv_type& argv, pmode mode); - - public: - /// Close the pipe. - void - close(); - - /// Report whether the stream's buffer has been initialised. - bool - is_open() const; - - /// Return the command used to initialise the stream. - const std::string& - command() const; - - /// Return a pointer to the stream buffer. - streambuf_type* - rdbuf() const; - -#if REDI_EVISCERATE_PSTREAMS - /// Obtain FILE pointers for each of the process' standard streams. - std::size_t - fopen(FILE*& in, FILE*& out, FILE*& err); -#endif - - protected: - std::string command_; ///< The command used to start the process. - streambuf_type buf_; ///< The stream buffer. - }; - - - /** - * @class basic_ipstream - * @brief Class template for Input PStreams. - * - * Reading from an ipstream reads the command's standard output and/or - * standard error (depending on how the ipstream is opened) - * and the command's standard input is the same as that of the process - * that created the object, unless altered by the command itself. - */ - - template > - class basic_ipstream - : public std::basic_istream - , public pstream_common - , virtual public pstreams - { - typedef std::basic_istream istream_type; - typedef pstream_common pbase_type; - - using pbase_type::buf_; // declare name in this scope - - pmode readable(pmode mode) - { - if (!(mode & (pstdout|pstderr))) - mode |= pstdout; - return mode; - } - - public: - /// Type used to specify how to connect to the process. - typedef typename pbase_type::pmode pmode; - - /// Type used to hold the arguments for a command. - typedef typename pbase_type::argv_type argv_type; - - /// Default constructor, creates an uninitialised stream. - basic_ipstream() - : istream_type(NULL), pbase_type() - { } - - /** - * @brief Constructor that initialises the stream by starting a process. - * - * Initialises the stream buffer by calling do_open() with the supplied - * arguments. - * - * @param command a string containing a shell command. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, pmode) - */ - basic_ipstream(const std::string& command, pmode mode = pstdout) - : istream_type(NULL), pbase_type(command, readable(mode)) - { } - - /** - * @brief Constructor that initialises the stream by starting a process. - * - * Initialises the stream buffer by calling do_open() with the supplied - * arguments. - * - * @param file a string containing the pathname of a program to execute. - * @param argv a vector of argument strings passed to the new program. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, const argv_type&, pmode) - */ - basic_ipstream( const std::string& file, - const argv_type& argv, - pmode mode = pstdout ) - : istream_type(NULL), pbase_type(file, argv, readable(mode)) - { } - - /** - * @brief Destructor. - * - * Closes the stream and waits for the child to exit. - */ - ~basic_ipstream() - { } - - /** - * @brief Start a process. - * - * Calls do_open( @a %command , @a mode|pstdout ). - * - * @param command a string containing a shell command. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, pmode) - */ - void - open(const std::string& command, pmode mode = pstdout) - { - this->do_open(command, readable(mode)); - } - - /** - * @brief Start a process. - * - * Calls do_open( @a file , @a argv , @a mode|pstdout ). - * - * @param file a string containing the pathname of a program to execute. - * @param argv a vector of argument strings passed to the new program. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, const argv_type&, pmode) - */ - void - open( const std::string& file, - const argv_type& argv, - pmode mode = pstdout ) - { - this->do_open(file, argv, readable(mode)); - } - - /** - * @brief Set streambuf to read from process' @c stdout. - * @return @c *this - */ - basic_ipstream& - out() - { - this->buf_.read_err(false); - return *this; - } - - /** - * @brief Set streambuf to read from process' @c stderr. - * @return @c *this - */ - basic_ipstream& - err() - { - this->buf_.read_err(true); - return *this; - } - }; - - - /** - * @class basic_opstream - * @brief Class template for Output PStreams. - * - * Writing to an open opstream writes to the standard input of the command; - * the command's standard output is the same as that of the process that - * created the pstream object, unless altered by the command itself. - */ - - template > - class basic_opstream - : public std::basic_ostream - , public pstream_common - , virtual public pstreams - { - typedef std::basic_ostream ostream_type; - typedef pstream_common pbase_type; - - using pbase_type::buf_; // declare name in this scope - - public: - /// Type used to specify how to connect to the process. - typedef typename pbase_type::pmode pmode; - - /// Type used to hold the arguments for a command. - typedef typename pbase_type::argv_type argv_type; - - /// Default constructor, creates an uninitialised stream. - basic_opstream() - : ostream_type(NULL), pbase_type() - { } - - /** - * @brief Constructor that initialises the stream by starting a process. - * - * Initialises the stream buffer by calling do_open() with the supplied - * arguments. - * - * @param command a string containing a shell command. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, pmode) - */ - basic_opstream(const std::string& command, pmode mode = pstdin) - : ostream_type(NULL), pbase_type(command, mode|pstdin) - { } - - /** - * @brief Constructor that initialises the stream by starting a process. - * - * Initialises the stream buffer by calling do_open() with the supplied - * arguments. - * - * @param file a string containing the pathname of a program to execute. - * @param argv a vector of argument strings passed to the new program. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, const argv_type&, pmode) - */ - basic_opstream( const std::string& file, - const argv_type& argv, - pmode mode = pstdin ) - : ostream_type(NULL), pbase_type(file, argv, mode|pstdin) - { } - - /** - * @brief Destructor - * - * Closes the stream and waits for the child to exit. - */ - ~basic_opstream() { } - - /** - * @brief Start a process. - * - * Calls do_open( @a %command , @a mode|pstdin ). - * - * @param command a string containing a shell command. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, pmode) - */ - void - open(const std::string& command, pmode mode = pstdin) - { - this->do_open(command, mode|pstdin); - } - - /** - * @brief Start a process. - * - * Calls do_open( @a file , @a argv , @a mode|pstdin ). - * - * @param file a string containing the pathname of a program to execute. - * @param argv a vector of argument strings passed to the new program. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, const argv_type&, pmode) - */ - void - open( const std::string& file, - const argv_type& argv, - pmode mode = pstdin) - { - this->do_open(file, argv, mode|pstdin); - } - }; - - - /** - * @class basic_pstream - * @brief Class template for Bidirectional PStreams. - * - * Writing to a pstream opened with @c pmode @c pstdin writes to the - * standard input of the command. - * Reading from a pstream opened with @c pmode @c pstdout and/or @c pstderr - * reads the command's standard output and/or standard error. - * Any of the process' @c stdin, @c stdout or @c stderr that is not - * connected to the pstream (as specified by the @c pmode) - * will be the same as the process that created the pstream object, - * unless altered by the command itself. - */ - template > - class basic_pstream - : public std::basic_iostream - , public pstream_common - , virtual public pstreams - { - typedef std::basic_iostream iostream_type; - typedef pstream_common pbase_type; - - using pbase_type::buf_; // declare name in this scope - - public: - /// Type used to specify how to connect to the process. - typedef typename pbase_type::pmode pmode; - - /// Type used to hold the arguments for a command. - typedef typename pbase_type::argv_type argv_type; - - /// Default constructor, creates an uninitialised stream. - basic_pstream() - : iostream_type(NULL), pbase_type() - { } - - /** - * @brief Constructor that initialises the stream by starting a process. - * - * Initialises the stream buffer by calling do_open() with the supplied - * arguments. - * - * @param command a string containing a shell command. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, pmode) - */ - basic_pstream(const std::string& command, pmode mode = pstdout|pstdin) - : iostream_type(NULL), pbase_type(command, mode) - { } - - /** - * @brief Constructor that initialises the stream by starting a process. - * - * Initialises the stream buffer by calling do_open() with the supplied - * arguments. - * - * @param file a string containing the pathname of a program to execute. - * @param argv a vector of argument strings passed to the new program. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, const argv_type&, pmode) - */ - basic_pstream( const std::string& file, - const argv_type& argv, - pmode mode = pstdout|pstdin ) - : iostream_type(NULL), pbase_type(file, argv, mode) - { } - - /** - * @brief Destructor - * - * Closes the stream and waits for the child to exit. - */ - ~basic_pstream() { } - - /** - * @brief Start a process. - * - * Calls do_open( @a %command , @a mode ). - * - * @param command a string containing a shell command. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, pmode) - */ - void - open(const std::string& command, pmode mode = pstdout|pstdin) - { - this->do_open(command, mode); - } - - /** - * @brief Start a process. - * - * Calls do_open( @a file , @a argv , @a mode ). - * - * @param file a string containing the pathname of a program to execute. - * @param argv a vector of argument strings passed to the new program. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, const argv_type&, pmode) - */ - void - open( const std::string& file, - const argv_type& argv, - pmode mode = pstdout|pstdin ) - { - this->do_open(file, argv, mode); - } - - /** - * @brief Set streambuf to read from process' @c stdout. - * @return @c *this - */ - basic_pstream& - out() - { - this->buf_.read_err(false); - return *this; - } - - /** - * @brief Set streambuf to read from process' @c stderr. - * @return @c *this - */ - basic_pstream& - err() - { - this->buf_.read_err(true); - return *this; - } - }; - - - /** - * @class basic_rpstream - * @brief template for Restricted PStreams. - * - * Writing to an rpstream opened with @c pmode @c pstdin writes to the - * standard input of the command. - * It is not possible to read directly from an rpstream object, to use - * an rpstream as in istream you must call either basic_rpstream::out() - * or basic_rpstream::err(). This is to prevent accidental reads from - * the wrong input source. If the rpstream was not opened with @c pmode - * @c pstderr then the class cannot read the process' @c stderr, and - * basic_rpstream::err() will return an istream that reads from the - * process' @c stdout, and vice versa. - * Reading from an rpstream opened with @c pmode @c pstdout and/or - * @c pstderr reads the command's standard output and/or standard error. - * Any of the process' @c stdin, @c stdout or @c stderr that is not - * connected to the pstream (as specified by the @c pmode) - * will be the same as the process that created the pstream object, - * unless altered by the command itself. - */ - - template > - class basic_rpstream - : public std::basic_ostream - , private std::basic_istream - , private pstream_common - , virtual public pstreams - { - typedef std::basic_ostream ostream_type; - typedef std::basic_istream istream_type; - typedef pstream_common pbase_type; - - using pbase_type::buf_; // declare name in this scope - - public: - /// Type used to specify how to connect to the process. - typedef typename pbase_type::pmode pmode; - - /// Type used to hold the arguments for a command. - typedef typename pbase_type::argv_type argv_type; - - /// Default constructor, creates an uninitialised stream. - basic_rpstream() - : ostream_type(NULL), istream_type(NULL), pbase_type() - { } - - /** - * @brief Constructor that initialises the stream by starting a process. - * - * Initialises the stream buffer by calling do_open() with the supplied - * arguments. - * - * @param command a string containing a shell command. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, pmode) - */ - basic_rpstream(const std::string& command, pmode mode = pstdout|pstdin) - : ostream_type(NULL) , istream_type(NULL) , pbase_type(command, mode) - { } - - /** - * @brief Constructor that initialises the stream by starting a process. - * - * Initialises the stream buffer by calling do_open() with the supplied - * arguments. - * - * @param file a string containing the pathname of a program to execute. - * @param argv a vector of argument strings passed to the new program. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, const argv_type&, pmode) - */ - basic_rpstream( const std::string& file, - const argv_type& argv, - pmode mode = pstdout|pstdin ) - : ostream_type(NULL), istream_type(NULL), pbase_type(file, argv, mode) - { } - - /// Destructor - ~basic_rpstream() { } - - /** - * @brief Start a process. - * - * Calls do_open( @a %command , @a mode ). - * - * @param command a string containing a shell command. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, pmode) - */ - void - open(const std::string& command, pmode mode = pstdout|pstdin) - { - this->do_open(command, mode); - } - - /** - * @brief Start a process. - * - * Calls do_open( @a file , @a argv , @a mode ). - * - * @param file a string containing the pathname of a program to execute. - * @param argv a vector of argument strings passed to the new program. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, const argv_type&, pmode) - */ - void - open( const std::string& file, - const argv_type& argv, - pmode mode = pstdout|pstdin ) - { - this->do_open(file, argv, mode); - } - - /** - * @brief Obtain a reference to the istream that reads - * the process' @c stdout. - * @return @c *this - */ - istream_type& - out() - { - this->buf_.read_err(false); - return *this; - } - - /** - * @brief Obtain a reference to the istream that reads - * the process' @c stderr. - * @return @c *this - */ - istream_type& - err() - { - this->buf_.read_err(true); - return *this; - } - }; - - - /// Type definition for common template specialisation. - typedef basic_pstreambuf pstreambuf; - /// Type definition for common template specialisation. - typedef basic_ipstream ipstream; - /// Type definition for common template specialisation. - typedef basic_opstream opstream; - /// Type definition for common template specialisation. - typedef basic_pstream pstream; - /// Type definition for common template specialisation. - typedef basic_rpstream rpstream; - - - /** - * When inserted into an output pstream the manipulator calls - * basic_pstreambuf::peof() to close the output pipe, - * causing the child process to receive the end-of-file indicator - * on subsequent reads from its @c stdin stream. - * - * @brief Manipulator to close the pipe connected to the process' stdin. - * @param s An output PStream class. - * @return The stream object the manipulator was invoked on. - * @see basic_pstreambuf::peof() - * @relates basic_opstream basic_pstream basic_rpstream - */ - template - inline std::basic_ostream& - peof(std::basic_ostream& s) - { - typedef basic_pstreambuf pstreambuf; - if (pstreambuf* p = dynamic_cast(s.rdbuf())) - p->peof(); - return s; - } - - - /* - * member definitions for pstreambuf - */ - - - /** - * @class basic_pstreambuf - * Provides underlying streambuf functionality for the PStreams classes. - */ - - /** Creates an uninitialised stream buffer. */ - template - inline - basic_pstreambuf::basic_pstreambuf() - : ppid_(-1) // initialise to -1 to indicate no process run yet. - , wpipe_(-1) - , wbuffer_(NULL) - , rsrc_(rsrc_out) - , status_(-1) - , error_(0) - { - init_rbuffers(); - } - - /** - * Initialises the stream buffer by calling open() with the supplied - * arguments. - * - * @param command a string containing a shell command. - * @param mode the I/O mode to use when opening the pipe. - * @see open() - */ - template - inline - basic_pstreambuf::basic_pstreambuf(const std::string& command, pmode mode) - : ppid_(-1) // initialise to -1 to indicate no process run yet. - , wpipe_(-1) - , wbuffer_(NULL) - , rsrc_(rsrc_out) - , status_(-1) - , error_(0) - { - init_rbuffers(); - open(command, mode); - } - - /** - * Initialises the stream buffer by calling open() with the supplied - * arguments. - * - * @param file a string containing the name of a program to execute. - * @param argv a vector of argument strings passsed to the new program. - * @param mode the I/O mode to use when opening the pipe. - * @see open() - */ - template - inline - basic_pstreambuf::basic_pstreambuf( const std::string& file, - const argv_type& argv, - pmode mode ) - : ppid_(-1) // initialise to -1 to indicate no process run yet. - , wpipe_(-1) - , wbuffer_(NULL) - , rsrc_(rsrc_out) - , status_(-1) - , error_(0) - { - init_rbuffers(); - open(file, argv, mode); - } - - /** - * Closes the stream by calling close(). - * @see close() - */ - template - inline - basic_pstreambuf::~basic_pstreambuf() - { - close(); - } - - /** - * Starts a new process by passing @a command to the shell (/bin/sh) - * and opens pipes to the process with the specified @a mode. - * - * If @a mode contains @c pstdout the initial read source will be - * the child process' stdout, otherwise if @a mode contains @c pstderr - * the initial read source will be the child's stderr. - * - * Will duplicate the actions of the shell in searching for an - * executable file if the specified file name does not contain a slash (/) - * character. - * - * @warning - * There is no way to tell whether the shell command succeeded, this - * function will always succeed unless resource limits (such as - * memory usage, or number of processes or open files) are exceeded. - * This means is_open() will return true even if @a command cannot - * be executed. - * Use pstreambuf::open(const std::string&, const argv_type&, pmode) - * if you need to know whether the command failed to execute. - * - * @param command a string containing a shell command. - * @param mode a bitwise OR of one or more of @c out, @c in, @c err. - * @return NULL if the shell could not be started or the - * pipes could not be opened, @c this otherwise. - * @see execl(3) - */ - template - basic_pstreambuf* - basic_pstreambuf::open(const std::string& command, pmode mode) - { - const char * shell_path = "/bin/sh"; -#if 0 - const std::string argv[] = { "sh", "-c", command }; - return this->open(shell_path, argv_type(argv, argv+3), mode); -#else - basic_pstreambuf* ret = NULL; - - if (!is_open()) - { - switch(fork(mode)) - { - case 0 : - // this is the new process, exec command - ::execl(shell_path, "sh", "-c", command.c_str(), (char*)NULL); - - // can only reach this point if exec() failed - - // parent can get exit code from waitpid() - ::_exit(errno); - // using std::exit() would make static dtors run twice - - case -1 : - // couldn't fork, error already handled in pstreambuf::fork() - break; - - default : - // this is the parent process - // activate buffers - create_buffers(mode); - ret = this; - } - } - return ret; -#endif - } - - /** - * @brief Helper function to close a file descriptor. - * - * Inspects @a fd and calls close(3) if it has a non-negative value. - * - * @param fd a file descriptor. - * @relates basic_pstreambuf - */ - inline void - close_fd(pstreams::fd_type& fd) - { - if (fd >= 0 && ::close(fd) == 0) - fd = -1; - } - - /** - * @brief Helper function to close an array of file descriptors. - * - * Calls @c close_fd() on each member of the array. - * The length of the array is determined automatically by - * template argument deduction to avoid errors. - * - * @param fds an array of file descriptors. - * @relates basic_pstreambuf - */ - template - inline void - close_fd_array(pstreams::fd_type (&fds)[N]) - { - for (std::size_t i = 0; i < N; ++i) - close_fd(fds[i]); - } - - /** - * Starts a new process by executing @a file with the arguments in - * @a argv and opens pipes to the process with the specified @a mode. - * - * By convention @c argv[0] should be the file name of the file being - * executed. - * - * If @a mode contains @c pstdout the initial read source will be - * the child process' stdout, otherwise if @a mode contains @c pstderr - * the initial read source will be the child's stderr. - * - * Will duplicate the actions of the shell in searching for an - * executable file if the specified file name does not contain a slash (/) - * character. - * - * Iff @a file is successfully executed then is_open() will return true. - * Otherwise, pstreambuf::error() can be used to obtain the value of - * @c errno that was set by execvp(3) in the child process. - * - * The exit status of the new process will be returned by - * pstreambuf::status() after pstreambuf::exited() returns true. - * - * @param file a string containing the pathname of a program to execute. - * @param argv a vector of argument strings passed to the new program. - * @param mode a bitwise OR of one or more of @c out, @c in and @c err. - * @return NULL if a pipe could not be opened or if the program could - * not be executed, @c this otherwise. - * @see execvp(3) - */ - template - basic_pstreambuf* - basic_pstreambuf::open( const std::string& file, - const argv_type& argv, - pmode mode ) - { - basic_pstreambuf* ret = NULL; - - if (!is_open()) - { - // constants for read/write ends of pipe - enum { RD, WR }; - - // open another pipe and set close-on-exec - fd_type ck_exec[] = { -1, -1 }; - if (-1 == ::pipe(ck_exec) - || -1 == ::fcntl(ck_exec[RD], F_SETFD, FD_CLOEXEC) - || -1 == ::fcntl(ck_exec[WR], F_SETFD, FD_CLOEXEC)) - { - error_ = errno; - close_fd_array(ck_exec); - } - else - { - switch(fork(mode)) - { - case 0 : - // this is the new process, exec command - { - char** arg_v = new char*[argv.size()+1]; - for (std::size_t i = 0; i < argv.size(); ++i) - { - const std::string& src = argv[i]; - char*& dest = arg_v[i]; - dest = new char[src.size()+1]; - dest[ src.copy(dest, src.size()) ] = '\0'; - } - arg_v[argv.size()] = NULL; - - ::execvp(file.c_str(), arg_v); - - // can only reach this point if exec() failed - - // parent can get error code from ck_exec pipe - error_ = errno; - - ::write(ck_exec[WR], &error_, sizeof(error_)); - ::close(ck_exec[WR]); - ::close(ck_exec[RD]); - - ::_exit(error_); - // using std::exit() would make static dtors run twice - } - - case -1 : - // couldn't fork, error already handled in pstreambuf::fork() - close_fd_array(ck_exec); - break; - - default : - // this is the parent process - - // check child called exec() successfully - ::close(ck_exec[WR]); - switch (::read(ck_exec[RD], &error_, sizeof(error_))) - { - case 0: - // activate buffers - create_buffers(mode); - ret = this; - break; - case -1: - error_ = errno; - break; - default: - // error_ contains error code from child - // call wait() to clean up and set ppid_ to 0 - this->wait(); - break; - } - ::close(ck_exec[RD]); - } - } - } - return ret; - } - - /** - * Creates pipes as specified by @a mode and calls @c fork() to create - * a new process. If the fork is successful the parent process stores - * the child's PID and the opened pipes and the child process replaces - * its standard streams with the opened pipes. - * - * If an error occurs the error code will be set to one of the possible - * errors for @c pipe() or @c fork(). - * See your system's documentation for these error codes. - * - * @param mode an OR of pmodes specifying which of the child's - * standard streams to connect to. - * @return On success the PID of the child is returned in the parent's - * context and zero is returned in the child's context. - * On error -1 is returned and the error code is set appropriately. - */ - template - pid_t - basic_pstreambuf::fork(pmode mode) - { - pid_t pid = -1; - - // Three pairs of file descriptors, for pipes connected to the - // process' stdin, stdout and stderr - // (stored in a single array so close_fd_array() can close all at once) - fd_type fd[] = { -1, -1, -1, -1, -1, -1 }; - fd_type* const pin = fd; - fd_type* const pout = fd+2; - fd_type* const perr = fd+4; - - // constants for read/write ends of pipe - enum { RD, WR }; - - // N.B. - // For the pstreambuf pin is an output stream and - // pout and perr are input streams. - - if (!error_ && mode&pstdin && ::pipe(pin)) - error_ = errno; - - if (!error_ && mode&pstdout && ::pipe(pout)) - error_ = errno; - - if (!error_ && mode&pstderr && ::pipe(perr)) - error_ = errno; - - if (!error_) - { - pid = ::fork(); - switch (pid) - { - case 0 : - { - // this is the new process - - // for each open pipe close one end and redirect the - // respective standard stream to the other end - - if (*pin >= 0) - { - ::close(pin[WR]); - ::dup2(pin[RD], STDIN_FILENO); - ::close(pin[RD]); - } - if (*pout >= 0) - { - ::close(pout[RD]); - ::dup2(pout[WR], STDOUT_FILENO); - ::close(pout[WR]); - } - if (*perr >= 0) - { - ::close(perr[RD]); - ::dup2(perr[WR], STDERR_FILENO); - ::close(perr[WR]); - } - break; - } - case -1 : - { - // couldn't fork for some reason - error_ = errno; - // close any open pipes - close_fd_array(fd); - break; - } - default : - { - // this is the parent process, store process' pid - ppid_ = pid; - - // store one end of open pipes and close other end - if (*pin >= 0) - { - wpipe_ = pin[WR]; - ::close(pin[RD]); - } - if (*pout >= 0) - { - rpipe_[rsrc_out] = pout[RD]; - ::close(pout[WR]); - } - if (*perr >= 0) - { - rpipe_[rsrc_err] = perr[RD]; - ::close(perr[WR]); - } - } - } - } - else - { - // close any pipes we opened before failure - close_fd_array(fd); - } - return pid; - } - - /** - * Closes all pipes and calls wait() to wait for the process to finish. - * If an error occurs the error code will be set to one of the possible - * errors for @c waitpid(). - * See your system's documentation for these errors. - * - * @return @c this on successful close or @c NULL if there is no - * process to close or if an error occurs. - */ - template - basic_pstreambuf* - basic_pstreambuf::close() - { - const bool running = is_open(); - - sync(); // this might call wait() and reap the child process - - // rather than trying to work out whether or not we need to clean up - // just do it anyway, all cleanup functions are safe to call twice. - - destroy_buffers(pstdin|pstdout|pstderr); - - // close pipes before wait() so child gets EOF/SIGPIPE - close_fd(wpipe_); - close_fd_array(rpipe_); - - do - { - error_ = 0; - } while (wait() == -1 && error() == EINTR); - - return running ? this : NULL; - } - - /** - * Called on construction to initialise the arrays used for reading. - */ - template - inline void - basic_pstreambuf::init_rbuffers() - { - rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1; - rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL; - rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL; - } - - template - void - basic_pstreambuf::create_buffers(pmode mode) - { - if (mode & pstdin) - { - delete[] wbuffer_; - wbuffer_ = new char_type[bufsz]; - this->setp(wbuffer_, wbuffer_ + bufsz); - } - if (mode & pstdout) - { - delete[] rbuffer_[rsrc_out]; - rbuffer_[rsrc_out] = new char_type[bufsz]; - rsrc_ = rsrc_out; - this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz, - rbuffer_[rsrc_out] + pbsz); - } - if (mode & pstderr) - { - delete[] rbuffer_[rsrc_err]; - rbuffer_[rsrc_err] = new char_type[bufsz]; - if (!(mode & pstdout)) - { - rsrc_ = rsrc_err; - this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz, - rbuffer_[rsrc_err] + pbsz); - } - } - } - - template - void - basic_pstreambuf::destroy_buffers(pmode mode) - { - if (mode & pstdin) - { - this->setp(NULL, NULL); - delete[] wbuffer_; - wbuffer_ = NULL; - } - if (mode & pstdout) - { - if (rsrc_ == rsrc_out) - this->setg(NULL, NULL, NULL); - delete[] rbuffer_[rsrc_out]; - rbuffer_[rsrc_out] = NULL; - } - if (mode & pstderr) - { - if (rsrc_ == rsrc_err) - this->setg(NULL, NULL, NULL); - delete[] rbuffer_[rsrc_err]; - rbuffer_[rsrc_err] = NULL; - } - } - - template - typename basic_pstreambuf::buf_read_src - basic_pstreambuf::switch_read_buffer(buf_read_src src) - { - if (rsrc_ != src) - { - char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()}; - this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]); - for (std::size_t i = 0; i < 3; ++i) - rbufstate_[i] = tmpbufstate[i]; - rsrc_ = src; - } - return rsrc_; - } - - /** - * Suspends execution and waits for the associated process to exit, or - * until a signal is delivered whose action is to terminate the current - * process or to call a signal handling function. If the process has - * already exited (i.e. it is a "zombie" process) then wait() returns - * immediately. Waiting for the child process causes all its system - * resources to be freed. - * - * error() will return EINTR if wait() is interrupted by a signal. - * - * @param nohang true to return immediately if the process has not exited. - * @return 1 if the process has exited and wait() has not yet been called. - * 0 if @a nohang is true and the process has not exited yet. - * -1 if no process has been started or if an error occurs, - * in which case the error can be found using error(). - */ - template - int - basic_pstreambuf::wait(bool nohang) - { - int exited = -1; - if (is_open()) - { - int status; - switch(::waitpid(ppid_, &status, nohang ? WNOHANG : 0)) - { - case 0 : - // nohang was true and process has not exited - exited = 0; - break; - case -1 : - error_ = errno; - break; - default : - // process has exited - ppid_ = 0; - status_ = status; - exited = 1; - // Close wpipe, would get SIGPIPE if we used it. - destroy_buffers(pstdin); - close_fd(wpipe_); - // Must free read buffers and pipes on destruction - // or next call to open()/close() - break; - } - } - return exited; - } - - /** - * Sends the specified signal to the process. A signal can be used to - * terminate a child process that would not exit otherwise. - * - * If an error occurs the error code will be set to one of the possible - * errors for @c kill(). See your system's documentation for these errors. - * - * @param signal A signal to send to the child process. - * @return @c this or @c NULL if @c kill() fails. - */ - template - inline basic_pstreambuf* - basic_pstreambuf::kill(int signal) - { - basic_pstreambuf* ret = NULL; - if (is_open()) - { - if (::kill(ppid_, signal)) - error_ = errno; - else - { -#if 0 - // TODO call exited() to check for exit and clean up? leave to user? - if (signal==SIGTERM || signal==SIGKILL) - this->exited(); -#endif - ret = this; - } - } - return ret; - } - - /** - * This function can call pstreambuf::wait() and so may change the - * object's state if the child process has already exited. - * - * @return True if the associated process has exited, false otherwise. - * @see basic_pstreambuf::wait() - */ - template - inline bool - basic_pstreambuf::exited() - { - return ppid_ == 0 || wait(true)==1; - } - - - /** - * @return The exit status of the child process, or -1 if wait() - * has not yet been called to wait for the child to exit. - * @see basic_pstreambuf::wait() - */ - template - inline int - basic_pstreambuf::status() const - { - return status_; - } - - /** - * @return The error code of the most recently failed operation, or zero. - */ - template - inline int - basic_pstreambuf::error() const - { - return error_; - } - - /** - * Closes the output pipe, causing the child process to receive the - * end-of-file indicator on subsequent reads from its @c stdin stream. - */ - template - inline void - basic_pstreambuf::peof() - { - sync(); - destroy_buffers(pstdin); - close_fd(wpipe_); - } - - /** - * Unlike pstreambuf::exited(), this function will not call wait() and - * so will not change the object's state. This means that once a child - * process is executed successfully this function will continue to - * return true even after the process exits (until wait() is called.) - * - * @return true if a previous call to open() succeeded and wait() has - * not been called and determined that the process has exited, - * false otherwise. - */ - template - inline bool - basic_pstreambuf::is_open() const - { - return ppid_ > 0; - } - - /** - * Toggle the stream used for reading. If @a readerr is @c true then the - * process' @c stderr output will be used for subsequent extractions, if - * @a readerr is false the the process' stdout will be used. - * @param readerr @c true to read @c stderr, @c false to read @c stdout. - * @return @c true if the requested stream is open and will be used for - * subsequent extractions, @c false otherwise. - */ - template - inline bool - basic_pstreambuf::read_err(bool readerr) - { - buf_read_src src = readerr ? rsrc_err : rsrc_out; - if (rpipe_[src]>=0) - { - switch_read_buffer(src); - return true; - } - return false; - } - - /** - * Called when the internal character buffer is not present or is full, - * to transfer the buffer contents to the pipe. - * - * @param c a character to be written to the pipe. - * @return @c traits_type::eof() if an error occurs, otherwise if @a c - * is not equal to @c traits_type::eof() it will be buffered and - * a value other than @c traits_type::eof() returned to indicate - * success. - */ - template - typename basic_pstreambuf::int_type - basic_pstreambuf::overflow(int_type c) - { - if (!empty_buffer()) - return traits_type::eof(); - else if (!traits_type::eq_int_type(c, traits_type::eof())) - return this->sputc(c); - else - return traits_type::not_eof(c); - } - - - template - int - basic_pstreambuf::sync() - { - return !exited() && empty_buffer() ? 0 : -1; - } - - /** - * @param s character buffer. - * @param n buffer length. - * @return the number of characters written. - */ - template - std::streamsize - basic_pstreambuf::xsputn(const char_type* s, std::streamsize n) - { - if (n < this->epptr() - this->pptr()) - { - traits_type::copy(this->pptr(), s, n); - this->pbump(n); - return n; - } - else - { - for (std::streamsize i = 0; i < n; ++i) - { - if (traits_type::eq_int_type(this->sputc(s[i]), traits_type::eof())) - return i; - } - return n; - } - } - - /** - * @return true if the buffer was emptied, false otherwise. - */ - template - bool - basic_pstreambuf::empty_buffer() - { - const std::streamsize count = this->pptr() - this->pbase(); - if (count > 0) - { - const std::streamsize written = this->write(this->wbuffer_, count); - if (written > 0) - { - if (const std::streamsize unwritten = count - written) - traits_type::move(this->pbase(), this->pbase()+written, unwritten); - this->pbump(-written); - return true; - } - } - return false; - } - - /** - * Called when the internal character buffer is is empty, to re-fill it - * from the pipe. - * - * @return The first available character in the buffer, - * or @c traits_type::eof() in case of failure. - */ - template - typename basic_pstreambuf::int_type - basic_pstreambuf::underflow() - { - if (this->gptr() < this->egptr() || fill_buffer()) - return traits_type::to_int_type(*this->gptr()); - else - return traits_type::eof(); - } - - /** - * Attempts to make @a c available as the next character to be read by - * @c sgetc(). - * - * @param c a character to make available for extraction. - * @return @a c if the character can be made available, - * @c traits_type::eof() otherwise. - */ - template - typename basic_pstreambuf::int_type - basic_pstreambuf::pbackfail(int_type c) - { - if (this->gptr() != this->eback()) - { - this->gbump(-1); - if (!traits_type::eq_int_type(c, traits_type::eof())) - *this->gptr() = traits_type::to_char_type(c); - return traits_type::not_eof(c); - } - else - return traits_type::eof(); - } - - template - std::streamsize - basic_pstreambuf::showmanyc() - { - int avail = 0; - if (sizeof(char_type) == 1) - avail = fill_buffer(true) ? this->egptr() - this->gptr() : -1; -#ifdef FIONREAD - else - { - if (::ioctl(rpipe(), FIONREAD, &avail) == -1) - avail = -1; - else if (avail) - avail /= sizeof(char_type); - } -#endif - return std::streamsize(avail); - } - - /** - * @return true if the buffer was filled, false otherwise. - */ - template - bool - basic_pstreambuf::fill_buffer(bool non_blocking) - { - const std::streamsize pb1 = this->gptr() - this->eback(); - const std::streamsize pb2 = pbsz; - const std::streamsize npb = std::min(pb1, pb2); - - char_type* const rbuf = rbuffer(); - - traits_type::move(rbuf + pbsz - npb, this->gptr() - npb, npb); - - std::streamsize rc = -1; - - if (non_blocking) - { - const int flags = ::fcntl(rpipe(), F_GETFL); - if (flags != -1) - { - const bool blocking = !(flags & O_NONBLOCK); - if (blocking) - ::fcntl(rpipe(), F_SETFL, flags | O_NONBLOCK); // set non-blocking - - error_ = 0; - rc = read(rbuf + pbsz, bufsz - pbsz); - - if (rc == -1 && error_ == EAGAIN) // nothing available - rc = 0; - else if (rc == 0) // EOF - rc = -1; - - if (blocking) - ::fcntl(rpipe(), F_SETFL, flags); // restore - } - } - else - rc = read(rbuf + pbsz, bufsz - pbsz); - - if (rc > 0 || (rc == 0 && non_blocking)) - { - this->setg( rbuf + pbsz - npb, - rbuf + pbsz, - rbuf + pbsz + rc ); - return true; - } - else - { - this->setg(NULL, NULL, NULL); - return false; - } - } - - /** - * Writes up to @a n characters to the pipe from the buffer @a s. - * - * @param s character buffer. - * @param n buffer length. - * @return the number of characters written. - */ - template - inline std::streamsize - basic_pstreambuf::write(const char_type* s, std::streamsize n) - { - std::streamsize nwritten = 0; - if (wpipe() >= 0) - { - nwritten = ::write(wpipe(), s, n * sizeof(char_type)); - if (nwritten == -1) - error_ = errno; - else - nwritten /= sizeof(char_type); - } - return nwritten; - } - - /** - * Reads up to @a n characters from the pipe to the buffer @a s. - * - * @param s character buffer. - * @param n buffer length. - * @return the number of characters read. - */ - template - inline std::streamsize - basic_pstreambuf::read(char_type* s, std::streamsize n) - { - std::streamsize nread = 0; - if (rpipe() >= 0) - { - nread = ::read(rpipe(), s, n * sizeof(char_type)); - if (nread == -1) - error_ = errno; - else - nread /= sizeof(char_type); - } - return nread; - } - - /** @return a reference to the output file descriptor */ - template - inline typename basic_pstreambuf::fd_type& - basic_pstreambuf::wpipe() - { - return wpipe_; - } - - /** @return a reference to the active input file descriptor */ - template - inline typename basic_pstreambuf::fd_type& - basic_pstreambuf::rpipe() - { - return rpipe_[rsrc_]; - } - - /** @return a reference to the specified input file descriptor */ - template - inline typename basic_pstreambuf::fd_type& - basic_pstreambuf::rpipe(buf_read_src which) - { - return rpipe_[which]; - } - - /** @return a pointer to the start of the active input buffer area. */ - template - inline typename basic_pstreambuf::char_type* - basic_pstreambuf::rbuffer() - { - return rbuffer_[rsrc_]; - } - - - /* - * member definitions for pstream_common - */ - - /** - * @class pstream_common - * Abstract Base Class providing common functionality for basic_ipstream, - * basic_opstream and basic_pstream. - * pstream_common manages the basic_pstreambuf stream buffer that is used - * by the derived classes to initialise an iostream class. - */ - - /** Creates an uninitialised stream. */ - template - inline - pstream_common::pstream_common() - : std::basic_ios(NULL) - , command_() - , buf_() - { - this->init(&buf_); - } - - /** - * Initialises the stream buffer by calling - * do_open( @a command , @a mode ) - * - * @param command a string containing a shell command. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, pmode) - */ - template - inline - pstream_common::pstream_common(const std::string& command, pmode mode) - : std::basic_ios(NULL) - , command_(command) - , buf_() - { - this->init(&buf_); - do_open(command, mode); - } - - /** - * Initialises the stream buffer by calling - * do_open( @a file , @a argv , @a mode ) - * - * @param file a string containing the pathname of a program to execute. - * @param argv a vector of argument strings passed to the new program. - * @param mode the I/O mode to use when opening the pipe. - * @see do_open(const std::string&, const argv_type&, pmode) - */ - template - inline - pstream_common::pstream_common( const std::string& file, - const argv_type& argv, - pmode mode ) - : std::basic_ios(NULL) - , command_(file) - , buf_() - { - this->init(&buf_); - do_open(file, argv, mode); - } - - /** - * This is a pure virtual function to make @c pstream_common abstract. - * Because it is the destructor it will be called by derived classes - * and so must be defined. It is also protected, to discourage use of - * the PStreams classes through pointers or references to the base class. - * - * @sa If defining a pure virtual seems odd you should read - * http://www.gotw.ca/gotw/031.htm (and the rest of the site as well!) - */ - template - inline - pstream_common::~pstream_common() - { - } - - /** - * Calls rdbuf()->open( @a command , @a mode ) - * and sets @c failbit on error. - * - * @param command a string containing a shell command. - * @param mode the I/O mode to use when opening the pipe. - * @see basic_pstreambuf::open(const std::string&, pmode) - */ - template - inline void - pstream_common::do_open(const std::string& command, pmode mode) - { - if (!buf_.open((command_=command), mode)) - this->setstate(std::ios_base::failbit); - } - - /** - * Calls rdbuf()->open( @a file, @a argv, @a mode ) - * and sets @c failbit on error. - * - * @param file a string containing the pathname of a program to execute. - * @param argv a vector of argument strings passed to the new program. - * @param mode the I/O mode to use when opening the pipe. - * @see basic_pstreambuf::open(const std::string&, const argv_type&, pmode) - */ - template - inline void - pstream_common::do_open( const std::string& file, - const argv_type& argv, - pmode mode ) - { - if (!buf_.open((command_=file), argv, mode)) - this->setstate(std::ios_base::failbit); - } - - /** Calls rdbuf->close() and sets @c failbit on error. */ - template - inline void - pstream_common::close() - { - if (!buf_.close()) - this->setstate(std::ios_base::failbit); - } - - /** - * @return rdbuf()->is_open(). - * @see basic_pstreambuf::is_open() - */ - template - inline bool - pstream_common::is_open() const - { - return buf_.is_open(); - } - - /** @return a string containing the command used to initialise the stream. */ - template - inline const std::string& - pstream_common::command() const - { - return command_; - } - - /** @return a pointer to the private stream buffer member. */ - // TODO document behaviour if buffer replaced. - template - inline typename pstream_common::streambuf_type* - pstream_common::rdbuf() const - { - return const_cast(&buf_); - } - - -#if REDI_EVISCERATE_PSTREAMS - /** - * @def REDI_EVISCERATE_PSTREAMS - * If this macro has a non-zero value then certain internals of the - * @c basic_pstreambuf template class are exposed. In general this is - * a Bad Thing, as the internal implementation is largely undocumented - * and may be subject to change at any time, so this feature is only - * provided because it might make PStreams useful in situations where - * it is necessary to do Bad Things. - */ - - /** - * @warning This function exposes the internals of the stream buffer and - * should be used with caution. It is the caller's responsibility - * to flush streams etc. in order to clear any buffered data. - * The POSIX.1 function fdopen(3) is used to obtain the - * @c FILE pointers from the streambuf's private file descriptor - * members so consult your system's documentation for - * fdopen(3). - * - * @param in A FILE* that will refer to the process' stdin. - * @param out A FILE* that will refer to the process' stdout. - * @param err A FILE* that will refer to the process' stderr. - * @return An OR of zero or more of @c pstdin, @c pstdout, @c pstderr. - * - * For each open stream shared with the child process a @c FILE* is - * obtained and assigned to the corresponding parameter. For closed - * streams @c NULL is assigned to the parameter. - * The return value can be tested to see which parameters should be - * @c !NULL by masking with the corresponding @c pmode value. - * - * @see fdopen(3) - */ - template - std::size_t - basic_pstreambuf::fopen(FILE*& in, FILE*& out, FILE*& err) - { - in = out = err = NULL; - std::size_t open_files = 0; - if (wpipe() > -1) - { - if ((in = ::fdopen(wpipe(), "w"))) - { - open_files |= pstdin; - } - } - if (rpipe(rsrc_out) > -1) - { - if ((out = ::fdopen(rpipe(rsrc_out), "r"))) - { - open_files |= pstdout; - } - } - if (rpipe(rsrc_err) > -1) - { - if ((err = ::fdopen(rpipe(rsrc_err), "r"))) - { - open_files |= pstderr; - } - } - return open_files; - } - - /** - * @warning This function exposes the internals of the stream buffer and - * should be used with caution. - * - * @param in A FILE* that will refer to the process' stdin. - * @param out A FILE* that will refer to the process' stdout. - * @param err A FILE* that will refer to the process' stderr. - * @return A bitwise-or of zero or more of @c pstdin, @c pstdout, @c pstderr. - * @see basic_pstreambuf::fopen() - */ - template - inline std::size_t - pstream_common::fopen(FILE*& fin, FILE*& fout, FILE*& ferr) - { - return buf_.fopen(fin, fout, ferr); - } - -#endif // REDI_EVISCERATE_PSTREAMS - - -} // namespace redi - -/** - * @mainpage PStreams Reference - * @htmlinclude mainpage.html - */ - -#endif // REDI_PSTREAM_H_SEEN - -// vim: ts=2 sw=2 expandtab - diff --git a/vendor/libblepp-master/src/att.cc b/vendor/libblepp-master/src/att.cc deleted file mode 100644 index dfc6165..0000000 --- a/vendor/libblepp-master/src/att.cc +++ /dev/null @@ -1,1181 +0,0 @@ -/* - Copyright (c) 2013 Edward Rosten - - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - - -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2010 Marcel Holtmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include - -#include - -#include -#include - -namespace BLEPP -{ - - #define MIN(A, B) (((A)<(B))?(A):(B)) - const char *att_ecode2str(uint8_t status) - { - switch (status) { - case ATT_ECODE_INVALID_HANDLE: - return "Invalid handle"; - case ATT_ECODE_READ_NOT_PERM: - return "Attribute can't be read"; - case ATT_ECODE_WRITE_NOT_PERM: - return "Attribute can't be written"; - case ATT_ECODE_INVALID_PDU: - return "Attribute PDU was invalid"; - case ATT_ECODE_AUTHENTICATION: - return "Attribute requires authentication before read/write"; - case ATT_ECODE_REQ_NOT_SUPP: - return "Server doesn't support the request received"; - case ATT_ECODE_INVALID_OFFSET: - return "Offset past the end of the attribute"; - case ATT_ECODE_AUTHORIZATION: - return "Attribute requires authorization before read/write"; - case ATT_ECODE_PREP_QUEUE_FULL: - return "Too many prepare writes have been queued"; - case ATT_ECODE_ATTR_NOT_FOUND: - return "No attribute found within the given range"; - case ATT_ECODE_ATTR_NOT_LONG: - return "Attribute can't be read/written using Read Blob Req"; - case ATT_ECODE_INSUFF_ENCR_KEY_SIZE: - return "Encryption Key Size is insufficient"; - case ATT_ECODE_INVAL_ATTR_VALUE_LEN: - return "Attribute value length is invalid"; - case ATT_ECODE_UNLIKELY: - return "Request attribute has encountered an unlikely error"; - case ATT_ECODE_INSUFF_ENC: - return "Encryption required before read/write"; - case ATT_ECODE_UNSUPP_GRP_TYPE: - return "Attribute type is not a supported grouping attribute"; - case ATT_ECODE_INSUFF_RESOURCES: - return "Insufficient Resources to complete the request"; - case ATT_ECODE_IO: - return "Internal application error: I/O"; - case ATT_ECODE_TIMEOUT: - return "A timeout occured"; - case ATT_ECODE_ABORTED: - return "The operation was aborted"; - default: - return "Unexpected error code"; - } - } - - - const char* att_op2str(uint8_t op) - { - switch(op) - { - case ATT_OP_ERROR: - return "Error"; - case ATT_OP_MTU_REQ: - return "MTU Request"; - case ATT_OP_MTU_RESP: - return "MTU Response"; - case ATT_OP_FIND_INFO_REQ: - return "Find Info Request"; - case ATT_OP_FIND_INFO_RESP: - return "Find Info Response"; - case ATT_OP_FIND_BY_TYPE_REQ: - return "Find By Type Request"; - case ATT_OP_FIND_BY_TYPE_RESP: - return "Find By Type Response"; - case ATT_OP_READ_BY_TYPE_REQ: - return "Read By Type Request"; - case ATT_OP_READ_BY_TYPE_RESP: - return "Read By Type Response"; - case ATT_OP_READ_REQ: - return "Read Request"; - case ATT_OP_READ_RESP: - return "Read Response"; - case ATT_OP_READ_BLOB_REQ: - return "Read Blob Request"; - case ATT_OP_READ_BLOB_RESP: - return "Read Blob Response"; - case ATT_OP_READ_MULTI_REQ: - return "Read Multi Request"; - case ATT_OP_READ_MULTI_RESP: - return "Read Multi Resources"; - case ATT_OP_READ_BY_GROUP_REQ: - return "Read By Group Request"; - case ATT_OP_READ_BY_GROUP_RESP: - return "Read By Group Response"; - case ATT_OP_WRITE_REQ: - return "Write Request"; - case ATT_OP_WRITE_RESP: - return "Write Request Response"; - case ATT_OP_WRITE_CMD: - return "Write Command"; - case ATT_OP_HANDLE_NOTIFY: - return "Notify"; - case ATT_OP_HANDLE_IND: - return "Indicate"; - case ATT_OP_PREP_WRITE_REQ: - case ATT_OP_PREP_WRITE_RESP: - case ATT_OP_EXEC_WRITE_REQ: - case ATT_OP_EXEC_WRITE_RESP: - case ATT_OP_HANDLE_CNF: - case ATT_OP_SIGNED_WRITE_CMD: - return "haha fill me in :)"; - - default: - return "Unnkown opcode"; - }; - } - - - /* - void att_data_list_free(struct att_data_list *list) - { - if (list == NULL) - return; - - if (list->data) { - int i; - for (i = 0; i < list->num; i++) - g_free(list->data[i]); - } - - g_free(list->data); - g_free(list); - } - */ - /* - struct att_data_list *att_data_list_alloc(uint16_t num, uint16_t len) - { - struct att_data_list *list; - int i; - - if (len > UINT8_MAX) - return NULL; - - list = g_new0(struct att_data_list, 1); - list->len = len; - list->num = num; - - list->data = g_malloc0(sizeof(uint8_t *) * num); - - for (i = 0; i < num; i++) - list->data[i] = g_malloc0(sizeof(uint8_t) * len); - - return list; - } - */ - - uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, - uint8_t *pdu, size_t len) - { - uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end); - uint16_t length; - - if (!uuid) - return 0; - - if (uuid->type == BT_UUID16) - length = 2; - else if (uuid->type == BT_UUID128) - length = 16; - else - return 0; - - if (len < min_len + length) - return 0; - - pdu[0] = ATT_OP_READ_BY_GROUP_REQ; - att_put_u16(start, &pdu[1]); - att_put_u16(end, &pdu[3]); - - att_put_uuid(*uuid, &pdu[5]); - - return min_len + length; - } - /* - uint16_t dec_read_by_grp_req(const uint8_t *pdu, size_t len, uint16_t *start, - uint16_t *end, bt_uuid_t *uuid) - { - const size_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end); - - if (pdu == NULL) - return 0; - - if (start == NULL || end == NULL || uuid == NULL) - return 0; - - if (pdu[0] != ATT_OP_READ_BY_GROUP_REQ) - return 0; - - if (len < min_len + 2) - return 0; - - *start = att_get_u16(&pdu[1]); - *end = att_get_u16(&pdu[3]); - if (len == min_len + 2) - *uuid = att_get_uuid16(&pdu[5]); - else - *uuid = att_get_uuid128(&pdu[5]); - - return len; - } - - uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu, - size_t len) - { - int i; - uint16_t w; - uint8_t *ptr; - - if (list == NULL) - return 0; - - if (len < list->len + sizeof(uint8_t) * 2) - return 0; - - pdu[0] = ATT_OP_READ_BY_GROUP_RESP; - pdu[1] = list->len; - - ptr = &pdu[2]; - - for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) { - memcpy(ptr, list->data[i], list->len); - ptr += list->len; - w += list->len; - } - - return w; - } - - struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, size_t len) - { - struct att_data_list *list; - const uint8_t *ptr; - uint16_t elen, num; - int i; - - if (pdu[0] != ATT_OP_READ_BY_GROUP_RESP) - return NULL; - - elen = pdu[1]; - num = (len - 2) / elen; - list = att_data_list_alloc(num, elen); - if (list == NULL) - return NULL; - - ptr = &pdu[2]; - - for (i = 0; i < num; i++) { - memcpy(list->data[i], ptr, list->len); - ptr += list->len; - } - - return list; - } - */ - uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, - const uint8_t *value, size_t vlen, - uint8_t *pdu, size_t len) - { - uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end) + - sizeof(uint16_t); - - if (pdu == NULL) - return 0; - - if (!uuid) - return 0; - - if (uuid->type != BT_UUID16) - return 0; - - if (len < min_len) - return 0; - - if (vlen > len - min_len) - vlen = len - min_len; - - pdu[0] = ATT_OP_FIND_BY_TYPE_REQ; - att_put_u16(start, &pdu[1]); - att_put_u16(end, &pdu[3]); - att_put_uuid16(*uuid, &pdu[5]); - - if (vlen > 0) { - memcpy(&pdu[7], value, vlen); - return min_len + vlen; - } - - return min_len; - } - - uint16_t dec_find_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start, - uint16_t *end, bt_uuid_t *uuid, - uint8_t *value, size_t *vlen) - { - size_t valuelen; - uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + - sizeof(*end) + sizeof(uint16_t); - - if (pdu == NULL) - return 0; - - if (len < min_len) - return 0; - - if (pdu[0] != ATT_OP_FIND_BY_TYPE_REQ) - return 0; - - /* First requested handle number */ - if (start) - *start = att_get_u16(&pdu[1]); - - /* Last requested handle number */ - if (end) - *end = att_get_u16(&pdu[3]); - - /* Always UUID16 */ - if (uuid) - *uuid = att_get_uuid16(&pdu[5]); - - valuelen = len - min_len; - - /* Attribute value to find */ - if (valuelen > 0 && value) - memcpy(value, pdu + min_len, valuelen); - - if (vlen) - *vlen = valuelen; - - return len; - } - - /* - uint16_t enc_find_by_type_resp(GSList *matches, uint8_t *pdu, size_t len) - { - GSList *l; - uint16_t offset; - - if (pdu == NULL || len < 5) - return 0; - - pdu[0] = ATT_OP_FIND_BY_TYPE_RESP; - - for (l = matches, offset = 1; - l && len >= (offset + sizeof(uint16_t) * 2); - l = l->next, offset += sizeof(uint16_t) * 2) { - struct att_range *range = l->data; - - att_put_u16(range->start, &pdu[offset]); - att_put_u16(range->end, &pdu[offset + 2]); - } - - return offset; - }*/ - - /* - GSList *dec_find_by_type_resp(const uint8_t *pdu, size_t len) - { - struct att_range *range; - GSList *matches; - off_t offset; - - if (pdu == NULL || len < 5) - return NULL; - - if (pdu[0] != ATT_OP_FIND_BY_TYPE_RESP) - return NULL; - - for (offset = 1, matches = NULL; - len >= (offset + sizeof(uint16_t) * 2); - offset += sizeof(uint16_t) * 2) { - range = g_new0(struct att_range, 1); - range->start = att_get_u16(&pdu[offset]); - range->end = att_get_u16(&pdu[offset + 2]); - - matches = g_slist_append(matches, range); - } - - return matches; - }*/ - - uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, - uint8_t *pdu, size_t len) - { - uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end); - uint16_t length; - - if (!uuid) - return 0; - - if (uuid->type == BT_UUID16) - length = 2; - else if (uuid->type == BT_UUID128) - length = 16; - else - return 0; - - if (len < min_len + length) - return 0; - - pdu[0] = ATT_OP_READ_BY_TYPE_REQ; - att_put_u16(start, &pdu[1]); - att_put_u16(end, &pdu[3]); - - att_put_uuid(*uuid, &pdu[5]); - - return min_len + length; - } - - uint16_t dec_read_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start, - uint16_t *end, bt_uuid_t *uuid) - { - const size_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end); - - if (pdu == NULL) - return 0; - - if (start == NULL || end == NULL || uuid == NULL) - return 0; - - if (len < min_len + 2) - return 0; - - if (pdu[0] != ATT_OP_READ_BY_TYPE_REQ) - return 0; - - *start = att_get_u16(&pdu[1]); - *end = att_get_u16(&pdu[3]); - - if (len == min_len + 2) - *uuid = att_get_uuid16(&pdu[5]); - else - *uuid = att_get_uuid128(&pdu[5]); - - return len; - } - /* - uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu, - size_t len) - { - uint8_t *ptr; - size_t i, w, l; - - if (list == NULL) - return 0; - - if (pdu == NULL) - return 0; - - l = MIN(len - 2, list->len); - - pdu[0] = ATT_OP_READ_BY_TYPE_RESP; - pdu[1] = l; - ptr = &pdu[2]; - - for (i = 0, w = 2; i < list->num && w + l <= len; i++) { - memcpy(ptr, list->data[i], l); - ptr += l; - w += l; - } - - return w; - }*/ - /* - struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, size_t len) - { - struct att_data_list *list; - const uint8_t *ptr; - uint16_t elen, num; - int i; - - if (pdu[0] != ATT_OP_READ_BY_TYPE_RESP) - return NULL; - - elen = pdu[1]; - num = (len - 2) / elen; - list = att_data_list_alloc(num, elen); - if (list == NULL) - return NULL; - - ptr = &pdu[2]; - - for (i = 0; i < num; i++) { - memcpy(list->data[i], ptr, list->len); - ptr += list->len; - } - - return list; - } - */ - uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, size_t vlen, - uint8_t *pdu, size_t len) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle); - - if (pdu == NULL) - return 0; - - if (len < min_len) - return 0; - - if (vlen > len - min_len) - vlen = len - min_len; - - pdu[0] = ATT_OP_WRITE_CMD; - att_put_u16(handle, &pdu[1]); - - if (vlen > 0) { - memcpy(&pdu[3], value, vlen); - return min_len + vlen; - } - - return min_len; - } - - uint16_t dec_write_cmd(const uint8_t *pdu, size_t len, uint16_t *handle, - uint8_t *value, size_t *vlen) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle); - - if (pdu == NULL) - return 0; - - if (value == NULL || vlen == NULL || handle == NULL) - return 0; - - if (len < min_len) - return 0; - - if (pdu[0] != ATT_OP_WRITE_CMD) - return 0; - - *handle = att_get_u16(&pdu[1]); - memcpy(value, pdu + min_len, len - min_len); - *vlen = len - min_len; - - return len; - } - - uint16_t enc_write_req(uint16_t handle, const uint8_t *value, size_t vlen, - uint8_t *pdu, size_t len) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle); - - if (pdu == NULL) - return 0; - - if (len < min_len) - return 0; - - if (vlen > len - min_len) - vlen = len - min_len; - - pdu[0] = ATT_OP_WRITE_REQ; - att_put_u16(handle, &pdu[1]); - - if (vlen > 0) { - memcpy(&pdu[3], value, vlen); - return min_len + vlen; - } - - return min_len; - } - - uint16_t dec_write_req(const uint8_t *pdu, size_t len, uint16_t *handle, - uint8_t *value, size_t *vlen) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle); - - if (pdu == NULL) - return 0; - - if (value == NULL || vlen == NULL || handle == NULL) - return 0; - - if (len < min_len) - return 0; - - if (pdu[0] != ATT_OP_WRITE_REQ) - return 0; - - *handle = att_get_u16(&pdu[1]); - *vlen = len - min_len; - if (*vlen > 0) - memcpy(value, pdu + min_len, *vlen); - - return len; - } - - uint16_t enc_write_resp(uint8_t *pdu, size_t len) - { - if (pdu == NULL) - return 0; - - pdu[0] = ATT_OP_WRITE_RESP; - - return sizeof(pdu[0]); - } - - uint16_t dec_write_resp(const uint8_t *pdu, size_t len) - { - if (pdu == NULL) - return 0; - - if (pdu[0] != ATT_OP_WRITE_RESP) - return 0; - - return len; - } - - uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, size_t len) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle); - - if (pdu == NULL) - return 0; - - if (len < min_len) - return 0; - - pdu[0] = ATT_OP_READ_REQ; - att_put_u16(handle, &pdu[1]); - - return min_len; - } - - uint16_t enc_read_blob_req(uint16_t handle, uint16_t offset, uint8_t *pdu, - size_t len) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle) + - sizeof(offset); - - if (pdu == NULL) - return 0; - - if (len < min_len) - return 0; - - pdu[0] = ATT_OP_READ_BLOB_REQ; - att_put_u16(handle, &pdu[1]); - att_put_u16(offset, &pdu[3]); - - return min_len; - } - - uint16_t dec_read_req(const uint8_t *pdu, size_t len, uint16_t *handle) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle); - - if (pdu == NULL) - return 0; - - if (handle == NULL) - return 0; - - if (len < min_len) - return 0; - - if (pdu[0] != ATT_OP_READ_REQ) - return 0; - - *handle = att_get_u16(&pdu[1]); - - return min_len; - } - - uint16_t dec_read_blob_req(const uint8_t *pdu, size_t len, uint16_t *handle, - uint16_t *offset) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle) + - sizeof(*offset); - - if (pdu == NULL) - return 0; - - if (handle == NULL) - return 0; - - if (offset == NULL) - return 0; - - if (len < min_len) - return 0; - - if (pdu[0] != ATT_OP_READ_BLOB_REQ) - return 0; - - *handle = att_get_u16(&pdu[1]); - *offset = att_get_u16(&pdu[3]); - - return min_len; - } - - uint16_t enc_read_resp(uint8_t *value, size_t vlen, uint8_t *pdu, size_t len) - { - if (pdu == NULL) - return 0; - - /* If the attribute value length is longer than the allowed PDU size, - * send only the octets that fit on the PDU. The remaining octets can - * be requested using the Read Blob Request. */ - if (vlen > len - 1) - vlen = len - 1; - - pdu[0] = ATT_OP_READ_RESP; - - memcpy(pdu + 1, value, vlen); - - return vlen + 1; - } - - uint16_t enc_read_blob_resp(uint8_t *value, size_t vlen, uint16_t offset, - uint8_t *pdu, size_t len) - { - if (pdu == NULL) - return 0; - - vlen -= offset; - if (vlen > len - 1) - vlen = len - 1; - - pdu[0] = ATT_OP_READ_BLOB_RESP; - - memcpy(pdu + 1, &value[offset], vlen); - - return vlen + 1; - } - - ssize_t dec_read_resp(const uint8_t *pdu, size_t len, uint8_t *value, size_t vlen) - { - if (pdu == NULL) - return -EINVAL; - - if (value == NULL) - return -EINVAL; - - if (pdu[0] != ATT_OP_READ_RESP) - return -EINVAL; - - if (vlen < (len - 1)) - return -ENOBUFS; - - memcpy(value, pdu + 1, len - 1); - - return len - 1; - } - - uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status, - uint8_t *pdu, size_t len) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(opcode) + - sizeof(handle) + sizeof(status); - uint16_t u16; - - if (len < min_len) - return 0; - - u16 = htobs(handle); - pdu[0] = ATT_OP_ERROR; - pdu[1] = opcode; - memcpy(&pdu[2], &u16, sizeof(u16)); - pdu[4] = status; - - return min_len; - } - - uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, size_t len) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end); - - if (pdu == NULL) - return 0; - - if (len < min_len) - return 0; - - pdu[0] = ATT_OP_FIND_INFO_REQ; - att_put_u16(start, &pdu[1]); - att_put_u16(end, &pdu[3]); - - return min_len; - } - - uint16_t dec_find_info_req(const uint8_t *pdu, size_t len, uint16_t *start, - uint16_t *end) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end); - - if (pdu == NULL) - return 0; - - if (len < min_len) - return 0; - - if (start == NULL || end == NULL) - return 0; - - if (pdu[0] != ATT_OP_FIND_INFO_REQ) - return 0; - - *start = att_get_u16(&pdu[1]); - *end = att_get_u16(&pdu[3]); - - return min_len; - } - /* - uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list, - uint8_t *pdu, size_t len) - { - uint8_t *ptr; - size_t i, w; - - if (pdu == NULL) - return 0; - - if (list == NULL) - return 0; - - if (len < list->len + sizeof(uint8_t) * 2) - return 0; - - pdu[0] = ATT_OP_FIND_INFO_RESP; - pdu[1] = format; - ptr = (void *) &pdu[2]; - - for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) { - memcpy(ptr, list->data[i], list->len); - ptr += list->len; - w += list->len; - } - - return w; - } - - struct att_data_list *dec_find_info_resp(const uint8_t *pdu, size_t len, - uint8_t *format) - { - struct att_data_list *list; - uint8_t *ptr; - uint16_t elen, num; - int i; - - if (pdu == NULL) - return 0; - - if (format == NULL) - return 0; - - if (pdu[0] != ATT_OP_FIND_INFO_RESP) - return 0; - - *format = pdu[1]; - elen = sizeof(pdu[0]) + sizeof(*format); - if (*format == 0x01) - elen += 2; - else if (*format == 0x02) - elen += 16; - - num = (len - 2) / elen; - - ptr = (void *) &pdu[2]; - - list = att_data_list_alloc(num, elen); - if (list == NULL) - return NULL; - - for (i = 0; i < num; i++) { - memcpy(list->data[i], ptr, list->len); - ptr += list->len; - } - - return list; - }*/ - - uint16_t enc_notification(uint16_t handle, uint8_t *value, size_t vlen, - uint8_t *pdu, size_t len) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t); - - if (pdu == NULL) - return 0; - - if (len < (vlen + min_len)) - return 0; - - pdu[0] = ATT_OP_HANDLE_NOTIFY; - att_put_u16(handle, &pdu[1]); - memcpy(&pdu[3], value, vlen); - - return vlen + min_len; - } - - uint16_t enc_indication(uint16_t handle, uint8_t *value, size_t vlen, - uint8_t *pdu, size_t len) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t); - - if (pdu == NULL) - return 0; - - if (len < (vlen + min_len)) - return 0; - - pdu[0] = ATT_OP_HANDLE_IND; - att_put_u16(handle, &pdu[1]); - memcpy(&pdu[3], value, vlen); - - return vlen + min_len; - } - - uint16_t dec_indication(const uint8_t *pdu, size_t len, uint16_t *handle, - uint8_t *value, size_t vlen) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t); - uint16_t dlen; - - if (pdu == NULL) - return 0; - - if (pdu[0] != ATT_OP_HANDLE_IND) - return 0; - - if (len < min_len) - return 0; - - dlen = MIN(len - min_len, vlen); - - if (handle) - *handle = att_get_u16(&pdu[1]); - - memcpy(value, &pdu[3], dlen); - - return dlen; - } - - uint16_t enc_confirmation(uint8_t *pdu, size_t len) - { - const uint16_t min_len = sizeof(pdu[0]); - - if (pdu == NULL) - return 0; - - if (len < min_len) - return 0; - - pdu[0] = ATT_OP_HANDLE_CNF; - - return min_len; - } - - uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, size_t len) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu); - - if (pdu == NULL) - return 0; - - if (len < min_len) - return 0; - - pdu[0] = ATT_OP_MTU_REQ; - att_put_u16(mtu, &pdu[1]); - - return min_len; - } - - uint16_t dec_mtu_req(const uint8_t *pdu, size_t len, uint16_t *mtu) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu); - - if (pdu == NULL) - return 0; - - if (mtu == NULL) - return 0; - - if (len < min_len) - return 0; - - if (pdu[0] != ATT_OP_MTU_REQ) - return 0; - - *mtu = att_get_u16(&pdu[1]); - - return min_len; - } - - uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, size_t len) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu); - - if (pdu == NULL) - return 0; - - if (len < min_len) - return 0; - - pdu[0] = ATT_OP_MTU_RESP; - att_put_u16(mtu, &pdu[1]); - - return min_len; - } - - uint16_t dec_mtu_resp(const uint8_t *pdu, size_t len, uint16_t *mtu) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu); - - if (pdu == NULL) - return 0; - - if (mtu == NULL) - return 0; - - if (len < min_len) - return 0; - - if (pdu[0] != ATT_OP_MTU_RESP) - return 0; - - *mtu = att_get_u16(&pdu[1]); - - return min_len; - } - - uint16_t enc_prep_write_req(uint16_t handle, uint16_t offset, - const uint8_t *value, size_t vlen, uint8_t *pdu, size_t len) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle) + - sizeof(offset); - - if (pdu == NULL) - return 0; - - if (len < min_len) - return 0; - - if (vlen > len - min_len) - vlen = len - min_len; - - pdu[0] = ATT_OP_PREP_WRITE_REQ; - att_put_u16(handle, &pdu[1]); - att_put_u16(offset, &pdu[3]); - - if (vlen > 0) { - memcpy(&pdu[5], value, vlen); - return min_len + vlen; - } - - return min_len; - } - - uint16_t dec_prep_write_resp(const uint8_t *pdu, size_t len, uint16_t *handle, - uint16_t *offset, uint8_t *value, size_t *vlen) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle) + - sizeof(*offset); - - if (pdu == NULL) - return 0; - - if (handle == NULL || offset == NULL || value == NULL || vlen == NULL) - return 0; - - if (len < min_len) - return 0; - - if (pdu[0] != ATT_OP_PREP_WRITE_REQ) - return 0; - - *handle = att_get_u16(&pdu[1]); - *offset = att_get_u16(&pdu[3]); - *vlen = len - min_len; - if (*vlen > 0) - memcpy(value, pdu + min_len, *vlen); - - return len; - } - - uint16_t enc_exec_write_req(uint8_t flags, uint8_t *pdu, size_t len) - { - const uint16_t min_len = sizeof(pdu[0]) + sizeof(flags); - - if (pdu == NULL) - return 0; - - if (len < min_len) - return 0; - - if (flags > 1) - return 0; - - pdu[0] = ATT_OP_EXEC_WRITE_REQ; - pdu[1] = flags; - - return min_len; - } - - uint16_t dec_exec_write_resp(const uint8_t *pdu, size_t len) - { - const uint16_t min_len = sizeof(pdu[0]); - - if (pdu == NULL) - return 0; - - if (len < min_len) - return 0; - - if (pdu[0] != ATT_OP_EXEC_WRITE_RESP) - return 0; - - return len; - } - -} diff --git a/vendor/libblepp-master/src/att_pdu.cc b/vendor/libblepp-master/src/att_pdu.cc deleted file mode 100644 index 799045e..0000000 --- a/vendor/libblepp-master/src/att_pdu.cc +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * blepp - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include - -using namespace std; - - -void BLEPP::pretty_print(const PDUResponse& pdu) -{ - if(log_level >= Debug) - { - cerr << "debug: ---PDU packet ---\n"; - cerr << "debug: " << to_hex(pdu.data, pdu.length) << endl; - cerr << "debug: " << to_str(pdu.data, pdu.length) << endl; - cerr << "debug: Packet type: " << to_hex(pdu.type()) << " " << att_op2str(pdu.type()) << endl; - - if(pdu.type() == ATT_OP_ERROR) - cerr << "debug: " << PDUErrorResponse(pdu).error_str() << " in response to " << att_op2str(PDUErrorResponse(pdu).request_opcode()) << " on handle " + to_hex(PDUErrorResponse(pdu).handle()) << endl; - else if(pdu.type() == ATT_OP_READ_BY_TYPE_RESP) - { - PDUReadByTypeResponse p(pdu); - - cerr << "debug: elements = " << p.num_elements() << endl; - cerr << "debug: value size = " << p.value_size() << endl; - - for(int i=0; i < p.num_elements(); i++) - { - cerr << "debug: " << to_hex(p.handle(i)) << " "; - if(p.value_size() != 2) - cerr << "-->" << to_str(p.value(i)) << "<--" << endl; - else - cerr << to_hex(p.value_uint16(i)) << endl; - } - - } - else if(pdu.type() == ATT_OP_READ_BY_GROUP_RESP) - { - PDUReadGroupByTypeResponse p(pdu); - cerr << "debug: elements = " << p.num_elements() << endl; - cerr << "debug: value size = " << p.value_size() << endl; - - for(int i=0; i < p.num_elements(); i++) - cerr << "debug: " << "[ " << to_hex(p.start_handle(i)) << ", " << to_hex(p.end_handle(i)) << ") :" << to_str(p.value(i)) << endl; - } - else if(pdu.type() == ATT_OP_WRITE_RESP) - { - } - else if(pdu.type() == ATT_OP_HANDLE_NOTIFY || pdu.type() == ATT_OP_HANDLE_IND) - { - PDUNotificationOrIndication p(pdu); - cerr << "debug: handle = " << p.handle() << endl; - cerr << "debug: data = " << to_hex(p.value().first, p.value().second - p.value().first) << endl; - cerr << "debug: data = " << to_str(p.value().first, p.value().second - p.value().first) << endl; - - } - else - cerr << "debug: --no pretty printer available--\n"; - - cerr << "debug:\n"; - } -}; - - diff --git a/vendor/libblepp-master/src/bledevice.cc b/vendor/libblepp-master/src/bledevice.cc deleted file mode 100644 index dfdb920..0000000 --- a/vendor/libblepp-master/src/bledevice.cc +++ /dev/null @@ -1,260 +0,0 @@ -/* - * - * blepp - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#include "blepp/bledevice.h" -#include "blepp/logging.h" -#include "blepp/att_pdu.h" - - -#include -#include - -#include - -#include - -using namespace std; - -namespace BLEPP -{ - - template const C& haxx(const C& X) - { - return X; - } - - inline int haxx(uint8_t X) - { - return X; - } - - #define test(X, Y) test_fd_(X, __LINE__) - #define TEST(X, S, B, L) call(X(),S, B, L) - - template void test_fd_(int fd, int line) - { - if(fd < 0) - { - LOG(Info, "Error on line " << line << "( " << __FILE__ << "): " <(write(sock, buf, len), line); - } - - - void call(const Read&, int sock, uint8_t* buf, size_t len, int line) - { - test_fd_(read(sock, buf, len), line); - } - - void BLEDevice::send_read_request(uint16_t handle) - { - int len = enc_read_req(handle, buf.data(), buf.size()); - test_pdu(len); - int ret = write(sock, buf.data(), len); - test(ret, Write); - } - - void BLEDevice::send_read_by_type(const bt_uuid_t& uuid, uint16_t start, uint16_t end) - { - int len = enc_read_by_type_req(start, end, const_cast(&uuid), buf.data(), buf.size()); - test_pdu(len); - int ret = write(sock, buf.data(), len); - test(ret, Write); - } - - void BLEDevice::send_find_information(uint16_t start, uint16_t end) - { - int len = enc_find_info_req(start, end, buf.data(), buf.size()); - test_pdu(len); - int ret = write(sock, buf.data(), len); - test(ret, Write); - } - - void BLEDevice::send_read_group_by_type(const bt_uuid_t& uuid, uint16_t start, uint16_t end) - { - int len = enc_read_by_grp_req(start, end, const_cast(&uuid), buf.data(), buf.size()); - test_pdu(len); - int ret = write(sock, buf.data(), len); - test(ret, Write); - } - - void BLEDevice::send_write_request(uint16_t handle, const uint8_t* data, int length) - { - int len = enc_write_req(handle, data, length, buf.data(), buf.size()); - test_pdu(len); - int ret = write(sock, buf.data(), len); - test(ret, Write); - } - - void BLEDevice::send_write_request(uint16_t handle, uint16_t data) - { - const uint8_t buf[2] = { (uint8_t)(data & 0xff), (uint8_t)((data & 0xff00) >> 8)}; - send_write_request(handle, buf, 2); - } - - void BLEDevice::send_handle_value_confirmation() - { - int len = enc_confirmation(buf.data(), buf.size()); - test_pdu(len); - int ret = write(sock, buf.data(), len); - test(ret, Write); - } - - void BLEDevice::send_write_command(uint16_t handle, const uint8_t* data, int length) - { - int len = enc_write_cmd(handle, data, length, buf.data(), buf.size()); - test_pdu(len); - int ret = write(sock, buf.data(), len); - test(ret, Write); - } - - void BLEDevice::send_write_command(uint16_t handle, uint16_t data) - { - const uint8_t buf[2] = { (uint8_t)(data & 0xff), (uint8_t)((data & 0xff00) >> 8)}; - send_write_command(handle, buf, 2); - } - - - PDUResponse BLEDevice::receive(uint8_t* buf, int max) - { - int len = read(sock, buf, max); - test(len, Read); - pretty_print(PDUResponse(buf, len)); - return PDUResponse(buf, len); - } - - PDUResponse BLEDevice::receive(vector& v) - { - return receive(v.data(), v.size()); - } - - - - - BLEDevice::BLEDevice(const int& sock_) - :sock(sock_) - { - /* - //Allocate socket and create endpoint. - sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); - test(sock); - - //////////////////////////////////////// - //Bind the socket - //I believe that l2 is for an l2cap socket. These are kind of like - //UDP in that they have port numbers and are packet oriented. - struct sockaddr_l2 addr; - - bdaddr_t source_address = {{0,0,0,0,0,0}}; //i.e. the adapter. Note, 0, corresponds to BDADDR_ANY - //However BDADDR_ANY uses a nonstandard C hack and does not compile - //under C++. So, set it manually. - //So, a sockaddr_l2 has the family (obviously) - //a PSM (wtf?) - // Protocol Service Multiplexer (WTF?) - //an address (of course) - //a CID (wtf) - // Channel ID (i.e. port number?) - //and an address type (wtf) - - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - - addr.l2_psm = 0; - addr.l2_cid = htobs(LE_ATT_CID); - - - bacpy(&addr.l2_bdaddr, &source_address); - - //Address type: Low Energy public - addr.l2_bdaddr_type=BDADDR_LE_PUBLIC; - - //Bind socket. This associates it with a particular adapter. - //We chose ANY as the source address, so packets will go out of - //whichever adapter necessary. - int ret = bind(sock, (sockaddr*)&addr, sizeof(addr)); - test(ret); - - - //////////////////////////////////////// - - //Need to do l2cap_set here - l2cap_options options; - unsigned int len = sizeof(options); - memset(&options, 0, len); - - //Get the options with a minor bit of cargo culting. - //SOL_L2CAP seems to mean that is should operate at the L2CAP level of the stack - //L2CAP_OPTIONS who knows? - ret = getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &options, &len); - test(ret); - - LOGVAR(options.omtu); - LOGVAR(options.imtu); - LOGVAR(options.flush_to); - LOGVAR(options.mode); - LOGVAR(options.fcs); - LOGVAR(options.max_tx); - LOGVAR(options.txwin_size); - - - - //Can also use bacpy to copy addresses about - str2ba(address.c_str(), &addr.l2_bdaddr); - ret = connect(sock, (sockaddr*)&addr, sizeof(addr)); - test(ret); - - - //And this seems to work up to here. - - //Get the options with a minor bit of cargo culting. - //SOL_L2CAP seems to mean that is should operate at the L2CAP level of the stack - //L2CAP_OPTIONS who knows? - ret = getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &options, &len); - test(ret); - - LOGVAR(options.omtu); - LOGVAR(options.imtu); - LOGVAR(options.flush_to); - LOGVAR(options.mode); - LOGVAR(options.fcs); - LOGVAR(options.max_tx); - LOGVAR(options.txwin_size); - */ - buf.resize(ATT_DEFAULT_MTU); - } - -} diff --git a/vendor/libblepp-master/src/blestatemachine.cc b/vendor/libblepp-master/src/blestatemachine.cc deleted file mode 100644 index 340d89f..0000000 --- a/vendor/libblepp-master/src/blestatemachine.cc +++ /dev/null @@ -1,836 +0,0 @@ -/* - * - * blepp - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "blepp/bledevice.h" -#include "blepp/logging.h" -#include "blepp/att_pdu.h" -#include "blepp/pretty_printers.h" -#include "blepp/blestatemachine.h" - -#include - -#include -#include -#include - -#include -#include -#include -#include -using namespace std; - - - -#define log_fd(X) log_fd_(X, __LINE__, __FILE__) - -namespace BLEPP -{ - - namespace { - int log_fd_(int fd, int line, const char* file) - { - if(fd < 0) - { - LOG(Error, "Error on line: " << line << " (" << file << "): " << strerror(errno)); - } - else - LOG(Info, "Socket success: " << line << " (" << file << ")"); - - return fd; - } - } - - const char* BLEGATTStateMachine::get_disconnect_string(Disconnect d) - { - switch(d.reason) - { - case Disconnect::ConnectionFailed: return "Connection failed."; - case Disconnect::UnexpectedError: return "Unexpected Error."; - case Disconnect::UnexpectedResponse: return "Unexpected Response."; - case Disconnect::WriteError: return "Write Error."; - case Disconnect::ReadError: return "Read Error."; - case Disconnect::ConnectionClosed: return "Connection Closed."; - default: return "Unknown reason."; - } - } - - - - const ServiceInfo* lookup_service_by_UUID(const UUID& uuid) - { - static vector vec; - - if(vec.size() == 0) - { - auto add = [](const char* n, const char* i, uint16_t u) - { - ServiceInfo s; - s.name=n; - s.id = i; - s.uuid = UUID(u); - vec.push_back(s); - }; - - add( "Alert Notification Service", "org.bluetooth.service.alert_notification", 0x1811); - add( "Battery Service", "org.bluetooth.service.battery_service", 0x180F); - add( "Blood Pressure", "org.bluetooth.service.blood_pressure", 0x1810); - add( "Body Composition", "org.bluetooth.service.body_composition", 0x181B); - add( "Bond Management", "org.bluetooth.service.bond_management", 0x181E); - add( "Current Time Service", "org.bluetooth.service.current_time", 0x1805); - add( "Cycling Power", "org.bluetooth.service.cycling_power", 0x1818); - add( "Cycling Speed and Cadence", "org.bluetooth.service.cycling_speed_and_cadence", 0x1816); - add( "Device Information", "org.bluetooth.service.device_information", 0x180A); - add( "Generic Access", "org.bluetooth.service.generic_access", 0x1800); - add( "Generic Attribute", "org.bluetooth.service.generic_attribute", 0x1801); - add( "Glucose", "org.bluetooth.service.glucose", 0x1808); - add( "Health Thermometer", "org.bluetooth.service.health_thermometer", 0x1809); - add( "Heart Rate", "org.bluetooth.service.heart_rate", 0x180D); - add( "Human Interface Device", "org.bluetooth.service.human_interface_device", 0x1812); - add( "Immediate Alert", "org.bluetooth.service.immediate_alert", 0x1802); - add( "Link Loss", "org.bluetooth.service.link_loss", 0x1803); - add( "Location and Navigation", "org.bluetooth.service.location_and_navigation", 0x1819); - add( "Next DST Change Service", "org.bluetooth.service.next_dst_change", 0x1807); - add( "Phone Alert Status Service", "org.bluetooth.service.phone_alert_status", 0x180E); - add( "Reference Time Update Service", "org.bluetooth.service.reference_time_update", 0x1806); - add( "Running Speed and Cadence", "org.bluetooth.service.running_speed_and_cadence", 0x1814); - add( "Scan Parameters", "org.bluetooth.service.scan_parameters", 0x1813); - add( "Tx Power", "org.bluetooth.service.tx_power", 0x1804); - add( "User Data", "org.bluetooth.service.user_data", 0x181C); - add( "Weight Scale", "org.bluetooth.service.weight_scale", 0x181D); - } - - auto f = find_if(vec.begin(), vec.end(), [&](const ServiceInfo& s) - { - return s.uuid == uuid; - }); - - if(f == vec.end()) - return 0; - else - return &*f; - } - - - void BLEGATTStateMachine::buggerall() - { - } - - void BLEGATTStateMachine::buggerall2(Disconnect) - { - } - - - void BLEGATTStateMachine::close() - { - reset(); - - state = Disconnected; - next_handle_to_read=-1; - last_request=-1; - - if(sock != -1) - log_fd(::close(sock)); - sock = -1; - } - - - int log_l2cap_options(int sock) - { - //Read and log the socket setup. - - l2cap_options options; - unsigned int len = sizeof(options); - memset(&options, 0, len); - - //Get the options with a minor bit of cargo culting. - //SOL_L2CAP seems to mean that is should operate at the L2CAP level of the stack - //L2CAP_OPTIONS who knows? - if(log_fd(getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &options, &len)) == -1) - return -1; - - LOGVAR(Info,options.omtu); - LOGVAR(Info,options.imtu); - LOGVAR(Info,options.flush_to); - LOGVAR(Info,options.mode); - LOGVAR(Info,options.fcs); - LOGVAR(Info,options.max_tx); - LOGVAR(Info,options.txwin_size); - - return 0; - } - - BLEGATTStateMachine::~BLEGATTStateMachine() - { - ENTER(); - close(); - } - - BLEGATTStateMachine::BLEGATTStateMachine() - :dev(sock) - { - ENTER(); - close(); - buf.resize(128); - } - - void BLEGATTStateMachine::connect_blocking(const string& address) - { - connect(address, true); - } - - - void BLEGATTStateMachine::connect_nonblocking(const string& address) - { - connect(address, false); - } - - void BLEGATTStateMachine::connect(const string& address, bool blocking, bool pubaddr, string device) - { - ENTER(); - - //The constructor sets up the socket. Unless something is badly broken, - //then we should succeed. Therefore errors are an exception. - - //Allocate socket and create endpoint. - //Make socket nonblocking so connect() doesn't hang. - - if(blocking) - sock = log_fd(::socket(PF_BLUETOOTH, SOCK_SEQPACKET , BTPROTO_L2CAP)); - else - sock = log_fd(::socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK , BTPROTO_L2CAP)); - - if(sock == -1) - throw SocketAllocationFailed(strerror(errno)); - - //////////////////////////////////////// - //Bind the socket - //I believe that l2 is for an l2cap socket. These are kind of like - //UDP in that they have port numbers and are packet oriented. - //However they are also ordered and reliable. - //So, a sockaddr_l2 has the family (obviously) - //a PSM (wtf?) - // Protocol Service Multiplexer (WTF?) - //an address (of course) - //a CID(Channel ID) - See bluetooth 4.2 core spec for more info - // Section 2.1 CHANNEL IDENTIFIERS ATTRIBUTE PROTOCOL - //and an address type - // See bluetooth 4.2 core spec for more info, section 15.1.1 - // Device will either have a registered "public" address, or a private "random" one that meets certain criteria - //Holy cargo cult, Batman! - - - sockaddr_l2 sba; - memset(&sba, 0, sizeof(sba)); - if (device == "") sba.l2_bdaddr={{0,0,0,0,0,0}}; //use default adapter - - else { - bdaddr_t btsrc_addr; - int dev_id = hci_devid(device.c_str()); //obtain device id from HCI device name - LOG(Debug, "dev_id = " << dev_id); - if (dev_id < 0) { - throw SocketConnectFailed("Error obtaining HCI device ID"); - } - hci_devba(dev_id, &btsrc_addr); - bacpy(&sba.l2_bdaddr,&btsrc_addr); //lifted from bluez example, populate src sockaddr with address of desired device - } - - - - - sba.l2_family=AF_BLUETOOTH; - sba.l2_cid = htobs(LE_ATT_CID); - sba.l2_bdaddr_type = BDADDR_LE_PUBLIC; - log_fd(bind(sock, (sockaddr*)&sba , sizeof(sba))); - - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - addr.l2_psm = 0; - addr.l2_cid = htobs(LE_ATT_CID); - - - //Address type: Low Energy PUBLIC or RANDOM - if (pubaddr) addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; - else addr.l2_bdaddr_type = BDADDR_LE_RANDOM; - - if(log_l2cap_options(sock) == -1) - { - reset(); - throw SocketGetSockOptFailed(strerror(errno)); - } - //Construct an address from the address string - - - - - - //Can also use bacpy to copy addresses about - int rr = str2ba(address.c_str(), &addr.l2_bdaddr); - LOG(Debug, "address = " << address); - LOG(Debug, "str2ba = " << rr); - int ret = log_fd(::connect(sock, (sockaddr*)&addr, sizeof(addr))); - - - - if(ret == 0) - { - state = Idle; - - if(log_l2cap_options(sock) == -1) - { - reset(); - throw SocketGetSockOptFailed(strerror(errno)); - } - - cb_connected(); - } - else if(errno == EINPROGRESS) - { - //This "error" means the connection is happening and - //we should come back later after select() returns. - state = Connecting; - } - else if(errno == ENETUNREACH || errno == EHOSTUNREACH) - { - close(); - cb_disconnected(Disconnect(Disconnect::Reason::ConnectionFailed, errno)); - } - else - { - reset(); - throw SocketConnectFailed(strerror(errno)); - } - } - - - - int BLEGATTStateMachine::socket() - { - return sock; - } - - void BLEGATTStateMachine::reset() - { - state = Idle; - next_handle_to_read=-1; - last_request=-1; - } - - - - - void BLEGATTStateMachine::state_machine_write() - { - try - { - if(state == ReadingPrimaryService) - { - last_request = ATT_OP_READ_BY_GROUP_REQ; - dev.send_read_group_by_type(UUID(GATT_UUID_PRIMARY), next_handle_to_read, 0xffff); - } - else if(state == FindAllCharacteristics) - { - last_request = ATT_OP_READ_BY_TYPE_REQ; - dev.send_read_by_type(UUID(GATT_CHARACTERISTIC), next_handle_to_read, 0xffff); - } - else if(state == GetClientCharaceristicConfiguration) - { - last_request = ATT_OP_READ_BY_TYPE_REQ; - dev.send_read_by_type(UUID(GATT_CLIENT_CHARACTERISTIC_CONFIGURATION), next_handle_to_read, 0xffff); - } - else if(state == AwaitingWriteResponse) - { - last_request = ATT_OP_WRITE_REQ; - //data already sent - } - } - catch(BLEDevice::WriteError) - { - fail(Disconnect(Disconnect::Reason::WriteError, errno)); - } - - } - - - - //////////////////////////////////////////////////////////////////////////////// - // - // Commands to move machine into other states explicitly - // - - void BLEGATTStateMachine::read_primary_services() - { - if(state != Idle) - throw logic_error("Error trying to issue command mid state"); - state = ReadingPrimaryService; - next_handle_to_read=1; - state_machine_write(); - } - - void BLEGATTStateMachine::find_all_characteristics() - { - if(state != Idle) - throw logic_error("Error trying to issue command mid state"); - state = FindAllCharacteristics; - next_handle_to_read=1; - state_machine_write(); - } - - void BLEGATTStateMachine::get_client_characteristic_configuration() - { - if(state != Idle) - throw logic_error("Error trying to issue command mid state"); - state = GetClientCharaceristicConfiguration; - next_handle_to_read=1; - state_machine_write(); - } - - void BLEGATTStateMachine::set_notify_and_indicate(Characteristic& c, bool notify, bool indicate) - { - LOG(Trace, "BLEGATTStateMachine::enable_indications(Characteristic&)"); - - if(state != Idle) - throw logic_error("Error trying to issue command mid state"); - - if(!c.indicate && indicate) - throw logic_error("Error: this is not indicateable"); - if(!c.notify && notify) - throw logic_error("Error: this is not notifiable"); - - //FIXME: check for CCC - c.ccc_last_known_value = notify | (indicate << 1); - - - try{ - dev.send_write_command(c.client_characteric_configuration_handle, c.ccc_last_known_value); - } - catch(BLEDevice::WriteError) - { - fail(Disconnect(Disconnect::Reason::WriteError, errno)); - } - } - - - bool BLEGATTStateMachine::wait_on_write() - { - if(state == Connecting) - return true; - else - return false; - } - - void BLEGATTStateMachine::fail(Disconnect d) - { - close(); - cb_disconnected(d); - } - - void BLEGATTStateMachine::unexpected_error(const PDUErrorResponse& r) - { - PDUErrorResponse err(r); - string msg = string("Received unexpected error:") + att_ecode2str(err.error_code()); - LOG(Error, msg); - fail(Disconnect(Disconnect::Reason::UnexpectedError, Disconnect::NoErrorCode)); - } - //////////////////////////////////////////////////////////////////////////////// - // - // The state machine itself! - void BLEGATTStateMachine::write_and_process_next() - { - ENTER(); - try - { - LOG(Debug, "State is: " << state); - if(state == Connecting) - { - int errval=-7; - socklen_t len; - len = sizeof(errval); - //Check the status of the socket - log_fd(getsockopt(sock, SOL_SOCKET, SO_ERROR, &errval, &len)); - - LOG(Info, "errval = " << strerror(errval)); - - if(errval == 0) - { - //Connected, so go to the idle state - reset(); - cb_connected(); - } - else - { - close(); - cb_disconnected(Disconnect(Disconnect::Reason::ConnectionFailed, errval)); - } - - } - else - { - LOG(Error, "Not implemented!"); - } - } - catch(BLEDevice::WriteError) - { - fail(Disconnect(Disconnect::Reason::WriteError, errno)); - } - catch(BLEDevice::ReadError) - { - fail(Disconnect(Disconnect::Reason::ReadError, errno)); - } - } - - void BLEGATTStateMachine::read_and_process_next() - { - ENTER(); - //This is always an error - if(state == Connecting) - throw logic_error("Trying to read socket while connecting"); - - - if(state == Disconnected) - { - //This is just possible. Imagine select() returning both read and write. - //The write is processed first and fails, causing a disconnect. - //The program then issues a call to read without checking for errors. - //The result is harmless and unlikely, so log a warning. - LOG(Warning, "Trying to read_and_process_next while disconnected"); - return; - } - - try - { - PDUResponse r = dev.receive(buf); - - if(r.type() == ATT_OP_HANDLE_NOTIFY || r.type() == ATT_OP_HANDLE_IND) - { - PDUNotificationOrIndication n(r); - //Find the correct characteristic - for(auto& s:primary_services) - if(n.handle() > s.start_handle && n.handle() <= s.end_handle) - for(auto& c:s.characteristics) - if(n.handle() == c.value_handle) - { - if(c.cb_notify_or_indicate) - c.cb_notify_or_indicate(n); - else if(cb_notify_or_indicate) - cb_notify_or_indicate(c, n); - else - LOG(Warning, "Notify arrived, but no callback set\n"); - } - - //Respond to indications after the callback has run - if(!n.notification()) - dev.send_handle_value_confirmation(); - } - else if(r.type() == ATT_OP_ERROR && PDUErrorResponse(r).request_opcode() != last_request) - { - PDUErrorResponse err(r); - - std::string msg = string("Unexpected opcode in error. Expected ") + att_op2str(last_request) + " got " + att_op2str(err.request_opcode()); - LOG(Error, msg); - fail(Disconnect(Disconnect::Reason::UnexpectedError, Disconnect::NoErrorCode)); - } - else if(r.type() != ATT_OP_ERROR && r.type() != last_request + 1) - { - string msg = string("Unexpected response. Expected ") + att_op2str(last_request+1) + " got " + att_op2str(r.type()); - LOG(Error, msg); - fail(Disconnect(Disconnect::Reason::UnexpectedResponse, Disconnect::NoErrorCode)); - } - else - { - if(state == ReadingPrimaryService) - { - if(r.type() == ATT_OP_ERROR) - { - if(PDUErrorResponse(r).error_code() == ATT_ECODE_ATTR_NOT_FOUND) - { - //Maybe ? Indicates that the last one has been read. - cb_services_read(); - reset(); - } - else - unexpected_error(r); - } - else - { - GATTReadServiceGroup g(r); - - for(int i=0; i < g.num_elements(); i++) - { - struct PrimaryService service; - service.start_handle = g.start_handle(i); - service.end_handle = g.end_handle(i); - service.uuid = UUID::from(g.uuid(i)); - primary_services.push_back(service); - } - - - if(primary_services.back().end_handle == 0xffff) - { - reset(); - cb_services_read(); - } - else - { - next_handle_to_read = primary_services.back().end_handle+1; - state_machine_write(); - } - } - } - else if(state == FindAllCharacteristics) - { - if(r.type() == ATT_OP_ERROR) - { - if(PDUErrorResponse(r).error_code() == ATT_ECODE_ATTR_NOT_FOUND) - { - //Maybe ? Indicates that the last one has been read. - reset(); - cb_find_characteristics(); - } - else - unexpected_error(r); - } - else - { - GATTReadCharacteristic rc(r); - - for(int i=0; i < rc.num_elements(); i++) - { - uint16_t handle = rc.handle(i); - GATTReadCharacteristic::Characteristic ch = rc.characteristic(i); - - LOG(Debug, "Found characteristic handle: " << to_hex(handle)); - - //Search for the correct service. - for(unsigned int s=0; s < primary_services.size(); s++) - { - if(handle > primary_services[s].start_handle && handle <= primary_services[s].end_handle) - { - LOG(Debug, " handle belongs to service " << s); - Characteristic c(this); - - - c.broadcast= ch.flags & GATT_CHARACTERISTIC_FLAGS_BROADCAST; - c.read = ch.flags & GATT_CHARACTERISTIC_FLAGS_READ; - c.write_without_response= ch.flags & GATT_CHARACTERISTIC_FLAGS_WRITE_WITHOUT_RESPONSE; - c.write = ch.flags & GATT_CHARACTERISTIC_FLAGS_WRITE; - c.notify = ch.flags & GATT_CHARACTERISTIC_FLAGS_NOTIFY; - c.indicate = ch.flags & GATT_CHARACTERISTIC_FLAGS_INDICATE; - c.authenticated_write = ch.flags & GATT_CHARACTERISTIC_FLAGS_AUTHENTICATED_SIGNED_WRITES; - c.extended = ch.flags & GATT_CHARACTERISTIC_FLAGS_EXTENDED_PROPERTIES; - c.uuid = UUID::from(ch.uuid); - c.value_handle = ch.handle; - c.client_characteric_configuration_handle = 0; - c.first_handle = handle; - - //Initially mark the end as the start of the current service - c.last_handle = primary_services[s].end_handle; - - //Terminate the previous characteristic - if(!primary_services[s].characteristics.empty()) - primary_services[s].characteristics.back().last_handle = handle-1; - - primary_services[s].characteristics.push_back(c); - - - - } - } - - next_handle_to_read = handle+1; - } - LOG(Debug, "Reading " << to_hex((uint16_t)next_handle_to_read) << " next"); - state_machine_write(); - } - } - else if(state == GetClientCharaceristicConfiguration) - { - if(r.type() == ATT_OP_ERROR) - { - if(PDUErrorResponse(r).error_code() == ATT_ECODE_ATTR_NOT_FOUND) - { - //Maybe ? Indicates that the last one has been read. - reset(); - cb_get_client_characteristic_configuration(); - } - else - unexpected_error(r); - } - else - { - GATTReadCCC rc(r); - - for(int i=0; i < rc.num_elements(); i++) - { - uint16_t handle = rc.handle(i); - next_handle_to_read = handle + 1; - LOG(Debug, "Handle: " << to_hex(rc.handle(i)) << " ccc: " << to_hex(rc.ccc(i))); - - - //Find the correct place - for(auto& s:primary_services) - if(handle > s.start_handle && handle <= s.end_handle) - for(auto& c:s.characteristics) - if(handle > c.first_handle && handle <= c.last_handle) - { - c.client_characteric_configuration_handle = rc.handle(i); - c.ccc_last_known_value = rc.ccc(i); - } - - } - state_machine_write(); - } - } - else if(state == AwaitingWriteResponse) - { - - if(r.type() == ATT_OP_ERROR) - unexpected_error(r); - else - { - reset(); - cb_write_response(); - } - } - } - } - catch(BLEDevice::WriteError) - { - fail(Disconnect(Disconnect::WriteError, errno)); - } - catch(BLEDevice::ReadError) - { - fail(Disconnect(Disconnect::ReadError, errno)); - } - } - - - void BLEGATTStateMachine::send_write_request(uint16_t handle, const uint8_t* data, int length) - { - if(state != Idle) - throw logic_error("Error trying to issue command mid state"); - dev.send_write_request(handle, data, length); - state = AwaitingWriteResponse; - state_machine_write(); - } - - void Characteristic::write_request(const uint8_t*data, int length) - { - s->send_write_request(value_handle, data, length); - } - - - void Characteristic::write_request(const uint8_t data) - { - s->send_write_request(value_handle, &data, 1); - } - - void Characteristic::set_notify_and_indicate(bool notify, bool indicate) - { - LOG(Trace, "Characteristic::enable_indications()"); - s->set_notify_and_indicate(*this, notify, indicate); - } - - - void pretty_print_tree(const BLEGATTStateMachine& s) - { - - cout << "Primary services:\n"; - for(auto& service: s.primary_services) - { - cout << "Start: " << to_hex(service.start_handle); - cout << " End: " << to_hex(service.end_handle); - cout << " UUID: " << to_str(service.uuid) << endl; - const ServiceInfo* s = lookup_service_by_UUID(UUID::from(service.uuid)); - if(s) - cout << " " << s->id << ": " << s->name << endl; - else - cout << " Unknown\n"; - - - for(auto& characteristic: service.characteristics) - { - cout << " Characteristic: " << to_str(characteristic.uuid) << endl; - cout << " Start: " << to_hex(characteristic.first_handle) << " End: " << to_hex(characteristic.last_handle) << endl; - - cout << " Flags: "; - if(characteristic.broadcast) - cout << "Broadcast "; - if(characteristic.read) - cout << "Read "; - if(characteristic.write_without_response) - cout << "Write (without response) "; - if(characteristic.write) - cout << "Write "; - if(characteristic.notify) - cout << "Notify "; - if(characteristic.indicate) - cout << "Indicate "; - if(characteristic.authenticated_write) - cout << "Authenticated signed writes "; - if(characteristic.extended) - cout << "Extended properties "; - cout << endl; - - cout << " Value at handle: " << characteristic.value_handle << endl; - - if(characteristic.client_characteric_configuration_handle != 0) - cout << " CCC: (" << to_hex(characteristic.client_characteric_configuration_handle) << ") " << to_hex(characteristic.ccc_last_known_value) << endl; - - cout << endl; - - } - - cout << endl; - } - } - - - //Handy utility function to do the sort of thing you'd normally do. - void BLEGATTStateMachine::setup_standard_scan(std::function& cb) - { - ENTER(); - - primary_services.clear(); - - cb_services_read = [this]() - { - this->find_all_characteristics(); - }; - - - cb_find_characteristics = [this]() - { - this->get_client_characteristic_configuration(); - }; - - cb_get_client_characteristic_configuration = [&cb]() - { - cb(); - }; - - cb_connected = [this]() - { - read_primary_services(); - }; - } - -} diff --git a/vendor/libblepp-master/src/float.cc b/vendor/libblepp-master/src/float.cc deleted file mode 100644 index 753d386..0000000 --- a/vendor/libblepp-master/src/float.cc +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include - -using namespace std; - -namespace BLEPP -{ - - float bluetooth_float_to_IEEE754(const uint8_t* bytes) - { - int exponent = (int8_t)bytes[3]; - - int mantissa = (bytes[0]) | (bytes[1] << 8) | (bytes[2] << 16); - - if(mantissa > 0x080000) - mantissa = - (0x100000-mantissa); - - - return mantissa * pow(10, exponent); - - } -} diff --git a/vendor/libblepp-master/src/lescan.cc b/vendor/libblepp-master/src/lescan.cc deleted file mode 100644 index e9310e5..0000000 --- a/vendor/libblepp-master/src/lescan.cc +++ /dev/null @@ -1,701 +0,0 @@ -#include "blepp/lescan.h" -#include "blepp/pretty_printers.h" -#include "blepp/gap.h" - -#include -#include -#include -#include -#include - -using namespace std; - -namespace BLEPP -{ - class Span - { - private: - const uint8_t* begin_; - const uint8_t* end_; - - public: - Span(const std::vector& d) - :begin_(d.data()),end_(begin_ + d.size()) - { - } - - Span(const Span&) = default; - - Span pop_front(size_t length) - { - if(length > size()) - throw std::out_of_range(""); - - Span s = *this; - s.end_ = begin_ + length; - - begin_ += length; - return s; - } - const uint8_t* begin() const - { - return begin_; - } - const uint8_t* end() const - { - return end_; - } - - const uint8_t& operator[](const size_t i) const - { - if(i >= size()) - throw std::out_of_range(""); - return begin_[i]; - } - - bool empty() const - { - return size()==0; - } - - size_t size() const - { - return end_ - begin_; - } - - const uint8_t* data() const - { - return begin_; - } - - const uint8_t& pop_front() - { - if(begin_ == end_) - throw std::out_of_range(""); - - begin_++; - return *(begin_-1); - } - }; - - AdvertisingResponse::Flags::Flags(vector&& s) - :flag_data(s) - { - //Remove the type field - flag_data.erase(flag_data.begin()); - if(!flag_data.empty()) - { - //See 4.0/4.C.18.1 - LE_limited_discoverable = flag_data[0] & (1<<0); - LE_general_discoverable = flag_data[0] & (1<<1); - BR_EDR_unsupported = flag_data[0] & (1<<2); - simultaneous_LE_BR_controller = flag_data[0] & (1<<3); - simultaneous_LE_BR_host = flag_data[0] & (1<<4); - } - } - - string to_hex(const Span& s) - { - return to_hex(s.data(), s.size()); - } - - HCIScanner::Error::Error(const string& why) - :std::runtime_error(why) - { - LOG(LogLevels::Error, why); - } - - HCIScanner::IOError::IOError(const string& why, int errno_val) - :Error(why + ": " + strerror(errno_val)) - { - } - - HCIScanner::HCIScanner(bool start_scan) - :HCIScanner(start_scan, FilterDuplicates::Both, ScanType::Active) - { - } - - - HCIScanner::HCIScanner(bool start_scan, FilterDuplicates filtering, ScanType st, string device) - { - if(filtering == FilterDuplicates::Hardware || filtering == FilterDuplicates::Both) - hardware_filtering = true; - else - hardware_filtering = false; - - if(filtering == FilterDuplicates::Software || filtering == FilterDuplicates::Both) - software_filtering = true; - else - software_filtering = false; - - scan_type=st; - - int dev_id = 0; - if (device == "") { - //Get a route to any(?) BTLE adapter (?) - dev_id = hci_get_route(NULL); - } - else { - dev_id = hci_devid(device.c_str()); - } - if (dev_id < 0) { - throw HCIError("Error obtaining HCI device ID"); - } - - //Open the device - //FIXME check errors - hci_fd.set(hci_open_dev(dev_id)); - - if(start_scan) - start(); - } - - HCIScanner::HCIScanner() - :HCIScanner(true) - { - - } - - void HCIScanner::start() - { - ENTER(); - if(running) - { - LOG(Trace, "Scanner is already running"); - return; - } - - //Cadged from the hcitool sources. No idea what - //these mean - uint16_t interval = htobs(0x0010); - uint16_t window = htobs(0x0010); - - //Address for the adapter (I think). Use a public address. - //other option is random. Works either way it seems. - uint8_t own_type = LE_PUBLIC_ADDRESS; - - //Don't use a whitelist (?) - uint8_t filter_policy = 0x00; - - - //The 10,000 thing seems to be some sort of retry logic timeout - //thing. Number of miliseconds, but there are multiple tries - //where it gets reduced by 10ms each time. It's a bit odd. - int err = hci_le_set_scan_parameters(hci_fd, static_cast(scan_type), interval, window, - own_type, filter_policy, 10000); - if(err < 0) - { - if(errno != EIO) - throw IOError("Setting scan parameters", errno); - else - { - //If the BLE device is already set to scanning, then we get an IO error. So - //try turning it off and trying again. This bad state would happen, if, to pick - //like a *totally* hypothetical example, the program segged-out during scanning - //and so never cleaned up properly. - LOG(LogLevels::Warning, "Received I/O error while setting scan parameters."); - LOG(LogLevels::Warning, "Switching off HCI scanner"); - err = hci_le_set_scan_enable(hci_fd, 0x00, 0x00, 10000); - if(err < 0) - throw IOError("Error disabling scan:", errno); - - - err = hci_le_set_scan_parameters(hci_fd, static_cast(scan_type), interval, window, own_type, filter_policy, 10000); - if(err < 0) - throw IOError("Error disabling scan:", errno); - else - LOG(LogLevels::Warning, "Setting scan parameters worked this time."); - - - } - } - - LOG(LogLevels::Info, "Starting scanner"); - scanned_devices.clear(); - - //Removal of duplicates done on the adapter itself - uint8_t filter_dup = hardware_filtering?0x01:0x00; - - - //Set up the filters. - socklen_t olen = sizeof(old_filter); - if (getsockopt(hci_fd, SOL_HCI, HCI_FILTER, &old_filter, &olen) < 0) - throw IOError("Getting HCI filter socket options", errno); - - - //Magic incantations to get scan events - struct hci_filter nf; - hci_filter_clear(&nf); - hci_filter_set_ptype(HCI_EVENT_PKT, &nf); - hci_filter_set_event(EVT_LE_META_EVENT, &nf); - if (setsockopt(hci_fd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) - throw IOError("Setting HCI filter socket options", errno); - - - //device disable/enable duplictes ???? - err = hci_le_set_scan_enable(hci_fd, 0x01, filter_dup, 10000); - if(err < 0) - throw IOError("Enabling scan", errno); - - running=true; - } - - void HCIScanner::stop() - { - ENTER(); - if(!running) - { - return; - } - - LOG(LogLevels::Info, "Cleaning up HCI scanner"); - int err = hci_le_set_scan_enable(hci_fd, 0x00, 0x00, 10000); - - if(err < 0) - throw IOError("Error disabling scan:", errno); - - err = setsockopt(hci_fd, SOL_HCI, HCI_FILTER, &old_filter, sizeof(old_filter)); - - if(err < 0) - throw IOError("Error resetting HCI socket:", errno); - - running = false; - } - - int HCIScanner::get_fd() const - { - return hci_fd; - } - - - HCIScanner::~HCIScanner() - { - try - { - stop(); - } - catch(IOError) - { - } - } - - HCIScanner::FilterEntry::FilterEntry(const AdvertisingResponse& a) - :mac_address(a.address),type(static_cast(a.type)) - {} - - bool HCIScanner::FilterEntry::operator<(const FilterEntry& f) const - { - //Simple lexi-sorting - if(mac_address < f.mac_address) - return true; - else if(mac_address == f.mac_address) - return type < f.type; - else - return false; - } - - vector HCIScanner::read_with_retry() - { - int len; - std::vector buf(HCI_MAX_EVENT_SIZE); - - - while((len = read(hci_fd, buf.data(), buf.size())) < 0) - { - if(errno == EAGAIN) - continue; - else if(errno == EINTR) - throw Interrupted("interrupted reading HCI packet"); - else - throw IOError("reading HCI packet", errno); - } - - buf.resize(len); - return buf; - } - - vector HCIScanner::get_advertisements() - { - vector adverts = parse_packet(read_with_retry()); - - if(software_filtering) - { - vector filtered; - - for(const auto& a: adverts) - { - auto r = scanned_devices.insert(FilterEntry(a)); - - if(r.second) - filtered.emplace_back(move(a)); - else - LOG(Debug, "Entry " << a.address << " " << static_cast(a.type) << " found already"); - } - - return filtered; - } - else - return adverts; - } - - /* - Hello comment-reader! - - This is a class for dealing with device scanning. The scans are done - using the HCI (Host Controller Interface). Interstingly, the HCI is - well specified even down to the transport layer (RS232 syle, USB, - SDIO and some sort of SLIP based serial). The HCI sometimes unpacks - and aggregates PDUs (the data part of packets) before sending them - for some reason, so you need to look in the HCI part of the spec, - not the PDU part of the spec. - - The HCI is also semi-autonomous, and can be instructed to do things like - sctive scanning (where it queries and reports additional information, - typically the device name) and filtering of duplicated advertising - events. This is great for low power draw because the host CPU doesn't need - to wake up to do menial or unimportant things. - - Also, the HCI of course gives you everything! The kernel contains no - permissioned control over filtering which means anything with permissions - to open the HCI can also get all data packets in both directions and - therefore sniff everything. As a result, scanning normally has to be - activated by root only. - - - The general HCI event format is (Bluetooth 4.0 Vol 2, Part E, 5.4.4) - - - Note that the HCI unpacks some of the bitfields in the advertising - PDU and presents them as whole bytes. - - Packet type is not part of the HCI command. In USB the type is - determined by the endpoint address. In all the serial protocols the - packet type is 1 byte at the beginning where - - Command = 0x01 Event = 0x04 - - See, e.g. 4.0/4/A.2 - - Linux seems to use these. - - And the LE events are all = 0x3E (HCI_LE_META_EVT) as per - 4.0/2/E.7.7.65 - And the format of is: - - - - And we're interested in advertising events, where - = 0x02 (as per 4.0/2/E.7.7.65.2) - - And the format of in this case is - - - - Where is - -
-
- - - - - is an advertising packet and that's specified - all over the place. 4.0/3/C.8 for example. The advertising packets - are of the format: - - - ... - - - Now, the meaning of type, and the valid data are not defined in the main - spec, but in "Supplement to the Bluetooth Core Specification" version 4, - referred to here as S4. Except that defines only the name of the types - not their numeric code for some reason. Those are on the web. - https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile - - - Some datatypes are not valid in advertising packets and some are also not - valid in LE applications. Apart from a small selection, many of the types - are rare to the point of nonexistence. I ignore them because I've got nothing - that generates tham and I wouldn't know what to do with them anyway. Feel free - to fix or ping me if you need them :) - - The ones generally of interest are: - <> - <> - <> - <> - <> - <> - <> - <> - <> - - Personal experience suggest UUIDs and flags are almost always present. - Names are often present. iBeacons use manufacturer specific data whereas - Eddystone beacons use service data. I've used neither. I've not personally - seen or heard of any of the other types, including 32 bit UUIDs. - - There are also some moderately sensible restrictions. A device SHALL NOT - report bot incomplete and complete lists of the same things in the same - packet S4/1.1.1. Furthermore an ommitted UUID specification is equivalent - to a incomplete list with no elements. - - - - Returns 1 on success, 0 on failure - such as an inability - to handle the packet, not an error. - - Return code can probably be ignored because - it will call lambdas on specific packets anyway. - - TODO: replace some errors with throw. - such as the HCI device spewing crap. - - */ - - vector parse_event_packet(Span packet); - vector parse_le_meta_event(Span packet); - vector parse_le_meta_event_advertisement(Span packet); - - vector HCIScanner::parse_packet(const vector& p) - { - Span packet(p); - LOG(Debug, to_hex(p)); - - if(packet.size() < 1) - { - LOG(LogLevels::Error, "Empty packet received"); - return {}; - } - - uint8_t packet_id = packet.pop_front(); - - - if(packet_id == HCI_EVENT_PKT) - { - LOG(Debug, "Event packet received"); - return parse_event_packet(packet); - } - else - { - LOG(LogLevels::Error, "Unknown HCI packet received"); - throw HCIError("Unknown HCI packet received"); - } - } - - vector parse_event_packet(Span packet) - { - if(packet.size() < 2) - throw HCIScanner::HCIError("Truncated event packet"); - - uint8_t event_code = packet.pop_front(); - uint8_t length = packet.pop_front(); - - - if(packet.size() != length) - throw HCIScanner::HCIError("Bad packet length"); - - if(event_code == EVT_LE_META_EVENT) - { - LOG(Info, "event_code = 0x" << hex << (int)event_code << ": Meta event" << dec); - LOGVAR(Info, length); - - return parse_le_meta_event(packet); - } - else - { - LOG(Info, "event_code = 0x" << hex << (int)event_code << dec); - LOGVAR(Info, length); - throw HCIScanner::HCIError("Unexpected HCI event packet"); - } - } - - - vector parse_le_meta_event(Span packet) - { - uint8_t subevent_code = packet.pop_front(); - - if(subevent_code == 0x02) // see big blob of comments above - { - LOG(Info, "subevent_code = 0x02: LE Advertising Report Event"); - return parse_le_meta_event_advertisement(packet); - } - else - { - LOGVAR(Info, subevent_code); - return {}; - } - } - - vector parse_le_meta_event_advertisement(Span packet) - { - vector ret; - - uint8_t num_reports = packet.pop_front(); - LOGVAR(Info, num_reports); - - for(int i=0; i < num_reports; i++) - { - LeAdvertisingEventType event_type = static_cast(packet.pop_front()); - - if(event_type == LeAdvertisingEventType::ADV_IND) - LOG(Info, "event_type = 0x00 ADV_IND, Connectable undirected advertising"); - else if(event_type == LeAdvertisingEventType::ADV_DIRECT_IND) - LOG(Info, "event_type = 0x01 ADV_DIRECT_IND, Connectable directed advertising"); - else if(event_type == LeAdvertisingEventType::ADV_SCAN_IND) - LOG(Info, "event_type = 0x02 ADV_SCAN_IND, Scannable undirected advertising"); - else if(event_type == LeAdvertisingEventType::ADV_NONCONN_IND) - LOG(Info, "event_type = 0x03 ADV_NONCONN_IND, Non connectable undirected advertising"); - else if(event_type == LeAdvertisingEventType::SCAN_RSP) - LOG(Info, "event_type = 0x04 SCAN_RSP, Scan response"); - else - LOG(Warning, "event_type = 0x" << hex << (int)event_type << dec << ", unknown"); - - uint8_t address_type = packet.pop_front(); - - if(address_type == 0) - LOG(Info, "Address type = 0: Public device address"); - else if(address_type == 1) - LOG(Info, "Address type = 0: Random device address"); - else - LOG(Info, "Address type = 0x" << to_hex(address_type) << ": unknown"); - - - string address; - for(int j=0; j < 6; j++) - { - ostringstream s; - s << hex << setw(2) << setfill('0') << (int) packet.pop_front(); - if(j != 0) - s << ":"; - - address = s.str() + address; - } - - - LOGVAR(Info, address); - - uint8_t length = packet.pop_front(); - LOGVAR(Info, length); - - - Span data = packet.pop_front(length); - - LOG(Debug, "Data = " << to_hex(data)); - - int8_t rssi = packet.pop_front(); - - if(rssi == 127) - LOG(Info, "RSSI = 127: unavailable"); - else if(rssi <= 20) - LOG(Info, "RSSI = " << (int) rssi << " dBm"); - else - LOG(Info, "RSSI = " << to_hex((uint8_t)rssi) << " unknown"); - - try{ - AdvertisingResponse rsp; - rsp.address = address; - rsp.type = event_type; - - while(data.size() > 0) - { - LOGVAR(Debug, data.size()); - LOG(Debug, "Packet = " << to_hex(data)); - //Format is length, type, crap - int length = data.pop_front(); - - LOGVAR(Debug, length); - - Span chunk = data.pop_front(length); - uint8_t type = chunk[0]; - LOGVAR(Debug, type); - - if(type == GAP::flags) - { - rsp.flags = AdvertisingResponse::Flags({chunk.begin(), chunk.end()}); - - LOG(Info, "Flags = " << to_hex(rsp.flags->flag_data)); - - if(rsp.flags->LE_limited_discoverable) - LOG(Info, " LE limited discoverable"); - - if(rsp.flags->LE_general_discoverable) - LOG(Info, " LE general discoverable"); - - if(rsp.flags->BR_EDR_unsupported) - LOG(Info, " BR/EDR unsupported"); - - if(rsp.flags->simultaneous_LE_BR_host) - LOG(Info, " simultaneous LE BR host"); - - if(rsp.flags->simultaneous_LE_BR_controller) - LOG(Info, " simultaneous LE BR controller"); - } - else if(type == GAP::incomplete_list_of_16_bit_UUIDs || type == GAP::complete_list_of_16_bit_UUIDs) - { - rsp.uuid_16_bit_complete = (type == GAP::complete_list_of_16_bit_UUIDs); - chunk.pop_front(); //remove the type field - - while(!chunk.empty()) - { - uint16_t u = chunk.pop_front() + chunk.pop_front()*256; - rsp.UUIDs.push_back(UUID(u)); - } - } - else if(type == GAP::incomplete_list_of_128_bit_UUIDs || type == GAP::complete_list_of_128_bit_UUIDs) - { - rsp.uuid_128_bit_complete = (type == GAP::complete_list_of_128_bit_UUIDs); - chunk.pop_front(); //remove the type field - - while(!chunk.empty()) - rsp.UUIDs.push_back(UUID::from(att_get_uuid128(chunk.pop_front(16).data()))); - } - else if(type == GAP::shortened_local_name || type == GAP::complete_local_name) - { - chunk.pop_front(); - AdvertisingResponse::Name n; - n.complete = type==GAP::complete_local_name; - n.name = string(chunk.begin(), chunk.end()); - rsp.local_name = n; - - LOG(Info, "Name (" << (n.complete?"complete":"incomplete") << "): " << n.name); - } - else if(type == GAP::manufacturer_data) - { - chunk.pop_front(); - rsp.manufacturer_specific_data.push_back({chunk.begin(), chunk.end()}); - LOG(Info, "Manufacturer data: " << to_hex(chunk)); - } - else - { - rsp.unparsed_data_with_types.push_back({chunk.begin(), chunk.end()}); - - LOG(Info, "Unparsed chunk " << to_hex(chunk)); - } - } - - if(rsp.UUIDs.size() > 0) - { - LOG(Info, "UUIDs (128 bit " << (rsp.uuid_128_bit_complete?"complete":"incomplete") - << ", 16 bit " << (rsp.uuid_16_bit_complete?"complete":"incomplete") << " ):"); - - for(const auto& uuid: rsp.UUIDs) - LOG(Info, " " << to_str(uuid)); - } - - ret.push_back(rsp); - - - } - catch(out_of_range r) - { - LOG(LogLevels::Error, "Corrupted data sent by device " << address); - } - } - - return ret; - } - - -} diff --git a/vendor/libblepp-master/src/logging.cc b/vendor/libblepp-master/src/logging.cc deleted file mode 100644 index 871578a..0000000 --- a/vendor/libblepp-master/src/logging.cc +++ /dev/null @@ -1,28 +0,0 @@ -/* - * - * blepp - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#include "blepp/logging.h" - -namespace BLEPP -{ - LogLevels log_level; -} - diff --git a/vendor/libblepp-master/src/pretty_printers.cc b/vendor/libblepp-master/src/pretty_printers.cc deleted file mode 100644 index 0fc85d6..0000000 --- a/vendor/libblepp-master/src/pretty_printers.cc +++ /dev/null @@ -1,110 +0,0 @@ -/* - * - * blepp - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#include - -#include -#include -using namespace std; - -namespace BLEPP -{ - - std::string to_hex(const std::uint16_t& u) - { - stringstream os; - os << setw(4) << setfill('0') << hex << u; - return os.str(); - } - - std::string to_hex(const std::uint8_t& u) - { - stringstream os; - os << setw(2) << setfill('0') << hex << (int)u; - return os.str(); - } - - std::string to_str(const std::uint8_t& u) - { - if(u < 32 || u > 126) - return "\\x" + to_hex(u); - else - { - char buf[] = {(char)u, 0}; - return buf; - } - } - - std::string to_str(const bt_uuid_t& uuid) - { - //8 4 4 4 12 - if(uuid.type == BT_UUID16) - return to_hex(uuid.value.u16); - else if(uuid.type == BT_UUID128) - { - char s[] = "xoxoxoxo-xoxo-xoxo-xoxo-xoxoxoxoxoxo"; - bt_uuid_to_string(&uuid, s, sizeof(s)); - return s; - } - else - return "uuid.wtf"; - - } - - std::string to_hex(const std::uint8_t* d, int l) - { - stringstream os; - for(int i=0; i < l; i++) - os << to_hex(d[i]) << " "; - return os.str(); - } - std::string to_hex(pair d) - { - return to_hex(d.first, d.second); - } - - std::string to_hex(const vector& v) - { - return to_hex(v.data(), v.size()); - } - - std::string to_str(const std::uint8_t* d, int l) - { - stringstream os; - for(int i=0; i < l; i++) - os << to_str(d[i]); - return os.str(); - } - std::string to_str(pair d) - { - return to_str(d.first, d.second); - } - std::string to_str(pair d) - { - return to_str(d.first, d.second - d.first); - } - - std::string to_str(const vector& v) - { - return to_str(v.data(), v.size()); - } - -} diff --git a/vendor/libblepp-master/src/uuid.cc b/vendor/libblepp-master/src/uuid.cc deleted file mode 100644 index 3d3fd43..0000000 --- a/vendor/libblepp-master/src/uuid.cc +++ /dev/null @@ -1,244 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2011 Nokia Corporation - * Copyright (C) 2011 Marcel Holtmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include - -namespace BLEPP -{ - - //Always store full UUIDs as little endian, since they come over - //the wire that way. - // - //Also, see Bluetooth 4.0, Part B, Section 2.5.1 - static uint128_t bluetooth_base_uuid = { - .data = { 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } - }; - - //12 = 96/8 - #define BASE_UUID_OFFSET 12 - - static void bt_uint32_to_uuid128(uint32_t src, bt_uuid_t *dst) - { - dst->value.u128 = bluetooth_base_uuid; - dst->type = BT_UUID128; - - for(int i=0; i < 4; i++) - dst->value.u128.data[BASE_UUID_OFFSET+i] = (src>>8*i) & 0xff; - } - - void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst) - { - switch (src->type) { - case BT_UUID128: - *dst = *src; - break; - case BT_UUID32: - bt_uint32_to_uuid128(src->value.u32, dst); - break; - case BT_UUID16: - bt_uint32_to_uuid128(src->value.u16, dst); - break; - default: - break; - } - } - - static int bt_uuid128_cmp(const bt_uuid_t *u1, const bt_uuid_t *u2) - { - return memcmp(&u1->value.u128, &u2->value.u128, sizeof(uint128_t)); - } - - int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value) - { - memset(btuuid, 0, sizeof(bt_uuid_t)); - btuuid->type = BT_UUID16; - btuuid->value.u16 = value; - - return 0; - } - - int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value) - { - memset(btuuid, 0, sizeof(bt_uuid_t)); - btuuid->type = BT_UUID32; - btuuid->value.u32 = value; - - return 0; - } - - int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value) - { - memset(btuuid, 0, sizeof(bt_uuid_t)); - btuuid->type = BT_UUID128; - btuuid->value.u128 = value; - - return 0; - } - - int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2) - { - bt_uuid_t u1, u2; - - bt_uuid_to_uuid128(uuid1, &u1); - bt_uuid_to_uuid128(uuid2, &u2); - - return bt_uuid128_cmp(&u1, &u2); - } - - - static uint16_t u16_from_le(const uint8_t* data) - { - return data[0] + (data[1]<<8); - } - - /* - * convert the UUID to string, copying a maximum of n characters. - */ - int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n) - { - if (!uuid) { - snprintf(str, n, "NULL"); - return -EINVAL; - } - - switch (uuid->type) { - case BT_UUID16: - snprintf(str, n, "%.4x", uuid->value.u16); - break; - case BT_UUID32: - snprintf(str, n, "%.8x", uuid->value.u32); - break; - case BT_UUID128: - snprintf(str, n, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", - u16_from_le(uuid->value.u128.data + 14), - u16_from_le(uuid->value.u128.data + 12), - u16_from_le(uuid->value.u128.data + 10), - u16_from_le(uuid->value.u128.data + 8), - u16_from_le(uuid->value.u128.data + 6), - u16_from_le(uuid->value.u128.data + 4), - u16_from_le(uuid->value.u128.data + 2), - u16_from_le(uuid->value.u128.data + 0)); - - break; - default: - snprintf(str, n, "Type of UUID (%x) unknown.", uuid->type); - return -EINVAL; /* Enum type of UUID not set */ - } - - return 0; - } - - static inline int is_uuid128(const char *string) - { - return (strlen(string) == 36 && - string[8] == '-' && - string[13] == '-' && - string[18] == '-' && - string[23] == '-'); - } - - static inline int is_uuid32(const char *string) - { - return (strlen(string) == 8 || strlen(string) == 10); - } - - static inline int is_uuid16(const char *string) - { - return (strlen(string) == 4 || strlen(string) == 6); - } - - static int bt_string_to_uuid16(bt_uuid_t *uuid, const char *string) - { - uint16_t u16; - char *endptr = NULL; - - u16 = strtol(string, &endptr, 16); - if (endptr && *endptr == '\0') { - bt_uuid16_create(uuid, u16); - return 0; - } - - return -EINVAL; - } - - static int bt_string_to_uuid32(bt_uuid_t *uuid, const char *string) - { - uint32_t u32; - char *endptr = NULL; - - u32 = strtol(string, &endptr, 16); - if (endptr && *endptr == '\0') { - bt_uuid32_create(uuid, u32); - return 0; - } - - return -EINVAL; - } - - - static int bt_string_to_uuid128(bt_uuid_t *uuid, const char *string) - { - unsigned int data[16]; - - if(sscanf(string, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - &data[15], &data[14], &data[13], &data[12], - &data[11], &data[10], &data[ 9], &data[ 8], - &data[ 7], &data[ 6], &data[ 5], &data[ 4], - &data[ 3], &data[ 2], &data[ 1], &data[ 0]) != 16) - return -EINVAL; - - uuid->type = BT_UUID128; - - for(int i=0; i < 16; i++) - uuid->value.u128.data[i] = data[i]; - return 0; - } - - int bt_string_to_uuid(bt_uuid_t *uuid, const char *string) - { - if (is_uuid128(string)) - return bt_string_to_uuid128(uuid, string); - else if (is_uuid32(string)) - return bt_string_to_uuid32(uuid, string); - else if (is_uuid16(string)) - return bt_string_to_uuid16(uuid, string); - - return -EINVAL; - } - - int bt_uuid_strcmp(const void *a, const void *b) - { - return strcasecmp(static_cast(a), static_cast(b)); - } - -} diff --git a/vendor/libblepp-master/temperature.cc b/vendor/libblepp-master/temperature.cc deleted file mode 100644 index 06a12aa..0000000 --- a/vendor/libblepp-master/temperature.cc +++ /dev/null @@ -1,104 +0,0 @@ -/* - * - * libble++ - Implementation of the Generic ATTribute Protocol - * - * Copyright (C) 2013, 2014 Edward Rosten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - - -#include -#include -#include -#include //BLE uses the obscure IEEE11073 decimal exponent floating point values -#include -#include -using namespace std; -using namespace chrono; -using namespace BLEPP; - -int main(int argc, char **argv) -{ - if(argc != 2) - { - cerr << "Please supply address.\n"; - cerr << "Usage:\n"; - cerr << "prog "; - exit(1); - } - - log_level = Error; - - //This class does all of the GATT interactions for you. - //It's a callback based interface, so you need to provide - //callbacks to make it do anything useful. Don't worry: this is - //a library, not a "framework", so it won't steal your main loop. - //In other examples, I show you how to get and use the file descriptor, so - //you will only make calls into BLEGATTStateMachine when there's data - //to process. - BLEGATTStateMachine gatt; - - //This function will be called when a push notification arrives from the device. - //Not much sanity/error checking here, just for clarity. - //Basically, extract the float and log it along with the time. - std::function notify_cb = [&](const PDUNotificationOrIndication& n) - { - auto ms_since_epoch = duration_cast(system_clock::now().time_since_epoch()); - float temp = bluetooth_float_to_IEEE754(n.value().first+1); - - cout << setprecision(15) << ms_since_epoch.count()/1000. << " " << setprecision(5) << temp << endl; - }; - - //This is called when a complete scan of the device is done, giving - //all services and characteristics. This one simply searches for the - //standardised "temperature" characteristic (aggressively cheating and not - //bothering to check if the service is correct) and sets up the device to - //send us notifications. - // - //This will simply sit there happily connected in blissful ignorance if there's - //no temperature characteristic. - std::function found_services_and_characteristics_cb = [&gatt, ¬ify_cb](){ - for(auto& service: gatt.primary_services) - for(auto& characteristic: service.characteristics) - if(characteristic.uuid == UUID("2a1c")) - { - characteristic.cb_notify_or_indicate = notify_cb; - characteristic.set_notify_and_indicate(true, false); - } - }; - - //This is the simplest way of using a bluetooth device. If you call this - //helper function, it will put everything in place to do a complete scan for - //services and characteristics when you connect. If you want to save a small amount - //of time on a connect and avoid the complete scan (you are allowed to cache this - //information in certain cases), then you can provide your own callbacks. - gatt.setup_standard_scan(found_services_and_characteristics_cb); - - //I think this one is reasonably clear? - gatt.cb_disconnected = [](BLEGATTStateMachine::Disconnect d) - { - cerr << "Disconnect for reason " << BLEGATTStateMachine::get_disconnect_string(d) << endl; - exit(1); - }; - - //This is how to use the blocking interface. It is very simple. You provide the main - //loop and just hammer on the state machine struct. - gatt.connect_blocking(argv[1]); - for(;;) - gatt.read_and_process_next(); - -} diff --git a/vendor/libblepp-master/tests/test_scan.cc b/vendor/libblepp-master/tests/test_scan.cc deleted file mode 100644 index 79cd7de..0000000 --- a/vendor/libblepp-master/tests/test_scan.cc +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - - -using namespace BLEPP; -using namespace std; - -#define check(X) do{\ -if(!(X))\ -{\ - cerr << "Test failed on line " << __LINE__ << ": " << #X << endl;\ - exit(1);\ -}}while(0) - -vector to_data(const string& ss) -{ - istringstream s(ss); - - //Format is > 04 3E ... - - string tmp; - s >> tmp; - s>>hex; - - vector ret; - - for(;;) - { - int x; - s >> x; - if(s.fail()) - { - return ret; - } - else - ret.push_back(x); - } - -} - -int main() -{ - log_level = LogLevels::Trace; -/* -HCI sniffer - Bluetooth packet analyzer ver 2.5 -device: hci0 snap_len: 1500 filter: 0xffffffffffffffff -< 01 0B 20 07 01 10 00 10 00 00 00 -> 04 0E 04 01 0B 20 00 -< 01 0C 20 02 01 01 -> 04 0E 04 01 0C 20 00 -> 04 3E 0C 02 01 04 01 0B 57 16 21 76 7C 00 C1 -< 01 0C 20 02 00 01 -> 04 0E 04 01 0C 20 00 -*/ - - AdvertisingResponse r = HCIScanner::parse_packet(to_data("> 04 3E 21 02 01 00 00 1B EE B5 80 07 00 15 02 01 06 11 06 64 97 81 D1 ED BA 6B AC 11 4C 9D 34 3E 20 09 73 BC")).back(); - check(r.UUIDs[0] == UUID("7309203e-349d-4c11-ac6b-baedd1819764")); - check(r.UUIDs.size() == 1); - check(r.service_data.empty()); - check(r.manufacturer_specific_data.empty()); - check(r.unparsed_data_with_types.empty()); - check(!r.local_name); - check(!r.uuid_16_bit_complete); - check(!r.uuid_32_bit_complete); - check(!r.uuid_128_bit_complete); - check(!r.flags->LE_limited_discoverable); - check(r.flags); - check(!r.flags->LE_limited_discoverable); - check(r.flags->LE_general_discoverable); - check(r.flags->BR_EDR_unsupported); - check(!r.flags->simultaneous_LE_BR_controller); - check(!r.flags->simultaneous_LE_BR_host); - - - r = HCIScanner::parse_packet(to_data("> 04 3E 24 02 01 04 00 1B EE B5 80 07 00 18 17 09 44 79 6E 6F 66 69 74 20 49 6E 63 20 44 4F 54 53 20 78 78 78 78 31 BE")).back(); - check(r.UUIDs.size() == 0); - check(r.service_data.empty()); - check(r.manufacturer_specific_data.empty()); - check(r.unparsed_data_with_types.empty()); - check(r.local_name); - check(r.local_name->complete); - check(r.local_name->name == "Dynofit Inc DOTS xxxx1"); - check(!r.uuid_16_bit_complete); - check(!r.uuid_32_bit_complete); - check(!r.uuid_128_bit_complete); - check(!r.flags); - - r = HCIScanner::parse_packet(to_data("> 04 3E 17 02 01 00 01 0B 57 16 21 76 7C 0B 02 01 1A 07 FF 4C 00 10 02 0A 00 BC")).back(); - vector vendor_data_1 = {0x4c, 0x00, 0x10, 0x02, 0x0a, 0x00}; - check(r.UUIDs.size() == 0); - check(r.service_data.empty()); - check(r.manufacturer_specific_data.size() == 1); - check(r.manufacturer_specific_data[0].size() == 6); - check(equal(vendor_data_1.begin(), vendor_data_1.end(), r.manufacturer_specific_data[0].begin())); - check(r.unparsed_data_with_types.empty()); - check(!r.local_name); - check(r.flags); - check(!r.flags->LE_limited_discoverable); - check(r.flags->LE_general_discoverable); - check(!r.flags->BR_EDR_unsupported); - check(r.flags->simultaneous_LE_BR_controller); - check(r.flags->simultaneous_LE_BR_host); - -} From 4b0f6898d715a7846b2b5621a420fa42bcdf8f75 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 4 Sep 2017 23:00:06 +0100 Subject: [PATCH 3/9] using git submodule so no need for patch as it has been merged by upstream --- vendor/libblepp-master.patch | 57 ------------------------------------ 1 file changed, 57 deletions(-) delete mode 100644 vendor/libblepp-master.patch diff --git a/vendor/libblepp-master.patch b/vendor/libblepp-master.patch deleted file mode 100644 index 5a5d058..0000000 --- a/vendor/libblepp-master.patch +++ /dev/null @@ -1,57 +0,0 @@ ---- ../libblepp-master.orig/Makefile.in 2017-03-06 16:13:49.000000000 +0000 -+++ Makefile.in 2017-07-29 21:22:54.740176669 +0100 -@@ -88,14 +88,14 @@ - install: install-so install-a install-hdr install-pkgconfig - - --install-a: $(archive) -+install-a: $(archive) | $(if $(wildcard $(lib)),,$(lib)) - cp $(archive) $(lib) - --install-so: $(soname) $(soname1) $(soname2) -+install-so: $(soname) $(soname1) $(soname2) | $(if $(wildcard $(lib)),,$(lib)) - cp $(soname) $(soname1) $(soname2) $(lib) - --install-hdr: -- cp -r blepp $(hdr) -+install-hdr: | $(if $(wildcard $(hdr)),,$(hdr)) -+ cp -r $(srcdir)/blepp $(hdr) - - install-pkgconfig: - [ "$(pkgconfig)" = "" ] || mkdir -p $(DESTDIR)$(pkgconfig) -@@ -108,7 +108,7 @@ - - - #Every .cc file in the tests directory is a test --TESTS=$(notdir $(basename $(wildcard tests/*.cc))) -+TESTS=$(notdir $(basename $(wildcard $(srcdir)/tests/*.cc))) - - - #Get the intermediate file names from the list of tests. -@@ -137,12 +137,12 @@ - - #Build a test executable from a test program. On compile error, - #create an executable which declares the error. --tests/%.test: tests/%.cc $(LIBOBJS) -+tests/%.test: tests/%.cc $(LIBOBJS) | $(if $(wildcard tests),,tests) - $(CXX) $(CXXFLAGS) $^ -o $@ -I . $(LDFLAGS) $(LOADLIBES) || { echo "echo 'Compile error!' ; return 126" > $@ ; chmod +x $@; } - - #Run the program and either use it's output (it should just say OK) - #or a failure message --tests/%.result_: tests/%.test -+tests/%.result_: tests/%.test | $(if $(wildcard tests),,tests) - $< > $@ 2>&1 ; \ - a=$$? ;\ - if [ $$a != 0 ]; \ -@@ -169,7 +169,11 @@ - - include .deps - -+$(LIBOBJS): $(foreach d,$(sort $(dir $(LIBOBJS))),$(if $(wildcard $d),,$d)) -+tests/results: $(if $(wildcard tests),,tests) - -+tests $(sort $(dir $(LIBOBJS))) $(lib) $(hdr): -+ mkdir -p $@ - - - From 37babc7083ce3af26cc7e437b6acd8d66637c91b Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 4 Sep 2017 23:20:27 +0100 Subject: [PATCH 4/9] move libblepp to use git submodule --- .gitmodules | 3 +++ CMakeLists.txt | 6 +++--- vendor/libblepp | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) create mode 160000 vendor/libblepp diff --git a/.gitmodules b/.gitmodules index a04afc2..9b4b4d4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "vendor/serial"] path = vendor/serial url = https://github.com/wjwwood/serial.git +[submodule "vendor/libblepp"] + path = vendor/libblepp + url = https://github.com/edrosten/libblepp.git diff --git a/CMakeLists.txt b/CMakeLists.txt index cdbebdd..95b2a6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,9 +10,8 @@ if (FIRMATA_WITH_BLUETOOTH) include (ExternalProject) ExternalProject_Add(libblepp - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/libblepp-master - PATCH_COMMAND patch -p0 < ../libblepp-master.patch - CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/libblepp-master/configure --prefix= + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/libblepp + CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/libblepp/configure --prefix= BUILD_COMMAND ${MAKE}) ExternalProject_Get_Property(libblepp install_dir) set(FIRMATA_BLESRC src/firmble.cpp) @@ -57,6 +56,7 @@ set(FIRMATACPP_INCLUDES SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3" ) add_library(firmatacpp ${FIRMATACPP_SOURCES} ${FIRMATA_BLESRC} ${FIRMATACPP_INCLUDES} ${FIRMATA_BLEHDR}) +add_dependencies(firmatacpp libblepp) generate_export_header(firmatacpp) set_target_properties(firmatacpp PROPERTIES COMPILE_FLAGS -DLIBSHARED_AND_STATIC_STATIC_DEFINE) diff --git a/vendor/libblepp b/vendor/libblepp new file mode 160000 index 0000000..7c88892 --- /dev/null +++ b/vendor/libblepp @@ -0,0 +1 @@ +Subproject commit 7c88892e254d9fe80e0ff004d2dde909bb189f8a From 247aad3b71a95cf1703582a9cd129c4ee88d0d8d Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 4 Sep 2017 23:22:01 +0100 Subject: [PATCH 5/9] add git submodule notes --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 5e793dc..0c9f617 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ #firmatacpp [![Donate](https://nourish.je/assets/images/donate.svg)](http://ko-fi.com/A250KJT) A C++ firmata client library. Currently implements the basic protocol and I2C extension, version 2.5. + +If you are having problems with messages like this: + +``` +CMake Error at vendor/serial/CMakeLists.txt:30 (add_library): + Cannot find source file: + + src/serial.cc +``` + +then the magic commands are: `git submodule init && git submodule update` From 3a2cb3789b453a02cee266ed373b3e038b379b5c Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 4 Sep 2017 23:22:18 +0100 Subject: [PATCH 6/9] add support for batching transmits --- include/firmble.h | 6 +++++ src/firmble.cpp | 60 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/include/firmble.h b/include/firmble.h index dacc321..f109f3c 100644 --- a/include/firmble.h +++ b/include/firmble.h @@ -38,6 +38,9 @@ namespace firmata { virtual std::vector read(size_t size = 1) override; // firmata transmit data virtual size_t write(std::vector bytes) override; + // firmata transmit data in batches + // call first with true then with false to release queued data + void write_batch(bool start); // firmata retrieve list of ports static std::vector listPorts(int timeout=10 /*seconds*/, int maxDevices=0); @@ -112,6 +115,9 @@ namespace firmata { // connect callback std::function m_scancallback; + // are we batching writes + bool m_writebatch = false; + ///////////////////////////////////////////////////////////// // ble methods // called in context of worker thread diff --git a/src/firmble.cpp b/src/firmble.cpp index ab73796..d8e49a9 100644 --- a/src/firmble.cpp +++ b/src/firmble.cpp @@ -30,6 +30,7 @@ #include //for UUID. FIXME mofo #include +#include #include using namespace std; @@ -39,14 +40,30 @@ using namespace BLEPP; #define DBG(__x...) \ if (s_debug) { \ std::ostringstream __s; \ - __s << "DBG:" << syscall(SYS_gettid) << ":" << __FILE__ ":" << __LINE__ << ":" << __FUNCTION__ << ":" << __x << std::endl; \ + struct timespec __t; \ + std::ios __f(NULL); \ + __f.copyfmt(__s); \ + clock_gettime(CLOCK_REALTIME, &__t); \ + __s << "DBG:" << syscall(SYS_gettid) << ":" \ + << __t.tv_sec << "." << setfill('0') << setw(9) << __t.tv_nsec << ":"; \ + __s.copyfmt(__f); \ + __s << __FILE__ ":" << __LINE__ << ":" << __FUNCTION__ << ":" \ + << __x << std::endl; \ std::cerr <<__s.str(); \ } #define DBGPKT(__d, __l) \ if (s_debug) { \ std::ostringstream __s; \ - __s << "PKT:" << syscall(SYS_gettid) << ":" << __FILE__ ":" << __LINE__ << ":" << __FUNCTION__ << ":" << __l << ":" << hex << setw(2) ; \ + struct timespec __t; \ + std::ios __f(NULL); \ + __f.copyfmt(__s); \ + clock_gettime(CLOCK_REALTIME, &__t); \ + __s << "PKT:" << syscall(SYS_gettid) << ":" \ + << __t.tv_sec << "." << setfill('0') << setw(9) << __t.tv_nsec << ":"; \ + __s.copyfmt(__f); \ + __s << __FILE__ ":" << __LINE__ << ":" << __FUNCTION__ << ":" \ + << __l << ":" << hex << setw(2) ; \ auto __p = __d; \ size_t __n = __l; \ while (__n > 0) { \ @@ -60,7 +77,7 @@ using namespace BLEPP; namespace { // debug integration - int s_debug = 0; + int s_debug = 1; // time to shut down bool s_shutdown = false; @@ -237,6 +254,31 @@ namespace firmata { return bytes; } + // firmata transmit data in batches + // call first with true then with false to release queued data + void FirmBle::write_batch(bool start) + { + if (start) { + m_writebatch = true; + } else { + m_writebatch = false; + bool queued = false; + { + std::lock_guard lock(m_tx_lock); + if (!m_tx_queue.empty()) { + queued = true; + } + } + // release any pending data + if (queued) { + DBG("waiting"); + start_thread_and_wait(st_write); + pthread_yield(); + DBG("waited"); + } + } + } + // firmata transmit data size_t FirmBle::write(std::vector bytes) { @@ -250,10 +292,14 @@ namespace firmata { std::lock_guard lock(m_tx_lock); m_tx_queue.push(bytes); } - DBG("waiting"); - start_thread_and_wait(st_write); - pthread_yield(); - DBG("waited"); + if (m_writebatch == false) { + DBG("waiting"); + start_thread_and_wait(st_write); + pthread_yield(); + DBG("waited"); + } else { + DBG("batched mode"); + } } // firmata retrieve list of ports From 1b9c5d5ef0e0e2690d22ce7760bc89b6d77f2d3c Mon Sep 17 00:00:00 2001 From: Andy Date: Sat, 23 Sep 2017 22:12:01 +0100 Subject: [PATCH 7/9] add support for turning debug on/off at runtime --- include/firmble.h | 2 ++ src/firmble.cpp | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/firmble.h b/include/firmble.h index f109f3c..a4c7788 100644 --- a/include/firmble.h +++ b/include/firmble.h @@ -43,6 +43,8 @@ namespace firmata { void write_batch(bool start); // firmata retrieve list of ports static std::vector listPorts(int timeout=10 /*seconds*/, int maxDevices=0); + // enable ble debug + static void enableDebug(bool enable=true); private: diff --git a/src/firmble.cpp b/src/firmble.cpp index d8e49a9..037b5ed 100644 --- a/src/firmble.cpp +++ b/src/firmble.cpp @@ -77,7 +77,7 @@ using namespace BLEPP; namespace { // debug integration - int s_debug = 1; + bool s_debug = 0; // time to shut down bool s_shutdown = false; @@ -109,6 +109,10 @@ namespace firmata { // max number of queued messages size_t FirmBle::s_max_queued_messages = 1000; + void FirmBle::enableDebug(bool enable) + { + s_debug = enable; + } /////////////////////////////////////////////////// // Firmata methods From bf19017887ed99c1b847c1a8380be30df74cc7a8 Mon Sep 17 00:00:00 2001 From: Andy Date: Sat, 23 Sep 2017 22:12:28 +0100 Subject: [PATCH 8/9] add support for input pullup mode --- include/firmata_constants.h | 7 ++++++- src/firmbase.cpp | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/firmata_constants.h b/include/firmata_constants.h index 62126ea..2f60896 100644 --- a/include/firmata_constants.h +++ b/include/firmata_constants.h @@ -11,6 +11,11 @@ #define MODE_SERVO 0x04 #define MODE_SHIFT 0x05 #define MODE_I2C 0x06 +#define MODE_ONEWIRE 0x07 +#define MODE_STEPPER 0x08 +#define MODE_ENCODER 0x09 +#define MODE_SERIAL 0x0a +#define MODE_PULLUP 0x0b #define LOW 0 #define HIGH 1 @@ -69,4 +74,4 @@ typedef struct s_pin std::vector resolutions; } t_pin; -#endif \ No newline at end of file +#endif diff --git a/src/firmbase.cpp b/src/firmbase.cpp index 0ce7861..6cf7ff6 100644 --- a/src/firmbase.cpp +++ b/src/firmbase.cpp @@ -223,8 +223,9 @@ namespace firmata { value = FIRMATA_COMBINE_LSB_MSB(lsb, msb); for (int pin = 0; pin < 8; pin++) { - if (pins[port * 8 + pin].mode == MODE_INPUT) { - pins[port * 8 + pin].value = FIRMATA_NTH_BIT(value, pin); + int thepin = port * 8 + pin; + if ((pins[thepin].mode == MODE_INPUT) || (pins[thepin].mode == MODE_PULLUP)) { + pins[thepin].value = FIRMATA_NTH_BIT(value, pin); } } i += 2; From ea2012d1ec4ec6d2dbc9cbc3a99faba476853da3 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 25 Sep 2017 21:47:06 +0100 Subject: [PATCH 9/9] add required Ubuntu packages --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0c9f617..1bcb59a 100644 --- a/README.md +++ b/README.md @@ -12,3 +12,5 @@ CMake Error at vendor/serial/CMakeLists.txt:30 (add_library): ``` then the magic commands are: `git submodule init && git submodule update` + +Packages required to build on Ubuntu are: bluetooth bluez libbluetooth-dev libboost-all-dev