/bluetooth/bluez.py

http://pybluez.googlecode.com/ · Python · 633 lines · 455 code · 49 blank · 129 comment · 70 complexity · 4336ed256b8c7c3b30fbb05bc2d29af1 MD5 · raw file

  1. import sys
  2. import struct
  3. import binascii
  4. if sys.version < '3':
  5. from .btcommon import *
  6. import _bluetooth as _bt
  7. else:
  8. from bluetooth.btcommon import *
  9. import bluetooth._bluetooth as _bt
  10. import array
  11. import fcntl
  12. _constants = [ 'HCI', 'RFCOMM', 'L2CAP', 'SCO', 'SOL_L2CAP', 'SOL_RFCOMM',\
  13. 'L2CAP_OPTIONS' ]
  14. for _c in _constants:
  15. command_ = "{C} = _bt.{C1}".format(C=_c, C1=_c)
  16. exec(command_)
  17. del _constants
  18. # ============== SDP service registration and unregistration ============
  19. def discover_devices (duration=8, flush_cache=True, lookup_names=False, lookup_class=False):
  20. sock = _gethcisock ()
  21. try:
  22. results = _bt.hci_inquiry (sock, duration=duration, flush_cache=True, lookup_class=lookup_class)
  23. except _bt.error:
  24. sock.close ()
  25. raise BluetoothError ("error communicating with local "
  26. "bluetooth adapter")
  27. if lookup_names:
  28. pairs = []
  29. for item in results:
  30. if lookup_class:
  31. addr, dev_class = item
  32. else:
  33. addr = item
  34. timeoutms = int (10 * 1000)
  35. try:
  36. name = _bt.hci_read_remote_name (sock, addr, timeoutms)
  37. except _bt.error as e:
  38. # name lookup failed. either a timeout, or I/O error
  39. continue
  40. pairs.append ((addr, name, dev_class) if lookup_class else (addr, name))
  41. sock.close ()
  42. return pairs
  43. else:
  44. sock.close ()
  45. return results
  46. def lookup_name (address, timeout=10):
  47. if not is_valid_address (address):
  48. raise BluetoothError ("%s is not a valid Bluetooth address" % address)
  49. sock = _gethcisock ()
  50. timeoutms = int (timeout * 1000)
  51. try:
  52. name = _bt.hci_read_remote_name (sock, address, timeoutms)
  53. except _bt.error as e:
  54. # name lookup failed. either a timeout, or I/O error
  55. name = None
  56. sock.close ()
  57. return name
  58. def set_packet_timeout (address, timeout):
  59. """
  60. Adjusts the ACL flush timeout for the ACL connection to the specified
  61. device. This means that all L2CAP and RFCOMM data being sent to that
  62. device will be dropped if not acknowledged in timeout milliseconds (maximum
  63. 1280). A timeout of 0 means to never drop packets.
  64. Since this affects all Bluetooth connections to that device, and not just
  65. those initiated by this process or PyBluez, a call to this method requires
  66. superuser privileges.
  67. You must have an active connection to the specified device before invoking
  68. this method
  69. """
  70. n = round (timeout / 0.625)
  71. _write_flush_timeout (address, n)
  72. def get_l2cap_options (sock):
  73. """get_l2cap_options (sock, mtu)
  74. Gets L2CAP options for the specified L2CAP socket.
  75. Options are: omtu, imtu, flush_to, mode, fcs, max_tx, txwin_size.
  76. """
  77. # TODO this should be in the C module, because it depends
  78. # directly on struct l2cap_options layout.
  79. s = sock.getsockopt (SOL_L2CAP, L2CAP_OPTIONS, 12)
  80. options = list( struct.unpack ("HHHBBBH", s))
  81. return options
  82. def set_l2cap_options (sock, options):
  83. """set_l2cap_options (sock, options)
  84. Sets L2CAP options for the specified L2CAP socket.
  85. The option list must be in the same format supplied by
  86. get_l2cap_options().
  87. """
  88. # TODO this should be in the C module, because it depends
  89. # directly on struct l2cap_options layout.
  90. s = struct.pack ("HHHBBBH", *options)
  91. sock.setsockopt (SOL_L2CAP, L2CAP_OPTIONS, s)
  92. def set_l2cap_mtu (sock, mtu):
  93. """set_l2cap_mtu (sock, mtu)
  94. Adjusts the MTU for the specified L2CAP socket. This method needs to be
  95. invoked on both sides of the connection for it to work! The default mtu
  96. that all L2CAP connections start with is 672 bytes.
  97. mtu must be between 48 and 65535, inclusive.
  98. """
  99. options = get_l2cap_options (sock)
  100. options[0] = options[1] = mtu
  101. set_l2cap_options (sock, options)
  102. def _get_available_port (protocol):
  103. """
  104. deprecated. bind to PORT_ANY instead.
  105. """
  106. if protocol == RFCOMM:
  107. for channel in range (1,31):
  108. s = BluetoothSocket (RFCOMM)
  109. try:
  110. s.bind ( ("", channel))
  111. s.close ()
  112. return channel
  113. except:
  114. s.close ()
  115. elif protocol == L2CAP:
  116. for psm in range (0x1001,0x8000,2):
  117. s = BluetoothSocket (L2CAP)
  118. try:
  119. s.bind ( ("", psm))
  120. s.close ()
  121. return psm
  122. except:
  123. s.close ()
  124. else:
  125. raise ValueError ("protocol must either RFCOMM or L2CAP")
  126. class BluetoothSocket:
  127. __doc__ = _bt.btsocket.__doc__
  128. def __init__ (self, proto = RFCOMM, _sock=None):
  129. if _sock is None:
  130. _sock = _bt.btsocket (proto)
  131. self._sock = _sock
  132. self._proto = proto
  133. def dup (self):
  134. """dup () -> socket object
  135. Return a new socket object connected to the same system resource."""
  136. return BluetoothSocket (proto=self._proto, _sock=self._sock)
  137. def accept (self):
  138. try:
  139. client, addr = self._sock.accept ()
  140. except _bt.error as e:
  141. raise BluetoothError (str (e))
  142. newsock = BluetoothSocket (self._proto, client)
  143. return (newsock, addr)
  144. accept.__doc__ = _bt.btsocket.accept.__doc__
  145. def bind (self, addrport):
  146. if self._proto == RFCOMM or self._proto == L2CAP:
  147. addr, port = addrport
  148. if port == 0: addrport = (addr, _get_available_port (self._proto))
  149. return self._sock.bind (addrport)
  150. def get_l2cap_options(self):
  151. """get_l2cap_options (sock, mtu)
  152. Gets L2CAP options for the specified L2CAP socket.
  153. Options are: omtu, imtu, flush_to, mode, fcs, max_tx, txwin_size.
  154. """
  155. return get_l2cap_options(self)
  156. def set_l2cap_options(self, options):
  157. """set_l2cap_options (sock, options)
  158. Sets L2CAP options for the specified L2CAP socket.
  159. The option list must be in the same format supplied by
  160. get_l2cap_options().
  161. """
  162. return set_l2cap_options(self, options)
  163. def set_l2cap_mtu(self, mtu):
  164. """set_l2cap_mtu (sock, mtu)
  165. Adjusts the MTU for the specified L2CAP socket. This method needs to be
  166. invoked on both sides of the connection for it to work! The default mtu
  167. that all L2CAP connections start with is 672 bytes.
  168. mtu must be between 48 and 65535, inclusive.
  169. """
  170. return set_l2cap_mtu(self, mtu)
  171. # import methods from the wraapped socket object
  172. _s = ("""def %s (self, *args, **kwargs):
  173. try:
  174. return self._sock.%s (*args, **kwargs)
  175. except _bt.error as e:
  176. raise BluetoothError (str (e))
  177. %s.__doc__ = _bt.btsocket.%s.__doc__\n""")
  178. for _m in ( 'connect', 'connect_ex', 'close',
  179. 'fileno', 'getpeername', 'getsockname', 'gettimeout',
  180. 'getsockopt', 'listen', 'makefile', 'recv', 'recvfrom', 'sendall',
  181. 'send', 'sendto', 'setblocking', 'setsockopt', 'settimeout',
  182. 'shutdown', 'setl2capsecurity'):
  183. exec( _s % (_m, _m, _m, _m))
  184. del _m, _s
  185. def advertise_service (sock, name, service_id = "", service_classes = [], \
  186. profiles = [], provider = "", description = "", protocols = []):
  187. if service_id != "" and not is_valid_uuid (service_id):
  188. raise ValueError ("invalid UUID specified for service_id")
  189. for uuid in service_classes:
  190. if not is_valid_uuid (uuid):
  191. raise ValueError ("invalid UUID specified in service_classes")
  192. for uuid, version in profiles:
  193. if not is_valid_uuid (uuid) or version < 0 or version > 0xFFFF:
  194. raise ValueError ("Invalid Profile Descriptor")
  195. for uuid in protocols:
  196. if not is_valid_uuid (uuid):
  197. raise ValueError ("invalid UUID specified in protocols")
  198. try:
  199. _bt.sdp_advertise_service (sock._sock, name, service_id, \
  200. service_classes, profiles, provider, description, \
  201. protocols)
  202. except _bt.error as e:
  203. raise BluetoothError (str (e))
  204. def stop_advertising (sock):
  205. try:
  206. _bt.sdp_stop_advertising (sock._sock)
  207. except _bt.error as e:
  208. raise BluetoothError (str (e))
  209. def find_service (name = None, uuid = None, address = None):
  210. if not address:
  211. devices = discover_devices ()
  212. else:
  213. devices = [ address ]
  214. results = []
  215. if uuid is not None and not is_valid_uuid (uuid):
  216. raise ValueError ("invalid UUID")
  217. try:
  218. for addr in devices:
  219. try:
  220. s = _bt.SDPSession ()
  221. s.connect (addr)
  222. matches = []
  223. if uuid is not None:
  224. matches = s.search (uuid)
  225. else:
  226. matches = s.browse ()
  227. except _bt.error:
  228. continue
  229. if name is not None:
  230. matches = [s for s in matches if s.get ("name", "") == name]
  231. for m in matches:
  232. m["host"] = addr
  233. results.extend (matches)
  234. except _bt.error as e:
  235. raise BluetoothError (str (e))
  236. return results
  237. # ================ BlueZ internal methods ================
  238. def _gethcisock (device_id = -1):
  239. try:
  240. sock = _bt.hci_open_dev (device_id)
  241. except:
  242. raise BluetoothError ("error accessing bluetooth device")
  243. return sock
  244. def _get_acl_conn_handle (hci_sock, addr):
  245. hci_fd = hci_sock.fileno ()
  246. reqstr = struct.pack ("6sB17s", _bt.str2ba (addr),
  247. _bt.ACL_LINK, "\0" * 17)
  248. request = array.array ("c", reqstr)
  249. try:
  250. fcntl.ioctl (hci_fd, _bt.HCIGETCONNINFO, request, 1)
  251. except IOError as e:
  252. raise BluetoothError ("There is no ACL connection to %s" % addr)
  253. # XXX should this be "<8xH14x"?
  254. handle = struct.unpack ("8xH14x", request.tostring ())[0]
  255. return handle
  256. def _write_flush_timeout (addr, timeout):
  257. hci_sock = _bt.hci_open_dev ()
  258. # get the ACL connection handle to the remote device
  259. handle = _get_acl_conn_handle (hci_sock, addr)
  260. # XXX should this be "<HH"
  261. pkt = struct.pack ("HH", handle, _bt.htobs (timeout))
  262. response = _bt.hci_send_req (hci_sock, _bt.OGF_HOST_CTL,
  263. 0x0028, _bt.EVT_CMD_COMPLETE, 3, pkt)
  264. status = struct.unpack ("B", response[0])[0]
  265. rhandle = struct.unpack ("H", response[1:3])[0]
  266. assert rhandle == handle
  267. assert status == 0
  268. def _read_flush_timeout (addr):
  269. hci_sock = _bt.hci_open_dev ()
  270. # get the ACL connection handle to the remote device
  271. handle = _get_acl_conn_handle (hci_sock, addr)
  272. # XXX should this be "<H"?
  273. pkt = struct.pack ("H", handle)
  274. response = _bt.hci_send_req (hci_sock, _bt.OGF_HOST_CTL,
  275. 0x0027, _bt.EVT_CMD_COMPLETE, 5, pkt)
  276. status = struct.unpack ("B", response[0])[0]
  277. rhandle = struct.unpack ("H", response[1:3])[0]
  278. assert rhandle == handle
  279. assert status == 0
  280. fto = struct.unpack ("H", response[3:5])[0]
  281. return fto
  282. # =============== DeviceDiscoverer ==================
  283. class DeviceDiscoverer:
  284. """
  285. Skeleton class for finer control of the device discovery process.
  286. To implement asynchronous device discovery (e.g. if you want to do
  287. something *as soon as* a device is discovered), subclass
  288. DeviceDiscoverer and override device_discovered () and
  289. inquiry_complete ()
  290. """
  291. def __init__ (self, device_id=-1):
  292. """
  293. __init__ (device_id=-1)
  294. device_id - The ID of the Bluetooth adapter that will be used
  295. for discovery.
  296. """
  297. self.sock = None
  298. self.is_inquiring = False
  299. self.lookup_names = False
  300. self.device_id = device_id
  301. self.names_to_find = {}
  302. self.names_found = {}
  303. def find_devices (self, lookup_names=True,
  304. duration=8,
  305. flush_cache=True):
  306. """
  307. find_devices (lookup_names=True, service_name=None,
  308. duration=8, flush_cache=True)
  309. Call this method to initiate the device discovery process
  310. lookup_names - set to True if you want to lookup the user-friendly
  311. names for each device found.
  312. service_name - set to the name of a service you're looking for.
  313. only devices with a service of this name will be
  314. returned in device_discovered () NOT YET IMPLEMENTED
  315. ADVANCED PARAMETERS: (don't change these unless you know what
  316. you're doing)
  317. duration - the number of 1.2 second units to spend searching for
  318. bluetooth devices. If lookup_names is True, then the
  319. inquiry process can take a lot longer.
  320. flush_cache - return devices discovered in previous inquiries
  321. """
  322. if self.is_inquiring:
  323. raise BluetoothError ("Already inquiring!")
  324. self.lookup_names = lookup_names
  325. self.sock = _gethcisock (self.device_id)
  326. flt = _bt.hci_filter_new ()
  327. _bt.hci_filter_all_events (flt)
  328. _bt.hci_filter_set_ptype (flt, _bt.HCI_EVENT_PKT)
  329. try:
  330. self.sock.setsockopt (_bt.SOL_HCI, _bt.HCI_FILTER, flt)
  331. except:
  332. raise BluetoothError ("problem with local bluetooth device.")
  333. # send the inquiry command
  334. max_responses = 255
  335. cmd_pkt = struct.pack ("BBBBB", 0x33, 0x8b, 0x9e, \
  336. duration, max_responses)
  337. self.pre_inquiry ()
  338. try:
  339. _bt.hci_send_cmd (self.sock, _bt.OGF_LINK_CTL, \
  340. _bt.OCF_INQUIRY, cmd_pkt)
  341. except:
  342. raise BluetoothError ("problem with local bluetooth device.")
  343. self.is_inquiring = True
  344. self.names_to_find = {}
  345. self.names_found = {}
  346. def cancel_inquiry (self):
  347. """
  348. Call this method to cancel an inquiry in process. inquiry_complete
  349. will still be called.
  350. """
  351. self.names_to_find = {}
  352. if self.is_inquiring:
  353. try:
  354. _bt.hci_send_cmd (self.sock, _bt.OGF_LINK_CTL, \
  355. _bt.OCF_INQUIRY_CANCEL)
  356. self.sock.close ()
  357. self.sock = None
  358. except:
  359. raise BluetoothError ("error canceling inquiry")
  360. self.is_inquiring = False
  361. def process_inquiry (self):
  362. """
  363. Repeatedly calls process_event () until the device inquiry has
  364. completed.
  365. """
  366. while self.is_inquiring or len (self.names_to_find) > 0:
  367. self.process_event ()
  368. def process_event (self):
  369. """
  370. Waits for one event to happen, and proceses it. The event will be
  371. either a device discovery, or an inquiry completion.
  372. """
  373. self._process_hci_event ()
  374. def _process_hci_event (self):
  375. import socket
  376. if self.sock is None: return
  377. # voodoo magic!!!
  378. pkt = self.sock.recv (258)
  379. ptype, event, plen = struct.unpack ("BBB", pkt[:3])
  380. pkt = pkt[3:]
  381. if event == _bt.EVT_INQUIRY_RESULT:
  382. nrsp = struct.unpack ("B", pkt[0])[0]
  383. for i in range (nrsp):
  384. addr = _bt.ba2str (pkt[1+6*i:1+6*i+6])
  385. psrm = pkt[ 1+6*nrsp+i ]
  386. pspm = pkt[ 1+7*nrsp+i ]
  387. devclass_raw = struct.unpack ("BBB",
  388. pkt[1+9*nrsp+3*i:1+9*nrsp+3*i+3])
  389. devclass = (devclass_raw[2] << 16) | \
  390. (devclass_raw[1] << 8) | \
  391. devclass_raw[0]
  392. clockoff = pkt[1+12*nrsp+2*i:1+12*nrsp+2*i+2]
  393. self._device_discovered (addr, devclass,
  394. psrm, pspm, clockoff, None)
  395. elif event == _bt.EVT_INQUIRY_RESULT_WITH_RSSI:
  396. nrsp = struct.unpack ("B", pkt[0])[0]
  397. for i in range (nrsp):
  398. addr = _bt.ba2str (pkt[1+6*i:1+6*i+6])
  399. psrm = pkt[ 1+6*nrsp+i ]
  400. pspm = pkt[ 1+7*nrsp+i ]
  401. # devclass_raw = pkt[1+8*nrsp+3*i:1+8*nrsp+3*i+3]
  402. # devclass = struct.unpack ("I", "%s\0" % devclass_raw)[0]
  403. devclass_raw = struct.unpack ("BBB",
  404. pkt[1+8*nrsp+3*i:1+8*nrsp+3*i+3])
  405. devclass = (devclass_raw[2] << 16) | \
  406. (devclass_raw[1] << 8) | \
  407. devclass_raw[0]
  408. clockoff = pkt[1+11*nrsp+2*i:1+11*nrsp+2*i+2]
  409. rssi = struct.unpack ("b", pkt[1+13*nrsp+i])[0]
  410. self._device_discovered (addr, devclass,
  411. psrm, pspm, clockoff, None)
  412. elif _bt.HAVE_EVT_EXTENDED_INQUIRY_RESULT and event == _bt.EVT_EXTENDED_INQUIRY_RESULT:
  413. nrsp = struct.unpack ("B", pkt[0])[0]
  414. for i in range (nrsp):
  415. addr = _bt.ba2str (pkt[1+6*i:1+6*i+6])
  416. psrm = pkt[ 1+6*nrsp+i ]
  417. pspm = pkt[ 1+7*nrsp+i ]
  418. devclass_raw = struct.unpack ("BBB",
  419. pkt[1+8*nrsp+3*i:1+8*nrsp+3*i+3])
  420. devclass = (devclass_raw[2] << 16) | \
  421. (devclass_raw[1] << 8) | \
  422. devclass_raw[0]
  423. clockoff = pkt[1+11*nrsp+2*i:1+11*nrsp+2*i+2]
  424. rssi = struct.unpack ("b", pkt[1+13*nrsp+i])[0]
  425. data_len = _bt.EXTENDED_INQUIRY_INFO_SIZE - _bt.INQUIRY_INFO_WITH_RSSI_SIZE
  426. data = pkt[1+14*nrsp+i:1+14*nrsp+i+data_len]
  427. name = None
  428. pos = 0
  429. while(pos <= len(data)):
  430. struct_len = ord(data[pos])
  431. if struct_len == 0:
  432. break
  433. eir_type = ord(data[pos+1])
  434. if eir_type == 0x09: # Complete local name
  435. name = data[pos+2:pos+struct_len+1]
  436. pos += struct_len + 2
  437. self._device_discovered (addr, devclass,
  438. psrm, pspm, clockoff, name)
  439. elif event == _bt.EVT_INQUIRY_COMPLETE:
  440. self.is_inquiring = False
  441. if len (self.names_to_find) == 0:
  442. # print "inquiry complete (evt_inquiry_complete)"
  443. self.sock.close ()
  444. self.inquiry_complete ()
  445. else:
  446. self._send_next_name_req ()
  447. elif event == _bt.EVT_CMD_STATUS:
  448. # XXX shold this be "<BBH"
  449. status, ncmd, opcode = struct.unpack ("BBH", pkt[:4])
  450. if status != 0:
  451. self.is_inquiring = False
  452. self.sock.close ()
  453. # print "inquiry complete (bad status 0x%X 0x%X 0x%X)" % \
  454. # (status, ncmd, opcode)
  455. self.names_to_find = {}
  456. self.inquiry_complete ()
  457. elif event == _bt.EVT_REMOTE_NAME_REQ_COMPLETE:
  458. status = struct.unpack ("B", pkt[0])[0]
  459. addr = _bt.ba2str (pkt[1:7])
  460. if status == 0:
  461. try:
  462. name = pkt[7:].split ('\0')[0]
  463. except IndexError:
  464. name = ''
  465. if addr in self.names_to_find:
  466. device_class = self.names_to_find[addr][0]
  467. self.device_discovered (addr, device_class, name)
  468. del self.names_to_find[addr]
  469. self.names_found[addr] = ( device_class, name)
  470. else:
  471. pass
  472. else:
  473. if addr in self.names_to_find: del self.names_to_find[addr]
  474. # XXX should we do something when a name lookup fails?
  475. # print "name req unsuccessful %s - %s" % (addr, status)
  476. if len (self.names_to_find) == 0:
  477. self.is_inquiring = False
  478. self.sock.close ()
  479. self.inquiry_complete ()
  480. # print "inquiry complete (name req complete)"
  481. else:
  482. self._send_next_name_req ()
  483. else:
  484. pass
  485. # print "unrecognized packet type 0x%02x" % ptype
  486. def _device_discovered (self, address, device_class,
  487. psrm, pspm, clockoff, name):
  488. if self.lookup_names:
  489. if name is not None:
  490. self.device_discovered (address, device_class, name)
  491. elif address not in self.names_found and \
  492. address not in self.names_to_find:
  493. self.names_to_find[address] = \
  494. (device_class, psrm, pspm, clockoff)
  495. else:
  496. self.device_discovered (address, device_class, None)
  497. def _send_next_name_req (self):
  498. assert len (self.names_to_find) > 0
  499. address = list(self.names_to_find.keys ())[0]
  500. device_class, psrm, pspm, clockoff = self.names_to_find[address]
  501. bdaddr = _bt.str2ba (address)
  502. cmd_pkt = "%s%s\0%s" % (bdaddr, psrm, clockoff)
  503. try:
  504. _bt.hci_send_cmd (self.sock, _bt.OGF_LINK_CTL, \
  505. _bt.OCF_REMOTE_NAME_REQ, cmd_pkt)
  506. except Exception as e:
  507. raise BluetoothError ("error request name of %s - %s" %
  508. (address, str (e)))
  509. def fileno (self):
  510. if not self.sock: return None
  511. return self.sock.fileno ()
  512. def pre_inquiry (self):
  513. """
  514. Called just after find_devices is invoked, but just before the
  515. inquiry is started.
  516. This method exists to be overriden
  517. """
  518. def device_discovered (self, address, device_class, name):
  519. """
  520. Called when a bluetooth device is discovered.
  521. address is the bluetooth address of the device
  522. device_class is the Class of Device, as specified in [1]
  523. passed in as a 3-byte string
  524. name is the user-friendly name of the device if lookup_names was
  525. set when the inquiry was started. otherwise None
  526. This method exists to be overriden.
  527. [1] https://www.bluetooth.org/foundry/assignnumb/document/baseband
  528. """
  529. if name:
  530. print(("found: %s - %s (class 0x%X)" % \
  531. (address, name, device_class)))
  532. else:
  533. print(("found: %s (class 0x%X)" % (address, device_class)))
  534. def inquiry_complete (self):
  535. """
  536. Called when an inquiry started by find_devices has completed.
  537. """
  538. print("inquiry complete")