From f63000fb84583a55247de2c56c76100fd8bb1892 Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Thu, 7 Dec 2023 21:20:30 +0000 Subject: [PATCH 1/6] Add ability for chip-repl to grab MaxPathsPerInvoke of remote node --- src/controller/python/chip/ChipDeviceCtrl.py | 12 ++++++++++++ .../python/chip/utils/DeviceProxyUtils.cpp | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index 4a38348575eccf..5042278ef14a67 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -808,6 +808,18 @@ def ComputeRoundTripTimeout(self, nodeid, upperLayerProcessingTimeoutMs: int = 0 res = self._ChipStack.Call(lambda: self._dmLib.pychip_DeviceProxy_ComputeRoundTripTimeout( device.deviceProxy, upperLayerProcessingTimeoutMs)) return res + + + def GetMaxPathsPerInvoke(self, nodeid) -> int: + ''' Returns the Max Paths Per Invoke supported by remote node associated with `nodeid` + + This will result in a session being established if one wasn't already established. + ''' + device = self.GetConnectedDeviceSync(nodeid) + res = self._ChipStack.Call(lambda: self._dmLib.pychip_DeviceProxy_GetMaxPathsPerInvoke( + device.deviceProxy)) + return res + async def TestOnlySendCommandTimedRequestFlagWithNoTimedInvoke(self, nodeid: int, endpoint: int, payload: ClusterObjects.ClusterCommand, responseType=None): diff --git a/src/controller/python/chip/utils/DeviceProxyUtils.cpp b/src/controller/python/chip/utils/DeviceProxyUtils.cpp index d3bb2c6e65e204..b40e6e49378857 100644 --- a/src/controller/python/chip/utils/DeviceProxyUtils.cpp +++ b/src/controller/python/chip/utils/DeviceProxyUtils.cpp @@ -59,4 +59,23 @@ uint32_t pychip_DeviceProxy_ComputeRoundTripTimeout(DeviceProxy * device, uint32 ->ComputeRoundTripTimeout(System::Clock::Milliseconds32(upperLayerProcessingTimeoutMs)) .count(); } + +/** + * @brief + * + * This gets the MaxPathsPerInvoke supported by remote node. + * + * A valid DeviceProxy pointer with a valid, established session is required for this method. + */ +uint16_t pychip_DeviceProxy_GetMaxPathsPerInvoke(DeviceProxy * device, uint32_t upperLayerProcessingTimeoutMs) +{ + VerifyOrDie(device != nullptr); + + auto * deviceProxy = static_cast(device); + VerifyOrDie(deviceProxy->GetSecureSession().HasValue()); + + auto remoteSessionParameters = deviceProxy->GetSecureSession().Value()->GetRemoteSessionParameters(); + + return remoteSessionParameters.GetMaxPathsPerInvoke(); +} } From f8b89c807dc695e10a65048767ff055d88670a01 Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Thu, 7 Dec 2023 21:43:56 +0000 Subject: [PATCH 2/6] Fix CI --- src/controller/python/chip/ChipDeviceCtrl.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index 5042278ef14a67..6ebf5af0194a6c 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -808,7 +808,6 @@ def ComputeRoundTripTimeout(self, nodeid, upperLayerProcessingTimeoutMs: int = 0 res = self._ChipStack.Call(lambda: self._dmLib.pychip_DeviceProxy_ComputeRoundTripTimeout( device.deviceProxy, upperLayerProcessingTimeoutMs)) return res - def GetMaxPathsPerInvoke(self, nodeid) -> int: ''' Returns the Max Paths Per Invoke supported by remote node associated with `nodeid` @@ -820,7 +819,6 @@ def GetMaxPathsPerInvoke(self, nodeid) -> int: device.deviceProxy)) return res - async def TestOnlySendCommandTimedRequestFlagWithNoTimedInvoke(self, nodeid: int, endpoint: int, payload: ClusterObjects.ClusterCommand, responseType=None): ''' From 7b72833f281b8b1aec5e658eef55e5ea21cef9fc Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Fri, 8 Dec 2023 19:45:38 +0000 Subject: [PATCH 3/6] Address PR comments --- src/controller/python/chip/ChipDeviceCtrl.py | 30 +++++++++++--- .../python/chip/interaction_model/__init__.py | 6 ++- .../python/chip/interaction_model/delegate.py | 21 ++++++++++ .../python/chip/utils/DeviceProxyUtils.cpp | 39 +++++++++++++++---- 4 files changed, 81 insertions(+), 15 deletions(-) diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index 6ebf5af0194a6c..0d3974273f99c6 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -53,7 +53,7 @@ from .clusters.CHIPClusters import ChipClusters from .crypto import p256keypair from .exceptions import UnknownAttribute, UnknownCommand -from .interaction_model import InteractionModelError +from .interaction_model import InteractionModelError, SessionParameters, SessionParametersStruct from .interaction_model import delegate as im from .native import PyChipError @@ -809,14 +809,34 @@ def ComputeRoundTripTimeout(self, nodeid, upperLayerProcessingTimeoutMs: int = 0 device.deviceProxy, upperLayerProcessingTimeoutMs)) return res - def GetMaxPathsPerInvoke(self, nodeid) -> int: - ''' Returns the Max Paths Per Invoke supported by remote node associated with `nodeid` + def GetRemoteSessionParameters(self, nodeid) -> typing.Optional[SessionParameters]: + ''' Returns the SessionParameters of reported by the remote node associated with `nodeid`. + If there is some error in getting SessionParameters None is returned. This will result in a session being established if one wasn't already established. ''' + + # First creating the struct to make building the ByteArray to be sent to CFFI easier. + sessionParametersStruct = SessionParametersStruct.parse(b'\x00' * SessionParametersStruct.sizeof()) + sessionParametersByteArray = SessionParametersStruct.build(sessionParametersStruct) device = self.GetConnectedDeviceSync(nodeid) - res = self._ChipStack.Call(lambda: self._dmLib.pychip_DeviceProxy_GetMaxPathsPerInvoke( - device.deviceProxy)) + res = self._ChipStack.Call(lambda: self._dmLib.pychip_DeviceProxy_GetRemoteSessionParameters( + device.deviceProxy, ctypes.c_char_p(sessionParametersByteArray))) + + # 0 is CHIP_NO_ERROR + if res != 0: + return None + + sessionParametersStruct = SessionParametersStruct.parse(sessionParametersByteArray) + return SessionParameters( + sessionIdleInterval=sessionParametersStruct.SessionIdleInterval if sessionParametersStruct.SessionIdleInterval is not 0 else None, + sessionActiveInterval=sessionParametersStruct.SessionActiveInterval if sessionParametersStruct.SessionActiveInterval is not 0 else None, + sessionActiveThreshold=sessionParametersStruct.SessionActiveThreshold if sessionParametersStruct.SessionActiveThreshold is not 0 else None, + dataModelRevision=sessionParametersStruct.DataModelRevision if sessionParametersStruct.DataModelRevision is not 0 else None, + interactionModelRevision=sessionParametersStruct.InteractionModelRevision if sessionParametersStruct.InteractionModelRevision is not 0 else None, + speficiationVersion=sessionParametersStruct.SpeficiationVersion if sessionParametersStruct.SpeficiationVersion is not 0 else None, + maxPathsPerInvoke=sessionParametersStruct.MaxPathsPerInvoke) + return res async def TestOnlySendCommandTimedRequestFlagWithNoTimedInvoke(self, nodeid: int, endpoint: int, diff --git a/src/controller/python/chip/interaction_model/__init__.py b/src/controller/python/chip/interaction_model/__init__.py index bd064f2df87d34..e65aec98929ae2 100644 --- a/src/controller/python/chip/interaction_model/__init__.py +++ b/src/controller/python/chip/interaction_model/__init__.py @@ -26,10 +26,12 @@ from chip.exceptions import ChipStackException -from .delegate import AttributePath, AttributePathIBstruct, DataVersionFilterIBstruct, EventPath, EventPathIBstruct +from .delegate import (AttributePath, AttributePathIBstruct, DataVersionFilterIBstruct, + EventPath, EventPathIBstruct, SessionParameters, SessionParametersStruct) __all__ = ["AttributePath", "AttributePathIBstruct", "DataVersionFilterIBstruct", - "EventPath", "EventPathIBstruct", "Status", "InteractionModelError"] + "EventPath", "EventPathIBstruct", "InteractionModelError", + "SessionParameters", "SessionParametersStruct", "Status"] # defined src/controller/python/chip/interaction_model/Delegate.h diff --git a/src/controller/python/chip/interaction_model/delegate.py b/src/controller/python/chip/interaction_model/delegate.py index f5037ec44cf9f4..4323c78bd2a843 100644 --- a/src/controller/python/chip/interaction_model/delegate.py +++ b/src/controller/python/chip/interaction_model/delegate.py @@ -69,6 +69,16 @@ "DataVersion" / Int32ul, ) +SessionParametersStruct = Struct( + "SessionIdleInterval" / Int32ul, + "SessionActiveInterval" / Int32ul, + "SessionActiveThreshold" / Int16ul, + "DataModelRevision" / Int16ul, + "InteractionModelRevision" / Int16ul, + "SpeficiationVersion" / Int32ul, + "MaxPathsPerInvoke" / Int16ul, +) + @dataclass class AttributePath: @@ -107,6 +117,17 @@ class AttributeWriteResult: status: int +@dataclass +class SessionParameters: + sessionIdleInterval: typing.Optional[int] + sessionActiveInterval: typing.Optional[int] + sessionActiveThreshold: typing.Optional[int] + dataModelRevision: typing.Optional[int] + interactionModelRevision: typing.Optional[int] + speficiationVersion: typing.Optional[int] + maxPathsPerInvoke: int + + # typedef void (*PythonInteractionModelDelegate_OnCommandResponseStatusCodeReceivedFunct)(uint64_t commandSenderPtr, # void * commandStatusBuf); # typedef void (*PythonInteractionModelDelegate_OnCommandResponseProtocolErrorFunct)(uint64_t commandSenderPtr, diff --git a/src/controller/python/chip/utils/DeviceProxyUtils.cpp b/src/controller/python/chip/utils/DeviceProxyUtils.cpp index b40e6e49378857..9b75b269587c74 100644 --- a/src/controller/python/chip/utils/DeviceProxyUtils.cpp +++ b/src/controller/python/chip/utils/DeviceProxyUtils.cpp @@ -33,6 +33,21 @@ using namespace chip; +namespace python { + +struct __attribute__((packed)) SessionParametersStruct +{ + uint32_t sessionIdleInterval = 0; + uint32_t sessionActiveInterval = 0; + uint16_t sessionActiveThreshold = 0; + uint16_t dataModelRevision = 0; + uint16_t interactionModelRevision = 0; + uint32_t speficiationVersion = 0; + uint16_t maxPathsPerInvoke = 0; +}; + +} // namespace python + extern "C" { /** @@ -61,21 +76,29 @@ uint32_t pychip_DeviceProxy_ComputeRoundTripTimeout(DeviceProxy * device, uint32 } /** - * @brief + * @brief This gets the Session Parameters reported by remote node. * - * This gets the MaxPathsPerInvoke supported by remote node. - * - * A valid DeviceProxy pointer with a valid, established session is required for this method. + * A valid DeviceProxy pointer with a valid established session is required for this method. */ -uint16_t pychip_DeviceProxy_GetMaxPathsPerInvoke(DeviceProxy * device, uint32_t upperLayerProcessingTimeoutMs) +PyChipError pychip_DeviceProxy_GetRemoteSessionParameters(DeviceProxy * device, void * sessionParametersStructPointer) { - VerifyOrDie(device != nullptr); + VerifyOrReturnError(device != nullptr || sessionParametersStructPointer, ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT)); auto * deviceProxy = static_cast(device); - VerifyOrDie(deviceProxy->GetSecureSession().HasValue()); + VerifyOrReturnError(deviceProxy->GetSecureSession().HasValue(), ToPyChipError(CHIP_ERROR_INCORRECT_STATE)); auto remoteSessionParameters = deviceProxy->GetSecureSession().Value()->GetRemoteSessionParameters(); + auto remoteMrpConfig = remoteSessionParameters.GetMRPConfig(); + + python::SessionParametersStruct * sessionParam = static_cast(sessionParametersStructPointer); - return remoteSessionParameters.GetMaxPathsPerInvoke(); + sessionParam->sessionIdleInterval = remoteMrpConfig.mIdleRetransTimeout.count(); + sessionParam->sessionActiveInterval = remoteMrpConfig.mActiveRetransTimeout.count(); + sessionParam->sessionActiveThreshold = remoteMrpConfig.mActiveThresholdTime.count(); + sessionParam->dataModelRevision = remoteSessionParameters.GetDataModelRevision().ValueOr(0); + sessionParam->interactionModelRevision = remoteSessionParameters.GetInteractionModelRevision().ValueOr(0); + sessionParam->speficiationVersion = remoteSessionParameters.GetSpecificationVersion().ValueOr(0); + sessionParam->maxPathsPerInvoke = remoteSessionParameters.GetMaxPathsPerInvoke(); + return ToPyChipError(CHIP_NO_ERROR); } } From 44e87612b74916781b923fd15d56906764779596 Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Fri, 8 Dec 2023 19:52:29 +0000 Subject: [PATCH 4/6] Restyle --- src/controller/python/chip/interaction_model/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controller/python/chip/interaction_model/__init__.py b/src/controller/python/chip/interaction_model/__init__.py index e65aec98929ae2..ec6065152d71c0 100644 --- a/src/controller/python/chip/interaction_model/__init__.py +++ b/src/controller/python/chip/interaction_model/__init__.py @@ -26,8 +26,8 @@ from chip.exceptions import ChipStackException -from .delegate import (AttributePath, AttributePathIBstruct, DataVersionFilterIBstruct, - EventPath, EventPathIBstruct, SessionParameters, SessionParametersStruct) +from .delegate import (AttributePath, AttributePathIBstruct, DataVersionFilterIBstruct, EventPath, EventPathIBstruct, + SessionParameters, SessionParametersStruct) __all__ = ["AttributePath", "AttributePathIBstruct", "DataVersionFilterIBstruct", "EventPath", "EventPathIBstruct", "InteractionModelError", From af3147c038c37c747b9ccbf877e30e980b100831 Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Fri, 8 Dec 2023 23:00:38 +0000 Subject: [PATCH 5/6] Address PR comments --- src/controller/python/chip/ChipDeviceCtrl.py | 12 ++++++------ .../python/chip/interaction_model/delegate.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index 0d3974273f99c6..0eb22d5f81bf47 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -829,12 +829,12 @@ def GetRemoteSessionParameters(self, nodeid) -> typing.Optional[SessionParameter sessionParametersStruct = SessionParametersStruct.parse(sessionParametersByteArray) return SessionParameters( - sessionIdleInterval=sessionParametersStruct.SessionIdleInterval if sessionParametersStruct.SessionIdleInterval is not 0 else None, - sessionActiveInterval=sessionParametersStruct.SessionActiveInterval if sessionParametersStruct.SessionActiveInterval is not 0 else None, - sessionActiveThreshold=sessionParametersStruct.SessionActiveThreshold if sessionParametersStruct.SessionActiveThreshold is not 0 else None, - dataModelRevision=sessionParametersStruct.DataModelRevision if sessionParametersStruct.DataModelRevision is not 0 else None, - interactionModelRevision=sessionParametersStruct.InteractionModelRevision if sessionParametersStruct.InteractionModelRevision is not 0 else None, - speficiationVersion=sessionParametersStruct.SpeficiationVersion if sessionParametersStruct.SpeficiationVersion is not 0 else None, + sessionIdleInterval=sessionParametersStruct.SessionIdleInterval if sessionParametersStruct.SessionIdleInterval != 0 else None, + sessionActiveInterval=sessionParametersStruct.SessionActiveInterval if sessionParametersStruct.SessionActiveInterval != 0 else None, + sessionActiveThreshold=sessionParametersStruct.SessionActiveThreshold if sessionParametersStruct.SessionActiveThreshold != 0 else None, + dataModelRevision=sessionParametersStruct.DataModelRevision if sessionParametersStruct.DataModelRevision != 0 else None, + interactionModelRevision=sessionParametersStruct.InteractionModelRevision if sessionParametersStruct.InteractionModelRevision != 0 else None, + specficiationVersion=sessionParametersStruct.SpecificationVersion if sessionParametersStruct.SpecificationVersion != 0 else None, maxPathsPerInvoke=sessionParametersStruct.MaxPathsPerInvoke) return res diff --git a/src/controller/python/chip/interaction_model/delegate.py b/src/controller/python/chip/interaction_model/delegate.py index 4323c78bd2a843..74acb3921ec820 100644 --- a/src/controller/python/chip/interaction_model/delegate.py +++ b/src/controller/python/chip/interaction_model/delegate.py @@ -75,7 +75,7 @@ "SessionActiveThreshold" / Int16ul, "DataModelRevision" / Int16ul, "InteractionModelRevision" / Int16ul, - "SpeficiationVersion" / Int32ul, + "SpecificationVersion" / Int32ul, "MaxPathsPerInvoke" / Int16ul, ) @@ -124,7 +124,7 @@ class SessionParameters: sessionActiveThreshold: typing.Optional[int] dataModelRevision: typing.Optional[int] interactionModelRevision: typing.Optional[int] - speficiationVersion: typing.Optional[int] + specficiationVersion: typing.Optional[int] maxPathsPerInvoke: int From 202440f96cce167ab385e3aea4515b37a27397e9 Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Mon, 11 Dec 2023 13:55:58 +0000 Subject: [PATCH 6/6] Address PR comments --- src/controller/python/chip/utils/DeviceProxyUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controller/python/chip/utils/DeviceProxyUtils.cpp b/src/controller/python/chip/utils/DeviceProxyUtils.cpp index 9b75b269587c74..e29c88cdb41d2c 100644 --- a/src/controller/python/chip/utils/DeviceProxyUtils.cpp +++ b/src/controller/python/chip/utils/DeviceProxyUtils.cpp @@ -42,7 +42,7 @@ struct __attribute__((packed)) SessionParametersStruct uint16_t sessionActiveThreshold = 0; uint16_t dataModelRevision = 0; uint16_t interactionModelRevision = 0; - uint32_t speficiationVersion = 0; + uint32_t specificationVersion = 0; uint16_t maxPathsPerInvoke = 0; }; @@ -97,7 +97,7 @@ PyChipError pychip_DeviceProxy_GetRemoteSessionParameters(DeviceProxy * device, sessionParam->sessionActiveThreshold = remoteMrpConfig.mActiveThresholdTime.count(); sessionParam->dataModelRevision = remoteSessionParameters.GetDataModelRevision().ValueOr(0); sessionParam->interactionModelRevision = remoteSessionParameters.GetInteractionModelRevision().ValueOr(0); - sessionParam->speficiationVersion = remoteSessionParameters.GetSpecificationVersion().ValueOr(0); + sessionParam->specificationVersion = remoteSessionParameters.GetSpecificationVersion().ValueOr(0); sessionParam->maxPathsPerInvoke = remoteSessionParameters.GetMaxPathsPerInvoke(); return ToPyChipError(CHIP_NO_ERROR); }