-
Notifications
You must be signed in to change notification settings - Fork 2.2k
BDX transfer support for Python tests #34821
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
60 commits
Select commit
Hold shift + click to select a range
281d8e2
Add the python-C++ translation.
harimau-qirex 1d17e6c
Add a BDX transfer server to handle unsolicited BDX init messages.
harimau-qirex 8832ed9
Add the manager to implement the transfer pool.
harimau-qirex d8cce79
Add the initial implementation of a BDX transfer.
harimau-qirex 0f92e4d
Use BdxTransfer in the other classes.
harimau-qirex 1b9b9d4
Update constructors to set the delegates etc. correctly.
harimau-qirex 39ca533
Implement the C++ side of the barrier. Move the data callback into th…
harimau-qirex d330e72
Add a way to map the transfer to the python contexts.
harimau-qirex 837d30a
Fix some of the minor TODOs.
harimau-qirex c50590f
Add init/shutdown to the transfer server.
harimau-qirex e4ea82a
Start on the implementation of the Python side.
harimau-qirex 6eaa9ac
Listen for all BDX protocol messages rather than just the init messages.
harimau-qirex c15f43d
Fix minor issues in the transfer server.
harimau-qirex d2fe4d0
Implement a good chunk of the python side.
harimau-qirex 4e5bb67
Fix compile errors.
harimau-qirex 7c458b4
Fix a number of issues preventing the BDX python code from running at…
harimau-qirex 614bafd
Return the results of the python-C methods.
harimau-qirex 2a62e8a
Fix the async-ness of the methods that prepare the system to receive …
harimau-qirex fee179b
Initialise the BDX transfer server.
harimau-qirex bac4a10
Fixes necessary to await on the future from PrepareToReceive/SendBdxD…
harimau-qirex 0f16585
Fix sending the accept message.
harimau-qirex 175c347
Acknowledge received blocks so the BDX transfer continues.
harimau-qirex a67f783
Fix the parameters of the python callback methods.
harimau-qirex b114126
Add another async transaction class to handle the transfer completed …
harimau-qirex a5b115d
Add comments to the C++ code.
harimau-qirex a345c55
Add a test for the BDX transfer that uses the diagnostic logs cluster.
harimau-qirex 4e0fb49
Move the calls to release a transfer out of the manager so it works t…
harimau-qirex dec62e9
Delay releasing the C++ BDX transfer object until after it's no longe…
harimau-qirex 2670d2d
Verify the diagnostic logs response is a success.
harimau-qirex 4049521
Restyled by whitespace
restyled-commits e64362d
Restyled by clang-format
restyled-commits 4129083
Restyled by gn
restyled-commits 8bfde70
Restyled by autopep8
restyled-commits e10ed98
Restyled by isort
restyled-commits de8c8a5
Improve BdxTransferManager's comments.
harimau-qirex 453afaa
Use a vector for the data to send over a BDX transfer rather than a r…
harimau-qirex d618ec3
Minor renames.
harimau-qirex 2148873
Improve the error message when the BDX transfer pool is exhausted.
harimau-qirex 36ee48f
Minor fixes.
harimau-qirex 4423da6
Pass the status report's status code up the stack.
harimau-qirex 37a9721
Merge the BDX transfer server into the manager.
harimau-qirex fdb9bcc
Rename BdxTransferManager to TestBdxTransferServer.
harimau-qirex 7d62ba8
Minor cleanup.
harimau-qirex 3b4d586
Improve the documentation of the ownership in the C++ side.
harimau-qirex 1ab7896
Restyled by clang-format
restyled-commits 0d90892
Restyled by autopep8
restyled-commits 2c4704a
Update the new test to work with the new formatting.
harimau-qirex 69d4db7
Lint fixes.
harimau-qirex 0b52760
Fix clang-tidy errors.
harimau-qirex 8c23dc2
Several fixes suggested by Andrei.
harimau-qirex e94fd49
Fix a name in a comment.
harimau-qirex fb1a231
Fix issues preventing test from working.
harimau-qirex c092c64
Rename the methods that accept transfers so it's clear which way the …
harimau-qirex ea73b94
Add doc comments to the Python classes and methods.
harimau-qirex 3f9372a
Fix issues found by mypy.
harimau-qirex 4b9586e
Restyled by clang-format
restyled-commits 49a5cc3
Restyled by autopep8
restyled-commits f5efad3
Fix python lint error.
harimau-qirex 8e6aaa6
Explicitly truncate the status code when generating the error.
harimau-qirex 07d519a
Generate the diagnostic log to transfer in the test.
harimau-qirex File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
# | ||
# 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. | ||
# | ||
|
||
import asyncio | ||
import builtins | ||
import ctypes | ||
from asyncio.futures import Future | ||
from ctypes import CFUNCTYPE, POINTER, c_char_p, c_size_t, c_uint8, c_uint16, c_uint64, c_void_p, py_object | ||
from typing import Callable, Optional | ||
|
||
import chip | ||
from chip.native import PyChipError | ||
|
||
from . import BdxTransfer | ||
|
||
c_uint8_p = POINTER(c_uint8) | ||
|
||
|
||
_OnTransferObtainedCallbackFunct = CFUNCTYPE( | ||
None, py_object, c_void_p, c_uint8, c_uint16, c_uint64, c_uint64, c_uint8_p, c_uint16, c_uint8_p, c_size_t) | ||
_OnFailedToObtainTransferCallbackFunct = CFUNCTYPE(None, py_object, PyChipError) | ||
_OnDataReceivedCallbackFunct = CFUNCTYPE(None, py_object, c_uint8_p, c_size_t) | ||
_OnTransferCompletedCallbackFunct = CFUNCTYPE(None, py_object, PyChipError) | ||
|
||
|
||
class AsyncTransferObtainedTransaction: | ||
harimau-qirex marked this conversation as resolved.
Show resolved
Hide resolved
|
||
''' The Python context when obtaining a transfer. This is passed into the C++ code to be sent back to Python as part | ||
of the callback when a transfer is obtained, and sets the result of the future after being called back. | ||
''' | ||
|
||
def __init__(self, future, event_loop, data=None): | ||
self._future = future | ||
self._data = data | ||
self._event_loop = event_loop | ||
|
||
def _handleTransfer(self, bdxTransfer, initMessage: BdxTransfer.InitMessage): | ||
transfer = BdxTransfer.BdxTransfer(bdx_transfer=bdxTransfer, init_message=initMessage, data=self._data) | ||
self._future.set_result(transfer) | ||
|
||
def handleTransfer(self, bdxTransfer, initMessage: BdxTransfer.InitMessage): | ||
self._event_loop.call_soon_threadsafe(self._handleTransfer, bdxTransfer, initMessage) | ||
|
||
def _handleError(self, result: PyChipError): | ||
self._future.set_exception(result.to_exception()) | ||
|
||
def handleError(self, result: PyChipError): | ||
self._event_loop.call_soon_threadsafe(self._handleError, result) | ||
|
||
|
||
class AsyncTransferCompletedTransaction: | ||
''' The Python context when accepting a transfer. This is passed into the C++ code to be sent back to Python as part | ||
of the callback when the transfer completes, and sets the result of the future after being called back. | ||
''' | ||
|
||
def __init__(self, future, event_loop): | ||
self._future = future | ||
self._event_loop = event_loop | ||
|
||
def _handleResult(self, result: PyChipError): | ||
if result.is_success: | ||
self._future.set_result(result) | ||
else: | ||
self._future.set_exception(result.to_exception()) | ||
|
||
def handleResult(self, result: PyChipError): | ||
self._event_loop.call_soon_threadsafe(self._handleResult, result) | ||
|
||
|
||
@_OnTransferObtainedCallbackFunct | ||
def _OnTransferObtainedCallback(transaction: AsyncTransferObtainedTransaction, bdxTransfer, transferControlFlags: int, | ||
maxBlockSize: int, startOffset: int, length: int, fileDesignator, fileDesignatorLength: int, | ||
metadata, metadataLength: int): | ||
fileDesignatorData = ctypes.string_at(fileDesignator, fileDesignatorLength) | ||
metadataData = ctypes.string_at(metadata, metadataLength) | ||
|
||
initMessage = BdxTransfer.InitMessage( | ||
transferControlFlags, | ||
maxBlockSize, | ||
startOffset, | ||
length, | ||
fileDesignatorData[:], | ||
metadataData[:], | ||
) | ||
|
||
transaction.handleTransfer(bdxTransfer, initMessage) | ||
|
||
|
||
@_OnFailedToObtainTransferCallbackFunct | ||
def _OnFailedToObtainTransferCallback(transaction: AsyncTransferObtainedTransaction, result: PyChipError): | ||
transaction.handleError(result) | ||
|
||
|
||
@_OnDataReceivedCallbackFunct | ||
def _OnDataReceivedCallback(context, dataBuffer: c_uint8_p, bufferLength: int): | ||
data = ctypes.string_at(dataBuffer, bufferLength) | ||
context(data) | ||
|
||
|
||
@_OnTransferCompletedCallbackFunct | ||
def _OnTransferCompletedCallback(transaction: AsyncTransferCompletedTransaction, result: PyChipError): | ||
transaction.handleResult(result) | ||
|
||
|
||
def _PrepareForBdxTransfer(future: Future, data: Optional[bytes]) -> PyChipError: | ||
''' Prepares the BDX system for a BDX transfer. The BDX transfer is set as the future's result. This must be called | ||
before the BDX transfer is initiated. | ||
|
||
Returns the CHIP_ERROR result from the C++ side. | ||
''' | ||
handle = chip.native.GetLibraryHandle() | ||
transaction = AsyncTransferObtainedTransaction(future=future, event_loop=asyncio.get_running_loop(), data=data) | ||
|
||
ctypes.pythonapi.Py_IncRef(ctypes.py_object(transaction)) | ||
res = builtins.chipStack.Call( | ||
lambda: handle.pychip_Bdx_ExpectBdxTransfer(ctypes.py_object(transaction)) | ||
) | ||
if not res.is_success: | ||
ctypes.pythonapi.Py_DecRef(ctypes.py_object(transaction)) | ||
return res | ||
|
||
|
||
def PrepareToReceiveBdxData(future: Future) -> PyChipError: | ||
''' Prepares the BDX system for a BDX transfer where this device receives data. This must be called before the BDX | ||
transfer is initiated. | ||
|
||
When a BDX transfer is found it's set as the future's result. If an error occurs while waiting it is set as the future's exception. | ||
|
||
Returns an error if there was an issue preparing to wait a BDX transfer. | ||
''' | ||
return _PrepareForBdxTransfer(future, None) | ||
|
||
|
||
def PrepareToSendBdxData(future: Future, data: bytes) -> PyChipError: | ||
''' Prepares the BDX system for a BDX transfer where this device sends data. This must be called before the BDX | ||
transfer is initiated. | ||
|
||
When a BDX transfer is found it's set as the future's result. If an error occurs while waiting it is set as the future's exception. | ||
|
||
Returns an error if there was an issue preparing to wait a BDX transfer. | ||
''' | ||
return _PrepareForBdxTransfer(future, data) | ||
|
||
|
||
def AcceptTransferAndReceiveData(transfer: c_void_p, dataReceivedClosure: Callable[[bytes], None], transferComplete: Future): | ||
''' Accepts a BDX transfer with the intent of receiving data. | ||
|
||
The data will be returned block-by-block in dataReceivedClosure. | ||
transferComplete will be fulfilled when the transfer completes. | ||
|
||
Returns an error if one is encountered while accepting the transfer. | ||
''' | ||
handle = chip.native.GetLibraryHandle() | ||
complete_transaction = AsyncTransferCompletedTransaction(future=transferComplete, event_loop=asyncio.get_running_loop()) | ||
ctypes.pythonapi.Py_IncRef(ctypes.py_object(dataReceivedClosure)) | ||
ctypes.pythonapi.Py_IncRef(ctypes.py_object(complete_transaction)) | ||
res = builtins.chipStack.Call( | ||
lambda: handle.pychip_Bdx_AcceptTransferAndReceiveData(transfer, dataReceivedClosure, complete_transaction) | ||
) | ||
if not res.is_success: | ||
ctypes.pythonapi.Py_DecRef(ctypes.py_object(dataReceivedClosure)) | ||
ctypes.pythonapi.Py_DecRef(ctypes.py_object(complete_transaction)) | ||
return res | ||
|
||
|
||
def AcceptTransferAndSendData(transfer: c_void_p, data: bytearray, transferComplete: Future): | ||
''' Accepts a BDX transfer with the intent of sending data. | ||
|
||
The data will be copied by C++. | ||
transferComplete will be fulfilled when the transfer completes. | ||
|
||
Returns an error if one is encountered while accepting the transfer. | ||
''' | ||
handle = chip.native.GetLibraryHandle() | ||
complete_transaction = AsyncTransferCompletedTransaction(future=transferComplete, event_loop=asyncio.get_running_loop()) | ||
ctypes.pythonapi.Py_IncRef(ctypes.py_object(complete_transaction)) | ||
res = builtins.chipStack.Call( | ||
lambda: handle.pychip_Bdx_AcceptTransferAndSendData(transfer, c_char_p(data), len(data), complete_transaction) | ||
) | ||
if not res.is_success: | ||
ctypes.pythonapi.Py_DecRef(ctypes.py_object(complete_transaction)) | ||
return res | ||
|
||
|
||
async def RejectTransfer(transfer: c_void_p): | ||
''' Rejects a BDX transfer. | ||
|
||
Returns an error if one is encountered while rejecting the transfer. | ||
''' | ||
handle = chip.native.GetLibraryHandle() | ||
return await builtins.chipStack.CallAsyncWithResult( | ||
lambda: handle.pychip_Bdx_RejectTransfer(transfer) | ||
) | ||
|
||
|
||
def Init(): | ||
handle = chip.native.GetLibraryHandle() | ||
# Uses one of the type decorators as an indicator for everything being initialized. | ||
if not handle.pychip_Bdx_ExpectBdxTransfer.argtypes: | ||
setter = chip.native.NativeLibraryHandleMethodArguments(handle) | ||
|
||
setter.Set('pychip_Bdx_ExpectBdxTransfer', | ||
PyChipError, [py_object]) | ||
setter.Set('pychip_Bdx_StopExpectingBdxTransfer', | ||
PyChipError, [py_object]) | ||
setter.Set('pychip_Bdx_AcceptTransferAndReceiveData', | ||
PyChipError, [c_void_p, py_object, py_object]) | ||
setter.Set('pychip_Bdx_AcceptTransferAndSendData', | ||
PyChipError, [c_void_p, c_uint8_p, c_size_t]) | ||
setter.Set('pychip_Bdx_RejectTransfer', | ||
PyChipError, [c_void_p]) | ||
setter.Set('pychip_Bdx_InitCallbacks', None, [ | ||
_OnTransferObtainedCallbackFunct, _OnFailedToObtainTransferCallbackFunct, _OnDataReceivedCallbackFunct, | ||
_OnTransferCompletedCallbackFunct]) | ||
|
||
handle.pychip_Bdx_InitCallbacks( | ||
_OnTransferObtainedCallback, _OnFailedToObtainTransferCallback, _OnDataReceivedCallback, _OnTransferCompletedCallback) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# | ||
# 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. | ||
# | ||
|
||
# These BDX constants are defined in the spec. | ||
|
||
# SendInit/ReceiveInit Proposed Transfer Control field structure. | ||
SENDER_DRIVE = 0x10 | ||
RECEIVER_DRIVE = 0x20 | ||
ASYNC = 0x40 |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.