summaryrefslogtreecommitdiff
path: root/btscan.py
diff options
context:
space:
mode:
Diffstat (limited to 'btscan.py')
-rwxr-xr-xbtscan.py305
1 files changed, 305 insertions, 0 deletions
diff --git a/btscan.py b/btscan.py
new file mode 100755
index 0000000..b183816
--- /dev/null
+++ b/btscan.py
@@ -0,0 +1,305 @@
+#!/usr/bin/python
+
+import bluetooth
+import select, socket, struct, os, time, random, shelve
+from threading import Thread
+
+#take out the osc stuff initially
+#change it to be run as a thread by wim
+#could have a bt_event function
+#and a gps_event function
+#saving a bit of processing
+import socket
+outsock = socket.socket( socket.AF_INET,socket.SOCK_DGRAM )
+
+import bluetooth._bluetooth as _bt
+#import the .so
+
+def debug(m):
+ print m
+
+def _gethcisock (device_id = -1):
+ try:
+ sock = _bt.hci_open_dev (device_id)
+ return sock
+ except:
+ debug("error accessing bluetooth device")
+ exit(0)
+
+
+class Devicemanager:
+ def __init__(s,log=False,host='127.0.0.1',port=9000):
+ s.devices={}
+ s.logi=0
+ s.now=time.time()
+ s.logging=log
+ s.host=host
+ s.port=port
+ s.triggers={}
+ def msg(s,message):
+ outsock.sendto(str(message[0])+' '+str(message[1])+'\n', (s.host, s.port))
+
+ def dolog(s,o):
+ log=shelve.open('s_btlog')
+ log[str(s.logi)]=o
+ log[str(s.logi)+'int']=time.time()-s.now
+ s.now=time.time()
+ log.close()
+ s.logi+=1
+ def play(s,e):
+ if e[0]=='discovered':
+ s.discovered(e[1],e[2],e[3])
+ elif e[0]=='name':
+ s.name_found(e[1],e[2])
+ elif e[0]=='complete':
+ s.inquiry_complete()
+ def discovered(s, address, device_class='',rssi=0):
+ if not address in s.devices:
+ s.devices[address]=True
+ if (debug):
+ print "wim: found:",address
+ if address in s.triggers:
+ s.msg(s.triggers[address])
+ if (debug):
+ print "wim: sending",str(s.triggers[address][0]),str(s.triggers[address][1])
+ def name_found(s,address,name):
+ #catch for log
+ if address not in s.devices:
+ s.discovered(address)
+ #s.devices[address].foundname(name)
+ #if s.logging:
+ # s.dolog(['name',address, name])
+ def inquiry_complete(s):
+ num=0
+ devs="";
+ #for i in s.devices:
+ # if s.devices[i].checklost():
+ # num +=1
+ # if num>1:
+ # devs+=","
+ # devs+=s.devices[i].name
+ #if s.logging:
+ # s.dolog(['complete'])
+
+ #print num,"bluetooth devices (",devs,")"
+ #s.msg("bt",[num])
+
+
+class MyDiscoverer(bluetooth.DeviceDiscoverer):
+
+ def __init__ (s,host='127.0.0.1',port=9000):
+ s.sock = None
+ s.is_inquiring = False
+ s.lookup_names = False
+ s.names_to_find = {}
+ s.names_found = {}
+ s.dm=Devicemanager(False,host,port)
+
+ def pre_inquiry(s):
+ s.done = False
+
+ def device_discovered(s, address, device_class,rssi=0):
+ s.dm.discovered(address, device_class,rssi=0)
+
+ def name_found(s,address,name):
+ s.dm.name_found(address,name)
+
+ def inquiry_complete(s):
+ s.dm.inquiry_complete()
+ s.done = True
+
+ def find_devices (s, lookup_names=True, duration=8, flush_cache=True):
+ if s.is_inquiring:
+ raise BluetoothError ("Already inquiring!")
+
+ s.lookup_names = lookup_names
+
+ s.sock = _gethcisock ()
+ flt = _bt.hci_filter_new ()
+ _bt.hci_filter_all_events (flt)
+ _bt.hci_filter_set_ptype (flt, _bt.HCI_EVENT_PKT)
+
+ try:
+ s.sock.setsockopt (_bt.SOL_HCI, _bt.HCI_FILTER, flt)
+ except:
+ raise BluetoothError ("problem with local bluetooth device.")
+
+ # send the inquiry command
+ max_responses = 255
+ cmd_pkt = struct.pack ("BBBBB", 0x33, 0x8b, 0x9e, \
+ duration, max_responses)
+
+ s.pre_inquiry ()
+
+ try:
+ _bt.hci_send_cmd (s.sock, _bt.OGF_LINK_CTL, \
+ _bt.OCF_INQUIRY, cmd_pkt)
+ except:
+ raise BluetoothError ("problem with local bluetooth device.")
+
+ s.is_inquiring = True
+
+ s.names_to_find = {}
+ #s.names_found = {}
+
+ def _process_hci_event (s):
+
+ if s.sock is None: return
+ # voodoo magic!!!
+ pkt = s.sock.recv (255)
+ ptype, event, plen = struct.unpack ("BBB", pkt[:3])
+ pkt = pkt[3:]
+ if event == _bt.EVT_INQUIRY_RESULT:
+ nrsp = struct.unpack ("B", pkt[0])[0]
+ for i in range (nrsp):
+ addr = _bt.ba2str (pkt[1+6*i:1+6*i+6])
+ psrm = pkt[ 1+6*nrsp+i ]
+ pspm = pkt[ 1+7*nrsp+i ]
+ devclass_raw = struct.unpack ("BBB",
+ pkt[1+9*nrsp+3*i:1+9*nrsp+3*i+3])
+ devclass = (devclass_raw[2] << 16) | \
+ (devclass_raw[1] << 8) | \
+ devclass_raw[0]
+ clockoff = pkt[1+12*nrsp+2*i:1+12*nrsp+2*i+2]
+
+ if addr not in s.names_found and addr not in s.names_to_find:
+ s.names_to_find[addr] = (devclass, psrm, pspm, clockoff)
+ s.device_discovered (addr, devclass)
+ elif event == _bt.EVT_INQUIRY_RESULT_WITH_RSSI:
+ nrsp = struct.unpack ("B", pkt[0])[0]
+ for i in range (nrsp):
+ addr = _bt.ba2str (pkt[1+6*i:1+6*i+6])
+ psrm = pkt[ 1+6*nrsp+i ]
+ pspm = pkt[ 1+7*nrsp+i ]
+ # devclass_raw = pkt[1+8*nrsp+3*i:1+8*nrsp+3*i+3]
+ # devclass = struct.unpack ("I", "%s\0" % devclass_raw)[0]
+ devclass_raw = struct.unpack ("BBB",
+ pkt[1+8*nrsp+3*i:1+8*nrsp+3*i+3])
+ devclass = (devclass_raw[2] << 16) | \
+ (devclass_raw[1] << 8) | \
+ devclass_raw[0]
+ clockoff = pkt[1+11*nrsp+2*i:1+11*nrsp+2*i+2]
+ rssi = struct.unpack ("b", pkt[1+13*nrsp+i])[0]
+ #print "%s rssi: %i" % (addr, rssi)
+ if addr not in s.names_found and addr not in s.names_to_find:
+ s.names_to_find[addr] = (devclass, psrm, pspm, clockoff)
+ s.device_discovered (addr, devclass,rssi)
+ #s.signalstrength(addr,rssi)
+ elif event == _bt.EVT_INQUIRY_COMPLETE:
+ s.is_inquiring = False
+ if len (s.names_to_find) == 0:
+ # print "inquiry complete (evt_inquiry_complete)"
+ s.sock.close ()
+ s.inquiry_complete ()
+ else:
+ s._send_next_name_req ()
+
+ elif event == _bt.EVT_CMD_STATUS:
+ # XXX shold this be "<BBH"
+ status, ncmd, opcode = struct.unpack ("BBH", pkt[:4])
+ if status != 0:
+ s.is_inquiring = False
+ s.sock.close ()
+
+ # print "inquiry complete (bad status 0x%X 0x%X 0x%X)" % \
+ # (status, ncmd, opcode)
+ s.names_to_find = {}
+ s.inquiry_complete ()
+ elif event == _bt.EVT_REMOTE_NAME_REQ_COMPLETE:
+ status = struct.unpack ("B", pkt[0])[0]
+ addr = _bt.ba2str (pkt[1:7])
+ if status == 0:
+ try:
+ name = pkt[7:].split ('\0')[0]
+ except IndexError:
+ name = ''
+ if addr in s.names_to_find:
+ device_class = s.names_to_find[addr][0]
+ s.names_found[addr] = ( device_class, name)
+ #s.device_discovered (addr, device_class, name)
+ del s.names_to_find[addr]
+ s.name_found(addr,name)
+ else:
+ pass
+ else:
+ if addr in s.names_to_find: del s.names_to_find[addr]
+ # XXX should we do something when a name lookup fails?
+ # print "name req unsuccessful %s - %s" % (addr, status)
+
+ if len (s.names_to_find) == 0:
+ s.is_inquiring = False
+ s.sock.close ()
+ s.inquiry_complete ()
+ # print "inquiry complete (name req complete)"
+ else:
+ s._send_next_name_req ()
+ else:
+ pass
+ # print "unrecognized packet type 0x%02x" % ptype
+
+class scanner(Thread):
+ def __init__ (s,host="127.0.0.1",port=9000,log=False):
+ s.host=host
+ s.port=port
+ s.d = MyDiscoverer(s.host,s.port)
+ s.simulate=False
+ Thread.__init__(s)
+ s.active=True
+ s.kill=False
+
+ def control(s,*msg):
+ x,y=msg
+ if x[2]=="sim":
+ s.devices={}
+ s.simulate=(x[3]==1)
+ if x[2]=="active":
+ s.active=(x[3]==1)
+ def run(s):
+ sock = _gethcisock ()
+ if sock is None:
+ print "bt scanner: no bluetooth"
+ exit(0)
+ else:
+ s.d.find_devices(lookup_names = False)
+ readfiles = [ s.d, ]
+
+ while not s.kill:
+ if s.active:
+ if s.simulate:
+ print "simulating bluetooth.."
+ try:
+ f=shelve.open('btlog')
+ except:
+ print "bt log not found."
+ break
+ while s.active and s.simulate:
+ i=1
+ n=len(f.dict.keys())
+ while i<n and s.active and s.simulate:
+ event=f[str(i)]
+ s.d.dm.play(event)
+ i+=1
+ time.sleep(f[str(i)+'int'])
+ f.close()
+
+ else:
+ rfds = select.select( readfiles, [], [] )[0]
+ if s.d in rfds:
+ s.d.process_event()
+ if s.d.done:
+ s.d.find_devices(lookup_names = False)
+ else:
+ time.sleep(1)
+
+def main():
+ sock = _gethcisock ()
+ if sock is None:
+ print "no bluetooth"
+ exit(0)
+ else:
+ scan=scanner("127.0.0.1",5401,False)
+ scan.start()
+ while True:
+ pass
+
+if __name__ == '__main__': main()