stream.py
1 # The MIT License (MIT) 2 # 3 # Copyright (c) 2019 Scott Shawcroft for Adafruit Industries 4 # 5 # Permission is hereby granted, free of charge, to any person obtaining a copy 6 # of this software and associated documentation files (the "Software"), to deal 7 # in the Software without restriction, including without limitation the rights 8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 # copies of the Software, and to permit persons to whom the Software is 10 # furnished to do so, subject to the following conditions: 11 # 12 # The above copyright notice and this permission notice shall be included in 13 # all copies or substantial portions of the Software. 14 # 15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 # THE SOFTWARE. 22 """ 23 `stream` 24 ==================================================== 25 26 This module provides stream characteristics that bind readable or writable objects to the Service 27 object they are on. 28 29 """ 30 import _bleio 31 32 from . import Attribute 33 from . import Characteristic 34 from . import ComplexCharacteristic 35 36 __version__ = "0.0.0-auto.0" 37 __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BLE.git" 38 39 40 class BoundWriteStream: 41 """Writes data out to the peer.""" 42 43 def __init__(self, bound_characteristic): 44 self.bound_characteristic = bound_characteristic 45 46 def write(self, buf): 47 """Write data from buf out to the peer.""" 48 # We can only write 20 bytes at a time. 49 offset = 0 50 while offset < len(buf): 51 self.bound_characteristic.value = buf[offset : offset + 20] 52 offset += 20 53 54 55 class StreamOut(ComplexCharacteristic): 56 """Output stream from the Service server.""" 57 58 def __init__( 59 self, 60 *, 61 uuid=None, 62 timeout=1.0, 63 buffer_size=64, 64 properties=Characteristic.NOTIFY, 65 read_perm=Attribute.OPEN, 66 write_perm=Attribute.OPEN 67 ): 68 self._timeout = timeout 69 self._buffer_size = buffer_size 70 super().__init__( 71 uuid=uuid, properties=properties, read_perm=read_perm, write_perm=write_perm 72 ) 73 74 def bind(self, service): 75 """Binds the characteristic to the given Service.""" 76 bound_characteristic = super().bind(service) 77 # If we're given a remote service then we're the client and need to buffer in. 78 if service.remote: 79 bound_characteristic.set_cccd(notify=True) 80 return _bleio.CharacteristicBuffer( 81 bound_characteristic, 82 timeout=self._timeout, 83 buffer_size=self._buffer_size, 84 ) 85 return BoundWriteStream(bound_characteristic) 86 87 88 class StreamIn(ComplexCharacteristic): 89 """Input stream into the Service server.""" 90 91 def __init__( 92 self, 93 *, 94 uuid=None, 95 timeout=1.0, 96 buffer_size=64, 97 properties=(Characteristic.WRITE | Characteristic.WRITE_NO_RESPONSE), 98 write_perm=Attribute.OPEN 99 ): 100 self._timeout = timeout 101 self._buffer_size = buffer_size 102 super().__init__( 103 uuid=uuid, 104 properties=properties, 105 read_perm=Attribute.NO_ACCESS, 106 write_perm=write_perm, 107 ) 108 109 def bind(self, service): 110 """Binds the characteristic to the given Service.""" 111 bound_characteristic = super().bind(service) 112 # If the service is remote need to write out. 113 if service.remote: 114 return BoundWriteStream(bound_characteristic) 115 # We're the server so buffer incoming writes. 116 return _bleio.CharacteristicBuffer( 117 bound_characteristic, timeout=self._timeout, buffer_size=self._buffer_size 118 )