#include #include #include #include #include #include "ble/Bluetooth.h" #include "apps.h" namespace trygvis { namespace apps { using namespace std; using namespace trygvis::bluetooth; using namespace trygvis::apps; namespace { enum class op { READ, NOTIFY, LISTEN }; std::istream &operator>>(std::istream &in, op &op) { std::string token; in >> token; if (token == "read") { op = op::READ; } else if (token == "notify") { op = op::NOTIFY; } else if (token == "listen") { op = op::LISTEN; } else { in.setstate(std::ios_base::failbit); } return in; } std::ostream &operator<<(std::ostream &out, const op op) { if (op == op::READ) { out << "read"; } else if (op == op::NOTIFY) { out << "notify"; } else if (op == op::LISTEN) { out << "listen"; } else { out.setstate(std::ios_base::failbit); } return out; } } class ble_read_characteristic : public app { public: ble_read_characteristic() : app("ble-read-characteristic") {} ~ble_read_characteristic() override = default; string adapter_name = "0"; enum op op_mode = op::READ; void add_options(po::options_description_easy_init &options) override { auto adapter_value = po::value<>(&adapter_name)->default_value(adapter_name); options("adapter", adapter_value, "Which adapter to use."); options("device", po::value()->required(), "The MAC of the device to inspect"); options("service", po::value()->required(), "The UUID of the service to read"); options("characteristic", po::value()->required(), "The UUID of the characteristic to read"); auto mode_value = po::value<>(&op_mode)->default_value(op_mode); options("mode", mode_value, "Operation mode"); } int with_device(const shared_ptr &device, const Uuid &service_uuid, const Uuid &characteristic_uuid) { cout << "Connecting to device: " << device->getMac().str() << endl; auto gatt = device->connectGatt(); cout << "Connected, discovering services" << endl; gatt->discoverServices(); auto serviceO = gatt->findService(service_uuid); if (!serviceO) { cout << "Device does not requested service (" << service_uuid.str() << ")" << endl; return EXIT_FAILURE; } auto service = serviceO->get(); auto characteristicO = service->findCharacteristic(characteristic_uuid); if (!characteristicO) { cout << "The device does not have requested characteristic (" << characteristic_uuid << ")" << endl; return EXIT_FAILURE; } auto characteristic = characteristicO.value(); if (op_mode == op::READ) { cout << "Reading data" << endl; StaticByteBuffer<100> buf; auto response = gatt->readValue(characteristic, buf); cout << "Got data, size=" << response.getSize() << endl; } else if (op_mode == op::NOTIFY) { auto cccd = characteristic.get()->getDescriptor(trygvis::bluetooth::uuids::CLIENT_CHARACTERISTIC_CONFIG); if (!cccd) { cout << "The characteristic does not have a CCCD" << endl; } else { cerr << "Enabling notifications" << endl; cccd->setValue(ByteBuffer::wrapInitialized(BluetoothGattDescriptor::ENABLE_NOTIFICATION_VALUE)); gatt->write(cccd); auto end = std::chrono::system_clock::now() + 10s; do { cerr << "Processing messages" << endl; gatt->process(2s); } while(std::chrono::system_clock::now() < end); } } else { cout << "Unsupported op mode: " << op_mode << endl; } return EXIT_SUCCESS; } int main(app_execution &execution) override { string mac_str = execution.vm["device"].as(); string service_str = execution.vm["service"].as(); string characteristic_str = execution.vm["characteristic"].as(); auto service_uuid = Uuid::fromString(service_str); auto characteristic_uuid = Uuid::fromString(characteristic_str); BluetoothSystem bluetoothSystem; try { Mac mac = Mac::parseMac(mac_str); auto adapter = bluetoothSystem.getAdapter(adapter_name); auto device = adapter->getDevice(mac); return with_device(device, service_uuid.value(), characteristic_uuid.value()); } catch (std::runtime_error &ex) { cout << "std::runtime_error: " << ex.what() << endl; return EXIT_FAILURE; } catch (std::exception &ex) { cout << "std::exception: " << ex.what() << endl; return EXIT_FAILURE; } } }; } // namespace apps } // namespace trygvis int main(int argc, const char *argv[]) { using namespace trygvis::apps; return real_main(new ble_read_characteristic(), argc, argv); }