Skip to content

Commit

Permalink
For CFFI in chip-repl, remove variadic arguments (#31159)
Browse files Browse the repository at this point in the history
  • Loading branch information
tehampson authored and pull[bot] committed Feb 21, 2024
1 parent 394ce65 commit 1147096
Show file tree
Hide file tree
Showing 7 changed files with 261 additions and 174 deletions.
97 changes: 56 additions & 41 deletions src/controller/python/chip/clusters/Attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import logging
import sys
from asyncio.futures import Future
from ctypes import CFUNCTYPE, c_size_t, c_uint8, c_uint16, c_uint32, c_uint64, c_void_p, py_object
from ctypes import CFUNCTYPE, POINTER, c_size_t, c_uint8, c_uint16, c_uint32, c_uint64, c_void_p, cast, py_object
from dataclasses import dataclass, field
from enum import Enum, unique
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
Expand All @@ -34,6 +34,7 @@
import chip.interaction_model
import chip.tlv
import construct
from chip.interaction_model import PyWriteAttributeData
from chip.native import ErrorSDKPart, PyChipError
from rich.pretty import pprint

Expand Down Expand Up @@ -955,22 +956,22 @@ def WriteAttributes(future: Future, eventLoop, device,
interactionTimeoutMs: Union[None, int] = None, busyWaitMs: Union[None, int] = None) -> PyChipError:
handle = chip.native.GetLibraryHandle()

writeargs = []
for attr in attributes:
numberOfAttributes = len(attributes)
pyWriteAttributesArrayType = PyWriteAttributeData * numberOfAttributes
pyWriteAttributes = pyWriteAttributesArrayType()
for idx, attr in enumerate(attributes):
if attr.Attribute.must_use_timed_write and timedRequestTimeoutMs is None or timedRequestTimeoutMs == 0:
raise chip.interaction_model.InteractionModelError(chip.interaction_model.Status.NeedsTimedInteraction)
path = chip.interaction_model.AttributePathIBstruct.parse(
b'\x00' * chip.interaction_model.AttributePathIBstruct.sizeof())
path.EndpointId = attr.EndpointId
path.ClusterId = attr.Attribute.cluster_id
path.AttributeId = attr.Attribute.attribute_id
path.DataVersion = attr.DataVersion
path.HasDataVersion = attr.HasDataVersion
path = chip.interaction_model.AttributePathIBstruct.build(path)

tlv = attr.Attribute.ToTLV(None, attr.Data)
writeargs.append(ctypes.c_char_p(path))
writeargs.append(ctypes.c_char_p(bytes(tlv)))
writeargs.append(ctypes.c_int(len(tlv)))

pyWriteAttributes[idx].attributePath.endpointId = c_uint16(attr.EndpointId)
pyWriteAttributes[idx].attributePath.clusterId = c_uint32(attr.Attribute.cluster_id)
pyWriteAttributes[idx].attributePath.attributeId = c_uint32(attr.Attribute.attribute_id)
pyWriteAttributes[idx].attributePath.dataVersion = c_uint32(attr.DataVersion)
pyWriteAttributes[idx].attributePath.hasDataVersion = c_uint8(attr.HasDataVersion)
pyWriteAttributes[idx].tlvData = cast(ctypes.c_char_p(bytes(tlv)), c_void_p)
pyWriteAttributes[idx].tlvLength = c_size_t(len(tlv))

transaction = AsyncWriteTransaction(future, eventLoop)
ctypes.pythonapi.Py_IncRef(ctypes.py_object(transaction))
Expand All @@ -980,7 +981,7 @@ def WriteAttributes(future: Future, eventLoop, device,
ctypes.c_size_t(0 if timedRequestTimeoutMs is None else timedRequestTimeoutMs),
ctypes.c_size_t(0 if interactionTimeoutMs is None else interactionTimeoutMs),
ctypes.c_size_t(0 if busyWaitMs is None else busyWaitMs),
ctypes.c_size_t(len(attributes)), *writeargs)
pyWriteAttributes, ctypes.c_size_t(numberOfAttributes))
)
if not res.is_success:
ctypes.pythonapi.Py_DecRef(ctypes.py_object(transaction))
Expand All @@ -990,26 +991,26 @@ def WriteAttributes(future: Future, eventLoop, device,
def WriteGroupAttributes(groupId: int, devCtrl: c_void_p, attributes: List[AttributeWriteRequest], busyWaitMs: Union[None, int] = None) -> PyChipError:
handle = chip.native.GetLibraryHandle()

writeargs = []
for attr in attributes:
path = chip.interaction_model.AttributePathIBstruct.parse(
b'\x00' * chip.interaction_model.AttributePathIBstruct.sizeof())
path.EndpointId = attr.EndpointId
path.ClusterId = attr.Attribute.cluster_id
path.AttributeId = attr.Attribute.attribute_id
path.DataVersion = attr.DataVersion
path.HasDataVersion = attr.HasDataVersion
path = chip.interaction_model.AttributePathIBstruct.build(path)
numberOfAttributes = len(attributes)
pyWriteAttributesArrayType = PyWriteAttributeData * numberOfAttributes
pyWriteAttributes = pyWriteAttributesArrayType()
for idx, attr in enumerate(attributes):

tlv = attr.Attribute.ToTLV(None, attr.Data)
writeargs.append(ctypes.c_char_p(path))
writeargs.append(ctypes.c_char_p(bytes(tlv)))
writeargs.append(ctypes.c_int(len(tlv)))

pyWriteAttributes[idx].attributePath.endpointId = c_uint16(attr.EndpointId)
pyWriteAttributes[idx].attributePath.clusterId = c_uint32(attr.Attribute.cluster_id)
pyWriteAttributes[idx].attributePath.attributeId = c_uint32(attr.Attribute.attribute_id)
pyWriteAttributes[idx].attributePath.dataVersion = c_uint32(attr.DataVersion)
pyWriteAttributes[idx].attributePath.hasDataVersion = c_uint8(attr.HasDataVersion)
pyWriteAttributes[idx].tlvData = cast(ctypes.c_char_p(bytes(tlv)), c_void_p)
pyWriteAttributes[idx].tlvLength = c_size_t(len(tlv))

return builtins.chipStack.Call(
lambda: handle.pychip_WriteClient_WriteGroupAttributes(
ctypes.c_size_t(groupId), devCtrl,
ctypes.c_size_t(0 if busyWaitMs is None else busyWaitMs),
ctypes.c_size_t(len(attributes)), *writeargs)
pyWriteAttributes, ctypes.c_size_t(numberOfAttributes))
)


