branch: externals/bluetooth commit eb1d4ea347e5d994c69aa6bf69b1c60d4a3589c6 Author: Raffael Stocker <r.stoc...@mnet-mail.de> Commit: Raffael Stocker <r.stoc...@mnet-mail.de>
adds UUID and service/device class parsing and display --- bluetooth.el | 755 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 717 insertions(+), 38 deletions(-) diff --git a/bluetooth.el b/bluetooth.el index d7aacf9..9ea275d 100644 --- a/bluetooth.el +++ b/bluetooth.el @@ -209,6 +209,7 @@ devices, as well as setting properties." tabulated-list-entries #'bluetooth--list-entries tabulated-list-padding 1) (bluetooth--make-commands) + (define-key bluetooth-mode-map [?i] #'bluetooth-show-device-info) (tabulated-list-init-header)) ;;; This function returns a list of bluetooth adapters and devices @@ -472,8 +473,10 @@ This function only uses the first adapter reported by Bluez." "Authorize Bluetooth service UUID for DEVICE." (bluetooth--maybe-cancel-reject (bluetooth--with-alias device - (y-or-n-p - (format "Authorize Bluetooth service `%s' for device `%s'? " uuid alias)))) + (let ((p-uuid (bluetooth--parse-service-class-uuid uuid))) + (y-or-n-p + (format "Authorize Bluetooth service `%s' for device `%s'? " + p-uuid alias))))) :ignore) (defun bluetooth--cancel () @@ -519,6 +522,337 @@ This function only uses the first adapter reported by Bluez." ;;; Application layer +(defconst bluetooth--base-uuid "0000-1000-8000-00805f9b34fb" + "Bluetooth base UUID.") + +(defun bluetooth--parse-service-class-uuid (uuid) + "Parse UUID and return short and long service class names." + (let ((uuid-re (rx (seq bos (submatch (= 8 xdigit)) + "-" (eval bluetooth--base-uuid) eos)))) + (save-match-data + (when (string-match uuid-re uuid) + (let ((service-id (string-to-number (match-string 1 uuid) 16))) + (cond ((>= service-id #xfd00) + (or (list (alist-get service-id bluetooth--member-uuid-alist)) + (list (format "#x%4x" service-id) + "unknown manufacturer"))) + ((>= service-id #x1800) + (subseq (or (alist-get service-id + bluetooth--gatt-service-uuid-alist) + (list (format "#x%4x" service-id) + "unknown GATT service")) + 0 2)) + (t (alist-get service-id + bluetooth--service-class-uuid-alist)))))))) + +(defun bluetooth--parse-class (class) + "Parse the CLASS property of a Bluetooth device." + (cl-labels ((parse (field-def acc) + (let-alist field-def + (let* ((m-field (lsh (logand class .mask) .shift)) + (res (cons .name + (list (funcall .fn m-field .data)))) + (n-acc (push res acc))) + (cond ((functionp .next) + (let ((spec (funcall .next m-field .data))) + (if spec + (parse spec n-acc) + (nreverse n-acc)))) + ((not (null .next)) + (parse (symbol-value .next) n-acc)) + (t (nreverse n-acc))))))) + (parse bluetooth--class-major-services '()))) + +(defun bluetooth--class-parse-bitfield (bitfield data) + "Parse BITFIELD using DATA as specification." + (or (delq nil (mapcar (lambda (x) + (if (/= 0 (logand bitfield (lsh 1 (car x)))) + (cdr x) + nil)) + data)) + "unknown")) + +(defun bluetooth--class-parse-major (field data) + "Parse major class FIELD using DATA as specification." + (or (car (alist-get field data)) + "unknown")) + +(defun bluetooth--class-parse-value (field data) + "Parse minor class FIELD using DATA as specification." + (or (alist-get field data) + "unknown")) + +(defun bluetooth--class-parse-peripheral (field data) + "Parse peripheral class FIELD using DATA as specification." + (or (list (bluetooth--class-parse-value (logand (caar data) field) + (cdar data)) + (bluetooth--class-parse-value (logand (caadr data) field) + (cdadr data))) + "unknown")) + +(defun bluetooth--class-get-minor (field data) + "Get the minor field spec for FIELD using DATA as specification." + (symbol-value (cdr (alist-get field data)))) + +;;; The following constants define the meaning of the Bluetooth +;;; CLASS property, which is made up of a number of fields. +;;; The following components are used: +;;; NAME (string): a name describing the field type, e.g. +;;; "service classes" +;;; MASK: the bit mask for the CLASS field +;;; SHIFT: a shift value to be applied before interpreting the +;;; CLASS field +;;; FN: a function to be invoked on the masked and shifted CLASS +;;; and DATA +;;; NEXT: the next field in the class property: NEXT can have +;;; one of three different kinds of values: +;;; - a field specification (e.g. bluetooth--class-major-dev-classes) +;;; - a function returning the next field specification when +;;; invoked with the masked and shifted CLASS and DATA +;;; - nil, if no further processing of CLASS is necessary +;;; DATA: the data passed to the parsing (FN) or NEXT functions +(defconst bluetooth--class-major-services + '((name . "major service classes") + (mask . #xffe000) + (shift . 0) + (fn . bluetooth--class-parse-bitfield) + (next . bluetooth--class-major-dev-classes) + (data . ((13 . "Limited Discoverable Mode") + (14 . "(reserved)") + (15 . "(reserved)") + (16 . "Positioning") + (17 . "Networking") + (18 . "Rendering") + (19 . "Capturing") + (20 . "Object Transfer") + (21 . "Audio") + (22 . "Telephony") + (23 . "Information")))) + "Bluetooth major service classes.") + +(defconst bluetooth--class-major-dev-classes + '((name . "major device class") + (mask . #x1f00) + (shift . -8) + (fn . bluetooth--class-parse-major) + (next . bluetooth--class-get-minor) + (data . ((#x0 . ("Miscellaneous" . nil)) + (#x1 . ("Computer" . bluetooth--class-computer-minor-classes)) + (#x2 . ("Phone" . bluetooth--class-phone-minor-classes)) + (#x3 . ("LAN /Network Access point" . + bluetooth--class-network-minor-classes)) + (#x4 . ("Audio/Video" . bluetooth--class-av-minor-classes)) + (#x5 . ("Peripheral" . bluetooth--class-peripheral-minor-classes)) + (#x6 . ("Imaging" . bluetooth--class-imaging-minor-classes)) + (#x7 . ("Wearable" . bluetooth--class-wearable-minor-classes)) + (#x8 . ("Toy" . bluetooth--class-toy-minor-classes)) + (#x9 . ("Health" . bluetooth--class-health-minor-classes)) + (#xf . ("Unspecified" . nil))))) + "Bluetooth major device classes") + +(defconst bluetooth--class-computer-minor-classes + '((name . "minor device class") + (mask . #xfc) + (shift . -2) + (fn . bluetooth--class-parse-value) + (next . nil) + (data . ((#x0 . "Uncategorized, code for device not assigned") + (#x1 . "Desktop workstation") + (#x2 . "Server-class computer") + (#x3 . "Laptop") + (#x4 . "Handheld PC/PDA (clamshell)") + (#x5 . "Palm-size PC/PDA") + (#x6 . "Wearable computer (watch size)") + (#x7 . "Tablet")))) + "Bluetooth computer minor classes") + +(defconst bluetooth--class-phone-minor-classes + '((name . "minor device class") + (mask . #xfc) + (shift . -2) + (fn . bluetooth--class-parse-value) + (next . nil) + (data . ((#x0 . "Uncategorized, code for device not assigned") + (#x1 . "Cellular") + (#x2 . "Cordless") + (#x3 . "Smartphone") + (#x4 . "Wired modem or voice gateway") + (#x5 . "Common ISDN access")))) + "Bluetooth phone minor classes.") + +(defconst bluetooth--class-network-minor-classes + '((name . "minor device class") + (mask . #xe0) + (shift . -5) + (fn . bluetooth--class-parse-value) + (next . nil) + (data . ((#x0 . "Fully available") + (#x1 . "1% to 17% utilized") + (#x2 . "17% to 33% utilized") + (#x3 . "33% to 50% utilized") + (#x4 . "50% to 67% utilized") + (#x5 . "67% to 83% utilized") + (#x6 . "83% to 99% utilized") + (#x7 . "No service available")))) + "Bluetooth LAN/network minor classes.") + +(defconst bluetooth--class-av-minor-classes + '((name . "minor device class") + (mask . #xfc) + (shift . -2) + (fn . bluetooth--class-parse-value) + (next . nil) + (data . ((#x0 . "Uncategorized") + (#x1 . "Wearable Headset Device") + (#x2 . "Hands-free Device") + (#x3 . "(Reserved)") + (#x4 . "Microphone") + (#x5 . "Loudspeaker") + (#x6 . "Headphones") + (#x7 . "Portable Audio") + (#x8 . "Car audio") + (#x9 . "Set-top box") + (#xa . "HiFi Audio Device") + (#xb . "VCR") + (#xc . "Video Camera") + (#xd . "Camcorder") + (#xe . "Video Monitor") + (#xf . "Video Display and Loudspeaker") + (#x10 . "Video Conferencing") + (#x11 . "(Reserved)") + (#x12 . "Gaming/Toy")))) + "Bluetooth audio/video minor classes.") + +(defconst bluetooth--class-peripheral-minor-classes + '((name . "minor device class") + (mask . #xfc) + (shift . -2) + (fn . bluetooth--class-parse-peripheral) + (next . nil) + (data . ((#x30 . ((#x00 . "Not Keyboard / Not Pointing Device") + (#x10 . "Keyboard") + (#x20 . "Pointing device") + (#x30 . "Combo keyboard/pointing device"))) + (#xf . ((#x0 . "Uncategorized device") + (#x1 . "Joystick") + (#x2 . "Gamepad") + (#x3 . "Remote control") + (#x4 . "Sensing device") + (#x5 . "Digitizer tablet") + (#x6 . "Card Reader") + (#x7 . "Digital Pen") + (#x8 . "Handheld scanner") + (#x9 . "Handheld gestural input device")))))) + "Bluetooth peripheral minor classes.") + +(defconst bluetooth--class-imaging-minor-classes + '((name . "minor device class") + (mask . #xf0) + (shift . 0) + (fn . bluetooth--class-parse-bitfield) + (next . nil) + (data . ((4 . "Display") + (5 . "Camera") + (6 . "Scanner") + (7 . "Printer")))) + "Bluetooth imaging minor class bits (inclusive).") + +(defconst bluetooth--class-wearable-minor-classes + '((name . "minor device class") + (mask . #xfc) + (shift . -2) + (fn . bluetooth--class-parse-value) + (next . nil) + (data . ((#x1 . "Wristwatch") + (#x2 . "Pager") + (#x3 . "Jacket") + (#x4 . "Helmet") + (#x5 . "Glasses")))) + "Bluetooth wearable minor classes.") + +(defconst bluetooth--class-toy-minor-classes + '((name . "minor device class") + (mask . #xfc) + (shift . -2) + (fn . bluetooth--class-parse-value) + (next . nil) + (data . ((#x1 . "Robot") + (#x2 . "Vehicle") + (#x3 . "Doll / Action figure") + (#x4 . "Controller") + (#x5 . "Game")))) + "Bluetooth toy minor classes.") + +(defconst bluetooth--class-health-minor-classes + '((name . "minor device class") + (mask . #xfc) + (shift . -2) + (fn . bluetooth--class-parse-value) + (next . nil) + (data . ((#x0 . "Undefined") + (#x1 . "Blood Pressure Monitor") + (#x2 . "Thermometer") + (#x3 . "Weighing Scale") + (#x4 . "Glucose Meter") + (#x5 . "Pulse Oximeter") + (#x6 . "Heart/Pulse Rate Monitor") + (#x7 . "Health Data Display") + (#x8 . "Step Counter") + (#x9 . "Body Composition Analyzer") + (#xa . "Peak Flow Monitor") + (#xb . "Medication Monitor") + (#xc . "Knee Prosthesis") + (#xd . "Ankle Prosthesis") + (#xe . "Generic Health Manager") + (#xf . "Personal Mobility Device")))) + "Bluetooth health minor classes.") + +(defun bluetooth-show-device-info () + "Show detail information on the device at point." + (interactive) + (bluetooth--show-device-info (tabulated-list-get-id))) + +(defun bluetooth--show-device-info (device) + "Show information about DEVICE in a temp buffer" + (bluetooth--with-alias device + (with-current-buffer-window + "*Bluetooth device info*" nil nil + (let ((address (bluetooth--call-method + (car (last (split-string device "/"))) :device + #'dbus-get-property "Address")) + (rssi (bluetooth--call-method + (car (last (split-string device "/"))) :device + #'dbus-get-property "RSSI")) + (class (bluetooth--call-method + (car (last (split-string device "/"))) :device + #'dbus-get-property "Class")) + (uuids (bluetooth--call-method + (car (last (split-string device "/"))) :device + #'dbus-get-property "UUIDs"))) + (insert "Alias:\t\t" alias "\n") + (when address + (insert "Address:\t" address "\n")) + (when rssi + (insert "RSSI:\t\t" (number-to-string rssi) "\n")) + (when class + (let ((p-class (bluetooth--parse-class class))) + (insert "\nService and device classes:\n") + (mapc (lambda (x) + (insert (car x) ":\n") + (if (listp (cadr x)) + (dolist (elt (cadr x)) + (insert "\t" elt "\n")) + (insert "\t" (cadr x) "\n"))) + p-class))) + (when uuids + (insert "\nServices (UUIDs):\n") + (dolist (id uuids) + (insert (mapconcat #'identity + (or (bluetooth--parse-service-class-uuid id) + (list id)) + " -- ") + "\n"))))))) + (defconst bluetooth--service-class-uuid-alist '((#x1000 . ("ServiceDiscoveryServerServiceClassID" "Bluetooth Core Specification")) @@ -685,43 +1019,388 @@ This function only uses the first adapter reported by Bluez." (#x181D . ("Weight Scale" "org.bluetooth.service.weight_scale" "GSS"))) "Bluetooth GATT service UUIDs.") +;;; This is a very long list of manufacturer UUIDs and therefore +;;; the last thing in this file. +(defconst bluetooth--member-uuid-alist + '((#xFEFF . "GN Netcom") + (#xFEFE . "GN ReSound A/S") + (#xFEFD . "Gimbal, Inc.") + (#xFEFC . "Gimbal, Inc.") + (#xFEFB . "Telit Wireless Solutions (Formerly Stollmann E+V GmbH)") + (#xFEFA . "PayPal, Inc.") + (#xFEF9 . "PayPal, Inc.") + (#xFEF8 . "Aplix Corporation") + (#xFEF7 . "Aplix Corporation") + (#xFEF6 . "Wicentric, Inc.") + (#xFEF5 . "Dialog Semiconductor GmbH") + (#xFEF4 . "Google") + (#xFEF3 . "Google") + (#xFEF2 . "CSR") + (#xFEF1 . "CSR") + (#xFEF0 . "Intel") + (#xFEEF . "Polar Electro Oy ") + (#xFEEE . "Polar Electro Oy ") + (#xFEED . "Tile, Inc.") + (#xFEEC . "Tile, Inc.") + (#xFEEB . "Swirl Networks, Inc.") + (#xFEEA . "Swirl Networks, Inc.") + (#xFEE9 . "Quintic Corp.") + (#xFEE8 . "Quintic Corp.") + (#xFEE7 . "Tencent Holdings Limited.") + (#xFEE6 . "Silvair, Inc.") + (#xFEE5 . "Nordic Semiconductor ASA") + (#xFEE4 . "Nordic Semiconductor ASA") + (#xFEE3 . "Anki, Inc.") + (#xFEE2 . "Anki, Inc.") + (#xFEE1 . "Anhui Huami Information Technology Co., Ltd. ") + (#xFEE0 . "Anhui Huami Information Technology Co., Ltd. ") + (#xFEDF . "Design SHIFT") + (#xFEDE . "Coin, Inc.") + (#xFEDD . "Jawbone") + (#xFEDC . "Jawbone") + (#xFEDB . "Perka, Inc.") + (#xFEDA . "ISSC Technologies Corp. ") + (#xFED9 . "Pebble Technology Corporation") + (#xFED8 . "Google") + (#xFED7 . "Broadcom") + (#xFED6 . "Broadcom") + (#xFED5 . "Plantronics Inc.") + (#xFED4 . "Apple, Inc.") + (#xFED3 . "Apple, Inc.") + (#xFED2 . "Apple, Inc.") + (#xFED1 . "Apple, Inc.") + (#xFED0 . "Apple, Inc.") + (#xFECF . "Apple, Inc.") + (#xFECE . "Apple, Inc.") + (#xFECD . "Apple, Inc.") + (#xFECC . "Apple, Inc.") + (#xFECB . "Apple, Inc.") + (#xFECA . "Apple, Inc.") + (#xFEC9 . "Apple, Inc.") + (#xFEC8 . "Apple, Inc.") + (#xFEC7 . "Apple, Inc.") + (#xFEC6 . "Kocomojo, LLC") + (#xFEC5 . "Realtek Semiconductor Corp.") + (#xFEC4 . "PLUS Location Systems") + (#xFEC3 . "360fly, Inc.") + (#xFEC2 . "Blue Spark Technologies, Inc.") + (#xFEC1 . "KDDI Corporation") + (#xFEC0 . "KDDI Corporation") + (#xFEBF . "Nod, Inc.") + (#xFEBE . "Bose Corporation") + (#xFEBD . "Clover Network, Inc") + (#xFEBC . "Dexcom Inc") + (#xFEBB . "adafruit industries") + (#xFEBA . "Tencent Holdings Limited") + (#xFEB9 . "LG Electronics") + (#xFEB8 . "Facebook, Inc.") + (#xFEB7 . "Facebook, Inc.") + (#xFEB6 . "Vencer Co., Ltd") + (#xFEB5 . "WiSilica Inc.") + (#xFEB4 . "WiSilica Inc.") + (#xFEB3 . "Taobao") + (#xFEB2 . "Microsoft Corporation") + (#xFEB1 . "Electronics Tomorrow Limited") + (#xFEB0 . "Nest Labs Inc") + (#xFEAF . "Nest Labs Inc") + (#xFEAE . "Nokia") + (#xFEAD . "Nokia") + (#xFEAC . "Nokia") + (#xFEAB . "Nokia") + (#xFEAA . "Google") + (#xFEA9 . "Savant Systems LLC") + (#xFEA8 . "Savant Systems LLC") + (#xFEA7 . "UTC Fire and Security") + (#xFEA6 . "GoPro, Inc.") + (#xFEA5 . "GoPro, Inc.") + (#xFEA4 . "Paxton Access Ltd") + (#xFEA3 . "ITT Industries") + (#xFEA2 . "Intrepid Control Systems, Inc.") + (#xFEA1 . "Intrepid Control Systems, Inc.") + (#xFEA0 . "Google") + (#xFE9F . "Google") + (#xFE9E . "Dialog Semiconductor B.V.") + (#xFE9D . "Mobiquity Networks Inc") + (#xFE9C . "GSI Laboratories, Inc.") + (#xFE9B . "Samsara Networks, Inc") + (#xFE9A . "Estimote") + (#xFE99 . "Currant Inc") + (#xFE98 . "Currant Inc") + (#xFE97 . "Tesla Motors Inc.") + (#xFE96 . "Tesla Motors Inc.") + (#xFE95 . "Xiaomi Inc.") + (#xFE94 . "OttoQ In") + (#xFE93 . "OttoQ In") + (#xFE92 . "Jarden Safety & Security") + (#xFE91 . "Shanghai Imilab Technology Co., Ltd") + (#xFE90 . "JUMA") + (#xFE8F . "CSR") + (#xFE8E . "ARM Ltd") + (#xFE8D . "Interaxon Inc.") + (#xFE8C . "TRON Forum") + (#xFE8B . "Apple, Inc.") + (#xFE8A . "Apple, Inc.") + (#xFE89 . "B&O Play A/S") + (#xFE88 . "SALTO SYSTEMS S.L.") + (#xFE87 . "Qingdao Yeelink Information Technology Co., Ltd. ( 青岛亿联客信息技术有限公司 )") + (#xFE86 . "HUAWEI Technologies Co., Ltd. ( 华为技术有限公司 )") + (#xFE85 . "RF Digital Corp") + (#xFE84 . "RF Digital Corp") + (#xFE83 . "Blue Bite") + (#xFE82 . "Medtronic Inc.") + (#xFE81 . "Medtronic Inc.") + (#xFE80 . "Doppler Lab") + (#xFE7F . "Doppler Lab") + (#xFE7E . "Awear Solutions Ltd") + (#xFE7D . "Aterica Health Inc.") + (#xFE7C . "Telit Wireless Solutions (Formerly Stollmann E+V GmbH)") + (#xFE7B . "Orion Labs, Inc.") + (#xFE7A . "Bragi GmbH") + (#xFE79 . "Zebra Technologies") + (#xFE78 . "Hewlett-Packard Company") + (#xFE77 . "Hewlett-Packard Company") + (#xFE76 . "TangoMe") + (#xFE75 . "TangoMe") + (#xFE74 . "unwire") + (#xFE73 . "Abbott (formerly St. Jude Medical, Inc.)") + (#xFE72 . "Abbott (formerly St. Jude Medical, Inc.)") + (#xFE71 . "Plume Design Inc") + (#xFE70 . "Beijing Jingdong Century Trading Co., Ltd.") + (#xFE6F . "LINE Corporation") + (#xFE6E . "The University of Tokyo") + (#xFE6D . "The University of Tokyo") + (#xFE6C . "TASER International, Inc.") + (#xFE6B . "TASER International, Inc.") + (#xFE6A . "Kontakt Micro-Location Sp. z o.o.") + (#xFE69 . "Capsule Technologies Inc.") + (#xFE68 . "Capsule Technologies Inc.") + (#xFE67 . "Lab Sensor Solutions") + (#xFE66 . "Intel Corporation") + (#xFE65 . "CHIPOLO d.o.o.") + (#xFE64 . "Siemens AG") + (#xFE63 . "Connected Yard, Inc.") + (#xFE62 . "Indagem Tech LLC") + (#xFE61 . "Logitech International SA") + (#xFE60 . "Lierda Science & Technology Group Co., Ltd.") + (#xFE5F . "Eyefi, Inc.") + (#xFE5E . "Plastc Corporation") + (#xFE5D . "Grundfos A/S") + (#xFE5C . "million hunters GmbH") + (#xFE5B . "GT-tronics HK Ltd") + (#xFE5A . "Cronologics Corporation") + (#xFE59 . "Nordic Semiconductor ASA") + (#xFE58 . "Nordic Semiconductor ASA") + (#xFE57 . "Dotted Labs") + (#xFE56 . "Google Inc.") + (#xFE55 . "Google Inc.") + (#xFE54 . "Motiv, Inc.") + (#xFE53 . "3M") + (#xFE52 . "SetPoint Medical") + (#xFE51 . "SRAM") + (#xFE50 . "Google Inc.") + (#xFE4F . "Molekule, Inc.") + (#xFE4E . "NTT docomo") + (#xFE4D . "Casambi Technologies Oy") + (#xFE4C . "Volkswagen AG") + (#xFE4B . "Signify Netherlands B.V. (formerly Philips Lighting B.V.)") + (#xFE4A . "OMRON HEALTHCARE Co., Ltd.") + (#xFE49 . "SenionLab AB") + (#xFE48 . "General Motors") + (#xFE47 . "General Motors") + (#xFE46 . "B&O Play A/S") + (#xFE45 . "Snapchat Inc") + (#xFE44 . "SK Telecom") + (#xFE43 . "Andreas Stihl AG & Co. KG") + (#xFE42 . "Nets A/S") + (#xFE41 . "Inugo Systems Limited") + (#xFE40 . "Inugo Systems Limited") + (#xFE3F . "Friday Labs Limited") + (#xFE3E . "BD Medical") + (#xFE3D . "BD Medical") + (#xFE3C . "alibaba") + (#xFE3B . "Dobly Laboratories") + (#xFE3A . "TTS Tooltechnic Systems AG & Co. KG") + (#xFE39 . "TTS Tooltechnic Systems AG & Co. KG") + (#xFE38 . "Spaceek LTD") + (#xFE37 . "Spaceek LTD") + (#xFE36 . "HUAWEI Technologies Co., Ltd") + (#xFE35 . "HUAWEI Technologies Co., Ltd") + (#xFE34 . "SmallLoop LLC") + (#xFE33 . "CHIPOLO d.o.o.") + (#xFE32 . "Pro-Mark, Inc.") + (#xFE31 . "Volkswagen AG") + (#xFE30 . "Volkswagen AG") + (#xFE2F . "CRESCO Wireless, Inc") + (#xFE2E . "ERi,Inc.") + (#xFE2D . "SMART INNOVATION Co., Ltd") + (#xFE2C . "Google") + (#xFE2B . "ITT Industries") + (#xFE2A . "DaisyWorks, Inc.") + (#xFE29 . "Gibson Innovations") + (#xFE28 . "Ayla Networks") + (#xFE27 . "Google") + (#xFE26 . "Google") + (#xFE25 . "Apple, Inc.") + (#xFE24 . "August Home Inc") + (#xFE23 . "Zoll Medical Corporation") + (#xFE22 . "Zoll Medical Corporation") + (#xFE21 . "Bose Corporation") + (#xFE20 . "Emerson") + (#xFE1F . "Garmin International, Inc.") + (#xFE1E . "Smart Innovations Co., Ltd") + (#xFE1D . "Illuminati Instrument Corporation") + (#xFE1C . "NetMedia, Inc.") + (#xFE1B . "Tyto Life LLC") + (#xFE1A . "Tyto Life LLC") + (#xFE19 . "Google, Inc") + (#xFE18 . "Runtime, Inc.") + (#xFE17 . "Telit Wireless Solutions GmbH") + (#xFE16 . "Footmarks, Inc.") + (#xFE15 . "Amazon.com Services, Inc.") + (#xFE14 . "Flextronics International USA Inc.") + (#xFE13 . "Apple Inc.") + (#xFE12 . "M-Way Solutions GmbH") + (#xFE11 . "GMC-I Messtechnik GmbH") + (#xFE10 . "Lapis Semiconductor Co., Ltd.") + (#xFE0F . "Signify Netherlands B.V. (formerly Philips Lighting B.V.)") + (#xFE0E . "Setec Pty Ltd") + (#xFE0D . "Procter & Gamble") + (#xFE0C . "Procter & Gamble") + (#xFE0B . "ruwido austria gmbh") + (#xFE0A . "ruwido austria gmbh") + (#xFE09 . "Pillsy, Inc.") + (#xFE08 . "Microsoft") + (#xFE07 . "Sonos, Inc.") + (#xFE06 . "Qualcomm Technologies, Inc.") + (#xFE05 . "CORE Transport Technologies NZ Limited") + (#xFE04 . "OpenPath Security Inc") + (#xFE03 . "Amazon.com Services, Inc.") + (#xFE02 . "Robert Bosch GmbH") + (#xFE01 . "Duracell U.S. Operations Inc.") + (#xFE00 . "Amazon.com Services, Inc.") + (#xFDFF . "OSRAM GmbH") + (#xFDFE . "ADHERIUM(NZ) LIMITED") + (#xFDFD . "RecursiveSoft Inc.") + (#xFDFC . "Optrel AG") + (#xFDFB . "Tandem Diabetes Care") + (#xFDFA . "Tandem Diabetes Care") + (#xFDF9 . "INIA") + (#xFDF8 . "Onvocal") + (#xFDF7 . "HP Inc.") + (#xFDF6 . "AIAIAI ApS") + (#xFDF5 . "Milwaukee Electric Tools") + (#xFDF4 . "O. E. M. Controls, Inc.") + (#xFDF3 . "Amersports") + (#xFDF2 . "AMICCOM Electronics Corporation") + (#xFDF1 . "LAMPLIGHT Co., Ltd") + (#xFDF0 . "Google Inc.") + (#xFDEF . "ART AND PROGRAM, INC.") + (#xFDEE . "Huawei Technologies Co., Ltd.") + (#xFDED . "Pole Star") + (#xFDEC . "Mannkind Corporation") + (#xFDEB . "Syntronix Corporation") + (#xFDEA . "SeeScan, Inc") + (#xFDE9 . "Spacesaver Corporation") + (#xFDE8 . "Robert Bosch GmbH") + (#xFDE7 . "SECOM Co., LTD") + (#xFDE6 . "Intelletto Technologies Inc") + (#xFDE5 . "SMK Corporation") + (#xFDE4 . "JUUL Labs, Inc.") + (#xFDE3 . "Abbott Diabetes Care") + (#xFDE2 . "Google Inc.") + (#xFDE1 . "Fortin Electronic Systems") + (#xFDE0 . "John Deere") + (#xFDDF . "Harman International") + (#xFDDE . "Noodle Technology Inc.") + (#xFDDD . "Arch Systems Inc") + (#xFDDC . "4iiii Innovations Inc.") + (#xFDDB . "Samsung Electronics Co., Ltd.") + (#xFDDA . "MHCS") + (#xFDD9 . "Jiangsu Teranovo Tech Co., Ltd.") + (#xFDD8 . "Jiangsu Teranovo Tech Co., Ltd.") + (#xFDD7 . "Emerson") + (#xFDD6 . "Ministry of Supply") + (#xFDD5 . "Brompton Bicycle Ltd") + (#xFDD4 . "LX Solutions Pty Limited") + (#xFDD3 . "FUBA Automotive Electronics GmbH") + (#xFDD2 . "Bose Corporation") + (#xFDD1 . "Huawei Technologies Co., Ltd") + (#xFDD0 . "Huawei Technologies Co., Ltd") + (#xFDCF . "Nalu Medical, Inc") + (#xFDCE . "SENNHEISER electronic GmbH & Co. KG") + (#xFDCD . "Qingping Technology (Beijing) Co., Ltd.") + (#xFDCC . "Shoof Technologies") + (#xFDCB . "Meggitt SA") + (#xFDCA . "Fortin Electronic Systems") + (#xFDC9 . "Busch-Jaeger Elektro GmbH") + (#xFDC8 . "Hach – Danaher") + (#xFDC7 . "Eli Lilly and Company") + (#xFDC6 . "Eli Lilly and Company") + (#xFDC5 . "Automatic Labs") + (#xFDC4 . "Simavita (Aust) Pty Ltd") + (#xFDC3 . "Baidu Online Network Technology (Beijing) Co., Ltd") + (#xFDC2 . "Baidu Online Network Technology (Beijing) Co., Ltd") + (#xFDC1 . "Hunter Douglas") + (#xFDC0 . "Hunter Douglas") + (#xFDBF . "California Things Inc.") + (#xFDBE . "California Things Inc.") + (#xFDBD . "Clover Network, Inc.") + (#xFDBC . "Emerson") + (#xFDBB . "Profoto") + (#xFDBA . "Comcast Cable Corporation") + (#xFDB9 . "Comcast Cable Corporation") + (#xFDB8 . "LivaNova USA Inc.") + (#xFDB7 . "LivaNova USA Inc.") + (#xFDB6 . "GWA Hygiene GmbH") + (#xFDB5 . "ECSG") + (#xFDB4 . "HP Inc") + (#xFDB3 . "Audiodo AB") + (#xFDB2 . "Portable Multimedia Ltd") + (#xFDB1 . "Proxy Technologies, Inc.") + (#xFDB0 . "Proxy Technologies, Inc.") + (#xFDAF . "Wiliot LTD") + (#xFDAE . "Houwa System Design, k.k.") + (#xFDAD . "Houwa System Design, k.k.") + (#xFDAC . "Tentacle Sync GmbH") + (#xFDAB . "Xiaomi Inc.") + (#xFDAA . "Xiaomi Inc.") + (#xFDA9 . "Rhombus Systems, Inc.") + (#xFDA8 . "PSA Peugeot Citroën") + (#xFDA7 . "WWZN Information Technology Company Limited") + (#xFDA6 . "WWZN Information Technology Company Limited") + (#xFDA5 . "Neurostim OAB, Inc.") + (#xFDA4 . "Inseego Corp.") + (#xFDA3 . "Inseego Corp.") + (#xFDA2 . "Groove X, Inc") + (#xFDA1 . "Groove X, Inc") + (#xFDA0 . "Secugen Corporation") + (#xFD9F . "VitalTech Affiliates LLC") + (#xFD9E . "The Coca-Cola Company") + (#xFD9D . "Gastec Corporation") + (#xFD9C . "Huawei Technologies Co., Ltd.") + (#xFD9B . "Huawei Technologies Co., Ltd.") + (#xFD9A . "Huawei Technologies Co., Ltd.") + (#xFD99 . "ABB Oy") + (#xFD98 . "Disney Worldwide Services, Inc.") + (#xFD97 . "June Life, Inc.") + (#xFD96 . "Google LLC") + (#xFD95 . "Rigado") + (#xFD94 . "Hewlett Packard Enterprise") + (#xFD93 . "Bayerische Motoren Werke AG") + (#xFD92 . "Qualcomm Technologies International, Ltd. (QTIL)") + (#xFD91 . "Groove X, Inc.") + (#xFD90 . "Guangzhou SuperSound Information Technology Co., Ltd") + (#xFD8F . "Matrix ComSec Pvt. Ltd.") + (#xFD8E . "Motorola Solutions") + (#xFD8D . "quip NYC Inc.") + (#xFD8C . "Google LLC") + (#xFD8B . "Jigowatts Inc.") + (#xFD8A . "Signify Netherlands B.V.") + (#xFD89 . "Urbanminded LTD") + (#xFD88 . "Urbanminded LTD") + (#xFD87 . "Google LLC")) + "Bluetooth manufacturer UUIDs.") -(defconst bluetooth--base-uuid "0000-1000-8000-00805f9b34fb" - "Bluetooth base UUID.") - -(defun bluetooth--parse-service-class-uuid (uuid) - "Parse UUID and return short and long service class names." - (let ((uuid-re (rx (seq bos (submatch (= 8 xdigit)) - "-" (eval bluetooth--base-uuid) eos)))) - (save-match-data - (when (string-match uuid-re uuid) - (let ((service-id (string-to-number (match-string 1 uuid) 16))) - (if (>= service-id #x1800) - (subseq (alist-get service-id - bluetooth--gatt-service-uuid-alist) - 0 2) - (alist-get service-id bluetooth--service-class-uuid-alist))))))) - -(defun bluetooth--show-device-info (device) - "Show information about DEVICE in a temp buffer" - (bluetooth--with-alias device - (with-current-buffer-window - (concat "*" alias "*") nil nil - (insert "Alias:\t\t" alias "\n") - (insert "Address:\t" (bluetooth--call-method - (car (last (split-string device "/"))) :device - #'dbus-get-property "Address") - "\n") - (let ((uuids (bluetooth--call-method - (car (last (split-string device "/"))) :device - #'dbus-get-property "UUIDs"))) - (insert "\nService classes:\n") - (dolist (id uuids) - (insert (mapconcat #'identity - (or (bluetooth--parse-service-class-uuid id) - (list id)) - " -- ") - "\n")))))) (provide 'bluetooth)