Initial bluetooth_socket implementation
This commit is contained in:
parent
076729d809
commit
8084bf24c9
207
__init__.py
Normal file
207
__init__.py
Normal file
@ -0,0 +1,207 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
"""
|
||||
bluetooth_socket (Bluetooth Socket)
|
||||
===================================
|
||||
|
||||
**Author:**
|
||||
|
||||
* Dirk Alders <sudo-dirk@mount-mockery.de>
|
||||
|
||||
**Description:**
|
||||
|
||||
This Module support bluetooth communication
|
||||
|
||||
**Submodules:**
|
||||
|
||||
* :mod:`mmod.module.sub1`
|
||||
* :class:`mmod.module.sub2`
|
||||
* :func:`mmod.module.sub2`
|
||||
|
||||
**Unittest:**
|
||||
|
||||
See also the :download:`unittest <../../bluetooth_socket/_testresults_/unittest.pdf>` documentation.
|
||||
"""
|
||||
import stringtools
|
||||
|
||||
import bluetooth
|
||||
import logging
|
||||
import time
|
||||
|
||||
BT_TIMEOUT = 0.1
|
||||
|
||||
|
||||
def nearby_devices():
|
||||
return bluetooth.discover_devices()
|
||||
|
||||
|
||||
def services(bt_id):
|
||||
return bluetooth.find_service(address=bt_id)
|
||||
|
||||
|
||||
class bt_base(object):
|
||||
def send(self, data, logger=None, log=True):
|
||||
logit = logger or self.logger
|
||||
if self.connected():
|
||||
if log:
|
||||
logit.debug('BT: TX -> %s', ' '.join(['%02x' % ord(byte) for byte in data]))
|
||||
try:
|
||||
self._client_sock.send(data)
|
||||
except bluetooth.btcommon.BluetoothError, e:
|
||||
if e.message == 'timed out':
|
||||
logit.debug('BT: On send - timeout')
|
||||
return False
|
||||
else:
|
||||
logit.warning('BT: On send - %s', str(e))
|
||||
self._connection_established = False
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
def receive(self, length=4096, logger=None, log=True):
|
||||
logit = logger or self.logger
|
||||
if self.connected():
|
||||
try:
|
||||
data = self._client_sock.recv(length)
|
||||
except bluetooth.btcommon.BluetoothError, e:
|
||||
if e.message == 'timed out':
|
||||
# logit.debug('BT: On receive - timeout')
|
||||
return None
|
||||
else:
|
||||
logit.warning('BT: On receive - %s', str(e))
|
||||
self._connection_established = False
|
||||
return None
|
||||
else:
|
||||
if log:
|
||||
logit.debug('BT: RX <- %s', ' '.join(['%02x' % ord(byte) for byte in data]))
|
||||
return data
|
||||
|
||||
def connected(self):
|
||||
return self._connection_established
|
||||
|
||||
|
||||
class stp_bt_base(object):
|
||||
def send(self, data, logger=None):
|
||||
logit = logger or self.logger
|
||||
|
||||
logit.debug('BT: TX(ETP) -> %s', ' '.join(['%02x' % ord(byte) for byte in data]))
|
||||
self._bt.send(self, stringtools.stp.build_frame(data), log=False)
|
||||
|
||||
def receive(self, timeout=5, logger=None):
|
||||
logit = logger or self.logger
|
||||
max_time = time.time() + timeout
|
||||
while self.connected() and (timeout is None or time.time() < max_time):
|
||||
data = self._bt.receive(self, 1, log=False)
|
||||
if data is not None:
|
||||
max_time += BT_TIMEOUT
|
||||
msg = self._stp.process(data)
|
||||
if msg is not None:
|
||||
logit.debug('BT: RX(ETP) <- %s', ' '.join(['%02x' % ord(byte) for byte in msg]))
|
||||
return msg
|
||||
|
||||
|
||||
class bt_server(bt_base):
|
||||
def __init__(self, uuid, port=2, name='BT-RFCOM-Server', logger=None):
|
||||
self._connection_established = False
|
||||
self._uuid = uuid
|
||||
self._name = name
|
||||
self._server_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
|
||||
self._server_sock.bind(("Python", port))
|
||||
self._server_sock.listen(1)
|
||||
|
||||
bluetooth.advertise_service(self._server_sock,
|
||||
name,
|
||||
service_classes=[self._uuid, bluetooth.SERIAL_PORT_CLASS],
|
||||
profiles=[bluetooth.SERIAL_PORT_PROFILE]
|
||||
)
|
||||
|
||||
def listen(self, logger=None):
|
||||
logit = logger or self.logger
|
||||
logit.info('BT: %s waiting for a connection on RFCOMM "%s", port=%d, uuid=%s', '??:??:??:??:??', self._name, self._server_sock.getsockname()[1], self._uuid)
|
||||
# TODO: find method to get my bt_id and use it instead of '??:??:??:??:??'
|
||||
self._client_sock, client_info = self._server_sock.accept()
|
||||
self._client_sock.settimeout(BT_TIMEOUT)
|
||||
logit.info("BT: Accepted connection from %s, port=%d", client_info[0], client_info[1])
|
||||
self._connection_established = True
|
||||
|
||||
def listen_receive_loop(self, callback=None, logger=None):
|
||||
while True:
|
||||
self.listen()
|
||||
while self.connected():
|
||||
data = self.receive()
|
||||
if callback is not None:
|
||||
callback(self, data, logger)
|
||||
|
||||
def close(self, logger=None):
|
||||
if self._client_sock is not None:
|
||||
self._client_sock.close()
|
||||
self._client_sock = None
|
||||
if self._server_sock is not None:
|
||||
self._server_sock.close()
|
||||
self._server_sock = None
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
|
||||
class stp_bt_server(stp_bt_base, bt_server):
|
||||
def __init__(self, *args, **kwargs):
|
||||
bt_server.__init__(self, *args, **kwargs)
|
||||
self._stp = stringtools.stp.stp()
|
||||
self._bt = bt_server
|
||||
|
||||
|
||||
class bt_client(bt_base):
|
||||
def __init__(self, bt_id, uuid, logger=None):
|
||||
self.logger = logger or logging.getLogger('%s' % (self.__class__.__name__))
|
||||
self._connection_established = False
|
||||
self._bt_id = bt_id
|
||||
self._uuid = uuid
|
||||
self._client_sock = None
|
||||
self._connected = False
|
||||
|
||||
def connect(self, logger=None):
|
||||
logit = logger or self.logger
|
||||
service_matches = bluetooth.find_service(uuid=self._uuid, address=self._bt_id)
|
||||
# TODO: find_named_service and remove service_id from classes
|
||||
if len(service_matches) == 0:
|
||||
logit.debug("BT: couldn't find the RFCOM service %s", self._uuid)
|
||||
else:
|
||||
first_match = service_matches[0]
|
||||
port = first_match["port"]
|
||||
name = first_match["name"]
|
||||
host = first_match["host"]
|
||||
|
||||
# Create the client socket
|
||||
logit.debug("connecting to \"%s\" on %s", name, host)
|
||||
self._client_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
|
||||
try:
|
||||
self._client_sock.connect((host, port))
|
||||
except bluetooth.btcommon.BluetoothError, e:
|
||||
if e.message == "(111, 'Connection refused')":
|
||||
logit.warning('BT: Connection refused')
|
||||
else:
|
||||
raise e
|
||||
else:
|
||||
self._client_sock.settimeout(0.1)
|
||||
logit.debug("connection established")
|
||||
self._connection_established = True
|
||||
return True
|
||||
return False
|
||||
|
||||
def close(self, logger=None):
|
||||
if self._client_sock is not None:
|
||||
self._client_sock.close()
|
||||
self._client_sock = None
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
|
||||
class stp_bt_client(stp_bt_base, bt_client):
|
||||
def __init__(self, *args, **kwargs):
|
||||
bt_client.__init__(self, *args, **kwargs)
|
||||
self._stp = stringtools.stp.stp()
|
||||
self._bt = bt_client
|
Loading…
x
Reference in New Issue
Block a user