Expand Down Expand Up @@ -1037,10 +1038,12 @@ def Read(future: Future, eventLoop, device, devCtrl,
transaction = AsyncReadTransaction(
future, eventLoop, devCtrl, returnClusterObject)

readargs = []

attributePathsForCffi = None
if attributes is not None:
for attr in attributes:
numberOfAttributePaths = len(attributes)
attributePathsForCffiArrayType = c_void_p * numberOfAttributePaths
attributePathsForCffi = attributePathsForCffiArrayType()
for idx, attr in enumerate(attributes):
path = chip.interaction_model.AttributePathIBstruct.parse(
b'\xff' * chip.interaction_model.AttributePathIBstruct.sizeof())
if attr.EndpointId is not None:
Expand All @@ -1050,10 +1053,14 @@ def Read(future: Future, eventLoop, device, devCtrl,
if attr.AttributeId is not None:
path.AttributeId = attr.AttributeId
path = chip.interaction_model.AttributePathIBstruct.build(path)
readargs.append(ctypes.c_char_p(path))
attributePathsForCffi[idx] = cast(ctypes.c_char_p(path), c_void_p)

dataVersionFiltersForCffi = None
if dataVersionFilters is not None:
for f in dataVersionFilters:
numberOfDataVersionFilters = len(dataVersionFilters)
dataVersionFiltersForCffiArrayType = c_void_p * numberOfDataVersionFilters
dataVersionFiltersForCffi = dataVersionFiltersForCffiArrayType()
for idx, f in enumerate(dataVersionFilters):
filter = chip.interaction_model.DataVersionFilterIBstruct.parse(
b'\xff' * chip.interaction_model.DataVersionFilterIBstruct.sizeof())
if f.EndpointId is not None:
Expand All @@ -1073,10 +1080,14 @@ def Read(future: Future, eventLoop, device, devCtrl,
"DataVersionFilter must provide DataVersion.")
filter = chip.interaction_model.DataVersionFilterIBstruct.build(
filter)
readargs.append(ctypes.c_char_p(filter))
dataVersionFiltersForCffi[idx] = cast(ctypes.c_char_p(filter), c_void_p)

eventPathsForCffi = None
if events is not None:
for event in events:
numberOfEvents = len(events)
eventPathsForCffiArrayType = c_void_p * numberOfEvents
eventPathsForCffi = eventPathsForCffiArrayType()
for idx, event in enumerate(events):
path = chip.interaction_model.EventPathIBstruct.parse(
b'\xff' * chip.interaction_model.EventPathIBstruct.sizeof())
if event.EndpointId is not None:
Expand All @@ -1090,7 +1101,7 @@ def Read(future: Future, eventLoop, device, devCtrl,
else:
path.Urgent = 0
path = chip.interaction_model.EventPathIBstruct.build(path)
readargs.append(ctypes.c_char_p(path))
eventPathsForCffi[idx] = cast(ctypes.c_char_p(path), c_void_p)

readClientObj = ctypes.POINTER(c_void_p)()
readCallbackObj = ctypes.POINTER(c_void_p)()
Expand All @@ -1116,12 +1127,14 @@ def Read(future: Future, eventLoop, device, devCtrl,
ctypes.byref(readCallbackObj),
device,
ctypes.c_char_p(params),
attributePathsForCffi,
ctypes.c_size_t(0 if attributes is None else len(attributes)),
dataVersionFiltersForCffi,
ctypes.c_size_t(
0 if dataVersionFilters is None else len(dataVersionFilters)),
eventPathsForCffi,
ctypes.c_size_t(0 if events is None else len(events)),
eventNumberFilterPtr,
*readargs))
eventNumberFilterPtr))

