Command.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. * Copyright (c) 2020 Project CHIP Authors
  3. * All rights reserved.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #pragma once
  19. #include <app/data-model/Nullable.h>
  20. #include <commands/clusters/ComplexArgument.h>
  21. #include <commands/clusters/CustomArgument.h>
  22. #include <inet/InetInterface.h>
  23. #include <lib/core/Optional.h>
  24. #include <lib/support/Span.h>
  25. #include <lib/support/logging/CHIPLogging.h>
  26. #include <atomic>
  27. #include <condition_variable>
  28. #include <memory>
  29. #include <mutex>
  30. #include <vector>
  31. class Command;
  32. template <typename T, typename... Args>
  33. std::unique_ptr<Command> make_unique(Args &&... args)
  34. {
  35. return std::unique_ptr<Command>(new T(std::forward<Args>(args)...));
  36. }
  37. struct movable_initializer_list
  38. {
  39. movable_initializer_list(std::unique_ptr<Command> && in) : item(std::move(in)) {}
  40. operator std::unique_ptr<Command>() const && { return std::move(item); }
  41. mutable std::unique_ptr<Command> item;
  42. };
  43. typedef std::initializer_list<movable_initializer_list> commands_list;
  44. enum ArgumentType
  45. {
  46. Number_uint8,
  47. Number_uint16,
  48. Number_uint32,
  49. Number_uint64,
  50. Number_int8,
  51. Number_int16,
  52. Number_int32,
  53. Number_int64,
  54. Float,
  55. Double,
  56. Bool,
  57. String,
  58. CharString,
  59. OctetString,
  60. Address,
  61. Complex,
  62. Custom,
  63. VectorBool,
  64. Vector16,
  65. Vector32,
  66. VectorCustom,
  67. VectorString, // comma separated string items
  68. };
  69. struct Argument
  70. {
  71. const char * name;
  72. ArgumentType type;
  73. int64_t min;
  74. uint64_t max;
  75. void * value;
  76. uint8_t flags;
  77. const char * desc;
  78. enum
  79. {
  80. kOptional = (1 << 0),
  81. kNullable = (1 << 1),
  82. };
  83. bool isOptional() const { return flags & kOptional; }
  84. bool isNullable() const { return flags & kNullable; }
  85. };
  86. struct ReadOnlyGlobalCommandArgument
  87. {
  88. const char * name;
  89. const char * value;
  90. const char * desc;
  91. };
  92. class Command
  93. {
  94. public:
  95. struct AddressWithInterface
  96. {
  97. ::chip::Inet::IPAddress address;
  98. ::chip::Inet::InterfaceId interfaceId;
  99. };
  100. Command(const char * commandName, const char * helpText = nullptr) : mName(commandName), mHelpText(helpText) {}
  101. virtual ~Command() {}
  102. const char * GetName(void) const { return mName; }
  103. const char * GetHelpText() const { return mHelpText; }
  104. const char * GetReadOnlyGlobalCommandArgument(void) const;
  105. const char * GetAttribute(void) const;
  106. const char * GetEvent(void) const;
  107. const char * GetArgumentName(size_t index) const;
  108. const char * GetArgumentDescription(size_t index) const;
  109. bool GetArgumentIsOptional(size_t index) const { return mArgs[index].isOptional(); }
  110. size_t GetArgumentsCount(void) const { return mArgs.size(); }
  111. bool InitArguments(int argc, char ** argv);
  112. void AddArgument(const char * name, const char * value, const char * desc = "");
  113. /**
  114. * @brief
  115. * Add a char string command argument
  116. *
  117. * @param name The name that will be displayed in the command help
  118. * @param value A pointer to a `char *` where the argv value will be stored
  119. * @param flags
  120. * @param desc The description of the argument that will be displayed in the command help
  121. * @returns The number of arguments currently added to the command
  122. */
  123. size_t AddArgument(const char * name, char ** value, const char * desc = "", uint8_t flags = 0);
  124. /**
  125. * Add an octet string command argument
  126. */
  127. size_t AddArgument(const char * name, chip::ByteSpan * value, const char * desc = "", uint8_t flags = 0);
  128. size_t AddArgument(const char * name, chip::Span<const char> * value, const char * desc = "", uint8_t flags = 0);
  129. size_t AddArgument(const char * name, AddressWithInterface * out, const char * desc = "", uint8_t flags = 0);
  130. // Optional Complex arguments are not currently supported via the <chip::Optional> class.
  131. // Instead, they must be explicitly specified as optional using kOptional in the flags parameter,
  132. // and the base TypedComplexArgument<T> class is referenced.
  133. size_t AddArgument(const char * name, ComplexArgument * value, const char * desc = "", uint8_t flags = 0);
  134. size_t AddArgument(const char * name, CustomArgument * value, const char * desc = "");
  135. size_t AddArgument(const char * name, int64_t min, uint64_t max, bool * out, const char * desc = "", uint8_t flags = 0)
  136. {
  137. return AddArgument(name, min, max, reinterpret_cast<void *>(out), Bool, desc, flags);
  138. }
  139. size_t AddArgument(const char * name, int64_t min, uint64_t max, int8_t * out, const char * desc = "", uint8_t flags = 0)
  140. {
  141. return AddArgument(name, min, max, reinterpret_cast<void *>(out), Number_int8, desc, flags);
  142. }
  143. size_t AddArgument(const char * name, int64_t min, uint64_t max, int16_t * out, const char * desc = "", uint8_t flags = 0)
  144. {
  145. return AddArgument(name, min, max, reinterpret_cast<void *>(out), Number_int16, desc, flags);
  146. }
  147. size_t AddArgument(const char * name, int64_t min, uint64_t max, int32_t * out, const char * desc = "", uint8_t flags = 0)
  148. {
  149. return AddArgument(name, min, max, reinterpret_cast<void *>(out), Number_int32, desc, flags);
  150. }
  151. size_t AddArgument(const char * name, int64_t min, uint64_t max, int64_t * out, const char * desc = "", uint8_t flags = 0)
  152. {
  153. return AddArgument(name, min, max, reinterpret_cast<void *>(out), Number_int64, desc, flags);
  154. }
  155. size_t AddArgument(const char * name, int64_t min, uint64_t max, uint8_t * out, const char * desc = "", uint8_t flags = 0)
  156. {
  157. return AddArgument(name, min, max, reinterpret_cast<void *>(out), Number_uint8, desc, flags);
  158. }
  159. size_t AddArgument(const char * name, int64_t min, uint64_t max, uint16_t * out, const char * desc = "", uint8_t flags = 0)
  160. {
  161. return AddArgument(name, min, max, reinterpret_cast<void *>(out), Number_uint16, desc, flags);
  162. }
  163. size_t AddArgument(const char * name, int64_t min, uint64_t max, uint32_t * out, const char * desc = "", uint8_t flags = 0)
  164. {
  165. return AddArgument(name, min, max, reinterpret_cast<void *>(out), Number_uint32, desc, flags);
  166. }
  167. size_t AddArgument(const char * name, int64_t min, uint64_t max, uint64_t * out, const char * desc = "", uint8_t flags = 0)
  168. {
  169. return AddArgument(name, min, max, reinterpret_cast<void *>(out), Number_uint64, desc, flags);
  170. }
  171. size_t AddArgument(const char * name, float min, float max, float * out, const char * desc = "", uint8_t flags = 0);
  172. size_t AddArgument(const char * name, double min, double max, double * out, const char * desc = "", uint8_t flags = 0);
  173. size_t AddArgument(const char * name, int64_t min, uint64_t max, std::vector<uint16_t> * value, const char * desc = "");
  174. size_t AddArgument(const char * name, int64_t min, uint64_t max, std::vector<uint32_t> * value, const char * desc = "");
  175. size_t AddArgument(const char * name, std::vector<CustomArgument *> * value, const char * desc = "");
  176. size_t AddArgument(const char * name, int64_t min, uint64_t max, chip::Optional<std::vector<bool>> * value,
  177. const char * desc = "");
  178. size_t AddArgument(const char * name, int64_t min, uint64_t max, chip::Optional<std::vector<uint32_t>> * value,
  179. const char * desc = "");
  180. template <typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
  181. size_t AddArgument(const char * name, int64_t min, uint64_t max, T * out, const char * desc = "", uint8_t flags = 0)
  182. {
  183. return AddArgument(name, min, max, reinterpret_cast<std::underlying_type_t<T> *>(out), desc, flags);
  184. }
  185. template <typename T>
  186. size_t AddArgument(const char * name, int64_t min, uint64_t max, chip::BitFlags<T> * out, const char * desc = "",
  187. uint8_t flags = 0)
  188. {
  189. // This is a terrible hack that relies on BitFlags only having the one
  190. // mValue member.
  191. return AddArgument(name, min, max, reinterpret_cast<T *>(out), desc, flags);
  192. }
  193. template <typename T>
  194. size_t AddArgument(const char * name, int64_t min, uint64_t max, chip::BitMask<T> * out, const char * desc = "",
  195. uint8_t flags = 0)
  196. {
  197. // This is a terrible hack that relies on BitMask only having the one
  198. // mValue member.
  199. return AddArgument(name, min, max, reinterpret_cast<T *>(out), desc, flags);
  200. }
  201. template <typename T>
  202. size_t AddArgument(const char * name, chip::Optional<T> * value, const char * desc = "")
  203. {
  204. return AddArgument(name, reinterpret_cast<T *>(value), desc, Argument::kOptional);
  205. }
  206. template <typename T>
  207. size_t AddArgument(const char * name, int64_t min, uint64_t max, chip::Optional<T> * value, const char * desc = "")
  208. {
  209. return AddArgument(name, min, max, reinterpret_cast<T *>(value), desc, Argument::kOptional);
  210. }
  211. template <typename T>
  212. size_t AddArgument(const char * name, chip::app::DataModel::Nullable<T> * value, const char * desc = "", uint8_t flags = 0)
  213. {
  214. return AddArgument(name, reinterpret_cast<T *>(value), desc, flags | Argument::kNullable);
  215. }
  216. template <typename T>
  217. size_t AddArgument(const char * name, int64_t min, uint64_t max, chip::app::DataModel::Nullable<T> * value,
  218. const char * desc = "", uint8_t flags = 0)
  219. {
  220. return AddArgument(name, min, max, reinterpret_cast<T *>(value), desc, flags | Argument::kNullable);
  221. }
  222. size_t AddArgument(const char * name, float min, float max, chip::app::DataModel::Nullable<float> * value,
  223. const char * desc = "", uint8_t flags = 0)
  224. {
  225. return AddArgument(name, min, max, reinterpret_cast<float *>(value), desc, flags | Argument::kNullable);
  226. }
  227. size_t AddArgument(const char * name, double min, double max, chip::app::DataModel::Nullable<double> * value,
  228. const char * desc = "", uint8_t flags = 0)
  229. {
  230. return AddArgument(name, min, max, reinterpret_cast<double *>(value), desc, flags | Argument::kNullable);
  231. }
  232. size_t AddArgument(const char * name, std::vector<std::string> * value, const char * desc);
  233. size_t AddArgument(const char * name, chip::Optional<std::vector<std::string>> * value, const char * desc);
  234. void ResetArguments();
  235. virtual CHIP_ERROR Run() = 0;
  236. bool IsInteractive() { return mIsInteractive; }
  237. CHIP_ERROR RunAsInteractive(const chip::Optional<char *> & interactiveStorageDirectory)
  238. {
  239. mStorageDirectory = interactiveStorageDirectory;
  240. mIsInteractive = true;
  241. return Run();
  242. }
  243. const chip::Optional<char *> & GetStorageDirectory() const { return mStorageDirectory; }
  244. protected:
  245. // mStorageDirectory lives here so we can just set it in RunAsInteractive.
  246. chip::Optional<char *> mStorageDirectory;
  247. private:
  248. bool InitArgument(size_t argIndex, char * argValue);
  249. size_t AddArgument(const char * name, int64_t min, uint64_t max, void * out, ArgumentType type, const char * desc,
  250. uint8_t flags);
  251. size_t AddArgument(const char * name, int64_t min, uint64_t max, void * out, const char * desc, uint8_t flags);
  252. /**
  253. * Add the Argument to our list. This preserves the property that all
  254. * optional arguments come at the end of the list.
  255. */
  256. size_t AddArgumentToList(Argument && argument);
  257. const char * mName = nullptr;
  258. const char * mHelpText = nullptr;
  259. bool mIsInteractive = false;
  260. chip::Optional<ReadOnlyGlobalCommandArgument> mReadOnlyGlobalCommandArgument;
  261. std::vector<Argument> mArgs;
  262. };