From 0ead7f33d457e6996819b9ddc8deb52749764e15 Mon Sep 17 00:00:00 2001 From: Andy Salisbury Date: Tue, 11 Jun 2024 12:54:53 -0400 Subject: [PATCH] Implement a good chunk of the python side. --- src/controller/python/chip/bdx/Bdx.py | 78 +++++++++++++++---- src/controller/python/chip/bdx/BdxTransfer.py | 51 ++++++++++++ src/controller/python/chip/bdx/bdx.cpp | 8 +- 3 files changed, 119 insertions(+), 18 deletions(-) create mode 100644 src/controller/python/chip/bdx/BdxTransfer.py diff --git a/src/controller/python/chip/bdx/Bdx.py b/src/controller/python/chip/bdx/Bdx.py index f4e69fbb90a826..abaed8c92f60fb 100644 --- a/src/controller/python/chip/bdx/Bdx.py +++ b/src/controller/python/chip/bdx/Bdx.py @@ -32,41 +32,89 @@ def _OnTransferObtainedCallback(future: Future, result: PyChipError, bdxTransfer startOffset: int, length: int, fileDesignator, fileDesignatorLength: int, metadata, metadataLength: int): if result is CHIP_NO_ERROR: - transfer = BdxTransfer() - # TODO: Set the parameters of the transfer. - future.set_result(transfer) + fileDesignatorData = ctypes.string_at(fileDesignator, fileDesignatorLength) + metadataData = ctypes.string_at(metadata, metadataLength) + + initMessage = InitMessage() + initMessage.TransferControlFlags = transferControlFlags + initMessage.MaxBlockSize = maxBlockSize + initMessage.StartOffset = startOffset + initMessage.Length = length + initMessage.FileDesignator = fileDesignatorData[:] + initMessage.Metadata = metadataData[:] + + future.handleTransfer(bdxTransfer, initMessage) else: - future.set_exception(result.to_exception()) + future.handleError(result) @_OnDataReceivedCallbackFunct def _OnDataReceivedCallback(context, dataBuffer, bufferLength: int): - # TODO: Call the context with the data. - pass + data = ctypes.string_at(dataBuffer, bufferLength) + context(data[:]) @_OnTransferCompletedCallbackFunct def _OnTransferCompletedCallback(future: Future, result: PyChipError): - future.set_result(result) + if result is CHIP_NO_ERROR: + future.set_result(result) + else: + future.set_exception(result.to_exception()) + + +class AsyncTransferObtainedTransaction: + def __init__(self, future, data=None): + self._future = future + self._data = data + + def handleTransfer(self, bdxTransfer, initMessage: InitMessage): + transfer = BdxTransfer(bdx_transfer=bdxTransfer, init_message=initMessage, data=self._data) + self._future.set_result(transfer) + + def handleError(self, result: PyChipError): + self._future.set_exception(result.to_exception()) async def PrepareToReceiveBdxData(future: Future): handle = chip.native.GetLibraryHandle() + transaction = AsyncTransferObtainedTransaction(future=future) + + ctypes.pythonapi.Py_IncRef(ctypes.py_object(transaction)) + return await builtins.chipStack.CallAsync( + lambda: handle.pychip_Bdx_ExpectBdxTransfer(ctypes.py_object(transaction)) + ) + + +async def PrepareToSendBdxData(future: Future, data: bytes): + handle = chip.native.GetLibraryHandle() + transaction = AsyncTransferObtainedTransaction(future=future, data=data) - # TODO: Do I need to increment a reference to the future? (using ctypes.pythonapi.Py_IncRef(ctypes.py_object(future))) + ctypes.pythonapi.Py_IncRef(ctypes.py_object(transaction)) return await builtins.chipStack.CallAsync( - lambda: handle.pychip_Bdx_ExpectBdxTransfer(future) + lambda: handle.pychip_Bdx_ExpectBdxTransfer(ctypes.py_object(transaction)) ) -async def PrepareToSendBdxData(future: Future, data): # TODO: Type of data? +async def AcceptSendTransfer(transfer: c_void_p, dataReceivedClosure, transferComplete: Future): handle = chip.native.GetLibraryHandle() + ctypes.pythonapi.Py_IncRef(ctypes.py_object(dataReceivedClosure)) + ctypes.pythonapi.Py_IncRef(ctypes.py_object(transferComplete)) + return await builtins.chipStack.CallAsync( + lambda: handle.pychip_Bdx_AcceptSendTransfer(transfer, dataReceivedClosure, transferComplete) + ) - # TODO: Store data somewhere. - # TODO: Do I need to increment a reference to the future? (using ctypes.pythonapi.Py_IncRef(ctypes.py_object(future))) +async def AcceptReceiveTransfer(transfer: c_void_p, data: bytes, transferComplete: Future): + handle = chip.native.GetLibraryHandle() + return await builtins.chipStack.CallAsync( + lambda: handle.pychip_Bdx_AcceptReceiveTransfer(transfer, ctypes.c_char_p(data), len(data), transferComplete) + ) + + +async def RejectTransfer(transfer: c_void_p): + handle = chip.native.GetLibraryHandle() return await builtins.chipStack.CallAsync( - lambda: handle.pychip_Bdx_ExpectBdxTransfer(future) + lambda: handle.pychip_Bdx_RejectTransfer(transfer) ) @@ -77,9 +125,9 @@ def Init(): setter = chip.native.NativeLibraryHandleMethodArguments(handle) setter.Set('pychip_Bdx_ExpectBdxTransfer', - PyChipError, []) + PyChipError, [py_object]) setter.Set('pychip_Bdx_StopExpectingBdxTransfer', - PyChipError, []) + PyChipError, [py_object]) setter.Set('pychip_Bdx_AcceptSendTransfer', PyChipError, [c_void_p, py_object, py_object]) setter.Set('pychip_Bdx_AcceptReceiveTransfer', diff --git a/src/controller/python/chip/bdx/BdxTransfer.py b/src/controller/python/chip/bdx/BdxTransfer.py new file mode 100644 index 00000000000000..d331a8361d07b3 --- /dev/null +++ b/src/controller/python/chip/bdx/BdxTransfer.py @@ -0,0 +1,51 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +@dataclass +class InitMessage: + TransferControlFlags: int + MaxBlockSize: int + StartOffset: int + Length: int + FileDesignator + Metadata + +class BdxTransfer: + __init__(self, bdx_transfer: c_void_p, init_message: InitMessage, data = None): + self.init_message = init_message + self._bdx_transfer = bdx_transfer + self._data = data + + async def accept(self): + eventLoop = asyncio.get_running_loop() + future = eventLoop.create_future() + + if self._data != None: + res = await Bdx.AcceptReceiveTransfer(self._bdx_transfer, self._data, future) + res.raise_on_error() + return await future + else: + self._data = [] + res = await Bdx.AcceptSendTransfer(self._bdx_transfer, lambda data: self._data.extend(data), future) + res.raise_on_error() + await future + return self._data + + async def reject(self): + res = await Bdx.RejectTransfer(self._bdx_transfer) + res.raise_on_error() + return res \ No newline at end of file diff --git a/src/controller/python/chip/bdx/bdx.cpp b/src/controller/python/chip/bdx/bdx.cpp index 9d7e5a4b682d61..47562e4c1e177f 100644 --- a/src/controller/python/chip/bdx/bdx.cpp +++ b/src/controller/python/chip/bdx/bdx.cpp @@ -178,6 +178,7 @@ PyChipError pychip_Bdx_ExpectBdxTransfer(PyObject transferObtainedContext) VerifyOrReturnValue(transferData != nullptr, ToPyChipError(CHIP_ERROR_NO_MEMORY)); transferData->OnTransferObtainedContext = transferObtainedContext; gBdxTransferManager.ExpectATransfer(); + return ToPyChipError(CHIP_NO_ERROR); } PyChipError pychip_Bdx_StopExpectingBdxTransfer(PyObject transferObtainedContext) @@ -186,6 +187,7 @@ PyChipError pychip_Bdx_StopExpectingBdxTransfer(PyObject transferObtainedContext VerifyOrReturnValue(transferData != nullptr, ToPyChipError(CHIP_ERROR_NOT_FOUND)); gBdxTransferManager.StopExpectingATransfer(); gTransfers.RemoveTransferData(transferData); + return ToPyChipError(CHIP_NO_ERROR); } PyChipError pychip_Bdx_AcceptSendTransfer(chip::bdx::BdxTransfer * transfer, PyObject dataReceivedContext, @@ -194,7 +196,7 @@ PyChipError pychip_Bdx_AcceptSendTransfer(chip::bdx::BdxTransfer * transfer, PyO TransferData * transferData = gTransfers.TransferDataForTransfer(transfer); transferData->OnDataReceivedContext = dataReceivedContext; transferData->OnTransferCompletedContext = transferCompletedContext; - transfer->AcceptSend(); + return ToPyChipError(transfer->AcceptSend()); } PyChipError pychip_Bdx_AcceptReceiveTransfer(chip::bdx::BdxTransfer * transfer, const uint8_t * dataBuffer, size_t dataLength, @@ -203,12 +205,12 @@ PyChipError pychip_Bdx_AcceptReceiveTransfer(chip::bdx::BdxTransfer * transfer, TransferData * transferData = gTransfers.TransferDataForTransfer(transfer); transferData->OnTransferCompletedContext = transferCompletedContext; chip::ByteSpan data(dataBuffer, dataLength); - transfer->AcceptReceive(data); + return ToPyChipError(transfer->AcceptReceive(data)); } PyChipError pychip_Bdx_RejectTransfer(chip::bdx::BdxTransfer * transfer) { - transfer->Reject(); + return ToPyChipError(transfer->Reject()); } }