transaction.SetClientObjPointers(readClientObj, readCallbackObj)

Expand Down Expand Up @@ -1168,8 +1181,10 @@ def Init():
# attribute information we want written using a vector. This possibility was not implemented at the
# time where simply specified the argtypes, because of time constraints. This solution was quicker
# to fix the crash on ARM64 Apple platforms without a refactor.
handle.pychip_WriteClient_WriteAttributes.argtypes = [py_object, c_void_p, c_size_t, c_size_t, c_size_t, c_size_t]
handle.pychip_WriteClient_WriteGroupAttributes.argtypes = [c_size_t, c_void_p, c_size_t, c_size_t]
handle.pychip_WriteClient_WriteAttributes.argtypes = [py_object, c_void_p,
c_size_t, c_size_t, c_size_t, POINTER(PyWriteAttributeData), c_size_t]
handle.pychip_WriteClient_WriteGroupAttributes.argtypes = [
c_size_t, c_void_p, c_size_t, POINTER(PyWriteAttributeData), c_size_t]

setter.Set('pychip_WriteClient_InitCallbacks', None, [
_OnWriteResponseCallbackFunct, _OnWriteErrorCallbackFunct, _OnWriteDoneCallbackFunct])
Expand Down
25 changes: 13 additions & 12 deletions src/controller/python/chip/clusters/Command.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@
import logging
import sys
from asyncio.futures import Future
from ctypes import CFUNCTYPE, c_bool, c_char_p, c_size_t, c_uint8, c_uint16, c_uint32, c_void_p, py_object
from ctypes import CFUNCTYPE, POINTER, c_bool, c_char_p, c_size_t, c_uint8, c_uint16, c_uint32, c_void_p, cast, py_object
from dataclasses import dataclass
from typing import List, Optional, Type, Union

