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          )