diff --git a/.vscode/settings.json b/.vscode/settings.json index d1820983dedf03..2510df9edd3170 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -79,7 +79,38 @@ "typeinfo": "cpp", "*.ipp": "cpp", "aes.h": "c", - "stdio.h": "c" + "stdio.h": "c", + "complex": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "bitset": "cpp", + "iomanip": "cpp", + "hashtable": "cpp", + "__bit_reference": "cpp", + "__config": "cpp", + "__debug": "cpp", + "__errc": "cpp", + "__functional_base": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "__mutex_base": "cpp", + "__node_handle": "cpp", + "__nullptr": "cpp", + "__split_buffer": "cpp", + "__string": "cpp", + "__threading_support": "cpp", + "__tree": "cpp", + "__tuple": "cpp", + "bit": "cpp", + "chrono": "cpp", + "ios": "cpp", + "locale": "cpp", + "map": "cpp", + "mutex": "cpp", + "queue": "cpp", + "ratio": "cpp", + "set": "cpp", + "stack": "cpp" }, "files.eol": "\n", "editor.formatOnSave": true, diff --git a/configure.ac b/configure.ac index 998d7f0df3f9e8..a4853c026cd5ee 100644 --- a/configure.ac +++ b/configure.ac @@ -2085,6 +2085,7 @@ src/lib/support/Makefile src/lib/support/tests/Makefile src/platform/Makefile tests/Makefile +src/qrcodetool/Makefile ]) # diff --git a/src/Makefile.am b/src/Makefile.am index dae592ff269834..364136d59cf837 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -51,6 +51,15 @@ MAYBE_PLATFORM_SUBDIRS += \ $(NULL) endif # CONFIG_DEVICE_LAYER +MAYBE_QRCODE_TOOL = \ + $(NULL) + +if !CONFIG_DEVICE_LAYER + MAYBE_QRCODE_TOOL += \ + qrcodetool \ + $(NULL) +endif + # Always package (e.g. for 'make dist') these subdirectories. DIST_SUBDIRS = \ @@ -63,6 +72,7 @@ DIST_SUBDIRS = \ setup_payload \ crypto \ $(PLATFORM_SUBDIRS) \ + qrcodetool \ $(NULL) # Always build (e.g. for 'make all') these subdirectories. @@ -78,6 +88,7 @@ SUBDIRS = \ setup_payload \ crypto \ $(MAYBE_PLATFORM_SUBDIRS) \ + $(MAYBE_QRCODE_TOOL) \ $(NULL) if CHIP_BUILD_TESTS diff --git a/src/chipcli/chiptool.cpp b/src/chipcli/chiptool.cpp new file mode 100644 index 00000000000000..a8553f0c918144 --- /dev/null +++ b/src/chipcli/chiptool.cpp @@ -0,0 +1,122 @@ +/* + * + * Copyright (c) 2020 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 + +#include +#include +#include + +#include "chiptool_command_manager.h" + +static int match_command(const char * command_name, const char * name) +{ + return !strncmp(command_name, name, strlen(name)); +} + +static int help(int argc, char ** argv) +{ + chiptool_command_t * cmd = NULL; + for (cmd = commands; cmd->c_name != NULL; cmd++) + { + ChipLogDetail(chipTool, "%s\t%s\n", cmd->c_name, cmd->c_help); + } +} + +static int usage(const char * prog_name) +{ + ChipLogDetail(chipTool, + "Usage: %s [-h] [command] [opt ...]\n" + "%s commands are:\n", + prog_name, prog_name); + help(0, NULL); + return 2; +} + +static int execute_command(int argc, char ** argv) +{ + if (argc == 0) + { + return -1; + } + const chiptool_command_t * command_to_execute = NULL; + bool found = false; + + for (command_to_execute = commands; command_to_execute->c_name; command_to_execute++) + { + if (match_command(command_to_execute->c_name, argv[0])) + { + found = true; + break; + } + } + + if (found) + { + ChipLogDetail(chipTool, "Executing cmd %s\n", command_to_execute->c_name); + return command_to_execute->c_func(argc, argv); + } + else + { + help(0, NULL); + } +} + +int main(int argc, char ** argv) +{ + int result = 0; + int do_help = 0; + int ch; + + /* Remember my name. */ + char * prog_name = strrchr(argv[0], '/'); + prog_name = prog_name ? prog_name + 1 : argv[0]; + /* Do getopt stuff for global options. */ + optind = 1; + + while ((ch = getopt(argc, argv, "h")) != -1) + { + switch (ch) + { + case 'h': + do_help = 1; + break; + + case '?': + default: + return usage(prog_name); + } + } + + argc -= optind; + argv += optind; + + if (do_help) + { + /* Munge argc/argv so that argv[0] is something. */ + help(0, NULL); + } + else if (argc > 0) + { + execute_command(argc, argv); + } + else + { + result = usage(prog_name); + } + return result; +} diff --git a/src/lib/support/logging/CHIPLogging.h b/src/lib/support/logging/CHIPLogging.h index 0e127318d8ffcb..c3a86f83b4e8bd 100644 --- a/src/lib/support/logging/CHIPLogging.h +++ b/src/lib/support/logging/CHIPLogging.h @@ -105,6 +105,7 @@ enum LogModule kLogModule_chipSystemLayer, kLogModule_EventLogging, kLogModule_Support, + kLogModule_chipTool, kLogModule_Max }; diff --git a/src/qrcodetool/Makefile.am b/src/qrcodetool/Makefile.am new file mode 100644 index 00000000000000..33d3682b05cf05 --- /dev/null +++ b/src/qrcodetool/Makefile.am @@ -0,0 +1,23 @@ +include $(abs_top_nlbuild_autotools_dir)/automake/pre.am + +bin_PROGRAMS = qrcodetool +qrcodetool_SOURCES = qrcodetool.cpp setup_payload_commands.cpp setup_payload_commands.h qrcodetool_command_manager.h + +qrcodetool_CPPFLAGS = \ + $(NLASSERT_CPPFLAGS) \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/system \ + -I$(top_srcdir)/src/include/ \ + $(NULL) + +qrcodetool_LDADD = \ + $(top_builddir)/src/lib/libCHIP.a \ + $(top_builddir)/src/setup_payload/libSetupPayload.a \ + $(NULL) + +NLFOREIGN_FILE_DEPENDENCIES = \ + $(qrcodetool_LDADD) \ + $(NULL) + +include $(abs_top_nlbuild_autotools_dir)/automake/post.am diff --git a/src/qrcodetool/qrcodetool.cpp b/src/qrcodetool/qrcodetool.cpp new file mode 100644 index 00000000000000..1232d018fdafed --- /dev/null +++ b/src/qrcodetool/qrcodetool.cpp @@ -0,0 +1,123 @@ +/* + * + * Copyright (c) 2020 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 + +#include +#include +#include + +#include "qrcodetool_command_manager.h" + +static int match_command(const char * command_name, const char * name) +{ + return !strncmp(command_name, name, strlen(name)); +} + +static int help(int argc, char ** argv) +{ + qrcodetool_command_t * cmd = NULL; + for (cmd = commands; cmd->c_name != NULL; cmd++) + { + ChipLogDetail(chipTool, "%s\t%s\n", cmd->c_name, cmd->c_help); + } + return 0; +} + +static int usage(const char * prog_name) +{ + ChipLogDetail(chipTool, + "Usage: %s [-h] [command] [opt ...]\n" + "%s commands are:\n", + prog_name, prog_name); + help(0, NULL); + return 2; +} + +static int execute_command(int argc, char ** argv) +{ + if (argc == 0) + { + return -1; + } + const qrcodetool_command_t * command_to_execute = NULL; + bool found = false; + + for (command_to_execute = commands; command_to_execute->c_name; command_to_execute++) + { + if (match_command(command_to_execute->c_name, argv[0])) + { + found = true; + break; + } + } + + if (found) + { + ChipLogDetail(chipTool, "Executing cmd %s\n", command_to_execute->c_name); + return command_to_execute->c_func(argc, argv); + } + else + { + return help(0, NULL); + } +} + +int main(int argc, char ** argv) +{ + int result = 0; + int do_help = 0; + int ch; + + /* Remember my name. */ + char * prog_name = strrchr(argv[0], '/'); + prog_name = prog_name ? prog_name + 1 : argv[0]; + /* Do getopt stuff for global options. */ + optind = 1; + + while ((ch = getopt(argc, argv, "h")) != -1) + { + switch (ch) + { + case 'h': + do_help = 1; + break; + + case '?': + default: + return usage(prog_name); + } + } + + argc -= optind; + argv += optind; + + if (do_help) + { + /* Munge argc/argv so that argv[0] is something. */ + result = help(0, NULL); + } + else if (argc > 0) + { + result = execute_command(argc, argv); + } + else + { + result = usage(prog_name); + } + return result; +} diff --git a/src/qrcodetool/qrcodetool_command_manager.h b/src/qrcodetool/qrcodetool_command_manager.h new file mode 100644 index 00000000000000..97970dc9e42407 --- /dev/null +++ b/src/qrcodetool/qrcodetool_command_manager.h @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2020 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. + */ + +#ifndef QRCODETOOL_CMD_MANAGER_H +#define QRCODETOOL_CMD_MANAGER_H + +#include "setup_payload_commands.h" + +typedef int (*command_func)(int argc, char * const * argv); + +typedef struct qrcodetool_command_t +{ + const char * c_name; /* name of the command. */ + command_func c_func; /* function to execute the command. */ + const char * c_usage; /* usage string for command. */ + const char * c_help; /* help string for (or description of) command. */ +} qrcodetool_command_t; + +qrcodetool_command_t commands[] = { { "generate-qr-code", setup_payload_operation_generate_qr_code, + " -f File path of payload.\n", "Generate qr code from payload in text file." }, + + { "generate-manual-code", setup_payload_operation_generate_manual_code, + "[-f file-path]\n" + " -f File path of payload.\n", + "Generate manual code from payload in text file." }, + // Last one + {} }; + +#endif diff --git a/src/qrcodetool/setup_payload_commands.cpp b/src/qrcodetool/setup_payload_commands.cpp new file mode 100644 index 00000000000000..ffa06567e75137 --- /dev/null +++ b/src/qrcodetool/setup_payload_commands.cpp @@ -0,0 +1,98 @@ +/* + * + * Copyright (c) 2020 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 "setup_payload_commands.h" +#include +#include +#include +#include + +using namespace chip; + +enum class SetupPayloadCodeType +{ + SetupPayloadCodeTypeQR, + SetupPayloadCodeTypeManual +}; + +static string _extractFilePath(int argc, char * const * argv) +{ + string path; + if (argc == 0) + { + return path; + } + int ch; + const char * filePath = NULL; + + while ((ch = getopt(argc, argv, "f:")) != -1) + { + switch (ch) + { + case 'f': + filePath = optarg; + break; + + case '?': + default: + return path; /* @@@ Return 2 triggers usage message. */ + } + } + return string(filePath); +} + +extern int setup_payload_operation_generate_qr_code(int argc, char * const * argv) +{ + ChipLogDetail(chipTool, "setup_payload_operation_generate_qr_code\n"); + string path = _extractFilePath(argc, argv); + if (path.length() == 0) + { + return 2; + } + string code; + CHIP_ERROR err = generateQRCodeFromFilePath(path, code); + if (err == CHIP_NO_ERROR) + { + ChipLogDetail(chipTool, "QR Code: %s", code.c_str()); + return 0; + } + else + { + return 2; + } +} + +extern int setup_payload_operation_generate_manual_code(int argc, char * const * argv) +{ + ChipLogDetail(chipTool, "setup_payload_operation_generate_qr_code\n"); + string path = _extractFilePath(argc, argv); + if (path.length() == 0) + { + return 2; + } + string code; + CHIP_ERROR err = generateManualCodeFromFilePath(path, code); + if (err == CHIP_NO_ERROR) + { + ChipLogDetail(chipTool, "Manual Code: %s", code.c_str()); + return 0; + } + else + { + return 2; + } +} diff --git a/src/qrcodetool/setup_payload_commands.h b/src/qrcodetool/setup_payload_commands.h new file mode 100644 index 00000000000000..8de4f3c94653dd --- /dev/null +++ b/src/qrcodetool/setup_payload_commands.h @@ -0,0 +1,24 @@ +/* + * + * Copyright (c) 2020 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. + */ + +#ifndef SETUP_PAYLOAD_COMMANDS +#define SETUP_PAYLOAD_COMMANDS + +extern int setup_payload_operation_generate_qr_code(int argc, char * const * argv); +extern int setup_payload_operation_generate_manual_code(int argc, char * const * argv); + +#endif diff --git a/src/setup_payload/Makefile.am b/src/setup_payload/Makefile.am index e2567c6622dfe6..76b7d1fb967cec 100644 --- a/src/setup_payload/Makefile.am +++ b/src/setup_payload/Makefile.am @@ -31,12 +31,17 @@ libSetupPayload_adir = $(includedir)/setup_payload libSetupPayload_a_CPPFLAGS = \ -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/include \ -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib/core \ -I$(top_srcdir)/src/system \ - -I$(top_srcdir)/src/include \ + $(NLASSERT_CPPFLAGS) \ + $(NLFAULTINJECTION_CPPFLAGS) \ + $(NLIO_CPPFLAGS) \ $(LWIP_CPPFLAGS) \ $(NULL) + libSetupPayload_a_SOURCES = \ ManualSetupPayloadGenerator.cpp \ ManualSetupPayloadParser.cpp \ @@ -44,6 +49,7 @@ libSetupPayload_a_SOURCES = \ SetupPayload.cpp \ Base41.cpp \ QRCodeSetupPayloadParser.cpp \ + SetupPayloadHelper.cpp \ $(NULL) dist_libSetupPayload_a_HEADERS = \ @@ -53,6 +59,7 @@ dist_libSetupPayload_a_HEADERS = \ SetupPayload.h \ Base41.h \ QRCodeSetupPayloadParser.h \ + SetupPayloadHelper.h \ $(NULL) include $(abs_top_nlbuild_autotools_dir)/automake/post.am diff --git a/src/setup_payload/SetupPayloadHelper.cpp b/src/setup_payload/SetupPayloadHelper.cpp new file mode 100644 index 00000000000000..ff905f45591a7b --- /dev/null +++ b/src/setup_payload/SetupPayloadHelper.cpp @@ -0,0 +1,200 @@ +/* + * + * Copyright (c) 2020 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 "SetupPayloadHelper.h" +#include "QRCodeSetupPayloadGenerator.h" +#include "ManualSetupPayloadGenerator.h" +#include "SetupPayload.h" +#include + +#include + +using namespace chip; + +namespace chip { + +enum SetupPayloadKey +{ + SetupPayloadKey_Version, + SetupPayloadKey_VendorID, + SetupPayloadKey_ProductID, + SetupPayloadKey_RequiresCustomFlowTrue, + SetupPayloadKey_RendezVousInformation, + SetupPayloadKey_Discriminator, + SetupPayloadKey_SetupPINCode, +}; + +struct SetupPayloadParameter +{ + SetupPayloadKey key; + string stringValue; + uint64_t uintValue; +}; + +static CHIP_ERROR resolveSetupPayloadParameter(SetupPayloadParameter & parameter, string key, string value) +{ + bool isUnsignedInt = true; + bool shouldHaveValue = true; + if (key.compare("version") == 0) + { + parameter.key = SetupPayloadKey_Version; + } + else if (key.compare("vendorID") == 0) + { + parameter.key = SetupPayloadKey_VendorID; + } + else if (key.compare("productID") == 0) + { + parameter.key = SetupPayloadKey_ProductID; + } + else if (key.compare("requiresCustomFlowTrue") == 0) + { + parameter.key = SetupPayloadKey_RequiresCustomFlowTrue; + shouldHaveValue = false; + } + else if (key.compare("rendezVousInformation") == 0) + { + parameter.key = SetupPayloadKey_RendezVousInformation; + } + else if (key.compare("discriminator") == 0) + { + parameter.key = SetupPayloadKey_Discriminator; + } + else if (key.compare("setUpPINCode") == 0) + { + parameter.key = SetupPayloadKey_SetupPINCode; + } + else + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + if (shouldHaveValue && value.length() > 0) + { + if (isUnsignedInt) + { + parameter.uintValue = stoul(value, nullptr, 10); + } + else + { + parameter.stringValue = value; + } + } + else if (shouldHaveValue) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + return CHIP_NO_ERROR; +} + +static CHIP_ERROR addParameter(SetupPayload & setupPayload, SetupPayloadParameter parameter) +{ + switch (parameter.key) + { + case SetupPayloadKey_Version: + printf("Loaded version: %llu\n", parameter.uintValue); + setupPayload.version = parameter.uintValue; + break; + case SetupPayloadKey_VendorID: + printf("Loaded vendorID: %llu\n", parameter.uintValue); + setupPayload.vendorID = parameter.uintValue; + break; + case SetupPayloadKey_ProductID: + printf("Loaded productID: %llu\n", parameter.uintValue); + setupPayload.productID = parameter.uintValue; + break; + case SetupPayloadKey_RequiresCustomFlowTrue: + printf("Requires custom flow was set to true\n"); + setupPayload.requiresCustomFlow = true; + break; + case SetupPayloadKey_RendezVousInformation: + printf("Loaded rendezvousInfo: %llu\n", parameter.uintValue); + setupPayload.rendezvousInformation = parameter.uintValue; + break; + case SetupPayloadKey_Discriminator: + printf("Loaded discriminator: %llu\n", parameter.uintValue); + setupPayload.discriminator = parameter.uintValue; + break; + case SetupPayloadKey_SetupPINCode: + printf("Loaded setupPinCode: %llu\n", parameter.uintValue); + setupPayload.setUpPINCode = (uint32_t) parameter.uintValue; + break; + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR loadPayloadFromFile(SetupPayload & setupPayload, string filePath) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + ifstream fileStream(filePath); + VerifyOrExit(!fileStream.fail(), err = CHIP_ERROR_INVALID_ARGUMENT); + + while (fileStream) + { + string key; + string value; + SetupPayloadParameter parameter; + + getline(fileStream, key, ' '); + fileStream >> value; + fileStream.ignore(); + + if (key.length() == 0) + { + continue; + } + err = resolveSetupPayloadParameter(parameter, key, value); + SuccessOrExit(err); + + err = addParameter(setupPayload, parameter); + SuccessOrExit(err); + } +exit: + return err; +} + +CHIP_ERROR generateQRCodeFromFilePath(string filePath, string & outCode) +{ + SetupPayload setupPayload; + CHIP_ERROR err = loadPayloadFromFile(setupPayload, filePath); + if (err != CHIP_NO_ERROR) + { + return err; + } + QRCodeSetupPayloadGenerator generator(setupPayload); + outCode = generator.payloadBase41Representation(); + if (outCode.length() == 0) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + return err; +} + +CHIP_ERROR generateManualCodeFromFilePath(string filePath, string & outCode) +{ + SetupPayload setupPayload; + CHIP_ERROR err = loadPayloadFromFile(setupPayload, filePath); + if (err != CHIP_NO_ERROR) + { + return err; + } + ManualSetupPayloadGenerator generator(setupPayload); + err = generator.payloadDecimalStringRepresentation(outCode); + return err; +} +} // namespace chip diff --git a/src/setup_payload/SetupPayloadHelper.h b/src/setup_payload/SetupPayloadHelper.h new file mode 100644 index 00000000000000..ebb8f2b2396521 --- /dev/null +++ b/src/setup_payload/SetupPayloadHelper.h @@ -0,0 +1,36 @@ +/* + * + * Copyright (c) 2020 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. + */ + +/** + * @file + * The implementation of the Setup Payload Helper. To be used by the chip command line tool. + */ + +#ifndef SetupPayloadHelper_h +#define SetupPayloadHelper_h + +#include +#include + +using namespace std; + +namespace chip { +CHIP_ERROR generateQRCodeFromFilePath(string filePath, string & outCode); +CHIP_ERROR generateManualCodeFromFilePath(string filePath, string & outCode); +} // namespace chip + +#endif /* SetupPayloadHelper_h */