Download a stream of data to a peripheral over BLE.

Dependencies:   BLE_API mbed nRF51822

A simple demonstration of downloading a stream onto a peripheral over BLE. There's a corresponding Python script to driver the client.

Committer:
rgrover1
Date:
Tue Dec 09 09:05:43 2014 +0000
Revision:
5:90b73268e270
Parent:
0:4eaf82806f06
fix build issues; and update underlying libraries.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rgrover1 0:4eaf82806f06 1 #!/usr/bin/python
rgrover1 0:4eaf82806f06 2 #
rgrover1 0:4eaf82806f06 3 # This is a very simple test driver for demonstrating the StreamDownloader.
rgrover1 0:4eaf82806f06 4
rgrover1 0:4eaf82806f06 5 import pexpect
rgrover1 0:4eaf82806f06 6 import sys
rgrover1 0:4eaf82806f06 7 import time
rgrover1 0:4eaf82806f06 8 import select
rgrover1 0:4eaf82806f06 9 import re
rgrover1 0:4eaf82806f06 10 import struct
rgrover1 0:4eaf82806f06 11
rgrover1 0:4eaf82806f06 12 class StreamDownloaderClient(object):
rgrover1 0:4eaf82806f06 13 """docstring for StreamDownloaderClient"""
rgrover1 0:4eaf82806f06 14 def __init__(self, bluetoothAddr, length):
rgrover1 0:4eaf82806f06 15 super(StreamDownloaderClient, self).__init__()
rgrover1 0:4eaf82806f06 16 self.bluetoothAddr = bluetoothAddr
rgrover1 0:4eaf82806f06 17
rgrover1 0:4eaf82806f06 18 self.con = pexpect.spawn('gatttool -b ' + bluetoothAddr + ' --interactive -t random')
rgrover1 0:4eaf82806f06 19 self.con.expect('\[LE\]>', timeout=600)
rgrover1 0:4eaf82806f06 20
rgrover1 0:4eaf82806f06 21 self.con.sendline('connect')
rgrover1 0:4eaf82806f06 22 self.con.expect('\[CON\]\[.+\]\[LE\]>')
rgrover1 0:4eaf82806f06 23 print('connected')
rgrover1 0:4eaf82806f06 24
rgrover1 0:4eaf82806f06 25 # ensure that we've got the correct primary service available
rgrover1 0:4eaf82806f06 26 self.con.sendline('primary')
rgrover1 0:4eaf82806f06 27 self.con.expect('\[CON\]\[.+\]\[LE\]>')
rgrover1 0:4eaf82806f06 28 self.con.expect('\[CON\]\[.+\]\[LE\]>')
rgrover1 0:4eaf82806f06 29
rgrover1 0:4eaf82806f06 30 emptyString = re.compile('^\s*$')
rgrover1 0:4eaf82806f06 31 for line in self.con.before.decode('utf-8').split('\r\n'):
rgrover1 0:4eaf82806f06 32 m = re.match('^attr handle: (0x[\dabcdef]{4}).*adc710c2-acdc-4bf5-8244-3ceaaa0f87f5.*', line)
rgrover1 0:4eaf82806f06 33 if m:
rgrover1 0:4eaf82806f06 34 break
rgrover1 0:4eaf82806f06 35 if not m:
rgrover1 0:4eaf82806f06 36 self.disconnect()
rgrover1 0:4eaf82806f06 37
rgrover1 0:4eaf82806f06 38 self.serviceHandle = m.group(1)
rgrover1 0:4eaf82806f06 39 print('discovered service handle as ' + self.serviceHandle)
rgrover1 0:4eaf82806f06 40
rgrover1 0:4eaf82806f06 41 self.discoverCharHandles()
rgrover1 0:4eaf82806f06 42 self.sendFileInfoBlock(length)
rgrover1 0:4eaf82806f06 43 for blocknum in range(64):
rgrover1 0:4eaf82806f06 44 self.sendFileDataBlock(blocknum)
rgrover1 0:4eaf82806f06 45
rgrover1 0:4eaf82806f06 46 self.disconnect()
rgrover1 0:4eaf82806f06 47
rgrover1 0:4eaf82806f06 48 def discoverCharHandles(self):
rgrover1 0:4eaf82806f06 49 self.con.sendline('characteristics ' + self.serviceHandle)
rgrover1 0:4eaf82806f06 50 self.con.expect('\[CON\]\[.+\]\[LE\]>')
rgrover1 0:4eaf82806f06 51 self.con.expect('\[CON\]\[.+\]\[LE\]>')
rgrover1 0:4eaf82806f06 52 for line in self.con.before.decode('utf-8').split('\r\n'):
rgrover1 0:4eaf82806f06 53 uuidRe = re.compile('.* char value handle: (0x[\dabcdef]{4}).*uuid: adc710c2\-(\w{4}).*')
rgrover1 0:4eaf82806f06 54 m = uuidRe.match(line)
rgrover1 0:4eaf82806f06 55 if m:
rgrover1 0:4eaf82806f06 56 if m.group(2) == 'acdf':
rgrover1 0:4eaf82806f06 57 self.transferFileInfoHandle = m.group(1)
rgrover1 0:4eaf82806f06 58 print("transferFileInfoHandle: " + self.transferFileInfoHandle)
rgrover1 0:4eaf82806f06 59 elif m.group(2) == 'ace0':
rgrover1 0:4eaf82806f06 60 self.transferFileBlockHandle = m.group(1)
rgrover1 0:4eaf82806f06 61 print("transferFileBlockHandle: " + self.transferFileBlockHandle)
rgrover1 0:4eaf82806f06 62
rgrover1 0:4eaf82806f06 63 def sendFileInfoBlock(self, length):
rgrover1 0:4eaf82806f06 64 print("setup fileInfoBlock for transferring {} bytes".format(length))
rgrover1 0:4eaf82806f06 65
rgrover1 0:4eaf82806f06 66 writeCommand = 'char-write-req ' + self.transferFileInfoHandle + ' '
rgrover1 0:4eaf82806f06 67 for c in struct.pack('<HH', length, 0):
rgrover1 0:4eaf82806f06 68 writeCommand = writeCommand + '{:02x}'.format(c)
rgrover1 0:4eaf82806f06 69 self.con.sendline(writeCommand)
rgrover1 0:4eaf82806f06 70 self.con.expect('\[CON\]\[.+\]\[LE\]> Characteristic value was written successfully', timeout=200)
rgrover1 0:4eaf82806f06 71
rgrover1 0:4eaf82806f06 72 def sendFileDataBlock(self, blocknum):
rgrover1 0:4eaf82806f06 73 print("will send command for block {}".format(blocknum))
rgrover1 0:4eaf82806f06 74
rgrover1 0:4eaf82806f06 75 writeCommand = 'char-write-req ' + self.transferFileBlockHandle + ' '
rgrover1 0:4eaf82806f06 76 for c in struct.pack('<HBBBBBBBBBBBBBBBB', blocknum, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15):
rgrover1 0:4eaf82806f06 77 writeCommand = writeCommand + '{:02x}'.format(c)
rgrover1 0:4eaf82806f06 78 self.con.sendline(writeCommand)
rgrover1 0:4eaf82806f06 79 self.con.expect('\[CON\]\[.+\]\[LE\]> Characteristic value was written successfully', timeout=200)
rgrover1 0:4eaf82806f06 80
rgrover1 0:4eaf82806f06 81 def disconnect(self):
rgrover1 0:4eaf82806f06 82 self.con.sendline('disconnect')
rgrover1 0:4eaf82806f06 83 self.con.expect('\[\s+\]\[.+\]\[LE\]>')
rgrover1 0:4eaf82806f06 84
rgrover1 0:4eaf82806f06 85 def main():
rgrover1 0:4eaf82806f06 86 bluetoothAddr = "CC:59:FD:D8:3B:A9" # update as necessary
rgrover1 0:4eaf82806f06 87
rgrover1 0:4eaf82806f06 88 target = StreamDownloaderClient(bluetoothAddr, 1024)
rgrover1 0:4eaf82806f06 89
rgrover1 0:4eaf82806f06 90 if __name__ == "__main__":
rgrover1 0:4eaf82806f06 91 main()