import chip.exceptions
import chip.interaction_model
from chip.interaction_model import PyInvokeRequestData
from chip.native import PyChipError

from .ClusterObjects import ClusterCommand
Expand Down Expand Up @@ -313,24 +314,24 @@ def SendBatchCommands(future: Future, eventLoop, device, commands: List[InvokeRe
handle = chip.native.GetLibraryHandle()

responseTypes = []
commandargs = []
for command in commands:
numberOfCommands = len(commands)
pyBatchCommandsDataArrayType = PyInvokeRequestData * numberOfCommands
pyBatchCommandsData = pyBatchCommandsDataArrayType()
for idx, command in enumerate(commands):
clusterCommand = command.Command
responseType = command.ResponseType
if (responseType is not None) and (not issubclass(responseType, ClusterCommand)):
raise ValueError("responseType must be a ClusterCommand or None")
if clusterCommand.must_use_timed_invoke and timedRequestTimeoutMs is None or timedRequestTimeoutMs == 0:
raise chip.interaction_model.InteractionModelError(chip.interaction_model.Status.NeedsTimedInteraction)

commandPath = chip.interaction_model.CommandPathIBStruct.build({
"EndpointId": command.EndpointId,
"ClusterId": clusterCommand.cluster_id,
"CommandId": clusterCommand.command_id})
payloadTLV = clusterCommand.ToTLV()

commandargs.append(c_char_p(commandPath))
commandargs.append(c_char_p(bytes(payloadTLV)))
commandargs.append(c_size_t(len(payloadTLV)))
pyBatchCommandsData[idx].commandPath.endpointId = c_uint16(command.EndpointId)
pyBatchCommandsData[idx].commandPath.clusterId = c_uint32(clusterCommand.cluster_id)
pyBatchCommandsData[idx].commandPath.commandId = c_uint32(clusterCommand.command_id)
pyBatchCommandsData[idx].tlvData = cast(c_char_p(bytes(payloadTLV)), c_void_p)
pyBatchCommandsData[idx].tlvLength = c_size_t(len(payloadTLV))

responseTypes.append(responseType)

Expand All @@ -344,7 +345,7 @@ def SendBatchCommands(future: Future, eventLoop, device, commands: List[InvokeRe
c_uint16(0 if interactionTimeoutMs is None else interactionTimeoutMs),
c_uint16(0 if busyWaitMs is None else busyWaitMs),
c_bool(False if suppressResponse is None else suppressResponse),
c_size_t(len(commands)), *commandargs)
pyBatchCommandsData, c_size_t(numberOfCommands))
)


Expand Down Expand Up @@ -375,7 +376,7 @@ def Init():
setter.Set('pychip_CommandSender_SendCommand',
PyChipError, [py_object, c_void_p, c_uint16, c_uint32, c_uint32, c_char_p, c_size_t, c_uint16, c_bool])
setter.Set('pychip_CommandSender_SendBatchCommands',
PyChipError, [py_object, c_void_p, c_uint16, c_uint16, c_uint16, c_bool, c_size_t])
PyChipError, [py_object, c_void_p, c_uint16, c_uint16, c_uint16, c_bool, POINTER(PyInvokeRequestData), c_size_t])
setter.Set('pychip_CommandSender_TestOnlySendCommandTimedRequestNoTimedInvoke',
PyChipError, [py_object, c_void_p, c_uint32, c_uint32, c_char_p, c_size_t, c_uint16, c_bool])
setter.Set('pychip_CommandSender_SendGroupCommand',
Expand Down
Loading

0 comments on commit 1147096

Please sign in to comment.