diff --git a/.vscode/settings.json b/.vscode/settings.json index c4290296d8315f..5370984750d7dc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -111,7 +111,13 @@ "ratio": "cpp", "set": "cpp", "stack": "cpp", - "regex": "cpp" + "regex": "cpp", + "compare": "cpp", + "concepts": "cpp", + "numeric": "cpp", + "random": "cpp", + "ranges": "cpp", + "variant": "cpp" }, "files.eol": "\n", "editor.formatOnSave": true, diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index aed111dc473cdc..089f09271eb7bf 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -852,6 +852,13 @@ CHIP_ERROR DeviceCommissioner::Shutdown() return CHIP_NO_ERROR; } +#if CHIP_CSG_TEST_HARNESS //CSG_TRACE_BEGIN +PASESession *DeviceCommissioner::GetPASESession() +{ + return &mPairingSession; +} +#endif //CSG_TRACE_END + CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParameters & params) { CHIP_ERROR err = CHIP_NO_ERROR; diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index 0bb5800a167afa..8260435381a76d 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -424,6 +424,9 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, public SessionEst */ CHIP_ERROR Shutdown() override; +#if CHIP_CSG_TEST_HARNESS //CSG_TRACE_BEGON + PASESession *GetPASESession(); +#endif //CSH_TRACE_END // ----- Connection Management ----- /** * @brief diff --git a/src/controller/python/ChipDeviceController-ScriptBinding.cpp b/src/controller/python/ChipDeviceController-ScriptBinding.cpp index 2ef0ee1d7e319d..50f8711790af95 100644 --- a/src/controller/python/ChipDeviceController-ScriptBinding.cpp +++ b/src/controller/python/ChipDeviceController-ScriptBinding.cpp @@ -91,6 +91,9 @@ pychip_DeviceController_GetAddressAndPort(chip::Controller::DeviceCommissioner * uint64_t maxAddressLen, uint16_t * outPort); CHIP_ERROR pychip_DeviceController_GetFabricId(chip::Controller::DeviceCommissioner * devCtrl, uint64_t * outFabricId); +#if CHIP_CSG_TEST_HARNESS //CSG_TRACE_BEGIN +const char * pychip_DeviceController_GetPASEData(chip::Controller::DeviceCommissioner * devCtrl); +#endif //CSG_TRACE_END // Rendezvous CHIP_ERROR pychip_DeviceController_ConnectBLE(chip::Controller::DeviceCommissioner * devCtrl, uint16_t discriminator, uint32_t setupPINCode, chip::NodeId nodeid); @@ -232,6 +235,19 @@ void pychip_DeviceController_SetLogFilter(uint8_t category) #endif } +#if CHIP_CSG_TEST_HARNESS //CSG_TRACE_BEGIN +const char * pychip_DeviceController_GetPASEData(chip::Controller::DeviceCommissioner * devCtrl) +{ + PASESession *pase_session = devCtrl->GetPASESession(); + std::map> *paseTrace = pase_session->getPASETrace(); + /* + TODO: Fix the string return memory leak + https://github.com/chip-csg/connectedhomeip/issues/32 + */ + return yaml_string_for_map(paseTrace); +} +#endif //CSG_TRACE_END + CHIP_ERROR pychip_DeviceController_ConnectBLE(chip::Controller::DeviceCommissioner * devCtrl, uint16_t discriminator, uint32_t setupPINCode, chip::NodeId nodeid) { diff --git a/src/controller/python/DEVELOPMENT_GUIDE.md b/src/controller/python/DEVELOPMENT_GUIDE.md new file mode 100644 index 00000000000000..67f9ad43ecb5a3 --- /dev/null +++ b/src/controller/python/DEVELOPMENT_GUIDE.md @@ -0,0 +1,87 @@ +# Admin Flow + +* CHIP SDK is maintained on a main branch `master` and release branches cut out for specific deliverables like `test_event2.2` +* CSG fork of the CHIP SDK is maintained with all existing main and release branches left untouched and pristine. +* All CSG specific changes should be done on newly created branches (with a `csg/` prefix) based on these release branches. eg: `test_event2.2` -> `csg/test_event2.2` +* Only admins on the repo have access to pull in changes from the upstream repo and update all local main and release branches using the following commands or equivalent: +```bash +git fetch upstream +git pull upstream +git push origin +``` +* Once updated create a local version of the release branch with a csg prefix to add our changes. This branch will be the main merge target for all the PRs in this dev period. + +# Development Flow + +* Developers must create a branch with the following prefix `csg/fix` or `csg/feature` and submit their PRs to be merged to only the csg version of the release branch. +* If the admins upstream the branches, the developers must rebase their changes resolve their conflicts locally before submitting the PR +* Changes should be only additive, isolated and minimal, effort should be made to minimize the footprint on changes in the existing code. + +# Building + +* At the root directory: +```bash +source scripts/activate.sh +gn gen --args='chip_mdns="platform"' out/debug +ninja -C out/debug +``` +* A .whl file is generate at `out/debug/controller/python/chip-0.0-cp37-abi3-linux_aarch64.whl` +* Copy this wheel file into the sample test client folder or into the test harness controller dockerfile folder. + +# Testing with a real accessory +* You need to map the the system dbus to the docker dbus and run the docker with --privileged to be able to communicate with the real accessory +* Launch the a Docker container for chip device controller +Sample Docker File Used: https://docs.google.com/document/d/1-CMDrKEBGnHhSvAUMHH7ZSRDiKhuu2iwI-GYVUjI7DY/edit?resourcekey=0-VTKXbTk9YYQmdq10xa_f7g#heading=h.yzihj7w54f7a +docker run --name docker-python-controller -v /var/run/dbus:/var/run/dbus --privileged -it + +* From the Launched Python controller Docker container run the chip device controller with the BLE adapter parameter set to hci0 +chip-device-ctrl --bluetooth-adapter=hci0 +* You should now be able to run 'ble-scan' and 'connect -ble' actions from the chip device controller + +# Testing with virtual BLE accessory +* For this you will need to create virtual BLE interfaces in the Test harness Docker dev Container +* You need to map the the system dbus to the docker dbus and run the docker with --privileged to be able to create the virtual ble interfaces using Bluez + +* Setting up the Virtual BLE interfaces from Inside a docker container to be used by Other docker containers on the same host: +The bluez in ubuntu seems already the same as the version as CHIP repo, so we don't have to build bluetoothd by ourselves. +Bluetoothd will start on the host on boot, So we infact skip the bluetoothd setup + +You still need to install bluez inside container + +* Starting with a Clean Raspi host post Bootup: +ubuntu@ubuntu:~$ ps -a + PID TTY TIME CMD + 2357 pts/0 00:00:00 ps + +hci0: Type: Primary Bus: UART + BD Address: B8:27:EB:C4:E2:93 ACL MTU: 1021:8 SCO MTU: 64:1 + UP RUNNING + RX bytes:794 acl:0 sco:0 events:52 errors:0 + TX bytes:2760 acl:0 sco:0 commands:52 errors:0 + +* Bringing up the Virtual Interfaces in Docker container 1: +Follow the instructions as mentioned on chip-device-controller documentation +```bash +cd third_party/bluez/repo/ +./bootstrap +./configure --prefix=/usr --mandir=/usr/share/man --sysconfdir=/etc --localstatedir=/var --enable-experimental --with-systemdsystemunitdir=/lib/systemd/system --with-systemduserunitdir=/usr/lib/systemd --enable-deprecated --enable-testing --enable-tools +make +emulator/btvirt -L -l & +``` +* Check hciconfig to confirm the said number of Virtual BLE interfaces are created + +* Launch the a Docker container for chip Linux Lighting app +Sample Docker File used: https://docs.google.com/document/d/1xOizHV3ZeG_mu70CJWp-tN4xYoDxRhjEnwFKzhkIiC0/edit#heading=h.9hjqswbm7x50 +docker run --name docker-chip-lighting-app -v /var/run/dbus:/var/run/dbus --privileged -it + +* Launch the Linux Lighting App in the docker-chip-lighting-app Docker container specifying the ble-device parameter as follows: +./chip-lighting-app --ble-device 1 --wifi + +* Launch the Chip Device controller in a different container(ex: docker-python-controller docker container as mentioned above in Testing with real accessory) +* Run the chip device controller with --ble-adapter set to one of the virtual BLE interfaces(ex: hci2 this interface has to be different then one used by the virtual BLE accessory) as follows: +chip-device-ctrl --bluetooth-adapter=hci2 +* You should now be able to run 'ble-scan' and 'connect -ble' actions from the chip device controller + +# Testing with Hybrid setup with Real and Virtual BLE accessories +* When we have a real accessory along with a virtual ble accessory you will be able to interact/control with only one accessory at a time. In such Hybrid Setup you will have to switch between BLE adapters in chip-device-controller to handle respective accessories. +* To switch between ble interfaces run "ble-adapter-select " diff --git a/src/controller/python/chip-device-ctrl.py b/src/controller/python/chip-device-ctrl.py index deea0c43923d1c..7bef21d7551a72 100755 --- a/src/controller/python/chip-device-ctrl.py +++ b/src/controller/python/chip-device-ctrl.py @@ -45,7 +45,12 @@ from cmd import Cmd from chip.ChipBleUtility import FAKE_CONN_OBJ_VALUE from chip.setup_payload import SetupPayload +from xmlrpc.server import SimpleXMLRPCServer +from enum import Enum +from typing import Any, Dict,Optional +from enum import Enum +from typing import Any, Dict,Optional # Extend sys.path with one or more directories, relative to the location of the # running script, in which the chip package might be found . This makes it # possible to run the device manager shell from a non-standard install location, @@ -73,6 +78,16 @@ elif sys.platform.startswith('linux'): from chip.ChipBluezMgr import BluezManager as BleManager + +class StatusCodeEnum(Enum): + SUCCESS = 0 + FAILED = 1 + +class RPCResponseKeyEnum(Enum): + STATUS = "status" + RESULT = "result" + ERROR = "error" + # The exceptions for CHIP Device Controller CLI @@ -854,8 +869,264 @@ def do_EOF(self, line): def emptyline(self): pass +### Additions needed by the Test Harness Tool ### +# TODO: Implement a custom device manager instead of using the existing manager object +# https://github.com/chip-csg/connectedhomeip/issues/8 +device_manager = DeviceMgrCmd(rendezvousAddr=None, + controllerNodeId=0, bluetoothAdapter=0) + + +# CHIP commands needed by the Harness Tool +def echo_alive(message): + print(message) + return message + +def resolve(fabric_id: int, node_id: int) -> Dict[str, Any]: + try: + __check_supported_os() + err = device_manager.devCtrl.ResolveNode(fabric_id, node_id) + if err != 0: + return __get_response_dict(status=StatusCodeEnum.FAILED, error=f"Failed to resolve node, with error code: {err}") + + address = device_manager.devCtrl.GetAddressAndPort(node_id) + if address is not None: + address = "{}:{}".format( + *address) + return __get_response_dict(status=StatusCodeEnum.SUCCESS, result={'address': address}) + + except Exception as e: + return __get_response_dict(status=StatusCodeEnum.FAILED, error=str(e)) + +def zcl_command( + cluster: str, + command: str, + node_id: int, + endpoint_id: Optional[int] = 1, + group_id: Optional[int] = 0, + optional_args: Optional[dict] = {} + ) -> Dict[str, Any] : + """Generic API for sending ZCL Cluster commands + Each ZCL command has following format: + zcl [optional arguments] + + Args: + cluster (str): Name of cluster + command (str): Command to be run for the mentioned cluster + node_id (int): node_id assigned to the DUT + endpoint_id (int): Optional, endpoint id + group_ip (int): Optional, group id + optional_args (dict): Optinal, dictionary of optional arguements for zcl + cluster commands + + Raises: + exceptions.UnknownCommand: when incorrect cluster and/or command passed + + Returns: + Dict[str, Any]: Dictionary of RPC response for ZCL cluster command + """ + try: + __check_supported_os() + + all_commands = device_manager.devCtrl.ZCLCommandList() + command_arg = all_commands.get(cluster).get(command, None) + if command_arg is None: + raise exceptions.UnknownCommand(cluster, command) + formatted_zcl_args = __format_zcl_arguments_from_dict(optional_args, command_arg) + + error, response = device_manager.devCtrl.ZCLSend( + cluster=cluster, + command=command, + nodeid=node_id, + endpoint=endpoint_id, + groupid=group_id, + args=formatted_zcl_args, + blocking=True) + if error: + return __get_response_dict(status = StatusCodeEnum.FAILED) + elif response: + return __get_response_dict(status = StatusCodeEnum.SUCCESS, result = str(response)) + else: + return __get_response_dict(status = StatusCodeEnum.SUCCESS) + + except Exception as e: + return __get_response_dict(status = StatusCodeEnum.FAILED, error = str(e)) + +def __format_zcl_arguments_from_dict(optional_args: dict, command: dict) -> Dict[str, Any]: + formatted_command_args = {} + for key, value in optional_args.items(): + valueType = command.get(key, None) + if valueType == 'int': + formatted_command_args[key] = int(value) + elif valueType == 'str': + formatted_command_args[key] = value + elif valueType == 'bytes': + formatted_command_args[key] = ParseEncodedString(value) + return formatted_command_args + + +def zcl_add_network(node_id: int, ssid: str, password: str, endpoint_id: Optional[int] = 1, group_id: Optional[int] = 0, breadcrumb: Optional[int] = 0, timeoutMs: Optional[int] = 1000) -> Dict[str, Any] : + try: + __check_supported_os() + args = {} + args['ssid'] = ssid.encode("utf-8") + b'\x00' + args['credentials'] = password.encode("utf-8") + b'\x00' + args['breadcrumb'] = breadcrumb + args['timeoutMs'] = timeoutMs + err, res = device_manager.devCtrl.ZCLSend("NetworkCommissioning", "AddWiFiNetwork", node_id, endpoint_id, group_id, args, blocking=True) + if err != 0: + return __get_response_dict(status=StatusCodeEnum.FAILED) + elif res != None: + return __get_response_dict(status=StatusCodeEnum.SUCCESS, result=str(res)) + else: + return __get_response_dict(status=StatusCodeEnum.SUCCESS) + + except Exception as e: + return __get_response_dict(status = StatusCodeEnum.FAILED, error = str(e)) + +def zcl_enable_network(node_id: int, ssid:str, endpoint_id: Optional[int] = 1, group_id: Optional[int] = 0, breadcrumb: Optional[int] = 0, timeoutMs: Optional[int] = 1000) -> Dict[str, Any]: + try: + __check_supported_os() + args = {} + args['networkID'] = ssid.encode("utf-8") + b'\x00' + args['breadcrumb'] = breadcrumb + args['timeoutMs'] = timeoutMs + + err, res = device_manager.devCtrl.ZCLSend("NetworkCommissioning", "EnableNetwork", node_id, endpoint_id, group_id, args, blocking=True) + if err != 0: + return __get_response_dict(status=StatusCodeEnum.FAILED) + else: + return __get_response_dict(status=StatusCodeEnum.SUCCESS, result=str(res)) + + except Exception as e: + return __get_response_dict(status=StatusCodeEnum.FAILED, error=str(e)) + +def ble_scan(): + try: + __check_supported_os() + device_manager.do_blescan("") + return __get_response_dict(status=StatusCodeEnum.SUCCESS, result=__get_peripheral_list()) + except Exception as e: + return __get_response_dict(status=StatusCodeEnum.FAILED, error=str(e)) + +def __get_peripheral_list() -> Dict[Any, Any]: + device_list = [] + for device in device_manager.bleMgr.peripheral_list: + device_detail = {} + devIdInfo = device_manager.bleMgr.get_peripheral_devIdInfo(device) + if devIdInfo != None: + device_detail['name'] = str(device.Name) + device_detail['id'] = str(device.device_id) + device_detail['rssi'] = str(device.RSSI) + device_detail['address'] = str(device.Address) + device_detail['pairing_state'] = devIdInfo.pairingState + device_detail['discriminator'] = devIdInfo.discriminator + device_detail['vendor_id'] = devIdInfo.vendorId + device_detail['product_id'] = devIdInfo.productId + if device.ServiceData: + for advuuid in device.ServiceData: + device_detail['adv_uuid'] = str(advuuid) + device_list.append(device_detail) + return device_list + +def ble_connect(discriminator: int, pin_code: int, node_id: int) -> Dict[str, Any]: + try: + __check_supported_os() + device_manager.devCtrl.ConnectBLE(discriminator, pin_code, node_id) + return __get_response_dict(status=StatusCodeEnum.SUCCESS) + except Exception as e: + return __get_response_dict(status=StatusCodeEnum.FAILED, error=str(e)) + +def ip_connect(ip_address: string, pin_code: int, node_id: int) -> Dict[str, Any]: + try: + __check_supported_os() + device_manager.devCtrl.ConnectIP(ip_address.encode("utf-8"), pin_code, node_id) + return __get_response_dict(status=StatusCodeEnum.SUCCESS) + except Exception as e: + return __get_response_dict(status=StatusCodeEnum.FAILED, error=str(e)) + +def qr_code_parse(qr_code): + try: + result = SetupPayload().ParseQrCode(qr_code).Dictionary() + return __get_response_dict(status=StatusCodeEnum.SUCCESS, result=result) + except Exception as e: + return __get_response_dict(status=StatusCodeEnum.FAILED, error=str(e)) + +def pin_code_parse(pin_code): + try: + result = SetupPayload().ParseManualPairingCode(pin_code).Dictionary() + return __get_response_dict(status=StatusCodeEnum.SUCCESS, result=result) + except Exception as e: + return __get_response_dict(status=StatusCodeEnum.FAILED, error=str(e)) + +def get_fabric_id(): + try: + fabricID = device_manager.devCtrl.GetFabricId() + if fabricID == 0: + return __get_response_dict(status=StatusCodeEnum.FAILED, error="Fabric ID not created or encountered an error") + return __get_response_dict(status=StatusCodeEnum.SUCCESS, result=fabricID) + except Exception as e: + return __get_response_dict(status=StatusCodeEnum.FAILED, error=str(e)) + +def ble_close(): + try: + __check_supported_os() + device_manager.devCtrl.CloseBLEConnection() + return __get_response_dict(status=StatusCodeEnum.SUCCESS, result=str(0)) + except Exception as e: + return __get_response_dict(status=StatusCodeEnum.FAILED, error=str(e)) + +def get_pase_data() -> Dict[Any, Any]: + """ + This method will return valid data only after the ble_connect, ip_connect method has been called + """ + try: + __check_supported_os() + pase_data = device_manager.devCtrl.GetPASEData() + return __get_response_dict(status = StatusCodeEnum.SUCCESS, result=pase_data) + except Exception as e: + return __get_response_dict(status = StatusCodeEnum.FAILED, error=str(e)) + +def start_rpc_server(): + with SimpleXMLRPCServer(("0.0.0.0", 5000), allow_none=True) as server: + server.register_function(echo_alive) + server.register_function(ble_scan) + server.register_function(resolve) + server.register_function(ble_connect) + server.register_function(ip_connect) + server.register_function(zcl_command) + server.register_function(zcl_add_network) + server.register_function(zcl_enable_network) + server.register_function(resolve) + server.register_function(qr_code_parse) + server.register_function(get_pase_data) + server.register_function(get_fabric_id) + server.register_function(pin_code_parse) + server.register_multicall_functions() + server.register_function(ble_close) + server.register_introspection_functions() + print('Serving XML-RPC on localhost port 5000') + try: + server.serve_forever() + except KeyboardInterrupt: + print("\nKeyboard interrupt received, exiting.") + sys.exit(0) + +def __get_response_dict(status: StatusCodeEnum, result: Optional[Dict[Any, Any]] = None, error:Optional[str] = None) -> Dict [str, Any]: + return { RPCResponseKeyEnum.STATUS.value : status.value, RPCResponseKeyEnum.RESULT.value : result, RPCResponseKeyEnum.ERROR.value : error } + +def __check_supported_os()-> bool: + if platform.system().lower() == 'darwin': + raise Exception(platform.system() + " not supported") + elif sys.platform.lower().startswith('linux'): + return True + + raise Exception("OS Not Supported") +######--------------------------------------------------###### def main(): + start_rpc_server() + + # Never Executed: does not return here optParser = OptionParser() optParser.add_option( "-r", diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index a8d1b0b86bdd93..a58fc333afec32 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -36,6 +36,7 @@ from .exceptions import * import enum +import yaml __all__ = ["ChipDeviceController"] @@ -184,6 +185,17 @@ def ConnectIP(self, ipaddr, setupPinCode, nodeid): self.devCtrl, ipaddr, setupPinCode, nodeid) ) + def GetPASEData(self): + pase_yaml_str = self._ChipStack.Call( + lambda: self._dmLib.pychip_DeviceController_GetPASEData(self.devCtrl) + ) + pase_dict = yaml.safe_load(pase_yaml_str) + if pase_dict is None: + print("ERROR: Failed to parse yaml data returned") + raise ValueError(f"Invalid PASE yaml string returned: {pase_yaml_str}") + return pase_dict + + def ResolveNode(self, fabricid, nodeid): return self._ChipStack.CallAsync( lambda: self._dmLib.pychip_Resolver_ResolveNode(fabricid, nodeid) @@ -359,6 +371,9 @@ def _InitLib(self): c_void_p] self._dmLib.pychip_DeviceController_DeleteDeviceController.restype = c_uint32 + self._dmLib.pychip_DeviceController_GetPASEData.argtypes = [c_void_p] + self._dmLib.pychip_DeviceController_GetPASEData.restype = c_char_p + self._dmLib.pychip_DeviceController_ConnectBLE.argtypes = [ c_void_p, c_uint16, c_uint32, c_uint64] self._dmLib.pychip_DeviceController_ConnectBLE.restype = c_uint32 diff --git a/src/controller/python/chip/setup_payload/setup_payload.py b/src/controller/python/chip/setup_payload/setup_payload.py index fc66e5323badf3..0021d00590044b 100644 --- a/src/controller/python/chip/setup_payload/setup_payload.py +++ b/src/controller/python/chip/setup_payload/setup_payload.py @@ -104,4 +104,15 @@ def __InitNativeFunctions(self, chipLib): [c_char_p, SetupPayload.AttributeVisitor, SetupPayload.VendorAttributeVisitor]) setter.Set("pychip_SetupPayload_PrintOnboardingCodes", c_int32, - [c_uint32, c_uint16, c_uint16, c_uint16, uint8_t, uint8_t]) \ No newline at end of file + [c_uint32, c_uint16, c_uint16, c_uint16, uint8_t, uint8_t]) + +######----------------------------------------------------------------------------------------###### + + def Dictionary(self): + payload_dict = {} + for name, value in self.attributes.items(): + payload_dict[name] = value + for tag, value in self.vendor_attributes.items(): + payload_dict[tag] = value + + return payload_dict diff --git a/src/controller/python/test_client/.dockerignore b/src/controller/python/test_client/.dockerignore new file mode 100644 index 00000000000000..062ec865671b2f --- /dev/null +++ b/src/controller/python/test_client/.dockerignore @@ -0,0 +1,25 @@ +**/__pycache__ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +README.md diff --git a/src/controller/python/test_client/Dockerfile b/src/controller/python/test_client/Dockerfile new file mode 100644 index 00000000000000..f0f9eaddced38d --- /dev/null +++ b/src/controller/python/test_client/Dockerfile @@ -0,0 +1,75 @@ +FROM ubuntu:latest + +# To override +ENV TZ=America/Los_Angeles +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# Executed during Image build +USER root +RUN apt-get update + +# Install Dependencies for setting up CHIP environment +RUN apt-get install -y apt-utils \ + gcc \ + g++ \ + python \ + pkg-config \ + libssl-dev \ + libdbus-1-dev \ + libglib2.0-dev \ + libavahi-client-dev \ + libgirepository1.0-dev \ + ninja-build \ + python3-venv \ + python3-dev \ + python3-pip \ + unzip + +# Additional Dependencies for Chip device controller +RUN apt-get install -y autotools-dev \ + automake \ + libusb-dev \ + libudev-dev \ + libical-dev \ + libreadline-dev \ + libdbus-glib-1-dev \ + libcairo2-dev \ + libtool \ + bluez \ + bluetooth \ + python3-gi \ + python-is-python3 \ + python3 \ + pi-bluetooth \ + avahi-daemon \ + libavahi-client-dev \ + build-essential \ + protobuf-compiler \ + wpasupplicant \ + wireless-tools \ + rfkill \ + libcairo2-dev \ + python3-widgetsnbextension \ + python3-testresources \ + isc-dhcp-client \ + avahi-utils \ + iproute2 \ + iputils-ping + +ADD requirements.txt . +RUN pip3 install -r requirements.txt --no-binary :all + +# Wheel needs to be in the same dir as the dockerfile and have the following name +ADD chip-0.0-cp37-abi3-linux_aarch64.whl . +RUN pip3 install chip-0.0-cp37-abi3-linux_aarch64.whl +WORKDIR /chip_tool + +# Switching to a non-root user, please refer to https://aka.ms/vscode-docker-python-user-rights +RUN useradd appuser && chown -R appuser /chip_tool +USER appuser + +# Set PYTHONPATH +ENV PYTHONPATH="/usr/bin/python3" + +# Executed when you start/launch a container +CMD ["chip-device-ctrl"] diff --git a/src/controller/python/test_client/README.md b/src/controller/python/test_client/README.md new file mode 100644 index 00000000000000..74318b21b071f0 --- /dev/null +++ b/src/controller/python/test_client/README.md @@ -0,0 +1,21 @@ +# Python client using xmlrpc and docker +Sample client program using XML-RPC to do RPC across multiple containers running chip stack. + + +**Setup:** +1. Install the pre-requisites mentioned [here](https://github.com/chip-csg/connectedhomeip/blob/master/docs/BUILDING.md) for linux and RaPi like so: + + `sudo apt-get install git gcc g++ python pkg-config libssl-dev libdbus-1-dev \ + libglib2.0-dev libavahi-client-dev ninja-build python3-venv python3-dev \ + python3-pip unzip libgirepository1.0-dev libcairo2-dev` + + `sudo apt-get install pi-bluetooth` +2. **Reboot** your RaPi after installing the pre-requisites. +3. Build the connectedhomeip repo or the certification fork repo by running the following scripts in the scripts directory: + To just build the container:`./scripts/build_container.sh` + To build both the sdk and the container: `./source scripts/build_sdk_container.sh` +4. Edit the rpc_client.py file and add your rpc calls, i/o validation. +5. Run the python script using `python3 rpc_client.py` + +**Note:** + - The script may emit warnings if the previous run did not cleanup the container properly. diff --git a/src/controller/python/test_client/chip-0.0-cp37-abi3-linux_aarch64.whl b/src/controller/python/test_client/chip-0.0-cp37-abi3-linux_aarch64.whl new file mode 100644 index 00000000000000..d8e2929546624c Binary files /dev/null and b/src/controller/python/test_client/chip-0.0-cp37-abi3-linux_aarch64.whl differ diff --git a/src/controller/python/test_client/requirements.txt b/src/controller/python/test_client/requirements.txt new file mode 100644 index 00000000000000..c58f3a86499b35 --- /dev/null +++ b/src/controller/python/test_client/requirements.txt @@ -0,0 +1,4 @@ +# To ensure app dependencies are ported from your virtual environment/host machine into your container, run 'pip freeze > requirements.txt' in the terminal to overwrite this file +pycairo==1.20.0 +six==1.14.0 +PyGObject==3.36.0 diff --git a/src/controller/python/test_client/rpc_client.py b/src/controller/python/test_client/rpc_client.py new file mode 100644 index 00000000000000..0d42bcd91d967d --- /dev/null +++ b/src/controller/python/test_client/rpc_client.py @@ -0,0 +1,168 @@ +from xmlrpc.client import ServerProxy +import docker +import time +import xmlrpc +from docker.models.containers import Container +import asyncio +from asyncio import TimeoutError, wait_for +from typing import Optional + +client = docker.from_env() + +def destroy_container(container: Container) -> None: + container.kill() + container.remove() + +async def container_running(container: Container) -> None: + sleep_interval = 0.2 + + while True: + # Check if the container is running, then sleep for 0.1 sec + if client.containers.get(container.id).status == "running": + return + + # Sleep first to give container some time + await asyncio.sleep(sleep_interval) + +async def container_ready(container: Container) -> None: + # Wait for the container for start running + try: + await wait_for( + container_running(container), 5 #seconds + ) + except TimeoutError as e: + print("Container timed out") + destroy_container(container) + raise e + +#Create docker containers +def run_new_container(docker_image_tag: str, port: int) -> Container: + # Create containers + try: + # Note: These options are different from test harness, because the network topology is different + # Test Harness has dedicated network on which we can find containers by hostname + # This container is launched from the host directly and is bridged, hence we can easily use ports to connect + mount_volumes = {"/var/run/dbus" : {'bind': '/var/run/dbus', 'mode': 'rw'}} + return client.containers.run( + docker_image_tag, detach=True, ports={5000:port}, volumes=mount_volumes, privileged=True + ) + except Exception as error: + print( + "Error ocurred while creating a container from image " + str(error) + ) + +def get_shortened_id(self, container: Container) -> str: + # Docker containers are addressable by first 12 chars of the container id + # https://github.com/docker/docker-py/issues/2660 + return container.id[:12] + +async def create_container(docker_image_tag: str, port: int) -> Container: + container = run_new_container(docker_image_tag=docker_image_tag, port=port) + if container is None: + print("Unable to run container: " + docker_image_tag) + await container_ready(container) + print("Container running for " + docker_image_tag) + + return container + +def call_rpc(device_server, method_name, *params): + method_list: List = device_server.system.listMethods() # type: ignore + if method_name in method_list: + response_dict = getattr(device_server, method_name)(*params) + return response_dict['result'] + else: + raise RuntimeError(f"RPC Method {method_name} is not available.") + +async def main(): + try: + container_1 = await create_container(docker_image_tag="chip-test", port=5050) + except AttributeError as e: + for container in client.containers.list(): + for tag in container.image.tags: + if tag == "chip-test:latest": + print("WARNING:Container already running, killing the container, please try running the script again") + destroy_container(container) + exit() + + print("List of containers: " + str(client.containers.list())) + + # Wait for the controller to start the rpc server + time.sleep(1) + + # Create an RPC server + server_1 = xmlrpc.client.ServerProxy("http://localhost:5050/") + discriminator = 3840 + pin_code = 20202021 + node_id = 1234 + + # Invoke RPCs + try: + print("Calling RPCs") + print("echo_alive Response:" + server_1.echo_alive("Test")) + print(server_1.system.listMethods()) + scan = call_rpc(server_1, "ble_scan") + print(f"scan: {scan}") + connect = server_1.ble_connect(discriminator, pin_code, node_id) + print(f"connect: {connect}") + pase_data = server_1.get_pase_data() + print(f"pase_data: {pase_data}") + fabric_id = server_1.get_fabric_id() + print(f"fabric_id: {fabric_id}") + + # Network Provisioning commands + ssid="str:UncharteredTerretory" + credentials="str:areaaa51" + zcl_add_network = server_1.zcl_command( + "NetworkCommissioning", + "AddWiFiNetwork", + node_id, 0, 0, + { + 'breadcrumb':0, + 'timeoutMs': 1000, + 'ssid':ssid, + 'credentials':credentials + } + ) + print(f"zcl_add_network: {zcl_add_network}") + zcl_enable_network = server_1.zcl_command( + "NetworkCommissioning", + "EnableNetwork", + node_id, + 0, 0, + { + 'breadcrumb':0, + 'timeoutMs': 1000, + 'networkID':ssid + } + ) + print(f"zcl_enable_network: {zcl_enable_network}") + + # OnOff ZCL commands + zcl_on_off = server_1.zcl_command("OnOff", "Toggle", node_id, 1, 0) + print(f"zcl_on_off: {zcl_on_off}") + + # LevelControl ZCL commands + zcl_level_control = server_1.zcl_command( + "LevelControl", + "MoveToLevel", + node_id, + 1, 0, + { + 'level':50, + 'transitionTime':10, + 'optionMask':10, + 'optionOverride':10 + } + ) + print(f"zcl_level_control: {zcl_level_control}") + + except Exception as e: + print(e) + + # Cleanup + destroy_container(container_1) + +if __name__ == "__main__": + loop = asyncio.get_event_loop() + loop.run_until_complete(main()) + loop.close() diff --git a/src/controller/python/test_client/scripts/activate_environment.sh b/src/controller/python/test_client/scripts/activate_environment.sh new file mode 100755 index 00000000000000..0654d4eca919ec --- /dev/null +++ b/src/controller/python/test_client/scripts/activate_environment.sh @@ -0,0 +1,6 @@ + +if [[ -z "${CHIP_SDK_ROOT}" ]]; then + export CHIP_SDK_ROOT=../../../.. + export TEST_CLIENT_ROOT=./ + source $CHIP_SDK_ROOT/scripts/activate.sh +fi diff --git a/src/controller/python/test_client/scripts/build_container.sh b/src/controller/python/test_client/scripts/build_container.sh new file mode 100755 index 00000000000000..654e5c6857405b --- /dev/null +++ b/src/controller/python/test_client/scripts/build_container.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash + +# Build docker image +docker build -t chip-test ./ diff --git a/src/controller/python/test_client/scripts/build_sdk.sh b/src/controller/python/test_client/scripts/build_sdk.sh new file mode 100755 index 00000000000000..16887b14014c5b --- /dev/null +++ b/src/controller/python/test_client/scripts/build_sdk.sh @@ -0,0 +1,8 @@ + +# Skip creating environment if it already exists + +source ./scripts/activate_environment.sh + +gn gen $CHIP_SDK_ROOT/out/debug +ninja -C $CHIP_SDK_ROOT/out/debug +cp $CHIP_SDK_ROOT/out/debug/controller/python/*.whl $TEST_CLIENT_ROOT/ diff --git a/src/controller/python/test_client/scripts/build_sdk_container.sh b/src/controller/python/test_client/scripts/build_sdk_container.sh new file mode 100755 index 00000000000000..95b9cac52b443f --- /dev/null +++ b/src/controller/python/test_client/scripts/build_sdk_container.sh @@ -0,0 +1,9 @@ +#! /usr/bin/env bash + +source ./scripts/activate_environment.sh + +# Build CHIP SDK +$TEST_CLIENT_ROOT/scripts/build_sdk.sh + +# Build Docker image +$TEST_CLIENT_ROOT/scripts/build_container.sh diff --git a/src/csg_test_harness/BUILD.gn b/src/csg_test_harness/BUILD.gn new file mode 100644 index 00000000000000..f1e0dca75baab8 --- /dev/null +++ b/src/csg_test_harness/BUILD.gn @@ -0,0 +1,11 @@ +import("//build_overrides/chip.gni") + +static_library("csg_test_harness") { + + sources = [ + "utilities.cpp", + "constants.h", + ] + + cflags = [ "-Wconversion" ] +} diff --git a/src/csg_test_harness/constants.h b/src/csg_test_harness/constants.h new file mode 100644 index 00000000000000..e24eed13d0ecf7 --- /dev/null +++ b/src/csg_test_harness/constants.h @@ -0,0 +1,51 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * 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. + */ + +#pragma once +#define CHIP_CSG_TEST_HARNESS 1 + +#define CHARS_PER_BYTE (uint16_t)2 +#include +#include +#include + +const char * yaml_string_for_map(std::map> *trace_map); +std::string stringForDataBuffer(const uint8_t *start, uint16_t data_length); + +// Message Keys +extern std::string messageFromInitiator_key; +extern std::string messageFromResponder_key; + +// Request parameter keys +extern std::string PBKDFParamRequest_key; + +// Response parameter keys +extern std::string PBKDFParamResponse_key; +extern std::string PBKDFParamResponse_salt_length_key; +extern std::string PBKDFParamResponse_iter_count_key; + +// PAKE Contribution (PAKE 1) +extern std::string PAKE_1_key; +extern std::string PAKE_1_Pa_key; +extern std::string PAKE_1_key_id_key; + +// PAKE Contrib. Verification (PAKE 2) +extern std::string PAKE_2_key; +extern std::string PAKE_2_encryption_id_key; + +// PAKE Verification (PAKE 3) +extern std::string PAKE_3_key; diff --git a/src/csg_test_harness/utilities.cpp b/src/csg_test_harness/utilities.cpp new file mode 100644 index 00000000000000..4531bcfee68a3a --- /dev/null +++ b/src/csg_test_harness/utilities.cpp @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * 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. + */ + +#include "constants.h" +#include +#include + +// Message Payload (Initiator/Responder) keys +std::string messageFromResponder_key ("MessageFromResponder"); +std::string messageFromInitiator_key ("MessageFromInitiator"); + +// Request Parameter Keys +std::string PBKDFParamRequest_key ("PBKDFParamRequest"); + +// Response Parameter Keys +std::string PBKDFParamResponse_key ("PBKDFParamResponse"); +std::string PBKDFParamResponse_salt_length_key ("SaltLength"); +std::string PBKDFParamResponse_iter_count_key ("IterCount"); + +// PAKE Contribution (PAKE 1) +std::string PAKE_1_key ("PAKE1"); +std::string PAKE_1_Pa_key ("PAKEPa"); +std::string PAKE_1_key_id_key ("PAKEKeyID"); + +std::string PAKE_2_key ("PAKE2"); +std::string PAKE_2_encryption_id_key ("EncryptionID"); + +std::string PAKE_3_key ("PAKE3"); + +const char * yaml_string_for_map(std::map> *trace_map) +{ + std::string result_yaml_str = ""; + for (auto& x: *trace_map) { + // for each message + result_yaml_str += x.first; + result_yaml_str += ":\n"; + for (auto& y: x.second) { + // for each message item + result_yaml_str += " "; // indent 2 spaces for nested hash + result_yaml_str += y.first; + result_yaml_str += ": "; + result_yaml_str += y.second; + result_yaml_str += "\n"; + } + } + + char * response = new char [result_yaml_str.length()+1]; + strcpy(response, result_yaml_str.c_str()); + return response; +} + +std::string stringForDataBuffer(const uint8_t *start, uint16_t data_length) +{ + uint16_t total_length = (uint16_t)((data_length * CHARS_PER_BYTE) + 1); + char * data_string_ptr = (char *)malloc(total_length * sizeof(char)); + std::string data_string; + for (uint16_t i=0; i < data_length; i++) { + sprintf(data_string_ptr+i*2, "%02x", start[i]); + } + data_string_ptr[data_length*2] = '\0'; + data_string = std::string(data_string_ptr); + return data_string; +} diff --git a/src/lib/BUILD.gn b/src/lib/BUILD.gn index baf56f56a5149f..8816ebaac63bdc 100644 --- a/src/lib/BUILD.gn +++ b/src/lib/BUILD.gn @@ -35,6 +35,7 @@ static_library("lib") { "${chip_root}/src/setup_payload", "${chip_root}/src/system", "${chip_root}/src/transport", + "${chip_root}/src/csg_test_harness", ] if (chip_build_libshell) { diff --git a/src/lib/core/BUILD.gn b/src/lib/core/BUILD.gn index e60a34ddff2752..b6a1673c53c652 100644 --- a/src/lib/core/BUILD.gn +++ b/src/lib/core/BUILD.gn @@ -113,6 +113,7 @@ static_library("core") { "${chip_root}/src/lib/support", "${chip_root}/src/system", "${nlio_root}:nlio", + "${chip_root}/src/csg_test_harness", ] allow_circular_includes_from = [ diff --git a/src/protocols/secure_channel/PASESession.cpp b/src/protocols/secure_channel/PASESession.cpp index bb935e2f3e0c70..dd3a55f51d9bd9 100644 --- a/src/protocols/secure_channel/PASESession.cpp +++ b/src/protocols/secure_channel/PASESession.cpp @@ -44,6 +44,7 @@ #include #include +#include namespace chip { using namespace Crypto; @@ -111,6 +112,13 @@ void PASESession::CloseExchange() } } +#if CHIP_CSG_TEST_HARNESS //CSG_TRACE_BEGIN +std::map> * PASESession::getPASETrace() +{ + return &mPASETrace; +} +#endif //CSG_TRACE_END + CHIP_ERROR PASESession::Serialize(PASESessionSerialized & output) { PASESessionSerializable serializable; @@ -184,6 +192,18 @@ CHIP_ERROR PASESession::Init(uint16_t myKeyId, uint32_t setupCode, SessionEstabl // Reset any state maintained by PASESession object (in case it's being reused for pairing) Clear(); +#if CHIP_CSG_TEST_HARNESS //CSG_TRACE_BEGIN + /* + TODO: Fix memory leak here? + https://github.com/chip-csg/connectedhomeip/issues/32 + */ + mPASETrace = std::map>(); + request_message_map = {}; + response_message_map = {}; + pake_1_message_map = {}; + pake_2_message_map = {}; + pake_3_message_map = {}; +#endif //CSG_TRACE_END ReturnErrorOnFailure(mCommissioningHash.Begin()); ReturnErrorOnFailure(mCommissioningHash.AddData(Uint8::from_const_char(kSpake2pContext), strlen(kSpake2pContext))); @@ -344,6 +364,11 @@ CHIP_ERROR PASESession::DeriveSecureSession(SecureSession & session, SecureSessi CHIP_ERROR PASESession::SendPBKDFParamRequest() { +#ifdef CHIP_CSG_TEST_HARNESS //CSG_TRACE_BEGIN + std::map random_initiator_map = {}; + std::string random_number_string; +#endif //CSG_TRACE_END + System::PacketBufferHandle req = System::PacketBufferHandle::New(kPBKDFParamRandomNumberSize); VerifyOrReturnError(!req.IsNull(), CHIP_ERROR_NO_MEMORY); @@ -352,6 +377,12 @@ CHIP_ERROR PASESession::SendPBKDFParamRequest() req->SetDataLength(kPBKDFParamRandomNumberSize); // Update commissioning hash with the pbkdf2 param request that's being sent. + +#ifdef CHIP_CSG_TEST_HARNESS //CSG_TRACE_BEGIN + request_message_map.insert(std::make_pair(messageFromInitiator_key, stringForDataBuffer(req->Start(), req->DataLength()))); + mPASETrace.insert (std::make_pair(PBKDFParamRequest_key, request_message_map)); +#endif //CSG_TRACE_END + ReturnErrorOnFailure(mCommissioningHash.AddData(req->Start(), req->DataLength())); mNextExpectedMsg = Protocols::SecureChannel::MsgType::PBKDFParamResponse; @@ -472,6 +503,12 @@ CHIP_ERROR PASESession::HandlePBKDFParamResponse(const System::PacketBufferHandl err = SetupSpake2p(static_cast(iterCount), msgptr, saltlen); SuccessOrExit(err); +#if CHIP_CSG_TEST_HARNESS //CSG_TRACE_BEGIN + response_message_map.insert(std::make_pair(messageFromResponder_key, stringForDataBuffer(msg->Start(), msg->DataLength()))); + response_message_map.insert(std::make_pair(PBKDFParamResponse_salt_length_key, std::to_string(saltlen))); + response_message_map.insert(std::make_pair(PBKDFParamResponse_iter_count_key, std::to_string(iterCount))); + mPASETrace.insert (std::make_pair(PBKDFParamResponse_key, response_message_map)); +#endif //CSG_TRACE_END } err = SendMsg1(); @@ -508,6 +545,11 @@ CHIP_ERROR PASESession::SendMsg1() SendFlags(SendMessageFlags::kExpectResponse))); ChipLogDetail(SecureChannel, "Sent spake2p msg1"); +#if CHIP_CSG_TEST_HARNESS //CSG_TRACE_BEGIN + pake_1_message_map.insert(std::make_pair(PAKE_1_Pa_key, stringForDataBuffer(&X[0], (uint16_t)X_len))); + pake_1_message_map.insert(std::make_pair(PAKE_1_key_id_key, std::to_string(mConnectionState.GetLocalKeyID()))); + mPASETrace.insert (std::make_pair(PAKE_1_key, pake_1_message_map)); +#endif //CSG_TRACE_END return CHIP_NO_ERROR; } @@ -617,6 +659,11 @@ CHIP_ERROR PASESession::HandleMsg2_and_SendMsg3(const System::PacketBufferHandle VerifyOrExit(CanCastTo(verifier_len_raw), err = CHIP_ERROR_INVALID_MESSAGE_LENGTH); verifier_len = static_cast(verifier_len_raw); +#if CHIP_CSG_TEST_HARNESS //CSG_TRACE_BEGIN + pake_2_message_map.insert(std::make_pair(messageFromResponder_key, stringForDataBuffer(msg->Start(), msg->DataLength()))); + pake_2_message_map.insert(std::make_pair(PAKE_2_encryption_id_key, std::to_string(encryptionKeyId))); + mPASETrace.insert (std::make_pair(PAKE_2_key, pake_2_message_map)); +#endif //CSG_TRACE_END { const uint8_t * hash = &buf[kMAX_Point_Length]; err = mSpake2p.KeyConfirm(hash, kMAX_Hash_Length); @@ -640,6 +687,10 @@ CHIP_ERROR PASESession::HandleMsg2_and_SendMsg3(const System::PacketBufferHandle // Call delegate to send the Msg3 to peer err = mExchangeCtxt->SendMessage(Protocols::SecureChannel::MsgType::PASE_Spake2p3, bbuf.Finalize()); SuccessOrExit(err); +#if CHIP_CSG_TEST_HARNESS //CSG_TRACE_BEGIN + pake_3_message_map.insert(std::make_pair(messageFromInitiator_key, stringForDataBuffer(&verifier[0], verifier_len))); + mPASETrace.insert (std::make_pair(PAKE_3_key, pake_3_message_map)); +#endif //CSG_TRACE_END } ChipLogDetail(SecureChannel, "Sent spake2p msg3"); diff --git a/src/protocols/secure_channel/PASESession.h b/src/protocols/secure_channel/PASESession.h index b2ec8e4f755ac2..d3fca29f79a6bb 100644 --- a/src/protocols/secure_channel/PASESession.h +++ b/src/protocols/secure_channel/PASESession.h @@ -26,6 +26,8 @@ #pragma once +#include + #include #if CHIP_CRYPTO_HSM #include @@ -77,6 +79,9 @@ class DLL_EXPORT PASESession : public Messaging::ExchangeDelegate, public Pairin PASESession & operator=(const PASESession &) = default; PASESession & operator=(PASESession &&) = default; +#ifdef CHIP_CSG_TEST_HARNESS //CSG_TRACE_BEGIN + std::map< std::string, std::map< std::string, std::string>> *getPASETrace(); +#endif //CSG_TRACE_END virtual ~PASESession(); /** @@ -272,6 +277,17 @@ class DLL_EXPORT PASESession : public Messaging::ExchangeDelegate, public Pairin Protocols::SecureChannel::MsgType mNextExpectedMsg = Protocols::SecureChannel::MsgType::PASE_Spake2pError; +#ifdef CHIP_CSG_TEST_HARNESS //CSG_TRACE_BEGIN + std::map< std::string, std::map< std::string, std::string>> mPASETrace; + // PASE parameters maps + std::map request_message_map; + std::map response_message_map; + std::map pake_1_message_map; + std::map pake_2_message_map; + std::map pake_3_message_map; + +#endif //CSG_TRACE_END + #ifdef ENABLE_HSM_SPAKE Spake2pHSM_P256_SHA256_HKDF_HMAC mSpake2p; #else