Sfoglia il codice sorgente

增加 ali-iotkit 源码

Signed-off-by: MurphyZhao <d2014zjt@163.com>
MurphyZhao 7 anni fa
parent
commit
ba1c8597f3
100 ha cambiato i file con 7529 aggiunte e 2 eliminazioni
  1. 1 0
      .gitignore
  2. 201 0
      LICENSE
  3. 143 2
      README.md
  4. 129 0
      SConscript
  5. 12 0
      docs/README.md
  6. 154 0
      docs/api.md
  7. BIN
      docs/figures/AliLinkDevelopAddDbgDevice.png
  8. BIN
      docs/figures/AliLinkDevelopAddDbgDevice1.png
  9. BIN
      docs/figures/AliLinkDevelopAddDev.png
  10. BIN
      docs/figures/AliLinkDevelopAddDevProperity.png
  11. BIN
      docs/figures/AliLinkDevelopAddPrj.png
  12. BIN
      docs/figures/AliLinkDevelopCreatePrj.png
  13. BIN
      docs/figures/AliLinkDevelopCreateProduct.png
  14. BIN
      docs/figures/AliLinkDevelopCreateProduct1.png
  15. BIN
      docs/figures/AliLinkDevelopCreateProduct2.png
  16. BIN
      docs/figures/AliLinkDevelopCreateProduct3.png
  17. BIN
      docs/figures/AliLinkDevelopCreateProduct4.png
  18. BIN
      docs/figures/AliLinkDevelopDbgConsole.png
  19. BIN
      docs/figures/AliLinkDevelopDevLog.png
  20. BIN
      docs/figures/AliLinkDevelopGetLicense.png
  21. BIN
      docs/figures/AliLinkDevelopOTAAddFirmware.png
  22. BIN
      docs/figures/AliLinkDevelopOTAPrecess.png
  23. BIN
      docs/figures/AliLinkDevelopOTAUpgradSuccess.png
  24. BIN
      docs/figures/AliLinkDevelopOTAUpgrading.png
  25. BIN
      docs/figures/AliLinkDevelopOTAVerifyFw.png
  26. BIN
      docs/figures/AliLinkDevelopOpenDbgConsole.png
  27. BIN
      docs/figures/AliLinkDevelopReg.png
  28. BIN
      docs/figures/AliLinkDevelopViewDev1.png
  29. BIN
      docs/figures/AliLinkDevelopViewMQTTMsg.png
  30. BIN
      docs/figures/AliLinkLinkPlatformCoapPrecess.png
  31. BIN
      docs/figures/AliLinkPlatformAddDevice.png
  32. BIN
      docs/figures/AliLinkPlatformAddOTAFw.png
  33. BIN
      docs/figures/AliLinkPlatformCloudPubMsg.png
  34. BIN
      docs/figures/AliLinkPlatformCreateProduct.png
  35. BIN
      docs/figures/AliLinkPlatformCustomTopic.png
  36. BIN
      docs/figures/AliLinkPlatformDeviceOnlineProcess.png
  37. BIN
      docs/figures/AliLinkPlatformEnableFwOTAserivices.png
  38. BIN
      docs/figures/AliLinkPlatformEnableFwOTAserivices1.png
  39. BIN
      docs/figures/AliLinkPlatformGetLicense.png
  40. BIN
      docs/figures/AliLinkPlatformLogConsole.png
  41. BIN
      docs/figures/AliLinkPlatformMQTTSequence.png
  42. BIN
      docs/figures/AliLinkPlatformOTASuccess.png
  43. BIN
      docs/figures/AliLinkPlatformOTAUpgrading.png
  44. BIN
      docs/figures/AliLinkPlatformOTAVerifyFw.png
  45. BIN
      docs/figures/AliLinkPlatformReg.png
  46. BIN
      docs/figures/AliLinkPlatformViewDeviceInfo.png
  47. BIN
      docs/figures/AliLinkPlatformViewDeviceInfo1.png
  48. BIN
      docs/figures/AliLinkPlatformViewDeviceLog.png
  49. BIN
      docs/figures/AliLinkPlatformViewOTAProcess.png
  50. BIN
      docs/figures/AliLinkPlatformViewTopicList.png
  51. BIN
      docs/figures/AliyunIoTKitSDKArch_AFDdedfafe3gvdas.png
  52. BIN
      docs/figures/AliyunIoTPlatformSceneArchitecture_dae1q2wqsddeewdr.png
  53. 124 0
      docs/introduction.md
  54. 16 0
      docs/principle.md
  55. 636 0
      docs/samples.md
  56. 371 0
      docs/user-guide.md
  57. 5 0
      docs/version.md
  58. 28 0
      iotkit-embedded/.gitignore
  59. 158 0
      iotkit-embedded/CMakeLists.txt
  60. 201 0
      iotkit-embedded/LICENSE
  61. 172 0
      iotkit-embedded/README.md
  62. 55 0
      iotkit-embedded/build-rules/_rules-complib.mk
  63. 41 0
      iotkit-embedded/build-rules/_rules-coverage.mk
  64. 35 0
      iotkit-embedded/build-rules/_rules-dist.mk
  65. 149 0
      iotkit-embedded/build-rules/_rules-flat.mk
  66. 35 0
      iotkit-embedded/build-rules/_rules-kmod.mk
  67. 80 0
      iotkit-embedded/build-rules/_rules-libs.mk
  68. 32 0
      iotkit-embedded/build-rules/_rules-modinfo.mk
  69. 120 0
      iotkit-embedded/build-rules/_rules-origin.mk
  70. 20 0
      iotkit-embedded/build-rules/_rules-prefix.mk
  71. 65 0
      iotkit-embedded/build-rules/_rules-prog.mk
  72. 16 0
      iotkit-embedded/build-rules/_rules-repo.mk
  73. 136 0
      iotkit-embedded/build-rules/_rules-submods.mk
  74. 194 0
      iotkit-embedded/build-rules/_rules-top.mk
  75. 41 0
      iotkit-embedded/build-rules/docs/Build-System-Config.md
  76. 16 0
      iotkit-embedded/build-rules/docs/Build-System-Debug.md
  77. 124 0
      iotkit-embedded/build-rules/docs/Build-System-Introduction.md
  78. 39 0
      iotkit-embedded/build-rules/docs/Build-System-Proj.md
  79. 130 0
      iotkit-embedded/build-rules/docs/Build-System-Units.md
  80. 23 0
      iotkit-embedded/build-rules/docs/Help.md
  81. 172 0
      iotkit-embedded/build-rules/funcs.mk
  82. 23 0
      iotkit-embedded/build-rules/hooks/pre-commit
  83. 2426 0
      iotkit-embedded/build-rules/misc/Doxyfile.tpl
  84. 2 0
      iotkit-embedded/build-rules/misc/config.generic.default
  85. 159 0
      iotkit-embedded/build-rules/misc/cut.c
  86. 247 0
      iotkit-embedded/build-rules/misc/cut.h
  87. 194 0
      iotkit-embedded/build-rules/pre-build.sh
  88. 173 0
      iotkit-embedded/build-rules/rules.mk
  89. 40 0
      iotkit-embedded/build-rules/scripts/add_license.sh
  90. 10 0
      iotkit-embedded/build-rules/scripts/del_license.sh
  91. 25 0
      iotkit-embedded/build-rules/scripts/exe_coverage_progs.sh
  92. 82 0
      iotkit-embedded/build-rules/scripts/gen_lcov_report.sh
  93. 65 0
      iotkit-embedded/build-rules/scripts/ops_repository.sh
  94. 64 0
      iotkit-embedded/build-rules/scripts/stats_static_lib.sh
  95. 83 0
      iotkit-embedded/build-rules/settings.mk
  96. 6 0
      iotkit-embedded/cmake/modules/iotx-sdk-version.cmake
  97. 21 0
      iotkit-embedded/doc/config.mdm9206.sim7000c
  98. 6 0
      iotkit-embedded/doc/export.sdk.demo/coap.mk
  99. 13 0
      iotkit-embedded/doc/export.sdk.demo/head.mk
  100. 16 0
      iotkit-embedded/doc/export.sdk.demo/head_id2.mk

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+/.vscode

+ 201 - 0
LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.

+ 143 - 2
README.md

@@ -1,2 +1,143 @@
-# ali-iotkit
- Ali Cloud SDK for IoT platform
+# Ali IoTKit
+
+## 1. 介绍
+
+**ali-iotkit** 是 RT-Thread 移植的用于连接阿里云 IoT 平台的软件包。基础 SDK 是阿里提供的 [**iotkit-embedded C-SDK**](https://github.com/aliyun/iotkit-embedded)。
+
+### 1.1 目录结构
+
+| 名称            | 说明 |
+| ----            | ---- |
+| docs            | 文档目录 |
+| iotkit-embedded | 阿里 iotkit 原文件目录 |
+| ports            | 移植文件目录 |
+| samples         | 示例文件目录 |
+
+### 1.2 许可证
+
+`ali-iotkit` 软件包延用阿里 `iotkit-embedded` 软件包许可协议,请见 `iotkit-embedded/LICENSE` 文件。
+
+### 1.3 依赖
+
+- [RT_Thread 3.0+](https://github.com/RT-Thread/rt-thread/releases/tag/v3.0.4)
+- [MbedTLS 软件包](https://github.com/RT-Thread-packages/mbedtls)
+
+## 2. 如何使用
+
+### 2.1 启用软件包
+
+- 使用 `menuconfig` 使能 iotkit 软件包并填写设备信息
+
+```shell
+RT-Thread online packages  --->
+    IoT - internet of things  --->
+        IoT Cloud  --->
+          [*] Ali-iotkit:  Ali Cloud SDK for IoT platform  --->
+                Select Aliyun platform (LinkDevelop Platform)  --->
+          (a1dSQSGZ77X) Config Product Key
+          (RGB-LED-DEV-1) Config Device Name
+          (Ghuiyd9nmGowdZzjPqFtxhm3WUHEbIlI) Config Device Secret
+          -*-   Enable MQTT
+          [*]     Enable MQTT sample
+          [*]     Enable MQTT direct connect
+          [*]     Enable SSL
+          [ ]   Enable COAP
+          [*]   Enable OTA
+                      Select OTA channel (Use MQTT OTA channel)  --->
+                    version (latest)  --->
+```
+
+- 增加 `mbedTLS` 帧大小(OTA 的时候**至少需要 8K 大小**)
+
+```shell
+RT-Thread online packages  --->
+    security packages  --->
+      -*- mbedtls:An open source, portable, easy to use, readable and flexible SSL library  --->
+      (8192) Maxium fragment length in bytes
+```
+
+- 使用 `pkgs --update` 命令下载软件包
+
+### 2.2 执行示例
+
+> 在 MSH 中使用命令执行预置的示例程序
+
+- MQTT Sample 单次发布订阅
+
+该示例程序演示了如何使用 MQTT 发布、订阅 Topic,MSH 命令如下所示:
+
+```shell
+msh />ali_mqtt_test
+ali_mqtt_test|502 :: iotkit-embedded sdk version: V2.10
+[inf] iotx_device_info_init(40): device_info created successfully!
+[dbg] iotx_device_info_set(50): start to set device info!
+[dbg] iotx_device_info_set(64): device_info set successfully!
+
+...
+
+mqtt_client|324 :: out of sample!
+```
+
+- MQTT Sample 监听订阅消息
+
+该示例程序演示了如何使用 MQTT 发布、订阅 Topic,并一直监听订阅 Topic 的消息,MSH 命令如下所示:
+
+```shell
+msh />ali_mqtt_test loop
+ali_mqtt_test|502 :: iotkit-embedded sdk version: V2.10
+[dbg] iotx_device_info_init(32): device_info already created, return!
+[dbg] iotx_device_info_set(50): start to set device info!
+[dbg] iotx_device_info_set(64): device_info set successfully!
+
+...
+
+[dbg] iotx_mc_cycle(1269): SUBACK
+event_handle|111 :: subscribe success, packet-id=0
+[dbg] iotx_mc_cycle(1269): SUBACK
+event_handle|111 :: subscribe success, packet-id=0
+```
+
+- OTA Sample
+
+该示例程序演示了如何使用阿里云 OTA 服务,使用 `ali_ota_test` 命令启动例程,这个时候,设备首先会上报当前版本号到阿里云,然后等待云端下发 OTA 升级命令。
+
+```shell
+msh />ali_ota_test
+ali_ota_main|325 :: iotkit-embedded sdk version: V2.10
+[dbg] iotx_device_info_init(32): device_info already created, return!
+[dbg] iotx_device_info_set(50): start to set device info!
+[dbg] iotx_device_info_set(64): device_info set successfully!
+
+...
+
+mqtt_client|232 :: wait ota upgrade command....
+[dbg] iotx_mc_cycle(1260): PUBACK
+event_handle|117 :: publish success, packet-id=2
+[dbg] iotx_mc_cycle(1269): SUBACK
+event_handle|093 :: subscribe success, packet-id=1
+mqtt_client|232 :: wait ota upgrade command....
+mqtt_client|232 :: wait ota upgrade command....
+mqtt_client|232 :: wait ota upgrade command....
+```
+
+## 3、 参考
+
+- 上手使用,请参考[用户指南](docs/user-guide.md)
+- 详细的示例介绍,请参考[示例文档](docs/samples.md)
+- API 介绍,请参考[API 说明文档](docs/api.md)
+- 更多详细文档,请访问 `/docs` 目录查看
+
+## 4、 注意事项
+
+- 使用前请在 `menuconfig` 里配置自己的设备信息(PRODUCT_KEY、DEVICE_NAME 和 DEVICE_SECRET)
+- 开启 OTA 功能必须使能加密连接(因为 OTA 升级必须使用 HTTPS 下载固件)
+
+## 5、 常见问题
+
+- MbedTLS 返回 0x7200 错误  
+  通常是由于 MbedTLS 帧长度过小,请增加 MbedTLS 帧长度,参考第二章节。
+
+## 6、 联系方式 & 感谢
+
+- 维护: Murphy
+- 主页: https://github.com/RT-Thread-packages/ali-iotkit

+ 129 - 0
SConscript

@@ -0,0 +1,129 @@
+import os
+from building import *
+import rtconfig
+
+cwd  = GetCurrentDir()
+
+src  = []
+CPPPATH = []
+CPPDEFINES = []
+LOCAL_CCFLAGS = ''
+
+#sample
+if GetDepend(['PKG_USING_ALI_IOTKIT_MQTT_SAMPLE']):
+    src += Glob('samples/mqtt/mqtt-example.c')
+
+if GetDepend(['PKG_USING_ALI_IOTKIT_OTA']):
+	src += Glob('samples/ota/ota_mqtt-example.c')
+
+if GetDepend(['PKG_USING_ALI_IOTKIT_COAP_SAMPLE']):
+	src += Glob('samples/coap/coap-example.c')
+
+#src/cmp, need to enable CMP_ENABLED
+#src += Glob('iotkit-embedded/src/cmp/Link-CMP/src/*.c')
+#CPPPATH += [cwd + '/iotkit-embedded/src/cmp/Link-CMP']
+#CPPPATH += [cwd + '/iotkit-embedded/src/cmp/Link-CMP/inc']
+
+#src/coap
+src += Glob('iotkit-embedded/src/coap/*.c')
+
+#packages/iot-coap-c
+src += Glob('iotkit-embedded/src/packages/iot-coap-c/*.c')
+CPPPATH += [cwd + '/iotkit-embedded/src/packages/iot-coap-c']
+
+#src/dm
+
+#src/http, need to enable HTTP_COMM_ENABLED
+#src += Glob('iotkit-embedded/src/http/*.c')
+
+#src/import
+
+#src/log
+src += Glob('iotkit-embedded/src/log/LITE-log/*.c')
+CPPPATH += [cwd + '/iotkit-embedded/src/log/LITE-log']
+
+#src/mqtt
+if GetDepend(['PKG_USING_ALI_IOTKIT_MQTT']):
+	src += Glob('iotkit-embedded/src/mqtt/Link-MQTT/*.c')
+	src += Glob('iotkit-embedded/src/mqtt/Link-MQTT/MQTTPacket/*.c')
+	CPPPATH += [cwd + '/iotkit-embedded/src/mqtt/Link-MQTT']
+	CPPPATH += [cwd + '/iotkit-embedded/src/mqtt/Link-MQTT/MQTTPacket']
+
+#src/ota
+if GetDepend(['PKG_USING_ALI_IOTKIT_OTA']):
+    src += Glob('iotkit-embedded/src/ota/Link-OTA/src/*.c')
+    CPPPATH += [cwd + '/iotkit-embedded/src/ota/Link-OTA']
+
+SrcRemove(src, 'iotkit-embedded/src/ota/Link-OTA/src/ota_lib.c')   # have been include by ota.c
+SrcRemove(src, 'iotkit-embedded/src/ota/Link-OTA/src/ota_mqtt.c')  # have been include by ota.c
+SrcRemove(src, 'iotkit-embedded/src/ota/Link-OTA/src/ota_coap.c')  # have been include by ota.c
+SrcRemove(src, 'iotkit-embedded/src/ota/Link-OTA/src/ota_fetch.c') # have been include by ota.c
+
+#src/cota
+#src += Glob('iotkit-embedded/src/cota/*.c')
+
+#src/fota
+#src += Glob('iotkit-embedded/src/fota/*.c')
+
+#src/packages
+src += Glob('iotkit-embedded/src/packages/LITE-utils/*.c')
+CPPPATH += [cwd + '/iotkit-embedded/src/packages/LITE-utils']
+
+SrcRemove(src, 'iotkit-embedded/src/packages/LITE-utils/lite-utils_prog.c')
+
+#src/platform
+#src/scripts
+
+#src/sdk-tests
+#src/shadow
+#src/subdev
+
+#src/system
+src += Glob('iotkit-embedded/src/system/iotkit-system/src/*.c')
+CPPPATH += [cwd + '/iotkit-embedded/src/system/iotkit-system']
+
+#src/tfs
+#src/tls
+
+#src/utils
+src += Glob('iotkit-embedded/src/utils/misc/*.c')
+src += Glob('iotkit-embedded/src/utils/digest/*.c')
+CPPPATH += [cwd + '/iotkit-embedded/src/utils/misc']
+CPPPATH += [cwd + '/iotkit-embedded/src/utils/digest']
+
+#ports
+src += Glob('ports/rtthread/*.c')
+
+if GetDepend(['PKG_USING_ALI_IOTKIT_MQTT_TLS']):
+	src += Glob('ports/ssl/mbedtls/*.c')
+
+#src/sdk-impl
+CPPPATH += [cwd + '/iotkit-embedded/src/sdk-impl']
+CPPPATH += [cwd + '/iotkit-embedded/src/sdk-impl/exports']
+CPPPATH += [cwd + '/iotkit-embedded/src/sdk-impl/imports']
+
+if GetDepend(['PKG_USING_ALI_IOTKIT_MQTT']):
+	CPPDEFINES += ['MQTT_COMM_ENABLED']
+	if GetDepend(['PKG_USING_ALI_IOTKIT_MQTT_DIRECT']):
+		CPPDEFINES += ['MQTT_DIRECT']
+	if not GetDepend(['PKG_USING_ALI_IOTKIT_MQTT_TLS']):
+		CPPDEFINES += ['IOTX_WITHOUT_TLS']
+
+if GetDepend(['PKG_USING_ALI_IOTKIT_COAP']):
+	CPPDEFINES += ['COAP_COMM_ENABLED']
+	if GetDepend(['PKG_USING_ALI_IOTKIT_COAP_DTLS']):
+		CPPDEFINES += ['COAP_DTLS_SUPPORT']
+
+# OTA_SIGNAL_CHANNEL: 1-mqtt; 2:coap; 4:http
+if GetDepend(['PKG_USING_ALI_IOTKIT_MQTT_OTA']):
+	CPPDEFINES += ['SERVICE_OTA_ENABLED', 'OTA_SIGNAL_CHANNEL=1']
+
+if GetDepend(['PKG_USING_ALI_IOTKIT_COAP_OTA']):
+	CPPDEFINES += ['SERVICE_OTA_ENABLED', 'OTA_SIGNAL_CHANNEL=2']
+
+CPPDEFINES += ['IOTX_NET_INIT_WITH_PK_EXT', '_PLATFORM_IS_RTTHREAD_', 'IOTX_WITHOUT_ITLS']
+
+CPPDEFINES += ['IOTX_PRJ_VERSION=\\"V2.10\\"']
+
+group = DefineGroup('ali-iotkit', src, depend = ['PKG_USING_ALI_IOTKIT'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)
+Return('group')

+ 12 - 0
docs/README.md

@@ -0,0 +1,12 @@
+# 文档
+
+## 文档列表
+
+|文件名                             |描述|
+|:-----                             |:----|
+|[version.md](version.md)           |版本信息|
+|[introduction.md](introduction.md) |详细介绍|
+|[principle.md](principle.md)       |工作原理|
+|[user-guide.md](user-guide.md)     |使用指南|
+|[api.md](api.md)                   |API 说明|
+|[samples.md](samples.md)           |示例说明|

+ 154 - 0
docs/api.md

@@ -0,0 +1,154 @@
+
+# API 说明
+
+**ali-iotkit** 是 RT-Thread 移植的用于连接阿里云 IoT 平台的软件包。基础 SDK 是阿里提供的 [**iotkit-embedded C-SDK**](https://github.com/aliyun/iotkit-embedded)。
+
+这里引用阿里 **iotkit-embedded** API 使用说明,内容如下。
+
+注:以下的 API 描述信息来自阿里云,更多详细内容请参阅 [iotkit-embedded **wiki**](https://github.com/aliyun/iotkit-embedded/wiki)。
+
+## 必选 API
+
+| 序号  | 函数名 | 说明  |
+|:----  | :---- |:----|
+|  1 | IOT_OpenLog         | 开始打印日志信息(log), 接受一个const char *为入参, 表示模块名字    |
+|  2 | IOT_CloseLog        | 停止打印日志信息(log), 入参为空                                  |
+|  3 | IOT_SetLogLevel     | 设置打印的日志等级, 接受入参从1到5, 数字越大, 打印越详细           |
+|  4 | IOT_DumpMemoryStats | 调试函数, 打印内存的使用统计情况, 入参为1-5, 数字越大, 打印越详细  |
+
+
+## MQTT 功能相关 API
+
+| 序号  | 函数名   | 说明   |
+|:----  | :---- |:----|
+|  1    | IOT_SetupConnInfo            | MQTT连接前的准备, 基于`DeviceName + DeviceSecret + ProductKey`产生MQTT连接的用户名和密码等 |
+|  2    | IOT_SetupConnInfoSecure      | MQTT连接前的准备, 基于`ID2 + DeviceSecret + ProductKey`产生MQTT连接的用户名和密码等,ID2模式启用|
+|  3    | IOT_MQTT_CheckStateNormal    | MQTT连接后, 调用此函数检查长连接是否正常                                       |
+|  4    | IOT_MQTT_Construct           | MQTT实例的构造函数, 入参为`iotx_mqtt_param_t`结构体, 连接MQTT服务器, 并返回被创建句柄 |
+|  5    | IOT_MQTT_ConstructSecure     | MQTT实例的构造函数, 入参为`iotx_mqtt_param_t`结构体, 连接MQTT服务器, 并返回被创建句柄 ,ID2模式启用|
+|  6    | IOT_MQTT_Destroy             | MQTT实例的摧毁函数, 入参为`IOT_MQTT_Construct()`创建的句柄                     |
+|  7    | IOT_MQTT_Publish             | MQTT会话阶段, 组织一个完整的`MQTT Publish`报文, 向服务端发送消息发布报文       |
+|  8    | IOT_MQTT_Subscribe           | MQTT会话阶段, 组织一个完整的`MQTT Subscribe`报文, 向服务端发送订阅请求         |
+|  9    | IOT_MQTT_Unsubscribe         | MQTT会话阶段, 组织一个完整的`MQTT UnSubscribe`报文, 向服务端发送取消订阅请求   |
+|  10   | IOT_MQTT_Yield               | MQTT会话阶段, MQTT主循环函数, 内含了心跳的维持, 服务器下行报文的收取等         |
+
+
+## CoAP 功能相关 API
+
+| 序号  | 函数名   | 说明   |
+|:----  | :---- |:----|
+|  1    | IOT_CoAP_Init                | CoAP实例的构造函数, 入参为`iotx_coap_config_t`结构体, 返回创建的CoAP会话句柄   |
+|  2    | IOT_CoAP_Deinit              | CoAP实例的摧毁函数, 入参为`IOT_CoAP_Init()`所创建的句柄                        |
+|  3    | IOT_CoAP_DeviceNameAuth      | 基于控制台申请的`DeviceName`, `DeviceSecret`, `ProductKey`做设备认证           |
+|  4    | IOT_CoAP_GetMessageCode      | CoAP会话阶段, 从服务器的`CoAP Response`报文中获取`Respond Code`                |
+|  5    | IOT_CoAP_GetMessagePayload   | CoAP会话阶段, 从服务器的`CoAP Response`报文中获取报文负载                      |
+|  6    | IOT_CoAP_SendMessage         | CoAP会话阶段, 连接已成功建立后调用, 组织一个完整的CoAP报文向服务器发送         |
+|  7    | IOT_CoAP_Yield               | CoAP会话阶段, 连接已成功建立后调用, 检查和收取服务器对`CoAP Request`的回复报文 |
+
+## HTTP 功能相关 API
+
+| 序号  | 函数名   | 说明   |
+|:----  | :---- |:----|
+|  1    | IOT_HTTP_Init                | Https实例的构造函数, 创建一个HTTP会话的句柄并返回                                      |
+|  2    | IOT_HTTP_DeInit              | Https实例的摧毁函数, 销毁所有相关的数据结构                                            |
+|  3    | IOT_HTTP_DeviceNameAuth      | 基于控制台申请的`DeviceName`, `DeviceSecret`, `ProductKey`做设备认证                   |
+|  4    | IOT_HTTP_SendMessage         | Https会话阶段, 组织一个完整的HTTP报文向服务器发送,并同步获取HTTP回复报文               |
+|  5    | IOT_HTTP_Disconnect          | Https会话阶段, 关闭HTTP层面的连接, 但是仍然保持TLS层面的连接                           |
+
+## OTA 功能相关 API
+
+| 序号  | 函数名   | 说明   |
+|:----  | :---- |:----|
+|  1    | IOT_OTA_Init                 | OTA实例的构造函数, 创建一个OTA会话的句柄并返回                                         |
+|  2    | IOT_OTA_Deinit               | OTA实例的摧毁函数, 销毁所有相关的数据结构                                              |
+|  3    | IOT_OTA_Ioctl                | OTA实例的输入输出函数, 根据不同的命令字可以设置OTA会话的属性, 或者获取OTA会话的状态    |
+|  4    | IOT_OTA_GetLastError         | OTA会话阶段, 若某个`IOT_OTA_*()`函数返回错误, 调用此接口可获得最近一次的详细错误码     |
+|  5    | IOT_OTA_ReportVersion        | OTA会话阶段, 向服务端汇报当前的固件版本号                                              |
+|  6    | IOT_OTA_FetchYield           | OTA下载阶段, 在指定的`timeout`时间内, 从固件服务器下载一段固件内容, 保存在入参buffer中 |
+|  7    | IOT_OTA_IsFetchFinish        | OTA下载阶段, 判断迭代调用`IOT_OTA_FetchYield()`是否已经下载完所有的固件内容            |
+|  8    | IOT_OTA_IsFetching           | OTA下载阶段, 判断固件下载是否仍在进行中, 尚未完成全部固件内容的下载                    |
+|  9    | IOT_OTA_ReportProgress       | 可选API, OTA下载阶段, 调用此函数向服务端汇报已经下载了全部固件内容的百分之多少         |
+|  10   | IOT_OTA_RequestImage         | 可选API,向服务端请求固件下载                                                          |
+|  11   | IOT_OTA_GetConfig            | 可选API,向服务端请求远程配置                                                          |
+
+## 云端连接 Cloud Connection 功能相关 API
+
+| 序号  | 函数名   | 说明   |
+|:----  | :---- |:----|
+|  1    | IOT_Cloud_Connection_Init    | 云端连接实例的构造函数, 入参为`iotx_cloud_connection_param_pt`结构体, 返回创建的云端连接会话句柄   |
+|  2    | IOT_Cloud_Connection_Deinit  | 云端连接实例的摧毁函数, 入参为`IOT_Cloud_Connection_Init()`所创建的句柄                        |
+|  3    | IOT_Cloud_Connection_Send_Message      | 发送数据给云端           |
+|  4    | IOT_Cloud_Connection_Yield   | 云端连接成功建立后,收取服务器发送的报文                |
+
+## CMP 功能相关 API
+
+| 序号  | 函数名   | 说明   |
+|:----  | :---- |:----|
+|  1    | IOT_CMP_Init                 | CMP实例的构造函数, 入参为`iotx_cmp_init_param_pt`结构体,只存在一个CMP实例     |
+|  2    | IOT_CMP_Register             | 通过CMP订阅服务                                                                |
+|  3    | IOT_CMP_Unregister           | 通过CMP取消服务订阅                                                            |
+|  4    | IOT_CMP_Send                 | 通过CMP发送数据,可以送给云端,也可以送给本地设备                              |
+|  5    | IOT_CMP_Send_Sync            | 通过CMP同步发送数据   ,暂不支持                                               |
+|  6    | IOT_CMP_Yield                | 通过CMP接收数据,单线程情况下才支持                                            |
+|  7    | IOT_CMP_Deinit               | CMP示例的摧毁函数                                                              |
+|  8    | IOT_CMP_OTA_Start            | 初始化ota功能,上报版本                                                        |
+|  9    | IOT_CMP_OTA_Set_Callback     | 设置OTA回调函数                                                                |
+|  10   | IOT_CMP_OTA_Get_Config       | 获取远程配置                                                                   |
+|  11   | IOT_CMP_OTA_Request_Image    | 获取固件                                                                       |
+|  12   | IOT_CMP_OTA_Yield            | 通过CMP完成OTA功能                                                             |
+
+
+## 设备影子相关(可选功能) API
+
+| 序号  | 函数名   | 说明   |
+|:----  | :---- |:----|
+|  1    | IOT_Shadow_Construct            | 建立一个设备影子的MQTT连接, 并返回被创建的会话句柄                              |
+|  2    | IOT_Shadow_Destroy              | 摧毁一个设备影子的MQTT连接, 销毁所有相关的数据结构, 释放内存, 断开连接          |
+|  3    | IOT_Shadow_Pull                 | 把服务器端被缓存的JSON数据下拉到本地, 更新本地的数据属性                        |
+|  4    | IOT_Shadow_Push                 | 把本地的数据属性上推到服务器缓存的JSON数据, 更新服务端的数据属性                |
+|  5    | IOT_Shadow_Push_Async           | 和`IOT_Shadow_Push()`接口类似, 但是异步的, 上推后便返回, 不等待服务端回应       |
+|  6    | IOT_Shadow_PushFormat_Add       | 向已创建的数据类型格式中增添成员属性                                            |
+|  7    | IOT_Shadow_PushFormat_Finalize  | 完成一个数据类型格式的构造过程                                                  |
+|  8    | IOT_Shadow_PushFormat_Init      | 开始一个数据类型格式的构造过程                                                  |
+|  9    | IOT_Shadow_RegisterAttribute    | 创建一个数据类型注册到服务端, 注册时需要`*PushFormat*()`接口创建的数据类型格式  |
+| 10    | IOT_Shadow_DeleteAttribute      | 删除一个已被成功注册的数据属性                                                  |
+| 11    | IOT_Shadow_Yield                | MQTT的主循环函数, 调用后接受服务端的下推消息, 更新本地的数据属性                |
+
+## 主子设备相关(可选功能) API
+
+| 序号  | 函数名   | 说明   |
+|:----  | :---- |:----|
+|  1    | IOT_Gateway_Construct           | 建立一个主设备,建立MQTT连接, 并返回被创建的会话句柄                            |
+|  2    | IOT_Gateway_Destroy             | 摧毁一个主设备的MQTT连接, 销毁所有相关的数据结构, 释放内存, 断开连接            |
+|  3    | IOT_Subdevice_Login             | 子设备上线,通知云端建立子设备session                                           |
+|  4    | IOT_Subdevice_Logout            | 子设备下线,销毁云端建立子设备session及所有相关的数据结构, 释放内存             |
+|  5    | IOT_Gateway_Yield               | MQTT的主循环函数, 调用后接受服务端的下推消息                                    |
+|  6    | IOT_Gateway_Subscribe           | 通过MQTT连接向服务端发送订阅请求                                                |
+|  7    | IOT_Gateway_Unsubscribe         | 通过MQTT连接向服务端发送取消订阅请求                                            |
+|  8    | IOT_Gateway_Publish             | 通过MQTT连接服务端发送消息发布报文                                              |
+|  9    | IOT_Gateway_RRPC_Register       | 注册设备的RRPC回调函数,接收云端发起的RRPC请求                                  |
+| 10    | IOT_Gateway_RRPC_Response       | 对云端的RRPC请求进行应答                                                        |
+| 11    | IOT_Gateway_Generate_Message_ID | 生成消息id                                                                      |
+| 12    | IOT_Gateway_Get_TOPO            | 向topo/get topic发送包并等待回复(TOPIC_GET_REPLY 回复)                        |
+| 13    | IOT_Gateway_Get_Config          | 向conifg/get topic发送包并等待回复(TOPIC_CONFIG_REPLY 回复)                   |
+| 14    | IOT_Gateway_Publish_Found_List  | 发现设备列表上报                                                                |
+
+## linkkit 功能相关 API
+
+| 序号  | 函数名   | 说明   |
+|:----  | :---- |:----|
+|  1    | linkkit_start                   | 启动 linkkit 服务,与云端建立连接并安装回调函数                                 |
+|  2    | linkkit_end                     | 停止 linkkit 服务,与云端断开连接并回收资源                                     |
+|  3    | linkkit_dispatch                | 事件分发函数,触发 linkkit_start 安装的回调                                      |
+|  4    | linkkit_yield                   | linkkit 主循环函数,内含了心跳的维持, 服务器下行报文的收取等;如果允许多线程,请不要调用此函数     |
+|  5    | linkkit_set_value               | 根据identifier设置物对象的 TSL 属性,如果标识符为struct类型、event output类型或者service output类型,使用点'.'分隔字段;例如"identifier1.identifier2"指向特定的项    |
+|  6    | linkkit_get_value               | 根据identifier获取物对象的 TSL 属性                                             |
+|  7    | linkkit_set_tsl                 | 从本地读取 TSL 文件,生成物的对象并添加到 linkkit 中                             |
+|  8    | linkkit_answer_service          | 对云端服务请求进行回应                                                          |
+|  9    | linkkit_invoke_raw_service      | 向云端发送裸数据                                                                |
+| 10    | linkkit_trigger_event           | 上报设备事件到云端                                                              |
+| 11    | linkkit_fota_init               | 初始化 OTA-fota 服务,并安装回调函数(需编译设置宏 SERVICE_OTA_ENABLED )              |
+| 12    | linkkit_invoke_fota_service     | 执行fota服务                                                                    |
+| 13    | linkkit_fota_init               | 初始化 OTA-cota 服务,并安装回调函数(需编译设置宏 SERVICE_OTA_ENABLED SERVICE_COTA_ENABLED )     |
+| 14    | linkkit_invoke_cota_get_config  | 设备请求远程配置                                                                    |
+| 15    | linkkit_invoke_cota_service     | 执行cota服务                                                                    |

BIN
docs/figures/AliLinkDevelopAddDbgDevice.png


BIN
docs/figures/AliLinkDevelopAddDbgDevice1.png


BIN
docs/figures/AliLinkDevelopAddDev.png


BIN
docs/figures/AliLinkDevelopAddDevProperity.png


BIN
docs/figures/AliLinkDevelopAddPrj.png


BIN
docs/figures/AliLinkDevelopCreatePrj.png


BIN
docs/figures/AliLinkDevelopCreateProduct.png


BIN
docs/figures/AliLinkDevelopCreateProduct1.png


BIN
docs/figures/AliLinkDevelopCreateProduct2.png


BIN
docs/figures/AliLinkDevelopCreateProduct3.png


BIN
docs/figures/AliLinkDevelopCreateProduct4.png


BIN
docs/figures/AliLinkDevelopDbgConsole.png


BIN
docs/figures/AliLinkDevelopDevLog.png


BIN
docs/figures/AliLinkDevelopGetLicense.png


BIN
docs/figures/AliLinkDevelopOTAAddFirmware.png


BIN
docs/figures/AliLinkDevelopOTAPrecess.png


BIN
docs/figures/AliLinkDevelopOTAUpgradSuccess.png


BIN
docs/figures/AliLinkDevelopOTAUpgrading.png


BIN
docs/figures/AliLinkDevelopOTAVerifyFw.png


BIN
docs/figures/AliLinkDevelopOpenDbgConsole.png


BIN
docs/figures/AliLinkDevelopReg.png


BIN
docs/figures/AliLinkDevelopViewDev1.png


BIN
docs/figures/AliLinkDevelopViewMQTTMsg.png


BIN
docs/figures/AliLinkLinkPlatformCoapPrecess.png


BIN
docs/figures/AliLinkPlatformAddDevice.png


BIN
docs/figures/AliLinkPlatformAddOTAFw.png


BIN
docs/figures/AliLinkPlatformCloudPubMsg.png


BIN
docs/figures/AliLinkPlatformCreateProduct.png


BIN
docs/figures/AliLinkPlatformCustomTopic.png


BIN
docs/figures/AliLinkPlatformDeviceOnlineProcess.png


BIN
docs/figures/AliLinkPlatformEnableFwOTAserivices.png


BIN
docs/figures/AliLinkPlatformEnableFwOTAserivices1.png


BIN
docs/figures/AliLinkPlatformGetLicense.png


BIN
docs/figures/AliLinkPlatformLogConsole.png


BIN
docs/figures/AliLinkPlatformMQTTSequence.png


BIN
docs/figures/AliLinkPlatformOTASuccess.png


BIN
docs/figures/AliLinkPlatformOTAUpgrading.png


BIN
docs/figures/AliLinkPlatformOTAVerifyFw.png


BIN
docs/figures/AliLinkPlatformReg.png


BIN
docs/figures/AliLinkPlatformViewDeviceInfo.png


BIN
docs/figures/AliLinkPlatformViewDeviceInfo1.png


BIN
docs/figures/AliLinkPlatformViewDeviceLog.png


BIN
docs/figures/AliLinkPlatformViewOTAProcess.png


BIN
docs/figures/AliLinkPlatformViewTopicList.png


BIN
docs/figures/AliyunIoTKitSDKArch_AFDdedfafe3gvdas.png


BIN
docs/figures/AliyunIoTPlatformSceneArchitecture_dae1q2wqsddeewdr.png


+ 124 - 0
docs/introduction.md

@@ -0,0 +1,124 @@
+# 软件包介绍
+
+**`ali-iotkit`** 是 RT-Thread 移植的用于连接阿里云 IoT 平台的软件包。基础 SDK 是阿里提供的 [iotkit-embedded C-SDK](https://github.com/aliyun/iotkit-embedded)。
+
+物联网套件提供了如下的能力:
+
+- 嵌入式设备快速接入(设备端SDK)
+- 设备管理
+- 设备和数据信息安全
+- 桥接到阿里云其他产品, 对设备数据存储/计算
+
+![阿里云物联网平台场景架构图](./figures/AliyunIoTPlatformSceneArchitecture_dae1q2wqsddeewdr.png)
+
+在物联网平台场景架构图中,左边物联网设备端 SDK 就是将嵌入式设备连接到阿里云的部分。
+
+## 软件框架图
+
+iotkit SDK 为了方便设备上云封装了丰富的连接协议,如 MQTT、CoAP、HTTP、TLS,并且对硬件平台进行了抽象,使其不收具体的硬件平台限制而更加灵活。在代码架构方面,iotkit SDK 分为三层,如下图所示:
+
+![iotkit SDK 软件框架图](./figures/AliyunIoTKitSDKArch_AFDdedfafe3gvdas.png)
+
+- 最底层称为硬件平台抽象层, 也简称HAL层(Hardware Abstract Layer)
+  
+    抽象不同的嵌入式目标板上,操作系统对SDK的支撑函数,包括网络收发、 TLS/DTLS 通道建立和读写, 内存申请是否和互斥量加锁解锁等。
+
+- 中间层称为SDK内核实现层(IoT SDK Core Implements)
+
+    物联网平台 C-SDK 的核心实现部分, 它基于 HAL 层接口完成了 MQTT/CoAP 通道等的功能封装, 包括 MQTT 的连接建立、 报文收发、CoAP 的连接建立、报文收发、 OTA 的固件状态查询和 OTA 的固件下载等。
+
+    中间层的封装,使得用户无需关心内部实现逻辑,可以不经修改地应用。
+
+- 最上层称为SDK接口声明层(IoT SDK Interface Layer)
+
+    最上层是为应用提供 API 的,用户使用该层的 API 完成具体的业务逻辑。
+
+## 软件包目录结构
+
+**ports** 目录是 RT-Thread 移植 iotkit-embedded 软件包时所涉及到的移植文件,使用 scons 进行重新构建。 
+
+**iotkit-embedded** 软件包是阿里物联网平台 C-SDK 源码,包含连接阿里云所必须的软件包。
+
+```shell
+ali-iotkit
+|   README.md                       // 软件包使用说明
+|   SConscript                      // RT-Thread 默认的构建脚本
++---docs
+|   +---figures                     // 文档使用图片
+|   |   api.md                      // API 使用说明
+|   |   introduction.md             // 软件包详细介绍
+|   |   LICENSE                     // 许可证文件
+|   |   principle.md                // 实现原理
+|   |   README.md                   // 文档结构说明
+|   |   samples.md                  // 软件包示例
+|   |   user-guide.md               // 使用说明
+|   +---version.md                  // 版本说明
++---ports                           // 移植文件
+|   +---rtthread                    // OS 相关移植文件
+|   +---ssl                         // MbedTLS 相关的移植文件
++---samples
+|   +---mqtt                        // MQTT 通道接入阿里云的示例程序
+|   +---ota                         // 阿里云 OTA 功能演示例程
++---iotkit-embedded                 // iotkit 源码
+```
+
+### iotkit-embedded 软件包目录结构
+
+iotkit-embedded 软件包是阿里物联网平台 C-SDK 源码,未经修改,包含里了连接阿里云 IoT 所必须的软件包。 RT-Thread 移植后,没有使用 iotkit-embedded 中默认的 Makefile 构建脚本,而是使用 scons 重新进行的构建。
+
+iotkit-embedded 软件包目录结构如下所示:
+
+```shell
++-- LICENSE           : 软件许可证, Apache-2.0 版本软件许可证
++-- make.settings     : 功能裁剪配置, 如 MQTT|CoAP, 或裁剪如 OTA|Shadow
++-- README.md         : 快速开始导引
++-- sample            : 例程目录, 演示通信模块和服务模块的使用
+|   +-- mqtt          :     演示如何使用通信模块 MQTT 的 API
+|   +-- coap          :     演示如何使用通信模块 CoAP 的 API
+|   +-- device-shadow :     演示如何使用服务模块 DeviceShadow 的 API
+|   +-- http          :     演示如何使用通信模块 HTTP 的 API
+|   +-- ota           :     演示如何使用服务模块 OTA 的 API
++-- src
+    +-- sdk-impl      : SDK 的接口层, 提供总体的头文件, 和一些 API 的接口封装
+    +-- sdk-tests     : SDK 的单元测试
+    +-- mqtt          : 通信模块, 实现以 MQTT 协议接入
+    +-- coap          : 通信模块, 实现以 CoAP 协议接入
+    +-- http          : 通信模块, 实现以 HTTP 协议接入
+    +-- ota           : 服务模块, 实现基于 MQTT|CoAP+HTTP+TLS 的固件下载通道
+    +-- shadow        : 服务模块, 实现设备影子
+    +-- platform      : 硬件平台抽象层, 需要移植适配
+    +-- import        : 外部输入目录, 存放芯片/模组厂商提供的头文件/二进制库
+    +-- configs       : 硬件平台编译配置, 如交叉编译工具链设置, 功能模块裁剪等
+    +-- scripts       : 编译过程将要外部引用的脚本, 用户不必关注
+    +-- packages      : SDK 引用的外部软件模块, 用户不必关注
+    +-- log           : 基础模块, 实现运行日志
+    +-- system        : 基础模块, 保存全局信息, 如 TLS 根证书, 设备标识 ID 等
+    +-- tls           : 基础模块, 实现 TLS/DTLS, 来自裁剪过的开源软件 mbedtls
+    +-- utils         : 基础模块, 实现工具函数, 如 SHA1 摘要计算、NTP 对时等
+```
+
+## 功能特点
+
+- 不同网络接入
+
+    提供不同网络的设备接入方案,例如 2/3/4G、NB-IoT、LoRa 等,解决企业异构网络设备接入管理的痛点。
+
+- 不同协议接入
+    
+    提供多种协议的设备 SDK,例如 MQTT、CoAP、HTTP 等,这样既能满足设备需要长连接保证实时性的需求,也能满足设备需要短连接降低功耗的需求。
+
+- 双向通信
+
+    提供设备与云端的上下行通道,能够稳定可靠的支撑设备上报与指令下发设备的场景。
+
+- 设备影子
+    
+    提供设备影子缓存机制,将设备与应用解耦,解决在无线网络不稳定情况下的通信不可靠痛点。
+
+- 设备认证
+    
+    提供一机一密的设备认证机制,降低设备被攻破的安全风险。
+
+- 安全传输
+    
+    提供 TLS 标准的数据传输通道,保证数据的机密性和完整性。

+ 16 - 0
docs/principle.md

@@ -0,0 +1,16 @@
+# 工作原理
+
+iotkit SDK 为了方便设备上云封装了丰富的连接协议,如 MQTT、CoAP、HTTP、TLS,并且对硬件平台进行了抽象,使其不收具体的硬件平台限制而更加灵活。
+
+通常用户并不需要关心 SDK 底层的实现机制,而只需要了解设备如何通过 SDK 与云端进行数据交互即可,方便用户理解如何使用应用层 API 接口进行业务逻辑编写。这里举例展示了 MQTT 和 OTA 应用的数据交互流程。
+
+## MQTT 数据交互流程
+
+![MQTT 数据交互流程](./figures/AliLinkPlatformMQTTSequence.png)
+
+## OTA 数据交互流程
+
+以 MQTT 通道为例,固件升级流程如下图所示:
+
+![OTA 固件升级流程](./figures/AliLinkDevelopOTAPrecess.png)
+

+ 636 - 0
docs/samples.md

@@ -0,0 +1,636 @@
+# 示例程序
+
+**ali-iotkit** 软件包同时支持阿里现有的 **[LinkDevelop](https://iot.aliyun.com/products/linkdevelop?spm=5176.8142029.loT.11.a7236d3eYH8ef9)** 和 **[LinkPlatform](https://www.aliyun.com/product/iot?spm=5176.8142029.loT.1.a7236d3eYH8ef9)** 平台。
+
+本文针对这两个平台分别进行示例程序的演示,用户可以根据自己的需求选择使用其中的一个。
+
+## LinkDevelop 平台
+
+LinkDevelop 平台以 RGB_LED 为例,介绍设备与云端如何进行双向通讯。
+
+### 准备工作
+
+- 注册 [LinkDevelop 平台](https://iot.aliyun.com/products/linkdevelop?spm=5176.8142029.loT.11.a7236d3eYH8ef9)
+
+![注册 LinkDevelop 平台](./figures/AliLinkDevelopReg.png)
+
+- 新建项目
+
+![新建项目](./figures/AliLinkDevelopAddPrj.png)
+
+- 新增产品
+
+  新增产品的时候,根据需要选择数据格式,这里使用 **Alink** 数据格式演示,并选择 WiFi 通信方式。
+
+![打开产品开发页面](./figures/AliLinkDevelopCreateProduct1.png)
+
+![创建产品](./figures/AliLinkDevelopCreateProduct2.png)
+
+![填写产品信息](./figures/AliLinkDevelopCreateProduct3.png)
+
+![进入产品开发](./figures/AliLinkDevelopCreateProduct4.png)
+
+- 增加功能
+
+  为 RGB LED 演示产品添加 RGB 调色功能,如下图所示:
+
+![增加产品功能](./figures/AliLinkDevelopAddDevProperity.png)
+
+- 添加设备
+
+  创建产品后,点击查看进入产品详情页面,点击设备开发,新增一个调试设备。
+
+![添加设备](./figures/AliLinkDevelopAddDbgDevice.png)
+
+成功创建设备后,可以获取到设备激活需要的三元组(**ProductKey、DeviceName、DeviceSecret**),后面需要使用 **menuconfig** 配置到设备 SDK 中。
+
+![获取设备激活凭证](./figures/AliLinkDevelopAddDbgDevice1.png)
+
+- **获取软件包**
+
+    打开 RT-Thread 提供的 ENV 工具,使用 **menuconfig** 配置软件包。
+  
+    - 配置 iotkit 软件包
+  
+      配置使能 iotkit 软件包并**填写设备激活凭证**。
+
+      `menuconfig` 中选择阿里云平台为 **LinkDevelop**,`OTA channel` 选择 **MQTT**(以 MQTT 为例),详细的配置如下所示:
+
+    ```shell
+    RT-Thread online packages  --->
+        IoT - internet of things  --->
+            IoT Cloud  --->
+              [*] Ali-iotkit:  Ali Cloud SDK for IoT platform  --->
+                    Select Aliyun platform (LinkDevelop Platform)  --->
+              (a1dSQSGZ77X) Config Product Key
+              (RGB-LED-DEV-1) Config Device Name
+              (Ghuiyd9nmGowdZzjPqFtxhm3WUHEbIlI) Config Device Secret
+              -*-   Enable MQTT
+              [*]     Enable MQTT sample
+              [*]     Enable MQTT direct connect
+              [*]     Enable SSL
+              [ ]   Enable COAP
+              [*]   Enable OTA
+                          Select OTA channel (Use MQTT OTA channel)  --->
+                        version (latest)  --->
+    ```
+  
+    - 增加 `mbedTLS` 帧大小
+
+      阿里 TLS 认证过程中数据包较大,这里需要增加 TLS 帧大小,OTA 的时候**至少需要 8K** 大小。
+
+      打开 RT-Thread 提供的 ENV 工具,使用 **menuconfig** 配置 **TLS** 帧大小。
+
+    ```shell
+    RT-Thread online packages  --->
+        security packages  --->
+          -*- mbedtls:An open source, portable, easy to use, 
+                      readable and flexible SSL library  --->
+          (8192) Maxium fragment length in bytes
+    ```
+
+    - 使用 `pkgs --update` 命令下载软件包
+
+### MQTT 示例
+
+该 MQTT 示例程序以 RGB-LED 为例,演示了如何在设备上使用 MQTT + TLS/SSL 通道与阿里云平台建立双向通信。
+
+**示例文件**
+
+| 示例程序路径                   | 验证平台      | 说明 |
+| ----                          | ---          | ---- |
+| samples/mqtt/mqtt-example.c   | LinkDevelop, LinkPlatform | 基于 MQTT 通道的设备和云双向通信例程 |
+
+**命令列表**
+
+例程中,使用 MSH 命令启动 MQTT 例程,命令如下所示:
+
+|命令|说明|
+|----|----|
+| ali_mqtt_test start     | 启动 MQTT 示例 |
+| ali_mqtt_test pub open  | 开灯,并向云端同步开灯状态 |
+| ali_mqtt_test pub close | 关灯,并向云端同步关灯状态 |
+| ali_mqtt_test stop      | 停止 MQTT 示例 |
+
+**启动 MQTT**
+
+使用 **`ali_mqtt_test start`** 命令启动 MQTT 示例,成功后设备 log 显示订阅成功。
+
+设备 log 如下所示:
+
+```shell
+msh />ali_mqtt_test start
+ali_mqtt_main|645 :: iotkit-embedded sdk version: V2.10
+[inf] iotx_device_info_init(40): device_info created successfully!
+[dbg] iotx_device_info_set(50): start to set device info!
+[dbg] iotx_device_info_set(64): device_info set successfully!
+···
+[inf] iotx_mc_init(1703): MQTT init success!
+[inf] _ssl_client_init(175): Loading the CA root certificate ...
+···
+[inf] _TLSConnectNetwork(420):   . Verifying peer X.509 certificate..
+[inf] _real_confirm(92): certificate verification result: 0x200
+[inf] iotx_mc_connect(2035): mqtt connect success!
+···
+[inf] iotx_mc_subscribe(1388): mqtt subscribe success,topic = /sys/a1HETlEuvri/RGB-LED-DEV-1/thing/service/property/set!
+[inf] iotx_mc_subscribe(1388): mqtt subscribe success,topic = /sys/a1HETlEuvri/RGB-LED-DEV-1/thing/event/property/post_reply!
+[dbg] iotx_mc_cycle(1269): SUBACK
+event_handle|124 :: subscribe success, packet-id=0
+[dbg] iotx_mc_cycle(1269): SUBACK
+event_handle|124 :: subscribe success, packet-id=0
+[inf] iotx_mc_keepalive_sub(2226): send MQTT ping...
+[inf] iotx_mc_cycle(1295): receive ping response!
+```
+
+**设备发布消息**
+
+使用 **`ali_mqtt_test pub open`** 命令发送 LED 状态到云端,成功后设备 log 显示**成功码 200**。
+
+设备 log 如下所示:
+
+```shell
+msh />ali_mqtt_test pub open
+···
+[dbg] iotx_mc_cycle(1277): PUBLISH
+[dbg] iotx_mc_handle_recv_PUBLISH(1091):         Packet Ident : 00000000
+[dbg] iotx_mc_handle_recv_PUBLISH(1092):         Topic Length : 57
+[dbg] iotx_mc_handle_recv_PUBLISH(1096):           Topic Name : /sys/a1HETlEuvri/RGB-LED-DEV-1/thing/service/property/set
+[dbg] iotx_mc_handle_recv_PUBLISH(1099):     Payload Len/Room : 100 / 962
+[dbg] iotx_mc_handle_recv_PUBLISH(1100):       Receive Buflen : 1024
+[dbg] iotx_mc_handle_recv_PUBLISH(1111): delivering msg ...
+[dbg] iotx_mc_deliver_message(866): topic be matched
+_demo_message_arrive|182 :: ----
+_demo_message_arrive|183 :: packetId: 0
+_demo_message_arrive|187 :: Topic: '/sys/a1HETlEuvri/RGB-LED-DEV-1/thing/service/property/set' (Length: 57)
+_demo_message_arrive|191 :: Payload: 
+'{"method": "thing.service.property.set","id": "36195462","params":{"LightSwitch":1},"version":"1.0.0"}' (Length: 100)
+_demo_message_arrive|192 :: ----
+```
+
+**云端查看发布的消息**
+
+在设备详情里的**运行状态**里可以查看设备的上报到云端的消息内容。
+
+![查看设备详情](./figures/AliLinkDevelopViewDev1.png)
+
+![查看设备运行状态](./figures/AliLinkDevelopViewMQTTMsg.png)
+
+**云端推送消息到设备**
+
+使用云端的调试控制台给设备推送消息。
+
+- 打开调试控制台
+
+![打开调试控制台](./figures/AliLinkDevelopOpenDbgConsole.png)
+
+- 发送调试命令
+
+![在线调试页面](./figures/AliLinkDevelopDbgConsole.png)
+
+**查看设备订阅日志**
+
+使用调试控制台发送命令后,设备可以接受到命令,log 如下所示:
+
+```shell
+[dbg] iotx_mc_handle_recv_PUBLISH(1091):         Packet Ident : 00000000
+[dbg] iotx_mc_handle_recv_PUBLISH(1092):         Topic Length : 52
+[dbg] iotx_mc_handle_recv_PUBLISH(1096):           Topic Name : /sys/a1Ayv8xhoIl/RGB-DEV1/thing/service/property/set
+[dbg] iotx_mc_handle_recv_PUBLISH(1099):     Payload Len/Room : 100 / 967
+[dbg] iotx_mc_handle_recv_PUBLISH(1100):       Receive Buflen : 1024
+[dbg] iotx_mc_handle_recv_PUBLISH(1111): delivering msg ...
+[dbg] iotx_mc_deliver_message(866): topic be matched
+_demo_message_arrive|178 :: ----
+_demo_message_arrive|179 :: packetId: 0
+_demo_message_arrive|183 :: Topic: '/sys/a1Ayv8xhoIl/RGB-DEV1/thing/service/property/set' (Length: 52)
+_demo_message_arrive|187 :: Payload: 
+'{"method":"thing.service.property.set","id":"35974024","params":{"LightSwitch":0},"version":"1.0.0"}' (Length: 100)
+_demo_message_arrive|188 :: ----
+```
+
+**退出 MQTT 示例**
+
+使用 **`ali_mqtt_test stop`** 命令退出 MQTT 示例,设备 log 如下所示:
+
+```
+msh />ali_mqtt_test stop
+[inf] iotx_mc_unsubscribe(1423): mqtt unsubscribe success,topic = /sys/a1HETlEuvri/RGB-LED-DEV-1/thing/event/property/post_reply!
+[inf] iotx_mc_unsubscribe(1423): mqtt unsubscribe success,topic = /sys/a1HETlEuvri/RGB-LED-DEV-1/thing/service/property/set!
+event_handle|136 :: unsubscribe success, packet-id=0
+event_handle|136 :: unsubscribe success, packet-id=0
+[dbg] iotx_mc_disconnect(2121): rc = MQTTDisconnect() = 0
+[inf] _network_ssl_disconnect(514): ssl_disconnect
+[inf] iotx_mc_disconnect(2129): mqtt disconnect!
+[inf] iotx_mc_release(2175): mqtt release!
+[err] LITE_dump_malloc_free_stats(594): WITH_MEM_STATS = 0
+mqtt_client|329 :: out of sample!
+```
+
+### OTA 示例
+
+固件升级支持对设备的固件进行远程空中升级(Over-The-Air),实现对设备的远程维护、功能升级、问题修复等场景的使用。您可以指定产品新增一个固件,对固件进行验证,验证通过后开始批量升级,并在固件详情中查看升级结果。
+
+**示例文件**
+
+| 示例程序路径                                    | 验证平台      | 说明 |
+| ----                                           | ---          | ---- |
+| samples/ota/ota_mqtt-example.c     | LinkDevelop, LinkPlatform  | 基于 MQTT 通道的设备 OTA 例程 |
+
+**命令列表**
+
+例程中,使用 MSH 命令启动 OTA 例程,命令如下所示:
+
+|命令|说明|
+|----|----|
+| ali_ota_test start | 启动 OTA 示例 |
+| ali_ota_test stop  | 手动退出 OTA 示例 |
+
+**运行 OTA 示例**
+
+使用 **`ali_ota_test start`** 命令启动 OTA 例程,然后等待云端发送 OTA 指令。
+
+设备 log 如下所示:
+
+```shell
+msh />ali_ota_test start
+ali_ota_main|372 :: iotkit-embedded sdk version: V2.10
+[inf] iotx_device_info_init(40): device_info created successfully!
+[dbg] iotx_device_info_set(50): start to set device info!
+[dbg] iotx_device_info_set(64): device_info set successfully!
+···
+[inf] iotx_mc_init(1703): MQTT init success!
+[inf] _ssl_client_init(175): Loading the CA root certificate ...
+···
+[inf] _TLSConnectNetwork(420):   . Verifying peer X.509 certificate..
+[inf] _real_confirm(92): certificate verification result: 0x200
+[inf] iotx_mc_connect(2035): mqtt connect success!
+···
+[inf] iotx_mc_subscribe(1388): mqtt subscribe success,topic = /ota/device/upgrade/a1HETlEuvri/RGB-LED-DEV-1!
+mqtt_client|241 :: wait ota upgrade command....
+[dbg] iotx_mc_cycle(1260): PUBACK
+event_handle|130 :: publish success, packet-id=2
+[dbg] iotx_mc_cycle(1269): SUBACK
+event_handle|106 :: subscribe success, packet-id=1
+mqtt_client|241 :: wait ota upgrade command....
+mqtt_client|241 :: wait ota upgrade command....
+```
+
+**新增固件**
+
+这里需要用户上传一个 bin 类型的测试固件,随意一个 bin 固件即可,演示例程只进行固件下载及校验,不会写入 Flash,所以也不会真正进行固件搬运升级。
+
+![LinkDevelop 平台新增 OTA 固件](figures/AliLinkDevelopOTAAddFirmware.png)
+
+**验证固件**
+
+![LinkDevelop 平台验证 OTA 固件](figures/AliLinkDevelopOTAVerifyFw.png)
+
+**设备日志**
+
+推送成功后,设备开始下载固件,下载完成后自动进行固件完整性校验,设备端测试日志如下所示:
+
+```shell
+···
+mqtt_client|254 :: Here write OTA data to file....
+[dbg] IOT_OTA_Ioctl(457): 
+origin=e4e54df52a3b530c7e0544b2872f1305, now=e4e54df52a3b530c7e0544b2872f1305
+mqtt_client|280 :: The firmware is valid!  Download firmware successfully.
+mqtt_client|294 :: OTA FW version: v10
+```
+
+**云端升级进度展示**
+
+设备升级过程中云端会显示设备下载固件的进度,固件下载完成并校验固件成功,设备 SDK 上报新的版本号到云端,云端会显示升级成功,如下图所示:
+
+![升级进度](./figures/AliLinkDevelopOTAUpgrading.png)
+
+![升级成功](./figures/AliLinkDevelopOTAUpgradSuccess.png)
+
+**退出 OTA 例程**
+
+升级成功或者升级失败会自动退出 OTA 例程,如果需要手动退出 OTA 例程,请使用 **`ali_ota_test stop`** 命令。
+
+```shell
+msh />ali_ota_test stop
+msh />[dbg] iotx_mc_disconnect(2121): rc = MQTTDisconnect() = 0
+[inf] _network_ssl_disconnect(514): ssl_disconnect
+[inf] iotx_mc_disconnect(2129): mqtt disconnect!
+[inf] iotx_mc_release(2175): mqtt release!
+[err] LITE_dump_malloc_free_stats(594): WITH_MEM_STATS = 0
+mqtt_client|340 :: out of sample!
+```
+
+## LinkPlatform 平台
+
+### 准备工作
+
+- 注册 [LinkPlatform 平台](https://www.aliyun.com/product/iot?spm=5176.8142029.loT.1.a7236d3eYH8ef9)
+
+![注册 LinkPlatform 平台](./figures/AliLinkPlatformReg.png)
+
+- 创建产品
+
+![创建产品](./figures/AliLinkPlatformCreateProduct.png)
+
+- 添加设备
+
+  在设备管理菜单下,新增一个测试设备,点击查看进入设备详情页面。
+
+  成功创建设备后,可以获取到设备激活需要的三元组(**ProductKey、DeviceName、DeviceSecret**),后面需要使用 **menuconfig** 配置到设备 SDK 中。
+
+![添加设备](./figures/AliLinkPlatformAddDevice.png)
+
+![设备激活凭证](./figures/AliLinkPlatformViewDeviceInfo.png)
+
+- 查看消息 Topic 列表
+
+  进入设备详情页面,然后在 **Topic 列表** 选项查看创建设备默认分配的 Topic 列表,以及 Topic 权限。
+
+![进入设备详情页](./figures/AliLinkPlatformViewDeviceInfo1.png)
+
+![查看 MQTT Topic 列表](./figures/AliLinkPlatformViewTopicList.png)
+
+- **自定义 Topic**
+
+  MQTT 示例程序中会用到名为 **data** 的 Topic,Topic 权限为**发布和订阅**,因此这里必须自定义一个 **data** Topic,如下图所示:
+
+![自定义 Topic](./figures/AliLinkPlatformCustomTopic.png)
+
+- **开通固件升级服务**
+
+![开通固件升级服务](./figures/AliLinkPlatformEnableFwOTAserivices.png)
+
+![开通固件升级服务](./figures/AliLinkPlatformEnableFwOTAserivices1.png)
+
+* **获取软件包**
+
+    打开 RT-Thread 提供的 ENV 工具,使用 **menuconfig** 配置软件包。
+  
+    + 配置 iotkit 软件包
+  
+      配置使能 iotkit 软件包并**填写设备激活凭证**。
+
+      `menuconfig` 中选择阿里云平台为 **LinkPlatform**,`OTA channel` 选择 **MQTT**(以 MQTT 为例),详细的配置如下所示:
+
+    ```shell
+    RT-Thread online packages  --->
+        IoT - internet of things  --->
+            IoT Cloud  --->
+              [*] Ali-iotkit:  Ali Cloud SDK for IoT platform  --->
+                    Select Aliyun platform (LinkPlatform Platform)  --->
+              (a1dSQSGZ77X) Config Product Key
+              (RGB-LED-DEV-1) Config Device Name
+              (Ghuiyd9nmGowdZzjPqFtxhm3WUHEbIlI) Config Device Secret
+              -*-   Enable MQTT
+              [*]     Enable MQTT sample
+              [*]     Enable MQTT direct connect
+              [*]     Enable SSL
+              [ ]   Enable COAP
+              [*]   Enable OTA
+                          Select OTA channel (Use MQTT OTA channel)  --->
+                        version (latest)  --->
+    ```
+  
+    + 增加 `mbedTLS` 帧大小
+
+      阿里 TLS 认证过程中数据包较大,这里需要增加 TLS 帧大小,OTA 的时候**至少需要 8K** 大小。
+
+      打开 RT-Thread 提供的 ENV 工具,使用 **menuconfig** 配置 **TLS** 帧大小。
+
+    ```{.c}
+    RT-Thread online packages  --->
+        security packages  --->
+          -*- mbedtls:An open source, portable, easy to use, 
+                      readable and flexible SSL library  --->
+          (8192) Maxium fragment length in bytes
+    ```
+
+    + 使用 `pkgs --update` 命令下载软件包
+
+
+### MQTT 示例
+
+该 MQTT 示例程序以**`data` Topic** 为例,演示了如何在设备上使用 MQTT + TLS/SSL 通道与阿里云平台建立双向通信。
+
+**示例文件**
+
+| 示例程序路径                   | 验证平台      | 说明 |
+| ----                          | ---          | ---- |
+| samples/mqtt/mqtt-example.c   | LinkDevelop, LinkPlatform | 基于 MQTT 通道的设备和云双向通信例程 |
+
+**命令列表**
+
+例程中,使用 MSH 命令启动 MQTT 例程,命令如下所示:
+
+|命令|说明|
+|----|----|
+| ali_mqtt_test start     | 启动 MQTT 示例 |
+| ali_mqtt_test pub open  | 开灯,并向云端同步开灯状态 |
+| ali_mqtt_test pub close | 关灯,并向云端同步关灯状态 |
+| ali_mqtt_test stop      | 停止 MQTT 示例 |
+
+**启动 MQTT**
+
+使用 **`ali_mqtt_test start`** 命令启动 MQTT 示例,成功后设备 log 显示订阅成功。
+
+设备 log 如下所示:
+
+```shell
+msh />ali_mqtt_test start
+ali_mqtt_main|645 :: iotkit-embedded sdk version: V2.10
+[inf] iotx_device_info_init(40): device_info created successfully!
+[dbg] iotx_device_info_set(50): start to set device info!
+[dbg] iotx_device_info_set(64): device_info set successfully!
+···
+[inf] iotx_mc_init(1703): MQTT init success!
+[inf] _ssl_client_init(175): Loading the CA root certificate ...
+···
+[inf] _TLSConnectNetwork(420):   . Verifying peer X.509 certificate..
+[inf] _real_confirm(92): certificate verification result: 0x200
+[inf] iotx_mc_connect(2035): mqtt connect success!
+···
+[inf] iotx_mc_subscribe(1388): mqtt subscribe success,topic = /a1P1TlTjU9Q/LP-TEST-DEV-1/data!
+[dbg] iotx_mc_cycle(1269): SUBACK
+event_handle|124 :: subscribe success, packet-id=0
+[inf] iotx_mc_keepalive_sub(2226): send MQTT ping...
+[inf] iotx_mc_cycle(1295): receive ping response!
+```
+
+**设备发布消息**
+
+使用 **`ali_mqtt_test pub open`** 命令发送消息 **`data`** Topic。
+
+设备 log 如下所示:
+
+```shell
+msh />ali_mqtt_test pub open
+ali_mqtt_test_pub|583 ::
+ publish message:
+ topic: /a1P1TlTjU9Q/LP-TEST-DEV-1/data
+ payload: {"id" : "1","version":"1.0","params" : {"RGBColor" : {"Red":247,"Green":60,"Blue":74},"LightSwitch" : 1},"method":"thing.event.property.post"}
+ rc = 3
+msh />[dbg] iotx_mc_cycle(1260): PUBACK
+event_handle|148 :: publish success, packet-id=0
+[dbg] iotx_mc_cycle(1260): PUBACK
+event_handle|148 :: publish success, packet-id=0
+[dbg] iotx_mc_cycle(1277): PUBLISH
+···
+[dbg] iotx_mc_handle_recv_PUBLISH(1100):       Receive Buflen : 1024
+[dbg] iotx_mc_handle_recv_PUBLISH(1111): delivering msg ...
+[dbg] iotx_mc_deliver_message(866): topic be matched
+_demo_message_arrive|182 :: ----
+_demo_message_arrive|183 :: packetId: 19324
+_demo_message_arrive|187 :: Topic: '/a1P1TlTjU9Q/LP-TEST-DEV-1/data' (Length: 31)
+_demo_message_arrive|191 :: Payload: 
+'{"id" : "1","version":"1.0","params" : {"RGBColor" : {"Red":247,"Green":60,"Blue":74},"LightSwitch" : 1},
+"method":"thing.event.property.post"}' (Length: 142)
+_demo_message_arrive|192 :: ----
+```
+
+**查看云端日志**
+
+在设备详情里的**运行状态**里可以查看设备的上报到云端的消息内容。
+
+![查看云端日志](./figures/AliLinkPlatformViewDeviceLog.png)
+
+**云端推送消息到设备**
+
+![云端发布消息到设备](./figures/AliLinkPlatformCloudPubMsg.png)
+
+**查看设备订阅日志**
+
+使用调试控制台发送命令后,设备可以接受到命令,log 如下所示:
+
+```shell
+msh />[dbg] iotx_mc_cycle(1277): PUBLISH
+[dbg] iotx_mc_handle_recv_PUBLISH(1091):         Packet Ident : 00000000
+[dbg] iotx_mc_handle_recv_PUBLISH(1092):         Topic Length : 31
+[dbg] iotx_mc_handle_recv_PUBLISH(1096):           Topic Name : /a1P1TlTjU9Q/LP-TEST-DEV-1/data
+[dbg] iotx_mc_handle_recv_PUBLISH(1099):     Payload Len/Room : 33 / 989
+[dbg] iotx_mc_handle_recv_PUBLISH(1100):       Receive Buflen : 1024
+[dbg] iotx_mc_handle_recv_PUBLISH(1111): delivering msg ...
+[dbg] iotx_mc_deliver_message(866): topic be matched
+_demo_message_arrive|182 :: ----
+_demo_message_arrive|183 :: packetId: 0
+_demo_message_arrive|187 :: Topic: '/a1P1TlTjU9Q/LP-TEST-DEV-1/data' (Length: 31)
+_demo_message_arrive|191 :: Payload: 'This message comes from the cloud' (Length: 33)
+_demo_message_arrive|192 :: ----
+```
+
+**退出 MQTT 示例**
+
+使用 **`ali_mqtt_test stop`** 命令退出 MQTT 示例,设备 log 如下所示:
+
+```
+msh />ali_mqtt_test stop
+msh />[inf] iotx_mc_unsubscribe(1423): mqtt unsubscribe success,topic = /a1P1TlTjU9Q/LP-TEST-DEV-1/data!
+event_handle|136 :: unsubscribe success, packet-id=0
+[dbg] iotx_mc_disconnect(2121): rc = MQTTDisconnect() = 0
+[inf] _network_ssl_disconnect(514): ssl_disconnect
+[inf] iotx_mc_disconnect(2129): mqtt disconnect!
+[inf] iotx_mc_release(2175): mqtt release!
+[err] LITE_dump_malloc_free_stats(594): WITH_MEM_STATS = 0
+mqtt_client|329 :: out of sample!
+```
+
+### OTA 示例
+
+固件升级支持对设备的固件进行远程空中升级(Over-The-Air),实现对设备的远程维护、功能升级、问题修复等场景的使用。您可以指定产品新增一个固件,对固件进行验证,验证通过后开始批量升级,并在固件详情中查看升级结果。
+
+**示例文件**
+
+| 示例程序路径                                    | 验证平台      | 说明 |
+| ----                                           | ---          | ---- |
+| samples/ota/ota_mqtt-example.c     | LinkDevelop, LinkPlatform  | 基于 MQTT 通道的设备 OTA 例程 |
+
+**命令列表**
+
+例程中,使用 MSH 命令启动 OTA 例程,命令如下所示:
+
+|命令|说明|
+|----|----|
+| ali_ota_test start | 启动 OTA 示例 |
+| ali_ota_test stop  | 手动退出 OTA 示例 |
+
+**运行 OTA 示例**
+
+使用 **`ali_ota_test start`** 命令启动 OTA 例程,然后等待云端发送 OTA 指令。
+
+设备 log 如下所示:
+
+```shell
+msh />ali_ota_test start
+ali_ota_main|372 :: iotkit-embedded sdk version: V2.10
+[inf] iotx_device_info_init(40): device_info created successfully!
+[dbg] iotx_device_info_set(50): start to set device info!
+[dbg] iotx_device_info_set(64): device_info set successfully!
+···
+[inf] iotx_mc_init(1703): MQTT init success!
+[inf] _ssl_client_init(175): Loading the CA root certificate ...
+···
+[inf] _TLSConnectNetwork(420):   . Verifying peer X.509 certificate..
+[inf] _real_confirm(92): certificate verification result: 0x200
+[inf] iotx_mc_connect(2035): mqtt connect success!
+···
+[dbg] iotx_mc_report_mid(2292): MID Report: topic name = '/sys/a1P1TlTjU9Q/LP-TEST-DEV-1/thing/status/update'
+[dbg] iotx_mc_report_mid(2309): MID Report: finished, IOT_MQTT_Publish() = 0
+[inf] iotx_mc_subscribe(1388): mqtt subscribe success,topic = /ota/device/upgrade/a1P1TlTjU9Q/LP-TEST-DEV-1!
+mqtt_client|241 :: wait ota upgrade command....
+mqtt_client|241 :: wait ota upgrade command....
+```
+
+**新增固件**
+
+这里需要用户上传一个 bin 类型的测试固件,随意一个 bin 固件即可,演示例程只进行固件下载及校验,不会写入 Flash,所以也不会真正进行固件搬运升级。
+
+![LinkPlatform 平台新增 OTA 固件](figures/AliLinkPlatformAddOTAFw.png)
+
+**验证固件**
+
+![LinkPlatform 验证 OTA 固件](figures/AliLinkDevelopOTAVerifyFw.png)
+
+**设备日志**
+
+推送成功后,设备开始下载固件,下载完成后自动进行固件完整性校验,设备端测试日志如下所示:
+
+```shell
+···
+mqtt_client|254 :: Here write OTA data to file....
+[dbg] IOT_OTA_Ioctl(457): 
+origin=e4e54df52a3b530c7e0544b2872f1305, now=e4e54df52a3b530c7e0544b2872f1305
+mqtt_client|280 :: The firmware is valid!  Download firmware successfully.
+mqtt_client|294 :: OTA FW version: v10
+```
+
+**云端升级进度展示**
+
+设备升级过程中云端会显示设备下载固件的进度,固件下载完成并校验固件成功,设备 SDK 上报新的版本号到云端,云端会显示升级成功,如下图所示:
+
+![升级进度](./figures/AliLinkPlatformViewOTAProcess.png)
+
+![升级成功](./figures/AliLinkPlatformOTASuccess.png)
+
+**退出 OTA 例程**
+
+升级成功或者升级失败会自动退出 OTA 例程,如果需要手动退出 OTA 例程,请使用 **`ali_ota_test stop`** 命令。
+
+```shell
+msh />ali_ota_test stop
+msh />[dbg] iotx_mc_disconnect(2121): rc = MQTTDisconnect() = 0
+[inf] _network_ssl_disconnect(514): ssl_disconnect
+[inf] iotx_mc_disconnect(2129): mqtt disconnect!
+[inf] iotx_mc_release(2175): mqtt release!
+[err] LITE_dump_malloc_free_stats(594): WITH_MEM_STATS = 0
+mqtt_client|340 :: out of sample!
+```
+
+## 注意事项
+
+- 使用前请在 `menuconfig` 里配置自己的设备激活凭证(PRODUCT_KEY、DEVICE_NAME 和 DEVICE_SECRET)
+- 使用 `menuconfig` 配置选择要接入的平台(**LinkDevelop** 或者 **LinkPlatform**)
+- 开启 OTA 功能必须使能加密连接,默认选择(因为 OTA 升级**必须使用 HTTPS** 下载固件)
+
+## 常见问题
+
+- MbedTLS 返回 0x7200 错误
+
+    通常是由于 MbedTLS 帧长度过小,请增加 MbedTLS 帧长度(**至少需要 8K 大小**)。

+ 371 - 0
docs/user-guide.md

@@ -0,0 +1,371 @@
+# 使用指南
+
+**ali-iotkit** 软件包封装了 HTTP、MQTT、CoAP 和 OTA 等应用层协议,方便了用户设备接入云平台,这里摘取部分做简要介绍。
+
+## MQTT 连接
+
+目前阿里云支持 MQTT 标准协议接入,兼容 3.1.1 和 3.1 版本协议,具体的协议请参考 [MQTT 3.1.1](http://mqtt.org/?spm=a2c4g.11186623.2.1.5CR1rL) 和 [MQTT 3.1](http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html?spm=a2c4g.11186623.2.2.5CR1rL) 协议文档。
+
+### 特征
+
+- 支持 MQTT 的 PUB、SUB、PING、PONG、CONNECT、DISCONNECT 和 UNSUB 等报文
+- 支持 cleanSession
+- 不支持 will、retain msg
+- 不支持 QOS2
+- 基于原生的 MQTT topic 上支持 RRPC 同步模式,服务器可以同步调用设备并获取设备回执结果
+
+### 安全等级
+
+支持 TLSV1、 TLSV1.1 和 TLSV1.2 版本的协议建立安全连接。
+
+- TCP 通道基础+芯片级加密(ID2硬件集成): 安全级别高
+- TCP 通道基础+对称加密(使用设备私钥做对称加密):安全级别中
+- TCP 方式(数据不加密): 安全级别低
+
+### 连接域名
+
+- 华东2节点:***productKey***.iot-as-mqtt.cn-shanghai.aliyuncs.com:1883
+- 美西节点:***productKey***.iot-as-mqtt.us-west-1.aliyuncs.com:1883
+- 新加坡节点:***productKey***.iot-as-mqtt.ap-southeast-1.aliyuncs.com:1883
+
+### Topic 规范
+
+默认情况下创建一个产品后,产品下的所有设备都拥有以下 Topic 类的权限:
+
+- /***productKey***/***deviceName***/update pub
+- /***productKey***/***deviceName***/update/error pub
+- /***productKey***/***deviceName***/get sub
+- /sys/***productKey***/***deviceName***/thing/# pub&sub
+- /sys/***productKey***/***deviceName***/rrpc/# pub&sub
+- /broadcast/***productKey***/# pub&sub
+
+每个 Topic 规则称为 topic 类,topic 类实行设备维度隔离。每个设备发送消息时,将 deviceName 替换为自己设备的 deviceName ,防止 topic 被跨设备越权,topic 说明如下:
+
+- pub:表示数据上报到 topic 的权限
+- sub:表示订阅 topic 的权限
+- /***productKey***/***deviceName***/xxx 类型的 topic 类:可以在物联网平台的控制台扩展和自定义
+- /sys 开头的 topic 类:属于系统约定的应用协议通信标准,不允许用户自定义的,约定的 topic 需要符合阿里云 ALink 数据标准
+- /sys/***productKey***/***deviceName***/thing/xxx 类型的 topic 类:网关主子设备使用的 topic 类,用于网关场景
+- /broadcast 开头的 topic 类:广播类特定 topic
+- /sys/***productKey***/***deviceName***/rrpc/request/${messageId}:用于同步请求,服务器会对消息 Id 动态生成 topic, 设备端可以订阅通配符
+- /sys/***productKey***/***deviceName***/rrpc/request/+:收到消息后,发送 pub 消息到 /sys/***productKey***/***deviceName***/rrpc/response/${messageId},服务器可以在发送请求时,同步收到结果
+
+### 建立 MQTT 连接
+
+使用 IOT_MQTT_Construct 接口与云端建立 MQTT 连接。
+
+如果要实现设备长期在线,需要程序代码中去掉 IOT_MQTT_Unregister 和 IOT_MQTT_Destroy 部分,使用 while 保持长连接状态。
+
+示例代码如下:
+
+```{.c}
+while(1)
+{
+    IOT_MQTT_Yield(pclient, 200); 
+    HAL_SleepMs(100);
+}
+```
+
+### 订阅 Topic 主题
+
+使用 IOT_MQTT_Subscribe 接口订阅某个 Topic。
+
+代码如下:
+
+```{.c}
+/* Subscribe the specific topic */
+rc = IOT_MQTT_Subscribe(pclient, TOPIC_DATA, IOTX_MQTT_QOS1, 
+                        _demo_message_arrive, NULL);
+if (rc < 0) {
+    IOT_MQTT_Destroy(&pclient);
+    EXAMPLE_TRACE("IOT_MQTT_Subscribe() failed, rc = %d", rc);
+    rc = -1;
+    goto do_exit;
+}
+```
+
+### 发布消息
+
+使用 IOT_MQTT_Publish 接口发布信息到云端。
+
+代码如下:
+
+```{.c}
+/* Initialize topic information */
+memset(&topic_msg, 0x0, sizeof(iotx_mqtt_topic_info_t));
+strcpy(msg_pub, "message: hello! start!");
+topic_msg.qos = IOTX_MQTT_QOS1;
+topic_msg.retain = 0;
+topic_msg.dup = 0;
+topic_msg.payload = (void *)msg_pub;
+topic_msg.payload_len = strlen(msg_pub);
+rc = IOT_MQTT_Publish(pclient, TOPIC_DATA, &topic_msg);
+EXAMPLE_TRACE("rc = IOT_MQTT_Publish() = %d", rc);
+```
+
+### 取消订阅
+
+使用 IOT_MQTT_Unsubscribe 接口取消订阅云端消息
+
+### 下行数据接收
+
+使用 IOT_MQTT_Yield 数据接收函数接收来自云端的消息。
+
+请在任何需要接收数据的地方调用这个 API。如果系统允许,请起一个单独的线程,执行该接口。
+
+代码如下:
+
+```{.c}
+/* handle the MQTT packet received from TCP or SSL connection */
+IOT_MQTT_Yield(pclient, 200);
+```
+
+### 销毁 MQTT 连接
+
+使用 IOT_MQTT_Destroy 接口销毁 MQTT 连接,释放内存。
+
+代码如下:
+
+```{.c}
+IOT_MQTT_Destroy(&pclient);
+```
+
+### 检查连接状态
+
+使用 IOT_MQTT_CheckStateNormal 接口查看当前的连接状态。
+
+该接口用于查询MQTT的连接状态。但是,该接口并不能立刻检测到设备断网,只会在有数据发送或是 keepalive 时才能侦测到 disconnect。
+
+### MQTT 保持连接
+
+设备端在 keepalive_interval_ms 时间间隔内,至少需要发送一次报文,包括 ping 请求。
+
+如果服务端在 keepalive_interval_ms 时间内无法收到任何报文,物联网平台会断开连接,设备端需要进行重连。
+
+在 IOT_MQTT_Construct 函数可以设置 keepalive_interval_ms 的取值,物联网平台通过该取值作为心跳间隔时间。keepalive_interval_ms 的取值范围是60000~300000。
+
+示例代码:
+
+```{.c}
+iotx_mqtt_param_t mqtt_params;
+
+memset(&mqtt_params, 0x0, sizeof(mqtt_params));
+mqtt_params.keepalive_interval_ms = 60000;
+mqtt_params.request_timeout_ms = 2000;
+
+/* Construct a MQTT client with specify parameter */
+pclient = IOT_MQTT_Construct(&mqtt_params);
+```
+
+## CoAP 连接
+
+- 支持 RFC 7252 Constrained Application Protocol协议,具体请参考:[RFC 7252](https://tools.ietf.org/html/rfc7252?spm=a2c4g.11186623.2.1.rjevKV)
+- 使用 DTLS v1.2 保证通道安全,具体请参考:[DTLS v1.2](https://tools.ietf.org/html/rfc6347?spm=a2c4g.11186623.2.2.rjevKV)
+- 服务器地址 endpoint = ***productKey***.iot-as-coap.cn-shanghai.aliyuncs.com:5684
+
+  其中 productKey 请替换为您申请的产品 Key
+
+### CoAP 约定
+
+- 不支持?号形式传参数
+- 暂时不支持资源发现
+- 仅支持 UDP 协议,并且目前必须通过 DTLS
+- URI 规范,CoAP 的 URI 资源和 MQTT TOPIC 保持一致,参考 [MQTT规范](https://help.aliyun.com/document_detail/30540.html?spm=a2c4g.11186623.2.4.rjevKV)
+
+### 应用场景
+
+CoAP 协议适用在资源受限的低功耗设备上,尤其是 NB-IoT 的设备使用,基于 CoAP 协议将 NB-IoT 设备接入物联网平台的流程如下图所示:
+
+![CoAP 应用场景](./figures/AliLinkLinkPlatformCoapPrecess.png)
+
+### 建立连接
+
+使用 IOT_CoAP_Init 和 IOT_CoAP_DeviceNameAuth 接口与云端建立 CoAP 认证连接。
+
+示例代码:
+
+```{.c}
+iotx_coap_context_t *p_ctx = NULL;
+p_ctx = IOT_CoAP_Init(&config);
+if (NULL != p_ctx) {
+    IOT_CoAP_DeviceNameAuth(p_ctx);
+    do {
+        count ++;
+        if (count == 11) {
+            count = 1;
+        }
+    IOT_CoAP_Yield(p_ctx);
+    } while (m_coap_client_running);
+    IOT_CoAP_Deinit(&p_ctx);
+} else {
+    HAL_Printf("IoTx CoAP init failed\r\n");
+}
+```
+
+### 收发数据
+
+SDK 使用接口 IOT_CoAP_SendMessage 发送数据,使用 IOT_CoAP_GetMessagePayload 和IOT_CoAP_GetMessageCode 接收数据。
+
+示例代码:
+
+```{.c}
+/* send data */
+static void iotx_post_data_to_server(void *param)
+{
+    char path[IOTX_URI_MAX_LEN + 1] = {0};
+    iotx_message_t message;
+    iotx_deviceinfo_t devinfo;
+    message.p_payload = (unsigned char *)"{\"name\":\"hello world\"}";
+    message.payload_len = strlen("{\"name\":\"hello world\"}");
+    message.resp_callback = iotx_response_handler;
+    message.msg_type = IOTX_MESSAGE_CON;
+    message.content_type = IOTX_CONTENT_TYPE_JSON;
+    iotx_coap_context_t *p_ctx = (iotx_coap_context_t *)param;
+    iotx_set_devinfo(&devinfo);
+    snprintf(path, IOTX_URI_MAX_LEN, "/topic/%s/%s/update/", 
+             (char *)devinfo.product_key,
+             (char *)devinfo.device_name);
+    IOT_CoAP_SendMessage(p_ctx, path, &message);
+}
+
+/* receive data */
+static void iotx_response_handler(void *arg, void *p_response)
+{
+    int len = 0;
+    unsigned char *p_payload = NULL;
+    iotx_coap_resp_code_t resp_code;
+    IOT_CoAP_GetMessageCode(p_response, &resp_code);
+    IOT_CoAP_GetMessagePayload(p_response, &p_payload, &len);
+    HAL_Printf("[APPL]: Message response code: 0x%x\r\n", resp_code);
+    HAL_Printf("[APPL]: Len: %d, Payload: %s, \r\n", len, p_payload);
+}
+```
+
+### 下行数据接收
+
+使用 IOT_CoAP_Yield 接口接收来自云端的下行数据。
+
+请在任何需要接收数据的地方调用这个API,如果系统允许,请起一个单独的线程,执行该接口。
+
+### 销毁 CoAP 连接
+
+使用 IOT_CoAP_Deinit 接口销毁 CoAP 连接并释放内存。
+
+## OTA 升级
+
+### 固件升级 Topic
+
+- 设备端上报固件版本给云端
+
+> /ota/device/inform/***productKey***/***deviceName***
+
+- 设备端订阅该topic接收云端固件升级通知
+
+> /ota/device/upgrade/***productKey***/***deviceName***
+
+- 设备端上报固件升级进度
+
+> /ota/device/progress/***productKey***/***deviceName***
+
+- 设备端请求是否固件升级
+
+> /ota/device/request/***productKey***/***deviceName***
+
+### 固件升级说明
+
+- 设备固件版本号只需要在系统启动过程中上报一次即可,不需要周期循环上报
+- 根据版本号来判断设备端OTA是否升级成功
+- 从OTA服务端控制台发起批量升级,设备升级操作记录状态是待升级
+  
+    实际升级以OTA系统接收到设备上报的升级进度开始,设备升级操作记录状态是升级中。
+
+- 设备离线时,接收不到服务端推送的升级消息
+
+    当设备上线后,主动通知服务端上线消息,OTA 服务端收到设备上线消息,验证该设备是否需要升级,如果需要,再次推送升级消息给设备, 否则,不推送消息。
+
+### OTA 代码说明
+
+**初始化**
+
+OTA 模块的初始化依赖于 MQTT 连接,即先获得的 MQTT 客户端句柄 pclient。
+
+```{.c}
+h_ota = IOT_OTA_Init(PRODUCT_KEY, DEVICE_NAME, pclient);
+if (NULL == h_ota) {
+    rc = -1;
+    printf("initialize OTA failed\n");
+}
+```
+
+**上报版本号**
+
+在 OTA 模块初始化之后,调用 IOT_OTA_ReportVersion 接口上报当前固件的版本号,升级成功后重启运行新固件,并使用该接口上报新固件版本号,云端与 OTA 升级任务的版本号对比成功后,提示 OTA 升级成功。
+
+示例代码如下:
+
+```{.c}
+if (0 != IOT_OTA_ReportVersion(h_ota, "version2.0")) {
+    rc = -1;
+    printf("report OTA version failed\n");
+}
+```
+
+**下载固件**
+
+MQTT 通道获取到 OTA 固件下载的 URL 后,使用 HTTPS 下载固件,边下载边存储到 Flash OTA 分区。
+
+- IOT_OTA_IsFetching() 接口:用于判断是否有固件可下载
+- IOT_OTA_FetchYield() 接口:用于下载一个固件块
+- IOT_OTA_IsFetchFinish() 接口:用于判断是否已下载完成
+
+示例代码:
+
+```{.c}
+// 判断是否有固件可下载
+if (IOT_OTA_IsFetching(h_ota)) {
+    unsigned char buf_ota[OTA_BUF_LEN];
+    uint32_t len, size_downloaded, size_file;
+    do {
+        // 循环下载固件
+        len = IOT_OTA_FetchYield(h_ota, buf_ota, OTA_BUF_LEN, 1); 
+        if (len > 0) {
+            // 写入到Flash等存储器中(边下载边存储)
+        }
+    } while (!IOT_OTA_IsFetchFinish(h_ota)); // 判断固件是否下载完毕
+}
+```
+
+**上报下载状态**
+
+使用 IOT_OTA_ReportProgress 接口上报固件下载进度。
+
+```{.c}
+if (percent - last_percent > 0) {
+    IOT_OTA_ReportProgress(h_ota, percent, NULL);
+}
+IOT_MQTT_Yield(pclient, 100);
+```
+
+**判断下载固件是否完整**
+
+固件下载完成后,使用 IOT_OTA_Ioctl 接口校验固件的完整性。
+
+```{.c}
+int32_t firmware_valid;
+IOT_OTA_Ioctl(h_ota, IOT_OTAG_CHECK_FIRMWARE, &firmware_valid, 4);
+if (0 == firmware_valid) {
+    printf("The firmware is invalid\n");
+} else {
+    printf("The firmware is valid\n");
+}
+```
+
+**销毁 OTA 连接**
+
+使用 IOT_OTA_Deinit 销毁 OTA 连接并释放内存。
+
+## 参考
+
+- 以上内容引自阿里云物联网平台使用文档,详细内容请访问[阿里云物联网平台文档中心](https://help.aliyun.com/document_detail/30522.html?spm=a2c4g.11186623.6.539.8UAzmn)进行查阅
+- 更多的 API 使用说明请参考 API 使用文档
+- 更多的示例代码请参考示例程序及示例使用说明

+ 5 - 0
docs/version.md

@@ -0,0 +1,5 @@
+# 版本和修订 #
+
+| Date       | Version   |  Author    | Note  |
+| --------   | :-----:   | :----      | :---- |
+| 2018-07-21 | v0.1      | MurphyZhao | 初始版本 |

+ 28 - 0
iotkit-embedded/.gitignore

@@ -0,0 +1,28 @@
+*.so
+*.exe
+.settings/
+*.cproject
+*.project
+*.o
+*.d
+*.lo
+*.gcno
+*.gcda
+/INSTALL
+cscope.*
+*.swp
+*.swo
+ltmain.sh
+*.kv
+*.bak
+/Default/
+.O/
+.config
+output/
+ota.bin
+vs_build/
+.vs/
+html/
+compile.log
+CMakeLists.txt.user
+qt_build/

+ 158 - 0
iotkit-embedded/CMakeLists.txt

@@ -0,0 +1,158 @@
+########################################################################
+# prevent in-tree builds
+########################################################################
+if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
+    message(FATAL_ERROR "not allowded in-tree build")
+endif(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
+
+########################################################################
+# project setup
+########################################################################
+cmake_minimum_required(VERSION 2.8)
+project(iotx-sdk-c)
+
+list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules")
+include(iotx-sdk-version)
+
+########################################################################
+# options
+########################################################################
+option(FEATURE_GIT_CLONE_BEFORE_BUILD     "git clone repos in packages folder when cmake configs"   OFF)
+option(FEATURE_MQTT_COMM_ENABLED          "MQTT communication enabled or not"                        ON)
+option(FEATURE_MQTT_DIRECT                "MQTT direct connection enabled or not"                    ON)
+option(FEATURE_MQTT_DIRECT_NOTLS          "MQTT direct connection w/o tls enabled or not"           OFF)
+option(FEATURE_COAP_COMM_ENABLED          "coap communication enabled or not"                        ON)
+option(FEATURE_HTTP_COMM_ENABLED          "HTTP communication enabled or not"                        ON)
+option(FEATURE_MQTT_SHADOW                "MQTT shadow enabled or not"     ${FEATURE_MQTT_COMM_ENABLED})
+option(FEATURE_COAP_DTLS_SUPPORT          "coap w/ dtls support or not"    ${FEATURE_COAP_COMM_ENABLED})
+option(FEATURE_SUBDEVICE_ENABLED          "subdev enabled or not"                                   OFF)
+option(FEATURE_CLOUD_CONN_ENABLED         "cloud connection enabled or not"                         OFF)
+option(FEATURE_CMP_ENABLED                "cmp enabled or not"                                       ON)
+option(FEATURE_DM_ENABLED                 "dm & linkkit enabled or not"                              ON)
+option(FEATURE_SERVICE_OTA_ENABLED        "ota enabled or not"                                       ON)
+option(FEATURE_SERVICE_COTA_ENABLED       "config ota enabled or not"                               OFF)
+option(FEATURE_SUPPORT_PRODUCT_SECRET     "support via product_secret get device_secret"            OFF)
+#option(FEATURE_OTA_FETCH_CHANNEL         "specify ota fetch channel"                                ON)HTTP
+#option(FEATURE_OTA_SIGNAL_CHANNEL        "specify ota signal channel"                               ON)MQTT
+set(GCC_ARCH native CACHE STRING "GCC compile for specific architecture.")
+
+########################################################################
+# Compiler specific setup
+########################################################################
+add_definitions(-DOTA_SIGNAL_CHANNEL=1)
+add_definitions(-DFORCE_SSL_VERIFY)
+add_definitions(-DUSING_UTILS_JSON)
+add_definitions(-DLITE_THING_MODEL)
+
+if(FEATURE_MQTT_DIRECT)
+    add_definitions(-DMQTT_DIRECT)
+endif(FEATURE_MQTT_DIRECT)
+
+add_definitions(-DUSING_SHA1_IN_HMAC)
+
+if(FEATURE_MQTT_COMM_ENABLED)
+    add_definitions(-DMQTT_COMM_ENABLED)
+endif(FEATURE_MQTT_COMM_ENABLED)
+
+if(FEATURE_SUBDEVICE_ENABLED)
+    add_definitions(-DSUBDEVICE_ENABLED)
+endif(FEATURE_SUBDEVICE_ENABLED)
+
+if(FEATURE_CMP_ENABLED)
+    add_definitions(-DCMP_ENABLED)
+endif(FEATURE_CMP_ENABLED)
+add_definitions(-DCMP_SUPPORT_TOPIC_DISPATCH)
+
+if(FEATURE_DM_ENABLED)
+    add_definitions(-DDM_ENABLED)
+    add_definitions(-DDEVICEINFO_ENABLED)
+endif(FEATURE_DM_ENABLED)
+
+if(FEATURE_SERVICE_OTA_ENABLED)
+    add_definitions(-DSERVICE_OTA_ENABLED)
+    if(FEATURE_SERVICE_COTA_ENABLED)
+        add_definitions(-DSERVICE_COTA_ENABLED)
+    endif(FEATURE_SERVICE_COTA_ENABLED)
+endif(FEATURE_SERVICE_OTA_ENABLED)
+
+if(FEATURE_SUPPORT_PRODUCT_SECRET)
+    add_definitions(-DSUPPORT_PRODUCT_SECRET)
+endif(FEATURE_SUPPORT_PRODUCT_SECRET)
+
+add_definitions(-DIOTX_WITHOUT_ITLS)
+add_definitions(-DIOTX_NET_INIT_WITH_PK_EXT)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${GCC_ARCH} -Wall -Wno-comment -Wno-write-strings -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format")
+########################################################################
+# add -fPIC property to all targets
+########################################################################
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+########################################################################
+# print project summary
+########################################################################
+message(STATUS "---------------------------------------------")
+message(STATUS "project name:\t" ${PROJECT_NAME})
+message(STATUS "source dir:\t" ${PROJECT_SOURCE_DIR})
+message(STATUS "binary dir:\t" ${PROJECT_BINARY_DIR})
+message(STATUS "system processor:\t" ${CMAKE_SYSTEM_PROCESSOR})
+message(STATUS "c compiler:\t" ${CMAKE_C_COMPILER})
+message(STATUS "system platform:\t" ${CMAKE_SYSTEM})
+message(STATUS "c compiler options:\t" ${CMAKE_C_FLAGS})
+
+if(WIN32)
+    message(STATUS "windows compiling...")
+    add_definitions(-D_PLATFORM_IS_WINDOWS_)
+else(WIN32)
+    message(STATUS "linux compiling...")
+    add_definitions( -D_PLATFORM_IS_LINUX_)
+endif(WIN32)
+message(STATUS "iotx sdk version:\t" ${iotx_sdk_version})
+message(STATUS "---------------------------------------------")
+
+########################################################################
+# git clone integrated repos
+########################################################################
+if(FEATURE_GIT_CLONE_BEFORE_BUILD)
+file(REMOVE_RECURSE ${PROJECT_SOURCE_DIR}/src/packages/LITE-log)
+file(REMOVE_RECURSE ${PROJECT_SOURCE_DIR}/src/packages/mbedtls-in-iotkit)
+file(REMOVE_RECURSE ${PROJECT_SOURCE_DIR}/src/packages/iotkit-system)
+file(REMOVE_RECURSE ${PROJECT_SOURCE_DIR}/src/packages/Link-MQTT)
+file(REMOVE_RECURSE ${PROJECT_SOURCE_DIR}/src/packages/Link-OTA)
+file(REMOVE_RECURSE ${PROJECT_SOURCE_DIR}/src/packages/Link-CMP)
+execute_process(COMMAND git clone ${PROJECT_SOURCE_DIR}/src/packages/LITE-log.git ${PROJECT_SOURCE_DIR}/src/packages/LITE-log)
+execute_process(COMMAND git clone ${PROJECT_SOURCE_DIR}/src/packages/mbedtls-in-iotkit.git ${PROJECT_SOURCE_DIR}/src/packages/mbedtls-in-iotkit)
+execute_process(COMMAND git clone ${PROJECT_SOURCE_DIR}/src/packages/iotkit-system.git ${PROJECT_SOURCE_DIR}/src/packages/iotkit-system)
+execute_process(COMMAND git clone ${PROJECT_SOURCE_DIR}/src/packages/Link-MQTT.git ${PROJECT_SOURCE_DIR}/src/packages/Link-MQTT)
+execute_process(COMMAND git clone ${PROJECT_SOURCE_DIR}/src/packages/Link-OTA.git ${PROJECT_SOURCE_DIR}/src/packages/Link-OTA)
+execute_process(COMMAND git clone ${PROJECT_SOURCE_DIR}/src/packages/Link-CMP.git ${PROJECT_SOURCE_DIR}/src/packages/Link-CMP)
+endif(FEATURE_GIT_CLONE_BEFORE_BUILD)
+
+include_directories(${PROJECT_SOURCE_DIR}/src/sdk-impl)
+include_directories(${PROJECT_SOURCE_DIR}/src/sdk-impl/imports)
+include_directories(${PROJECT_SOURCE_DIR}/src/sdk-impl/exports)
+include_directories(${PROJECT_SOURCE_DIR}/src/packages/mbedtls-in-iotkit/include)
+include_directories(${PROJECT_SOURCE_DIR}/src/packages/LITE-log)
+include_directories(${PROJECT_SOURCE_DIR}/src/packages/LITE-utils)
+include_directories(${PROJECT_SOURCE_DIR}/src/packages/Link-MQTT)
+include_directories(${PROJECT_SOURCE_DIR}/src/packages/Link-OTA)
+include_directories(${PROJECT_SOURCE_DIR}/src/packages/Link-CMP/inc)
+include_directories(${PROJECT_SOURCE_DIR}/src/packages/iot-coap-c)
+include_directories(${PROJECT_SOURCE_DIR}/src/packages/iotkit-system)
+include_directories(${PROJECT_SOURCE_DIR}/src/packages/iot-coap-c)
+include_directories(${PROJECT_SOURCE_DIR}/src/utils/digest)
+include_directories(${PROJECT_SOURCE_DIR}/src/utils/misc)
+include_directories(${PROJECT_SOURCE_DIR}/src/tfs)
+if(FEATURE_SUBDEVICE_ENABLED)
+include_directories(${PROJECT_SOURCE_DIR}/src/subdev)
+endif(FEATURE_SUBDEVICE_ENABLED)
+if(FEATURE_DM_ENABLED)
+include_directories(${PROJECT_SOURCE_DIR}/src/dm/include)
+endif(FEATURE_DM_ENABLED)
+include_directories(${PROJECT_SOURCE_DIR}/src/import/linux/include)
+
+########################################################################
+# Add the subdirectories
+########################################################################
+add_subdirectory(src)
+add_subdirectory(sample)

+ 201 - 0
iotkit-embedded/LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.

+ 172 - 0
iotkit-embedded/README.md

@@ -0,0 +1,172 @@
+# 阿里云物联网套件
+
+物联网套件是阿里云专门为物联网领域的开发人员推出的, 其目的是帮助开发者搭建安全且性能强大的数据通道, 方便终端(如传感器, 执行器, 嵌入式设备或智能家电等等)和云端的双向通信.
+
+-   **[官方代码首页](https://github.com/aliyun/iotkit-embedded)**
+-   **[官方维基首页](https://github.com/aliyun/iotkit-embedded/wiki)**
+
+# 快速开始
+
+本节描述如何申请自己的设备, 并结合本SDK快速体验该设备通过`MQTT`+`TLS/SSL`协议连接到阿里云, 上报和接收业务报文. 关于SDK的更多使用方式, 请访问[官方WiKi](https://github.com/aliyun/iotkit-embedded/wiki)
+
+> 实现原理:
+>
+> `MQTT协议`(`Message Queuing Telemetry Transport`, 消息队列遥测传输)是IBM开发的一个即时通讯协议, 是为大量计算能力有限, 且工作在低带宽, 不可靠的网络的远程传感器和控制设备通讯而设计的协议
+>
+> 利用MQTT协议是一种基于二进制消息的发布/订阅编程模式的消息协议, 下面的应用程序先在阿里云IoT平台订阅(`Subscribe`)一个`Topic`成功, 然后自己向该`Topic`做发布(`Publish`)动作
+> 阿里云IoT平台收到之后, 就会原样推送回这个应用程序, 因为该程序之前已经通过订阅(`Subscribe`)动作成为该`Topic`的一个接收者, 发布到这个`Topic`上的任何消息, 都会被推送到已订阅该`Topic`的所有终端上
+
+## 一. 开发环境准备
+
+#### **1. 安装Ubuntu16.04**
+
+本SDK的编译环境是`64位`的`Ubuntu16.04`, 在其它Linux上尚未测试过, 所以推荐安装与阿里开发者一致的发行版
+
+如果您使用`Windows`操作系统, 建议安装虚拟机软件`Virtualbox`, 下载地址: [https://www.virtualbox.org/wiki/Downloads](https://www.virtualbox.org/wiki/Downloads)
+
+然后安装64位的desktop版本`Ubuntu 16.04.x LTS`, 下载地址: [https://www.ubuntu.com/download/desktop](https://www.ubuntu.com/download/desktop)
+
+#### **2. 安装必备软件**
+
+本SDK的开发编译环境使用如下软件: `make-4.1`, `git-2.7.4`, `gcc-5.4.0`, `gcov-5.4.0`, `lcov-1.12`, `bash-4.3.48`, `tar-1.28`, `mingw-5.3.1`
+
+可使用如下命令行安装必要的软件:
+
+    apt-get install -y build-essential make git gcc
+
+## 二. 在控制台创建设备
+
+#### **1. 注册/登录阿里云账号**
+
+访问阿里云[登录页面](https://account.aliyun.com/login/login.htm), 点击[免费注册](https://account.aliyun.com/register/register.htm), 免费获得一个阿里云账号. 若您已有账号, 可直接登录
+
+#### **2. 访问物联网套件控制台**
+
+登入之后, 鼠标悬停在**产品**上, 弹出层叠菜单
+
+![image](https://raw.githubusercontent.com/wiki/aliyun/iotkit-embedded/pics/iotconsole-product.png)
+
+然后向下滚动页面, 点击**物联网套件**
+
+![image](https://raw.githubusercontent.com/wiki/aliyun/iotkit-embedded/pics/iotconsole-iotkit.png)
+
+或直接访问[https://www.aliyun.com/product/iot](https://www.aliyun.com/product/iot), 之后点击**立即开通**, 或者**管理控制台**, 登入[控制台主界面](https://iot.console.aliyun.com/)
+
+#### **3. 创建产品和设备**
+
+点击页面右上角的**创建产品**按钮, 创建一个品类, 然后在左侧导航栏点击**设备管理**, 再到页面右侧点**添加设备**, 创建该品类下的一个设备, 如下图则得到创建成功后的**设备标识三元组**
+
+- `productKey`: 标识产品的品类
+- `deviceName`: 标识品类下的具体设备
+- `deviceSecret`: 该设备的密钥, 需填写到SDK中, 用于连接阿里云服务器时完成认证
+
+![image](https://raw.githubusercontent.com/wiki/aliyun/iotkit-embedded/pics/iotconsole-devinfo.png)
+
+#### **4. 创建可订阅可发布的Topic**
+
+点击左侧导航栏的**消息通信**, 再到页面右侧点**定义Topic类**, 创建一个新的`/${productKey}/${deviceName}/data`, 并设置为**可订阅可发布**权限
+
+![image](https://raw.githubusercontent.com/wiki/aliyun/iotkit-embedded/pics/iotconsole-subpub.png)
+
+## 三. 编译样例程序
+
+#### **1. 下载SDK**
+
+登录Linux, 运行如下命令从github克隆代码, 或者访问最新地址[下载页面](https://github.com/aliyun/iotkit-embedded/releases/latest), **将下载到的压缩包在Linux上解压缩**
+
+    $ git clone https://github.com/aliyun/iotkit-embedded
+
+#### **2. 填入设备信息**
+
+编辑文件`sample/mqtt/mqtt-example.c`, 编辑如下代码段, 填入之前**创建产品和设备**步骤中得到的**设备标识三元组**:
+
+![image](https://raw.githubusercontent.com/wiki/aliyun/iotkit-embedded/pics/sdk-devinfo.png)
+
+#### **3. 编译SDK产生样例程序**
+
+运行如下命令:
+
+    $ make distclean
+    $ make
+
+编译成功完成后, 生成的样例程序在当前目录的`output/release/bin`目录下:
+
+    $ tree output/release
+    output/release
+    ├── bin
+    │   ├── coap-example
+    │   ├── http-example
+    │   ├── mqtt-example
+    │   ├── mqtt_rrpc-example
+    │   ├── ota_mqtt-example
+    │   ├── sdk-testsuites
+    │   ├── shadow-testsuites
+    │   └── subdev-example
+    ...
+    ...
+
+## 四. 运行样例程序
+
+#### **1. 执行样例程序**
+
+    $ ./output/release/bin/mqtt-example
+    [inf] iotx_device_info_init(40): device_info created successfully!
+    [dbg] iotx_device_info_set(50): start to set device info!
+    [dbg] iotx_device_info_set(64): device_info set successfully!
+    [dbg] _calc_hmac_signature(57): | source: clientId2UCRZpAbCGC.ExampleDevdeviceNameExampleDevproductKey2UCRZpAbCGCtimestamp2524608000000 (93)
+    [dbg] _calc_hmac_signature(58): | secret: fbh47lGBSayncmTHEjF1E5x4CZdeJTO9 (32)
+    [dbg] _calc_hmac_signature(61): | method: hmacsha1
+    [dbg] _calc_hmac_signature(74): | signature: 326a4a6ed38b1bd5ddb6a5d11d27928bfb5a62d0 (40)
+    [dbg] guider_print_dev_guider_info(236): ....................................................
+    [dbg] guider_print_dev_guider_info(237):           ProductKey : 2UCRZpAbCGC
+    [dbg] guider_print_dev_guider_info(238):           DeviceName : ExampleDev
+    [dbg] guider_print_dev_guider_info(239):             DeviceID : 2UCRZpAbCGC.ExampleDev
+    [dbg] guider_print_dev_guider_info(240):         DeviceSecret : fbh47lGBSayncmTHEjF1E5x4CZdeJTO9
+    [dbg] guider_print_dev_guider_info(241): ....................................................
+    ...
+    ...
+    _demo_message_arrive|136 :: ----
+    _demo_message_arrive|140 :: Topic: '/2UCRZpAbCGC/ExampleDev/data' (Length: 28)
+    _demo_message_arrive|144 :: Payload: '{"attr_name":"temperature", "attr_value":"1"}' (Length: 45)
+    _demo_message_arrive|145 :: ----
+    [inf] iotx_mc_unsubscribe(1416): mqtt unsubscribe success,topic = /2UCRZpAbCGC/ExampleDev/data!
+    [dbg] iotx_mc_disconnect(2106): rc = MQTTDisconnect() = 0
+    [inf] _network_ssl_disconnect(413): ssl_disconnect
+    [inf] iotx_mc_disconnect(2114): mqtt disconnect!
+    [inf] iotx_mc_release(2160): mqtt release!
+
+    ---------------------------------------------------
+    . bytes_total_allocated:    1292
+    . bytes_total_freed:        1292
+    . bytes_total_in_use:       0
+    . bytes_max_allocated:      560
+    . bytes_max_in_use:         1066
+    . iterations_allocated:     20
+    . iterations_freed:         20
+    . iterations_in_use:        0
+    . iterations_max_in_use:    11
+    ---------------------------------------------------
+    main|441 :: out of sample!
+
+#### **2. 观察消息上报**
+
+如下日志信息显示样例程序正在通过`MQTT`的`Publish`类型消息, 上报业务数据到`/${prodcutKey}/${deviceName}/data`
+
+    mqtt_client|256 :: packet-id=3, publish topic msg={"attr_name":"temperature", "attr_value":"1"}
+
+#### **3. 观察消息下推**
+
+如下日志信息显示该消息因为是到达已被订阅的`Topic`, 所以又被服务器原样推送到样例程序, 并进入相应的回调函数
+
+    _demo_message_arrive|136 :: ----
+    _demo_message_arrive|140 :: Topic: '/2UCRZpAbCGC/ExampleDev/data' (Length: 28)
+    _demo_message_arrive|144 :: Payload: '{"attr_name":"temperature", "attr_value":"1"}' (Length: 45)
+    _demo_message_arrive|145 :: ----
+
+#### **4. 观察控制台日志**
+
+可以登录物联网套件控制台, 到[设备页面](https://iot.console.aliyun.com/#/product/detail), 找到刚才填写在SDK中的设备并点击进入, 点左边导航栏的**日志服务**, 可以看到刚才被上报的消息
+
+![image](https://raw.githubusercontent.com/wiki/aliyun/iotkit-embedded/pics/iotconsole-publog.png)
+
+# 关于SDK的更多使用方式, 请访问[官方WiKi](https://github.com/aliyun/iotkit-embedded/wiki)

+ 55 - 0
iotkit-embedded/build-rules/_rules-complib.mk

@@ -0,0 +1,55 @@
+.PHONY: comp-lib
+
+ifdef COMP_LIB
+ifeq (dynamic,$(CONFIG_LIB_EXPORT))
+define Finalize_CompLib
+( \
+    $(CC) -shared -Os -o $(2)/lib$(3).so $(1) $(LDFLAGS); \
+)
+endef
+define Info_CompLib
+( \
+	EXIST_OBJS="$$(ls $(2) 2>/dev/null)"; \
+\
+    echo -ne "\033[1;32m"; \
+    printf "\r%-32s%s\n" "[AR] lib$(1).a" "<=      "; \
+    for i in $${EXIST_OBJS}; do \
+        printf "%-32s%s\n" "" "   $${i}"|$(SED) 's:$(LIBOBJ_TMPDIR)/::g'; \
+    done; \
+    echo -ne "\033[0m"; \
+)
+endef
+else
+define Finalize_CompLib
+( \
+	EXIST_OBJS="$$(ls $(1) 2>/dev/null)"; \
+\
+	if [ "$${EXIST_OBJS}" != "" ]; then \
+	    $(AR) -rcs $(2)/lib$(3).a $${EXIST_OBJS}; \
+	fi \
+)
+endef
+define Info_CompLib
+( \
+	EXIST_OBJS="$$(ls $(2) 2>/dev/null)"; \
+\
+    echo -ne "\033[1;35m"; \
+    printf "\r%-32s%s\n" "[AR] lib$(1).a" "<=      "; \
+    for i in $${EXIST_OBJS}; do \
+        printf "%-32s%s\n" "" "   $${i}"|$(SED) 's:$(LIBOBJ_TMPDIR)/::g'; \
+    done; \
+    echo -ne "\033[0m"; \
+)
+endef
+endif # dynamic
+endif # COMP_LIB
+
+comp-lib: toolchain
+ifdef COMP_LIB
+	$(TOP_Q)+( \
+	if [ -f $(STAMP_PRJ_CFG) ]; then true; else \
+	    $(call Build_CompLib,FORCE) \
+	fi)
+else
+	$(Q)true
+endif

+ 41 - 0
iotkit-embedded/build-rules/_rules-coverage.mk

@@ -0,0 +1,41 @@
+.PHONY: coverage lcov test
+
+ifneq (,$(COVERAGE_LIST))
+COVERAGE_PROGS  := \(
+COVERAGE_PROGS  += $(COVERAGE_LIST)
+COVERAGE_PROGS  += \)
+COVERAGE_CMD    := $(RULE_DIR)/scripts/exe_coverage_progs.sh
+endif
+
+ifeq (,$(COVERAGE_CMD))
+coverage lcov test:
+	@echo "COVERAGE_CMD not defined, skip"
+else
+coverage lcov test: all $(UTEST_RECP)
+#
+#	SKIP --coverage existing in $(CFLAGS) check for now
+#
+	$(Q)rm -rf $(OUTPUT_DIR)/$(LCOV_DIR) $(DIST_DIR)/$(LCOV_DIR)
+	$(Q)rm -f $(OUTPUT_DIR)/{files,tests,all,final}.info
+	$(Q)find $(OUTPUT_DIR) -name "*.gcno" -o -name "*.gcda" -exec rm -f {} \;
+	$(Q)OUTPUT_DIR=$(OUTPUT_DIR) bash <($(SED) '2iPROGS=$(COVERAGE_PROGS)' $(COVERAGE_CMD)) || true
+	$(Q)lcov --quiet \
+	    --capture --initial --directory $(OUTPUT_DIR)/ \
+	    -o $(OUTPUT_DIR)/files.info
+	$(Q)lcov --quiet \
+	    --capture --directory $(OUTPUT_DIR) \
+	    -o $(OUTPUT_DIR)/tests.info
+	$(Q)lcov --quiet \
+	    --add-tracefile $(OUTPUT_DIR)/files.info \
+	    --add-tracefile $(OUTPUT_DIR)/tests.info \
+	    -o $(OUTPUT_DIR)/all.info
+	$(Q)lcov --quiet \
+	    --remove $(OUTPUT_DIR)/all.info \
+	    -o $(OUTPUT_DIR)/final.info '*.h'
+	$(Q)genhtml --quiet \
+	    --legend --no-branch-coverage -o $(OUTPUT_DIR)/$(LCOV_DIR) $(OUTPUT_DIR)/final.info
+	$(Q)cp -rf $(OUTPUT_DIR)/$(LCOV_DIR) $(DIST_DIR)/$(LCOV_DIR)
+	$(Q)cd $(DIST_DIR)/$(LCOV_DIR) && \
+	    $(SED) -i 's:\(coverFile.*\)>$(OUTPUT_DIR)/:\1>:g' index.html
+	$(Q)bash $(RULE_DIR)/scripts/gen_lcov_report.sh $(DIST_DIR)/$(LCOV_DIR)
+endif

+ 35 - 0
iotkit-embedded/build-rules/_rules-dist.mk

@@ -0,0 +1,35 @@
+
+final-out: sub-mods
+ifneq (,$(COMP_LIB_NAME))
+	$(TOP_Q) \
+	if  [ ! -f $(SYSROOT_LIB)/lib$(COMP_LIB_NAME).a ] && \
+	    [ ! -f $(SYSROOT_LIB)/lib$(COMP_LIB_NAME).so ]; then \
+	    $(call Build_CompLib, FORCE) \
+	fi;
+endif
+
+	$(TOP_Q) \
+	if [ -f $(STAMP_PRJ_CFG) ]; then true; else \
+	    rm -rf $(DIST_DIR); \
+	    mkdir -p $(DIST_DIR) $(FINAL_DIR); \
+	    for i in bin lib include; do \
+	        if [ -d $(OUTPUT_DIR)/usr/$${i} ]; then \
+	            cp -rf $(OUTPUT_DIR)/usr/$${i} $(FINAL_DIR); \
+	        fi; \
+	    done; \
+	    VDR_NAME=$$(grep -m 1 "VENDOR *:" $(CONFIG_TPL) 2>/dev/null|awk '{ print $$NF }'); \
+	    if [ "$$(ls $(IMPORT_DIR)/$${VDR_NAME}/$(PREBUILT_LIBDIR)/lib* 2>/dev/null)" != "" ]; then \
+	        cp -f $(IMPORT_DIR)/$${VDR_NAME}/$(PREBUILT_LIBDIR)/lib* $(FINAL_DIR)/lib; \
+	    fi; \
+	fi
+
+	$(TOP_Q) \
+	if [ "$$(ls $(FINAL_DIR)/bin/)" != "" ]; then \
+	    $(STRIP) $(FINAL_DIR)/bin/* 2>/dev/null || (echo "$(STRIP) $(FINAL_DIR)/bin/* failed!" && exit 1); \
+	fi
+	$(TOP_Q) \
+	if [ "$$(ls $(FINAL_DIR)/lib/*.so 2>/dev/null)" != "" ]; then \
+	    $(STRIP) $(STRIP_DBGOPT) $(FINAL_DIR)/lib/*.so 2>/dev/null || (echo "$(STRIP) $(FINAL_DIR)/lib/*.so failed!" && exit 1); \
+	fi
+
+	$(TOP_Q)+$(call $(POST_FINAL_OUT_HOOK))

+ 149 - 0
iotkit-embedded/build-rules/_rules-flat.mk

@@ -0,0 +1,149 @@
+ifneq ($(TOP_DIR),$(CURDIR))
+INTERNAL_INCLUDES += -I$(SYSROOT_INC)
+INTERNAL_INCLUDES += $(foreach d, $(shell find $(SYSROOT_INC) -type d), -I$(d))
+INTERNAL_INCLUDES += -I$(TOP_DIR)
+INTERNAL_INCLUDES += -I$(IMPORT_DIR)
+INTERNAL_INCLUDES += -I$(IMPORT_DIR)/include
+INTERNAL_INCLUDES += \
+$(foreach d, \
+    $(shell [ -d $(IMPORT_DIR)/$(CONFIG_VENDOR) ] && find -L $(IMPORT_DIR)/$(CONFIG_VENDOR)/include -type d), \
+    -I$(d) \
+)
+INTERNAL_INCLUDES += $(foreach mod, $(MODULE_NAME) $(HDR_REFS), \
+    $(foreach d, \
+        $(shell [ -d $(TOP_DIR)/$(mod) ] && \
+            find -L $(TOP_DIR)/$(mod)/ -type d \
+                -a -name "[^.]*" \
+                -not -path "*.git*"), \
+        -I$(d) \
+    ) \
+)
+
+# INTERNAL_INCLUDES += \
+    $(foreach d, \
+        $(shell find $(OUTPUT_DIR)/$(MODULE_NAME) -type d -a -name "[^.]*"), \
+        -I$(d) \
+    )
+
+INTERNAL_INCLUDES := $(strip $(sort $(INTERNAL_INCLUDES)))
+
+EXTERNAL_INCLUDES += $(foreach mod, $(DEPENDS), \
+    $(foreach d, \
+        $(shell $(SHELL_DBG) find \
+            $(SYSROOT_INC)/$(mod)/ -maxdepth 2 -type d 2>/dev/null) \
+        $(shell $(SHELL_DBG) find \
+            $(IMPORT_VDRDIR)/include/$(mod)/ -maxdepth 2 -type d 2>/dev/null), \
+        -I$(d) \
+    ) \
+)
+EXTERNAL_INCLUDES := $(strip $(EXTERNAL_INCLUDES))
+endif   # ifneq ($(TOP_DIR),$(CURDIR))
+
+ifeq (dynamic,$(strip $(CONFIG_LIB_EXPORT)))
+CFLAGS  += -fPIC
+endif
+
+CFLAGS  := $(sort $(strip $(CFLAGS)))
+
+LDFLAGS += -L$(SYSROOT_LIB)
+ifeq (y,$(shell [ -d $(IMPORT_VDRDIR)/$(PREBUILT_LIBDIR) ] && echo y))
+LDFLAGS += -L$(IMPORT_VDRDIR)/$(PREBUILT_LIBDIR)
+endif
+
+LDFLAGS += $(foreach d,$(DEPENDS_$(MODULE_NAME)),$(REF_LDFLAGS_$(d)))
+
+WATCHED_VARS = \
+    TARGET \
+    CFLAGS \
+    CC \
+    LDFLAGS \
+    CURDIR \
+    INTERNAL_INCLUDES \
+    DEPENDS \
+    MAKECMDGOALS \
+    EXTERNAL_INCLUDES \
+    LIBA_TARGET \
+    LIBSO_TARGET \
+
+ALL_TARGETS := $(TARGET) $(LIBSO_TARGET) $(LIBA_TARGET) $(firstword $(KMOD_TARGET))
+
+ifneq (,$(strip $(PKG_SWITCH)))
+all: $(ALL_TARGETS)
+else
+all:
+	$(Q)true
+endif
+
+clean:
+	$(Q)rm -f \
+        $(strip \
+            $(ALL_TARGETS) $(OBJS) $(LIB_OBJS) \
+            $(OBJS:.o=.d) $(LIB_OBJS:.o=.d) \
+            $(LIB_OBJS:.o=.gcno) $(LIB_OBJS:.o=.gcda) \
+        ) \
+        *.o.e *.d *.o *.a *.so *.log *.gc*
+
+%.o: %.c $(HD_MAKEFILE)
+	@$(call Brief_Log,"CC")
+	$(call Inspect_Env,$(WATCHED_VARS))
+	$(Q) \
+	set -o pipefail; \
+	$(CC) -I$(CURDIR) \
+	    $(INTERNAL_INCLUDES) \
+	    $(EXTERNAL_INCLUDES) \
+	    $(CFLAGS) \
+	    -c -o $@ $<
+ifneq (,$(OBJCOPY_FLAGS))
+	$(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) $@
+endif
+
+NODEP_LIST = \
+    $(SYSROOT_INC)/git_version.h \
+    $(SYSROOT_INC)/platform.h \
+    $(SYSROOT_INC)/product.h \
+    $(SYSROOT_INC)/product_config.h \
+
+ifneq (,$(findstring gcc,$(CC)))
+ifeq (,$(filter modinfo,$(MAKECMDGOALS)))
+%.d: %.c
+	$(Q) \
+( \
+	D=$$(dirname $<|$(SED) 's:$(TOP_DIR):$(OUTPUT_DIR):1'); \
+	F=$$(basename $<); \
+	mkdir -p $${D}; \
+	$(CC) -MM -I$(CURDIR) \
+	    $(INTERNAL_INCLUDES) \
+	    $(EXTERNAL_INCLUDES) \
+	    $(CFLAGS) \
+	$< > $${D}/$${F}.$$$$; \
+	$(SED) -i 's!$(shell basename $*)\.o[ :]!$*.o:!1' $${D}/$${F}.$$$$; \
+	mv $${D}/$${F}.$$$$ $@; \
+)
+endif
+endif
+
+%.o: %.cpp
+	@$(call Brief_Log,"CC")
+	$(call Inspect_Env,$(WATCHED_VARS))
+	$(Q)$(CXX) -I$(CURDIR) \
+	    $(INTERNAL_INCLUDES) \
+	    $(EXTERNAL_INCLUDES) \
+	    $(CFLAGS) \
+	    -c -o $@ $<
+
+ifneq (,$(findstring gcc,$(CC)))
+%.d: %.cpp
+	$(Q) \
+	$(CXX) -MM -I$(CURDIR) \
+	    $(INTERNAL_INCLUDES) \
+	    $(EXTERNAL_INCLUDES) \
+	    $(CFLAGS) \
+	$< > $@.$$$$; \
+	$(foreach D,$(NODEP_LIST),$(SED) -i 's:$(D)::g' $@.$$$$;) \
+	$(SED) 's,\($*\)\.o[ :]*,\1.o $@: ,g' < $@.$$$$ > $@; \
+	rm -f $@.$$$$;
+endif
+
+include $(RULE_DIR)/_rules-libs.mk
+include $(RULE_DIR)/_rules-prog.mk
+include $(RULE_DIR)/_rules-kmod.mk

+ 35 - 0
iotkit-embedded/build-rules/_rules-kmod.mk

@@ -0,0 +1,35 @@
+ifdef KMOD_TARGET
+KMOD_NAME := $(subst .o,,$(obj-m))
+KMOD_OBJS := $(foreach mod, $(KMOD_NAME), $($(mod)-objs))
+KMOD_SRCS := $(subst .o,.c,$(KMOD_OBJS))
+KMOD_BUILD_DIR := $(CURDIR)/build-$(shell $(SHELL_DBG) basename $(CURDIR))-kmod
+KMOD_MAKEFILE := $(KMOD_BUILD_DIR)/Makefile
+
+$(firstword $(KMOD_TARGET)): $(KMOD_SRCS)
+	$(Q)rm -rf $(KMOD_BUILD_DIR) && mkdir -p $(KMOD_BUILD_DIR)
+	$(Q)cp -f $(KMOD_SRCS) $(KMOD_BUILD_DIR)
+	$(Q)echo "EXTRA_CFLAGS += " \
+	         "-I$(CURDIR)" \
+	         "$(INTERNAL_INCLUDES)" \
+	         | $(SED) 's/-I/\\\n    -I/g' \
+	         >> $(KMOD_MAKEFILE)
+	$(Q)echo "" >> $(KMOD_MAKEFILE)
+	$(Q)echo "obj-m := $(obj-m)" >> $(KMOD_MAKEFILE)
+	$(Q)echo "" >> $(KMOD_MAKEFILE)
+	$(Q) \
+	$(foreach mod, $(KMOD_NAME), \
+	    echo "$(mod)-objs := $($(mod)-objs)" \
+	    | $(SED) 's/ [_a-z]*\.o/ \\\n   &/g' \
+	    >> $(KMOD_MAKEFILE); \
+	    echo "" >> $(KMOD_MAKEFILE); \
+	)
+	@$(call Brief_Log,"CC",$(KMOD_TARGET))
+	$(Q) \
+	LDFLAGS=""; \
+	    $(MAKE) -C $(KERNEL_DIR) M=$(KMOD_BUILD_DIR) CROSS_COMPILE=$(CROSS_PREFIX) modules
+	$(Q)cp -f $(KMOD_BUILD_DIR)/*.ko $(CURDIR)
+	$(Q)mkdir -p $(SYSROOT_LIB)
+	$(Q)install -m 0755 $(KMOD_BUILD_DIR)/*.ko $(SYSROOT_LIB)
+
+endif   # ifdef KMOD_TARGET
+

+ 80 - 0
iotkit-embedded/build-rules/_rules-libs.mk

@@ -0,0 +1,80 @@
+VPATH    := $(TOP_DIR)/$(MODULE_NAME)
+LIB_SRCS ?= $(foreach M,*.c */*.c */*/*.c,$(wildcard $(TOP_DIR)/$(MODULE_NAME)/$(M))) $(wildcard *.c)
+LIB_OBJS := $(LIB_SRCS:.c=.o)
+LIB_OBJS := $(subst $(TOP_DIR)/$(MODULE_NAME)/,,$(LIB_OBJS))
+
+ifdef LIB_SRCS_PATTERN
+SRC_LIST := $(foreach M,$(LIB_SRCS_PATTERN),$(shell ls $(TOP_DIR)/$(MODULE_NAME)/$(M) 2>/dev/null))
+LIB_SRCS := $(SRC_LIST)
+LIB_OBJS := $(SRC_LIST:.c=.o)
+LIB_OBJS := $(subst $(TOP_DIR)/$(MODULE_NAME)/,,$(LIB_OBJS))
+endif
+
+sinclude $(LIB_OBJS:.o=.d)
+
+ifdef LIBA_TARGET
+.PHONY: StaticLib_Install
+
+ifeq (1,$(words $(LIBA_TARGET)))
+
+$(LIBA_TARGET) :: $(LIB_OBJS)
+	@$(call Brief_Log,"AR")
+	$(call Inspect_Env,$(WATCHED_VARS))
+	$(Q)rm -f $@
+ifdef CONFIG_LIBOBJ_STRIP
+	@$(call Brief_Log,"ST")
+	$(TOP_Q)$(STRIP) $(STRIP_DBGOPT) $(LIB_OBJS)
+endif
+	$(TOP_Q) \
+	if [ "$$(echo "$(LIB_OBJS)"|awk '{ print NF }')" != "0" ]; then \
+	    $(AR) -rcs $@ $(LIB_OBJS); \
+	fi
+
+$(LIBA_TARGET) :: StaticLib_Install
+	$(Q)mkdir -p $(LIBOBJ_TMPDIR)/$(MODULE_NAME)
+ifneq (,$(strip $(LIB_OBJS)))
+ifneq ($(LIBA_TARGET),$(LIBA_SKIP_COMBO))
+	$(Q)cp -f $(LIB_OBJS) $(LIBOBJ_TMPDIR)/$(MODULE_NAME)
+endif
+endif
+	$(Q)mkdir -p $(SYSROOT_LIB)
+	$(Q)if [ -f $@ ]; then cp -f $@ $(SYSROOT_LIB); fi
+	$(call Copy_Headers, $(LIB_HEADERS),$(SYSROOT_INC),$(LIB_HDRS_DIR))
+
+else
+
+$(foreach t,$(sort $(LIBA_TARGET)),$(t)): FORCE
+	$(Q) \
+	$(MAKE) LIBA_TARGET=$@ \
+	    LIB_SRCS="$(LIB_SRCS_$(subst .a,,$(subst lib,,$@)))" \
+	    LIB_SRCS_PATTERN="$(LIB_SRCS_PATTERN_$(subst .a,,$(subst lib,,$@)))" \
+
+
+endif   # ifeq (1,$(words $(LIBA_TARGET)))
+
+endif   # ifdef LIBA_TARGET
+
+ifdef LIBSO_TARGET
+.PHONY: DynamicLib_Install
+
+$(LIBSO_TARGET) :: SELF_LIBNAME = $(subst lib,,$(subst .so,,$(LIBSO_TARGET)))
+$(LIBSO_TARGET) :: LDFLAGS := $(filter-out -l$(SELF_LIBNAME), $(LDFLAGS))
+$(LIBSO_TARGET) :: $(LIB_OBJS) $(foreach d,$(DEPENDS_$(MODULE_NAME)),$(SYSROOT_LIB)/$(LIBA_TARGET_$(d)))
+	@$(call Brief_Log,"CC")
+	$(call Inspect_Env,$(WATCHED_VARS))
+	$(Q)$(CC) -shared -Os \
+	    $(CFLAGS) \
+	    $(RPATH_CFLAGS) \
+	    -o $@ \
+	    $(LIB_OBJS) \
+	    -Wl,--start-group $(LDFLAGS) -Wl,--end-group
+
+$(LIBSO_TARGET) :: DynamicLib_Install
+	$(Q)mkdir -p $(LIBOBJ_TMPDIR)/$(shell $(SHELL_DBG) basename $(CURDIR))
+	$(Q)cp -f $(LIB_OBJS) $(LIBOBJ_TMPDIR)/$(shell $(SHELL_DBG) basename $(CURDIR))
+	$(Q)mkdir -p $(SYSROOT_LIB)
+	$(Q)install -m 0755 $@ $(SYSROOT_LIB)
+	$(call Copy_Headers, $(LIB_HEADERS),$(SYSROOT_INC),$(LIB_HDRS_DIR))
+
+endif   # ifdef LIBSO_TARGET
+

+ 32 - 0
iotkit-embedded/build-rules/_rules-modinfo.mk

@@ -0,0 +1,32 @@
+.PHONY: modinfo
+
+modinfo:
+	@true
+
+MODINFO_VARS := \
+    EXTRA_SRCS \
+    PKG_SWITCH \
+    ORIGIN \
+    PKG_SOURCE \
+    PKG_BRANCH \
+    PKG_REVISION \
+    PKG_UPSTREAM \
+    REF_CFLAGS \
+    REF_LDFLAGS \
+    LDFLAGS \
+    LIBA_TARGET \
+    TARGET \
+    LIBSO_TARGET \
+
+$(if $(filter modinfo,$(MAKECMDGOALS)), \
+    $(if $(strip $(DEPENDS)), \
+        $(info DEPENDS_$(MODULE_NAME) = $(strip $(DEPENDS))) \
+    ) \
+)
+$(if $(filter modinfo,$(MAKECMDGOALS)), \
+    $(foreach v, $(MODINFO_VARS), \
+        $(if $(strip $($(v))), \
+            $(info $(v)_$(MODULE_NAME) = $(strip $($(v)))) \
+        ) \
+    ) \
+)

+ 120 - 0
iotkit-embedded/build-rules/_rules-origin.mk

@@ -0,0 +1,120 @@
+CFLAGS := $(filter-out -Werror,$(CFLAGS))
+LDFLAGS :=
+
+.PHONY: config build install post-install
+
+ORIGIN_Q ?= @
+ifeq ($(strip $(PKG_SWITCH)),y)
+all :
+ifeq ($(PKG_SOURCE),)
+$(error PKG_SOURCE for $(PKG_NAME) cannot be found!)
+endif
+
+	$(ORIGIN_Q) \
+	MESSAGE=$(strip $(if $(filter 0 1,$(MAKELEVEL)), \
+	    "\r$(PKG_NAME) already pre-built at $(IMPORT_VDRDIR)/$(PREBUILT_LIBDIR)\n","")); \
+	if  [ "$(LIBA_TARGET)"  != "" -a -f $(IMPORT_VDRDIR)/$(PREBUILT_LIBDIR)/$(LIBA_TARGET) ] || \
+	    [ "$(LIBSO_TARGET)" != "" -a -f $(IMPORT_VDRDIR)/$(PREBUILT_LIBDIR)/$(LIBSO_TARGET) ]; then \
+	    echo -ne $${MESSAGE}; \
+	    cp -P -f $(IMPORT_VDRDIR)/$(PREBUILT_LIBDIR)/{$(LIBA_TARGET),$(LIBSO_TARGET)*} \
+	        $(SYSROOT_LIB) 2>/dev/null; \
+	    for t in $(TARGET); do \
+	        cp -f $(IMPORT_VDRDIR)/$(PREBUILT_BINDIR)/$${t} $(SYSROOT_BIN); \
+	    done; \
+	    touch $(STAMP_SHIELD); \
+	fi
+
+	$(ORIGIN_Q) \
+	MESSAGE=$(if $(filter 0 1,$(MAKELEVEL)),"\r$(PKG_NAME) already unpacked\n",""); \
+	if [ -f $(STAMP_SHIELD) ]; then true; \
+	elif [ -f $(STAMP_UNPACK) ]; then \
+	    echo -ne $${MESSAGE}; \
+	else \
+	    rm -rf $(PKG_NAME)* && \
+	    if [ -f $(PKG_SOURCE) ]; then \
+	        tar xf $(PKG_SOURCE) -C . && \
+	        for i in $(wildcard *.patch); do \
+	            cd $(PKG_NAME)* && patch -d . -p 1 < ../$${i} && cd $${OLDPWD}; \
+	        done \
+	    fi \
+	    && touch $(STAMP_UNPACK); \
+	fi
+
+	$(ORIGIN_Q) \
+	MESSAGE=$(if $(filter 0 1,$(MAKELEVEL)),"\r$(PKG_NAME) already configured\n",""); \
+	if [ -f $(STAMP_SHIELD) ]; then true; \
+	elif [ -f $(STAMP_CONFIG) ]; then \
+	    echo -ne $${MESSAGE}; \
+	else \
+	    if grep -q 'config *:' $(HD_MAKEFILE); then \
+	        export SHELL=$(SHELL); \
+	        $(MAKE) config -f $(HD_MAKEFILE); \
+	    else \
+	        cd $(PKG_NAME)* && ( \
+	        ./configure \
+	            --prefix=$(OUTPUT_DIR)/usr \
+	            --host=$(HOST) \
+	            --target=$(shell $(SHELL_DBG) basename $(CROSS_PREFIX) 2>/dev/null) \
+	            --enable-static --enable-shared \
+	        || \
+	        ./configure \
+	            --prefix=$(OUTPUT_DIR)/usr \
+	            --host=$(HOST) \
+	            --target=$(shell $(SHELL_DBG) basename $(CROSS_PREFIX) 2>/dev/null|cut -d'-' -f1) \
+	            --enable-static --enable-shared \
+	        ) && cd $${OLDPWD}; \
+	    fi \
+	    && touch $(STAMP_CONFIG); \
+	fi
+
+	$(ORIGIN_Q) \
+	MESSAGE=$(if $(filter 0 1,$(MAKELEVEL)),"\r$(PKG_NAME) already built\n",""); \
+	if [ -f $(STAMP_SHIELD) ]; then true; \
+	elif [ -f $(STAMP_BUILD) ]; then \
+	    echo -ne $${MESSAGE}; \
+	else \
+	    if grep -q 'build *:' $(HD_MAKEFILE); then \
+	        $(MAKE) build -f $(HD_MAKEFILE); \
+	    else \
+	        if [ -d $(PKG_NAME)* ]; then \
+	            cd $(PKG_NAME)* && $(MAKE) -j8 all && cd ..; \
+	        fi \
+	    fi \
+	    && touch $(STAMP_BUILD); \
+	fi
+
+	$(ORIGIN_Q) \
+	MESSAGE=$(if $(filter 0 1,$(MAKELEVEL)),"\r$(PKG_NAME) already installed\n",""); \
+	if [ -f $(STAMP_SHIELD) ]; then true; \
+	elif [ -f $(STAMP_INSTALL) ]; then \
+	    echo -ne $${MESSAGE}; \
+	else \
+	    if grep -q 'install *:' $(HD_MAKEFILE); then \
+	        $(MAKE) install -f $(HD_MAKEFILE); \
+	    else \
+	        if [ -d $(PKG_NAME)* ]; then \
+	            cd $(PKG_NAME)* && $(MAKE) install && cd ..; \
+	        fi \
+	    fi \
+	    && touch $(STAMP_INSTALL); \
+	fi
+
+	$(ORIGIN_Q) \
+	MESSAGE=$(if $(filter 0 1,$(MAKELEVEL)),"\r$(PKG_NAME) already post-installed\n",""); \
+	if [ -f $(STAMP_POSTINS) ]; then \
+	    echo -ne $${MESSAGE}; \
+	else \
+	    if grep -q 'post-install *:' $(HD_MAKEFILE); then \
+	        $(MAKE) post-install -f $(HD_MAKEFILE); \
+	    fi \
+	    && touch $(STAMP_POSTINS); \
+	fi
+
+clean-prepare:
+	$(Q)rm -f $(STAMP_BUILD) $(STAMP_INSTALL) $(STAMP_POSTINS)
+else
+all:
+	$(Q)true
+clean:
+	$(Q)true
+endif   # ifeq ($(strip $(PKG_SWITCH)),y)

+ 20 - 0
iotkit-embedded/build-rules/_rules-prefix.mk

@@ -0,0 +1,20 @@
+CFLAGS  := $(sort $(CFLAGS) $(CONFIG_ENV_CFLAGS))
+LDFLAGS := $(sort $(LDFLAGS) $(CONFIG_ENV_LDFLAGS))
+
+ifeq (dynamic,$(CONFIG_LIB_EXPORT))
+CFLAGS  := $(filter-out --coverage,$(CFLAGS))
+endif
+
+MAKE_ENV_VARS := \
+$(foreach v, \
+    $(shell grep -o 'CONFIG_ENV_[_A-Z]*' $(CONFIG_TPL) 2>/dev/null), \
+        $(subst CONFIG_ENV_,,$(v)) \
+)
+
+# $(eval ...) causes '$' in CFLAGS lost
+MAKE_ENV_VARS := $(sort $(filter-out CFLAGS LDFLAGS,$(MAKE_ENV_VARS)))
+
+$(foreach V, \
+    $(MAKE_ENV_VARS), \
+        $(eval export $(V) := $(sort $(CONFIG_ENV_$(V)))) \
+)

+ 65 - 0
iotkit-embedded/build-rules/_rules-prog.mk

@@ -0,0 +1,65 @@
+VPATH   := $(TOP_DIR)/$(MODULE_NAME)
+SRCS    ?= $(foreach M,*.c */*.c */*/*.c,$(wildcard $(TOP_DIR)/$(MODULE_NAME)/$(M))) $(wildcard *.c)
+OBJS    := $(SRCS:.c=.o)
+OBJS    := $(subst $(TOP_DIR)/$(MODULE_NAME)/,,$(OBJS))
+
+ifdef SRCS_PATTERN
+PROG_LIST	:= $(foreach M,$(SRCS_PATTERN),$(shell ls $(TOP_DIR)/$(MODULE_NAME)/$(M) 2>/dev/null))
+SRCS 		:= $(PROG_LIST)
+OBJS 		:= $(PROG_LIST:.c=.o)
+OBJS 		:= $(subst $(TOP_DIR)/$(MODULE_NAME)/,,$(OBJS))
+endif
+
+ifdef TARGET
+
+ifneq (modinfo,$(MAKECMDGOALS))
+ifneq (clean,$(MAKECMDGOALS))
+sinclude $(OBJS:.o=.d)
+endif
+endif
+
+ifdef LIBA_TARGET
+$(TARGET): $(LIBA_TARGET)
+
+LDFLAGS := -l$(subst .a,,$(subst lib,,$(LIBA_TARGET))) $(LDFLAGS)
+endif
+
+ifdef LIBSO_TARGET
+$(TARGET): $(LIBSO_TARGET)
+
+LDFLAGS := -l$(subst .so,,$(subst lib,,$(LIBSO_TARGET))) $(LDFLAGS)
+endif
+
+LDFLAGS += $(sort $(CONFIG_ENV_LDFLAGS))
+
+ifneq (,$(filter %.cpp %.cc,$(SRCS)))
+CCLD    := $(CXX)
+else
+CCLD    := $(CC)
+endif
+
+ifeq (1,$(words $(TARGET)))
+
+$(TARGET): $(OBJS) FORCE
+	$(call Inspect_Env,$(WATCHED_VARS))
+	$(Q) \
+( \
+	if [ "$(strip $(CC))" = "gcc" ] || [ "$(filter -D_PLATFORM_IS_LINUX_,$(CFLAGS))" != "" ]; then \
+	    $(call Brief_Log,"LD"); \
+	    mkdir -p $(OUTPUT_DIR)${bindir}; \
+	    $(CCLD) $(CFLAGS) -o $@ \
+	        $(RPATH_CFLAGS) \
+	        $(OBJS) \
+	        $(LDFLAGS) && \
+	    cp -f $@ $(OUTPUT_DIR)${bindir}; \
+	fi; \
+)
+
+else
+
+$(foreach t,$(sort $(TARGET)),$(t)): FORCE
+	$(Q)$(MAKE) TARGET=$@ OBJS="$(SRCS_$@:.c=.o)"
+
+endif
+
+endif   # ifdef TARGET

+ 16 - 0
iotkit-embedded/build-rules/_rules-repo.mk

@@ -0,0 +1,16 @@
+OPS_CMDLINE_V := \
+    PACKAGE_DIR \
+    TOP_DIR \
+    STAMP_BLD_VAR \
+
+OPS_SCRIPT := \
+    $(strip $(foreach V, $(OPS_CMDLINE_V), $(V)="$($(V))")) \
+    $(SHELL) \
+    $(RULE_DIR)/scripts/ops_repository.sh \
+    $(STAMP_BLD_VAR)
+
+repo-list: config
+	$(TOP_Q)$(OPS_SCRIPT) list
+
+repo-update: config
+	$(TOP_Q)$(OPS_SCRIPT) update

+ 136 - 0
iotkit-embedded/build-rules/_rules-submods.mk

@@ -0,0 +1,136 @@
+SUB_LOG_OPTION := $(if $(Q),,| tee -a $(OUTPUT_DIR)/$${i}/$(COMPILE_LOG))
+ALL_LOG_OPTION := $(if $(Q),,| tee -a $(COMPILE_LOG))
+
+sub-mods: toolchain
+	$(Q) \
+	if [ -f $(STAMP_PRJ_CFG) ]; then true; else \
+	    set -o pipefail; \
+	    for i in \
+	        $$(echo $(IMPORT_DIR)|$(SED) 's:$(TOP_DIR)/*::g')/$(CONFIG_VENDOR)/platform \
+	        $(SUBDIRS); do \
+	            if [ ! -d $${i} ]; then continue; fi; \
+	            $(MAKE) --no-print-directory Q=$(Q) $${i} 2>&1 $(SUB_LOG_OPTION); \
+	            RETVAL=$$?; \
+	            if [ $${RETVAL} != 0 ]; then exit $${RETVAL}; fi; \
+	    done 2>&1 $(ALL_LOG_OPTION); \
+	fi
+
+SUB_BUILD_VARS := \
+    CFLAGS LDFLAGS \
+    PACKAGE_DIR \
+    IMPORT_DIR \
+    TOP_DIR \
+    RULE_DIR \
+    CONFIG_VENDOR \
+    COMP_LIB \
+    $(CROSS_CANDIDATES) \
+    $(MAKE_ENV_VARS) \
+    INSTALL_DIR \
+    INSTALL_LIB_DIR \
+    SYSROOT_INC \
+    KERNEL_DIR \
+    MAKE_ENV_VARS \
+    CROSS_PREFIX \
+    CROSS_CANDIDATES \
+    ALL_SUB_DIRS \
+
+CMDLINE_VARS := \
+    HD_MAKEFILE \
+    MAKE_SEGMENT \
+    OUTPUT_DIR \
+    PACKAGE_DIR \
+    STAMP_BLD_ENV \
+    STAMP_UNPACK \
+    TOP_DIR \
+    RULE_DIR \
+
+# When SUB_BUILD_VARS like $(CFLAGS) contains special character '$'
+# simply echo its value into 'Makefile' will cause '$' lost when GNU make read in again
+#
+$(STAMP_BLD_ENV): $(TOP_DIR)/makefile $(shell ls $(CONFIG_TPL) 2>/dev/null) \
+                  $(wildcard $(RULE_DIR)/*.mk) \
+                  $(shell grep "^ *include" $(TOP_DIR)/$(TOP_MAKEFILE)|awk '{ print $$NF }'|$(SED) '/^\$$/d')
+	@rm -f $@
+	@$(foreach V, \
+	    $(sort $(SUB_BUILD_VARS)), \
+	        echo "$(V) := $(sort $($(V)))"|$(SED) 's:\$$:$$$$:g' >> $(STAMP_BLD_ENV); \
+	)
+
+# note:
+#   $(SED) -i "/CONFIG_$${i//\//\\/}.*/d" $(CONFIG_TPL);
+# above
+#   $(SED) -i "1iCONFIG_$${i} = y" $(CONFIG_TPL)
+# was removed since modules will be skipped in some cases
+
+$(STAMP_BLD_VAR): $(foreach d,$(ALL_SUB_DIRS),$(d)/$(MAKE_SEGMENT)) $(STAMP_BLD_ENV) $(wildcard $(RULE_DIR)/*.mk)
+	$(TOP_Q) \
+( \
+	if [ ! -f $(STAMP_BLD_VAR) ]; then echo ""; VERBOSE=1; fi; \
+	rm -f $(STAMP_BLD_VAR); \
+	for i in $(shell echo "$(ALL_SUB_DIRS)"|tr ' ' '\n'|sort -u); do \
+	    if [ "$${VERBOSE}" != "" ]; then \
+	        if [ ! -L $${i} ]; then \
+	            printf "CONFIGURE .............................. [%s]\n" $${i}; \
+	        fi; \
+	        $(SED) -i "1iCONFIG_$${i} = y" $(CONFIG_TPL); \
+	        [ -f $(STAMP_POST_RULE) ] && $(SED) -i "/target-$${i//\//\\/}.*/d" $(STAMP_POST_RULE) || true; \
+	        echo "target-$${i}:; @true" >> $(STAMP_POST_RULE); \
+	    fi; \
+	    $(foreach V, $(CMDLINE_VARS), $(V)="$($(V))") \
+	        bash $(RULE_DIR)/pre-build.sh $${i} makefile-only > /dev/null; \
+	    if [ -d $(OUTPUT_DIR)/$${i} ]; then \
+	        $(MAKE) -s -C $(OUTPUT_DIR)/$${i} modinfo > /dev/null; \
+	        if [ $$? = 0 ]; then \
+	            $(MAKE) --no-print-directory -s -C $(OUTPUT_DIR)/$${i} modinfo >> $(STAMP_BLD_VAR); \
+	        else \
+	            echo ""; \
+	            echo "ERROR detected in '$${i}/$(MAKE_SEGMENT)'..."|grep --color '.*'; \
+	            echo ""; \
+	            rm -f $(STAMP_BLD_VAR) $(STAMP_PRJ_CFG); \
+	            exit 13; \
+	        fi \
+	    fi \
+	done; \
+	sort -o $(STAMP_BLD_VAR) $(STAMP_BLD_VAR); \
+	if [ "$${VERBOSE}" != "" ]; then echo ""; fi; \
+)
+
+pre-build: MOD = $(subst target-,,$(filter-out $@,$(MAKECMDGOALS)))
+pre-build: $(STAMP_BLD_ENV)
+	$(TOP_Q)rm -f $(OUTPUT_DIR)/$(MOD)/$(STAMP_UNPACK)
+	$(if $(filter 0,$(MAKELEVEL)),,@) \
+	$(strip $(foreach V, $(CMDLINE_VARS), $(V)="$($(V))") \
+	    PKG_SOURCE="$(PKG_SOURCE_$(MOD))" \
+	    PKG_BRANCH="$(PKG_BRANCH_$(MOD))" \
+	    PKG_REVISION="$(PKG_REVISION_$(MOD))" \
+	    PKG_UPSTREAM="$(PKG_UPSTREAM_$(MOD))" \
+	    PKG_SWITCH="$(PKG_SWITCH_$(MOD))" \
+	) \
+	$(if $(filter 0,$(MAKELEVEL)),VERBOSE_PRE_BLD=1) \
+	    bash $(RULE_DIR)/pre-build.sh $(subst target-,,$(filter-out $@,$(MAKECMDGOALS)))
+
+.PHONY: $(ALL_SUB_DIRS)
+
+$(ALL_SUB_DIRS): ALL_LOG_OPT = $(if $(Q),,2>&1|tee -a $(OUTPUT_DIR)/$(COMPILE_LOG))
+$(ALL_SUB_DIRS): SUB_LOG_OPT = $(if $(Q),,2>&1|tee -a $(OUTPUT_DIR)/$@/$(COMPILE_LOG))
+
+$(ALL_SUB_DIRS): $(if $(filter 0,$(MAKELEVEL)),toolchain) $(STAMP_BLD_VAR)
+	$(TOP_Q)rm -f $(STAMP_PRJ_CFG)
+	$(TOP_Q)$(MAKE) --no-print-directory pre-build target-$@
+ifeq (0,$(MAKELEVEL))
+	$(TOP_Q)$(MAKE) --no-print-directory -C $(OUTPUT_DIR)/$@ clean
+endif
+	$(TOP_Q) \
+	if [ "$$( $(call Require_Build,$@) )" = "TRUE" ]; then \
+	    $(call Build_Depends,$@) && \
+	    $(call Build_CompLib,$@) && \
+	    $(call Update_Extra_Srcs,$(EXTRA_SRCS_$@),$@) && \
+	    $(MAKE) --no-print-directory -C $(OUTPUT_DIR)/$@ all $(SUB_LOG_OPT) $(ALL_LOG_OPT) && \
+	    if [ "$$(echo $(ORIGIN_$@))" != "" ]; then \
+	        touch $(OUTPUT_DIR)/$@/{$(STAMP_UNPACK),$(STAMP_CONFIG),$(STAMP_BUILD),$(STAMP_INSTALL)}; \
+	    fi \
+	else \
+	    echo -ne "\r$$(printf '%40s' '')\r"; \
+	fi
+
+	@mkdir -p $(STAMP_DIR) && touch $(STAMP_DIR)/$$(echo "$@"|$(SED) 's:/:~:g').build.done

+ 194 - 0
iotkit-embedded/build-rules/_rules-top.mk

@@ -0,0 +1,194 @@
+.PHONY: doc detect config reconfig toolchain sub-mods final-out env help
+
+all: detect config toolchain sub-mods final-out
+	$(TOP_Q) \
+	if [ -f $(STAMP_PRJ_CFG) ]; then \
+	    $(RECURSIVE_MAKE) toolchain; \
+	    rm -f $(STAMP_PRJ_CFG); \
+	fi
+	@rm -rf $(STAMP_DIR)
+
+RESET_ENV_VARS := \
+    CROSS_PREFIX \
+    CFLAGS \
+    HOST \
+    LDFLAGS \
+
+help:
+	@echo -e "\033[1;37m[$(RULE_DIR)/docs]\e[0m"
+	@echo ""
+	@cat $(RULE_DIR)/docs/Help.md
+	@echo ""
+
+doc:
+	$(TOP_Q)rm -rf html
+	$(TOP_Q) \
+	$(SED) \
+	    's:^PROJECT_NAME.*:PROJECT_NAME = $(PRJ_NAME):g; s:^PROJECT_NUMBER.*:PROJECT_NUMBER = $(PRJ_VERSION):g' \
+	build-rules/misc/Doxyfile.tpl > $(OUTPUT_DIR)/.doxygen.cfg
+	$(TOP_Q)doxygen $(OUTPUT_DIR)/.doxygen.cfg
+
+detect:
+	@if [ -d .git ]; then \
+	    mkdir -p .git/hooks; \
+	    for i in $(RULE_DIR)/hooks/*; do \
+	        cp -f $$i .git/hooks && chmod a+x .git/hooks/$$(basename $$i); \
+	    done; \
+	fi
+
+unzip: config $(STAMP_BLD_VAR)
+	@echo "Components: "
+	@echo ""
+	@for i in $(ALL_SUB_DIRS); do \
+	    $(MAKE) --no-print-directory pre-build target-$${i} ; \
+	    echo -ne "\r. $${i}"; \
+	    echo -e "                                          "; \
+	done
+	@echo ""
+
+#	@for i in $$(grep "^ *include" $(TOP_DIR)/$(TOP_MAKEFILE)|awk '{ print $$NF }'|$(SED) '/^\$$/d'); do \
+#	    if [ $$i -nt $(CONFIG_TPL) ]; then \
+#	        echo "Re-configure project since '$${i}' updated"|grep --color ".*"; \
+#	        $(RECURSIVE_MAKE) reconfig; \
+#	    fi; \
+#	done
+#
+#	@if [ ! -d $(OUTPUT_DIR) ]; then \
+#	    echo "Re-configure project since '$(OUTPUT_DIR)' non-exist!"|grep --color ".*"; \
+#	    $(RECURSIVE_MAKE) reconfig; \
+#	fi
+
+config:
+
+	@mkdir -p $(OUTPUT_DIR) $(STAMP_DIR) $(INSTALL_DIR)
+	@mkdir -p $(SYSROOT_BIN) $(SYSROOT_INC) $(SYSROOT_LIB)
+
+	$(TOP_Q) \
+	if [ -f $(STAMP_BLD_VAR) ]; then \
+	    if [ "$$($(SED) '/[-_/a-zA-Z0-9]* = ..*/d' $(STAMP_BLD_VAR)|wc -l|$(SED) 's:^  *::g')" != "0" ]; then \
+	        rm -f $(STAMP_BLD_VAR); \
+	    fi \
+	fi
+
+	$(TOP_Q)+( \
+	if [ -f $(CONFIG_TPL) ]; then \
+	    if [ "$(filter comp-lib,$(MAKECMDGOALS))" = "" ]; then \
+	        printf "BUILDING WITH EXISTING CONFIGURATION:\n\n"; \
+	        command grep -m 1 "VENDOR *:" $(CONFIG_TPL)|cut -c 3-; \
+	        command grep -m 1 "MODEL *:" $(CONFIG_TPL)|cut -c 3-; \
+	        echo ""; \
+	    fi \
+	else \
+	    if [ "$(DEFAULT_BLD)" != "" ] && [ -f $(DEFAULT_BLD) ] && \
+	       ([ "$(DEFAULT_BLD)" = "$(RULE_DIR)/misc/config.generic.default" ] || [ "$(MAKECMDGOALS)" = "" ]); then \
+	        printf "# Automatically Generated Section End\n\n" >> $(CONFIG_TPL); \
+	        printf "# %-10s %s\n" "VENDOR :" $$(basename $(DEFAULT_BLD)|cut -d. -f2) >> $(CONFIG_TPL); \
+	        printf "# %-10s %s\n" "MODEL  :" $$(basename $(DEFAULT_BLD)|cut -d. -f3) >> $(CONFIG_TPL); \
+	        cat $(DEFAULT_BLD) >> $(CONFIG_TPL); \
+	    else \
+	        printf "SELECT A CONFIGURATION:\n\n"; \
+	        LIST=$$(for i in $(CONFIG_DIR)/config.*.*; do basename $${i}; done|sort); \
+	        select V in $${LIST}; do \
+	            echo ""; \
+	            printf "# Automatically Generated Section End\n\n" >> $(CONFIG_TPL); \
+	            printf "# %-10s %s\n" "VENDOR :" $$(echo $${V}|cut -d. -f2) >> $(CONFIG_TPL); \
+	            printf "# %-10s %s\n" "MODEL  :" $$(echo $${V}|cut -d. -f3) >> $(CONFIG_TPL); \
+	            cp -f -P $(IMPORT_DIR)/$$(echo $${V}|cut -d. -f2)/$(PREBUILT_LIBDIR)/*.so* $(SYSROOT_LIB) 2>/dev/null; \
+	            cat $(CONFIG_DIR)/$${V} >> $(CONFIG_TPL); \
+	            break; \
+	        done; \
+	    fi && \
+	    printf "SELECTED CONFIGURATION:\n\n" && \
+	    command grep -m 1 "VENDOR *:" $(CONFIG_TPL)|cut -c 3- && \
+	    command grep -m 1 "MODEL *:" $(CONFIG_TPL)|cut -c 3- && \
+	    echo ""; \
+	    if [ "$(MAKECMDGOALS)" = "config" ]; then true; else \
+	        if [ "$(DEFAULT_BLD)" = "" ]; then \
+	            touch $(STAMP_PRJ_CFG); \
+	        fi; \
+	    fi; \
+	    for i in $(RESET_ENV_VARS); do unset $${i}; done; \
+	    $(MAKE) --no-print-directory -f $(TOP_MAKEFILE) $(STAMP_BLD_VAR) unzip; \
+	fi)
+
+toolchain: VSP_TARBALL = $(shell $(SHELL_DBG) basename $(CONFIG_TOOLCHAIN_RPATH))
+toolchain: config
+ifneq ($(CONFIG_TOOLCHAIN_NAME),)
+ifeq (,$(CONFIG_TOOLCHAIN_RPATH))
+	@echo "Error! CONFIG_TOOLCHAIN_NAME defined, but CONFIG_TOOLCHAIN_RPATH undefined!" && exit 1
+else
+	$(TOP_Q) \
+( \
+	if [ -e $(OUTPUT_DIR)/$(CONFIG_TOOLCHAIN_NAME) ]; then \
+	    exit 0; \
+	fi; \
+\
+	if [ ! -d /tmp/$(CONFIG_TOOLCHAIN_NAME) -a -f /tmp/$(VSP_TARBALL) ]; then \
+	    echo "De-compressing Cached ToolChain ..." && \
+	    tar xf /tmp/$(VSP_TARBALL) -C /tmp; \
+	fi; \
+	if [ -d /tmp/$(CONFIG_TOOLCHAIN_NAME) ]; then \
+	    echo "Using Cached ToolChain ..." && \
+	    ln -sf /tmp/$(CONFIG_TOOLCHAIN_NAME) $(OUTPUT_DIR)/$(CONFIG_TOOLCHAIN_NAME); \
+	    exit 0; \
+	fi; \
+\
+	echo "Downloading ToolChain ..." && \
+	wget -O $(OUTPUT_DIR)/$(VSP_TARBALL) $(CONFIG_VSP_WEBSITE)/$(CONFIG_TOOLCHAIN_RPATH) && \
+	echo "De-compressing ToolChain ..." && \
+	tar xf $(OUTPUT_DIR)/$(VSP_TARBALL) -C $(OUTPUT_DIR); \
+	cp -f $(OUTPUT_DIR)/$(VSP_TARBALL) /tmp; \
+	rm -rf /tmp/$(CONFIG_TOOLCHAIN_NAME); \
+	tar xf /tmp/$(VSP_TARBALL) -C /tmp; \
+)
+endif
+endif
+
+reconfig: distclean
+	$(TOP_Q)+( \
+	if [ -d $(CONFIG_DIR) ]; then \
+	    $(RECURSIVE_MAKE) config DEFAULT_BLD=not-exist-actually; \
+	else \
+	    $(RECURSIVE_MAKE) config; \
+	fi)
+	$(TOP_Q)rm -f $(STAMP_PRJ_CFG)
+
+clean:
+	$(TOP_Q) \
+	for i in $(SUBDIRS) $(COMP_LIB_COMPONENTS); do \
+	    if [ -d $(OUTPUT_DIR)/$${i} ]; then \
+	        $(MAKE) --no-print-directory -C $(OUTPUT_DIR)/$${i} clean; \
+	    fi \
+	done
+
+	$(TOP_Q) \
+	rm -rf \
+	        $(LIBOBJ_TMPDIR) \
+	        $(COMPILE_LOG) \
+	        $(DIST_DIR)/* \
+	        $(STAMP_DIR) \
+	        $(SYSROOT_INC)/* $(SYSROOT_LIB)/* $(SYSROOT_LIB)/../bin/* \
+	        $(shell $(SHELL_DBG) find $(OUTPUT_DIR) -name "$(COMPILE_LOG)" \
+	                             -o -name "$(WARNING_LOG)" \
+	                             -o -name "$(STAMP_BUILD)" \
+	                             -o -name "$(STAMP_INSTALL)" \
+	                             -o -name "$(STAMP_POSTINS)" \
+	        2>/dev/null)
+
+distclean:
+	$(TOP_Q) \
+	rm -rf \
+	    $(CONFIG_TPL) $(COMPILE_LOG) \
+	    $(STAMP_PRJ_CFG) $(STAMP_BLD_ENV) $(STAMP_BLD_VAR) $(STAMP_POST_RULE) \
+	    $(DIST_DIR) $(STAMP_DIR) \
+
+	$(TOP_Q) \
+	if [ -d $(OUTPUT_DIR) ]; then \
+	    cd $(OUTPUT_DIR); \
+	    if [ "$(CONFIG_TOOLCHAIN_NAME)" = "" ]; then \
+	        rm -rf *; \
+	    else \
+	        rm -rf $$(ls -I $(CONFIG_TOOLCHAIN_NAME)); \
+	    fi \
+	fi
+

+ 41 - 0
iotkit-embedded/build-rules/docs/Build-System-Config.md

@@ -0,0 +1,41 @@
+# 构建系统配置
+
+## 定制目录排布
+
+默认情况下, 构建系统采用如下的目录排布:
+
+    CONFIG_DIR      ?= $(TOP_DIR)/configs
+    DIST_DIR        ?= $(TOP_DIR)/output
+    FINAL_DIR       ?= $(DIST_DIR)/release
+    IMPORT_DIR      ?= $(TOP_DIR)/import
+    LCOV_DIR        ?= Coverage
+    MAKE_SEGMENT    ?= iot.mk
+    OUTPUT_DIR      ?= $(TOP_DIR)/.O
+    PACKAGE_DIR     ?= $(TOP_DIR)/packages
+    RULE_DIR        ?= $(TOP_DIR)/build-rules
+    TOP_DIR         ?= $(CURDIR)
+
+含义如下:
+
+| 变量名            | 说明                                      |
+|-------------------|-------------------------------------------|
+| `CONFIG_DIR`      | *硬件平台配置文件*的存放目录, 其中的文件需要以`config.XXX.YYY`形式命名, 其中`XXX`一般表示操作系统, `YYY`一般表示具体的硬件型号 |
+| `DIST_DIR`        | 最终的编译产物, 例如可执行程序, SDK的总库等, 存放的顶层目录 |
+| `FINAL_DIR`       | 最终的编译产物摆放时, 会放在`$(FINAL_DIR)`下, 这个变量可以指定最终摆放位置在顶层目录下的子目录路径 |
+| `IMPORT_DIR`      | 输入目录, 用于摆放预编译的二进制库, 以及使用这些预编译库对应的头文件 |
+| `LCOV_DIR`        | 覆盖率文件产生目录, 用于存放`lcov`软件产生的中间文件和最终的`HTML`格式图形化文件 |
+| `MAKE_SEGMENT`    | 构建单元中的片段文件, 开发者唯一需要编辑的文件, 指导构建系统如何编译该文件所在的构建单元 |
+| `OUTPUT_DIR`      | 编译树中间目录 |
+| `PACKAGE_DIR`     | 打包目录, 其中可以存放其它组件, 也可以存放压缩包形式的第三方软件, 例如`openssl-0.9.8.tar.gz`等 |
+| `RULE_DIR`        | 构建系统核心目录, 如果不喜欢`build-rules`存放在自己的工程里, 完全可以通过这个变量把它移出去 |
+| `TOP_DIR`         | 工程的顶级目录, 默认就是顶层`makefile`所在的路径, 极少改动 |
+
+可以完全不对它们做任何改动, 依照上文的含义和默认值来排布自己工程
+
+---
+也可以通过顶层目录的`project.mk`, 可以改动它们, 例如:
+
+    $ cat project.mk
+    MAKE_SEGMENT := alink.mk
+
+则表示在每个构建单元中, 指导构建过程的片段文件不再是默认的`iot.mk`, 而是`alink.mk`

+ 16 - 0
iotkit-embedded/build-rules/docs/Build-System-Debug.md

@@ -0,0 +1,16 @@
+# 构建系统调试
+
+## 调试开关
+
+* 在`make ...`命令行中, 设置`TOP_Q`变量为空, 可打印工程顶层的执行逻辑, 例如硬件平台的选择, SDK主库的生成等
+
+        make .... TOP_Q=
+
+* 在`make ...`命令行中, 设置`Q`变量为空, 可打印模块内部的构建过程, 例如目标文件的生成, 头文件搜寻路径的组成等
+
+        make .... Q=
+
+## 对单个构建单元调试
+
+* 可以用`make foo/bar`单独对`foo/bar`进行构建, 不过, 这可能需要先执行`make reconfig`
+* 可以进入`.O/foo/bar`路径, 看到完整的编译临时目录, 有makefile和全部源码, 所以在这里执行`make`, 效果和`make foo/bar`等同

+ 124 - 0
iotkit-embedded/build-rules/docs/Build-System-Introduction.md

@@ -0,0 +1,124 @@
+# 如何获取
+
+* 可访问样板组件`LITE-utils`的仓库: [*git@gitlab.alibaba-inc.com:iot-middleware/LITE-utils.git*](http://gitlab.alibaba-inc.com/iot-middleware/LITE-utils)
+* 从`master`分支的`build-rules`目录复制得到构建系统的最新副本
+* 也可以直接在`LITE-utils`中体验构建系统的工作方式和观察工作过程
+
+# 常用命令
+
+| 命令                  | 解释                                                                              |
+|-----------------------|-----------------------------------------------------------------------------------|
+| `make distclean`      | **清除一切构建过程产生的中间文件, 使当前目录仿佛和刚刚clone下来一样**             |
+| `make [all]`          | **使用默认的平台配置文件开始编译**                                                |
+| `make reconfig`       | **弹出多平台选择菜单, 用户可按数字键选择, 然后根据相应的硬件平台配置开始编译**    |
+| `make config`         | **显示当前被选择的平台配置文件**                                                  |
+| `make help`           | **打印帮助文本**                                                                  |
+| `make <directory>`    | **单独编译被<directory>指定的目录, 或者叫构建单元**                               |
+
+# 如何开发
+
+* 访问[**构建系统配置**](https://code.aliyun.com/edward.yangx/public-docs/wikis/build/build-system-config), 了解如何配置来影响构建系统的行为
+* 访问[**构建工程说明**](https://code.aliyun.com/edward.yangx/public-docs/wikis/build/build-system-proj), 了解如何定制工程全局的编译
+* 访问[**构建单元说明**](https://code.aliyun.com/edward.yangx/public-docs/wikis/build/build-system-units), 了解如何增删改查你自己的构建单元
+* 访问[**构建系统调试**](https://code.aliyun.com/edward.yangx/public-docs/wikis/build/build-system-debug), 了解在定制构建单元时, 如何自己调试
+
+# 高级命令
+
+| 命令                  | 解释                                                                                      |
+|-----------------------|-------------------------------------------------------------------------------------------|
+| `make test`           | **运行指定的测试集程序, 统计显示测试例的通过率和源代码的覆盖率**                          |
+| `make doc`            | **扫描源码目录中以`Doxygen`格式或者`Markdown`格式编写的注释, 在`html`目录产生帮助文档**   |
+| `make repo-list`      | **列出当前工程引用的外部组件和它们的云端仓库地址**                                        |
+| `make repo-update`    | **对所有引用到的外部组件, 用云端仓库更新本地仓库**                                        |
+
+# 组成部分
+
+    LITE-utils$ tree -A -L 1
+    .
+    +-- build-rules     # 构建系统核心
+    +-- example
+    +-- external
+    +-- makefile        # 工程的makefile
+    +-- packages
+    +-- project.mk      # 工程设置文件
+    +-- src
+    +-- testsuites
+
+> 以`LITE-utils`为例, 对整个构建过程需要知道的只有如上三个部分:
+
+| 组成部分      | 说明                                                                          |
+|---------------|-------------------------------------------------------------------------------|
+| `project.mk`  | 本工程的目录排布, 工程名称, 版本信息等, 可选                                  |
+| `makefile`    | 本工程的makefile, 基于`GNU Make`, 通常只含有极少的内容, 指定编译的范围, 必选  |
+| `build-rules` | 构建系统核心, 指定编译的规则, 不需要关注                                      |
+
+# 工作过程
+
+可以从一个简单的`makefile`样例看起
+
+     1  sinclude project.mk
+     2  sinclude $(CONFIG_TPL)
+     3
+     4  SUBDIRS += \
+     5      external/cut \
+     6      src \
+     7      example \
+     8      testsuites \
+     9
+    10  include $(RULE_DIR)/rules.mk
+
+0. 构建系统是基于`GNU Make`的简化系统, 所以工作过程的起点仍然是顶层的`makefile`
+1. 读取`project.mk`, 如果当前工程的目录排布和默认的不一样, 则用当前设置, 可选
+2. 读取`.config`文件, 这个文件其实是构建系统运行时所有输入的集合, 也称为*硬件平台配置文件*, 可选
+3. 读取`SUBDIRS`变量, 这个变量指定了编译的范围, 必选
+4. 读取`CFLAGS`或者`LDFLAGS`等变量, 顶层`makefile`的变量会被应用到每个构建单元的编译和链接, 可选
+5. 读取`.../rules.mk`文件, 开始进入构建系统核心, 必选, 这又可以细分为如下过程
+
+## 详细工作过程
+
+* 产生*硬件平台配置文件*, 这个过程是为了产生顶层的`.config`文件, 也就是所谓的`$(CONFIG_TPL)`
+* 识别构建单元, 所谓构建单元在构建系统看来就是一个又一个包含`iot.mk`的目录, 如果不希望用`iot.mk`作为每个单元的编译片段文件, 在`project.mk`中设置`MAKE_SEGMENT`变量即可
+* 从`$(SUBDIRS)`变量从前往后逐个编译每个构建单元
+* 构建单元如果有依赖到其它构建单元, 则先去编译被依赖的单元; 若后者又有依赖的其它的单元, 则同样, 递归的先去编译其依赖; 以此类推
+
+# 高级命令示例
+
+- **make test: 运行指定的测试集程序, 统计显示测试例的通过率和源代码的覆盖率**
+
+![image](https://yuncodeweb.oss-cn-hangzhou.aliyuncs.com/uploads/edward.yangx/public-docs/52c806dd879f18cd7ea855a8549461f6/image.png)  
+
+- **make doc: 扫描源码目录中以`Doxygen`格式或者`Markdown`格式编写的注释, 在`html`目录产生帮助文档**
+
+        LITE-utils $ make doc
+        ...
+        ...
+        Patching output file 15/16
+        Patching output file 16/16
+        lookup cache used 256/65536 hits=882 misses=258
+        finished...
+
+![image](https://yuncodeweb.oss-cn-hangzhou.aliyuncs.com/uploads/edward.yangx/public-docs/b9ea5662e866913efcaca28549d9f033/image.png)
+
+- **make repo-list: 列出当前工程引用的外部组件和它们的云端仓库地址**
+
+        LITE-utils $ make repo-list
+        [external/log] git@gitlab.alibaba-inc.com:iot-middleware/LITE-log.git
+
+> 以上输出表示在构建单元`external/log`, 引用了云端仓库位于`git@gitlab.alibaba-inc.com:iot-middleware/LITE-log.git`的外部组件`LITE-log`
+
+- **make repo-update: 将所有引用的外部组件用云端仓库更新本地仓库**
+
+        LITE-utils $ make repo-update
+        [ LITE-log.git ] <= : git@gitlab.alibaba-inc.com:iot-middleware/LITE-log.git :: master
+        + cd /home/edward/srcs/iot-middleware/LITE-utils/packages
+        + rm -rf LITE-log.git
+        + git clone -q --bare -b master --single-branch git@gitlab.alibaba-inc.com:iot-middleware/LITE-log.git LITE-log.git
+        + rm -rf LITE-log.git/hooks/
+        + mkdir -p LITE-log.git/hooks/
+        + touch LITE-log.git/hooks/.gitkeep
+        + touch LITE-log.git/refs/heads/.gitkeep LITE-log.git/refs/tags/.gitkeep
+        + rm -rf /home/edward/srcs/iot-middleware/LITE-utils.pkgs/LITE-log
+        + cd /home/edward/srcs/iot-middleware/LITE-utils
+        + set +x
+
+> 以上输出表示从`git@gitlab.alibaba-inc.com:iot-middleware/LITE-log.git`拉取最新的云端仓库, 更新到本地仓库`packages/LITE-log.git`

+ 39 - 0
iotkit-embedded/build-rules/docs/Build-System-Proj.md

@@ -0,0 +1,39 @@
+# 定制工程全局的编译行为
+
+## 增加硬件平台配置文件
+
+在默认的`configs`目录, 或者在指定的`$(CONFIG_DIR)`目录下, 文件名形式为`config.<VENDOR>.<MODEL>`的文本文件, 会被构建系统认为是硬件平台配置文件, 每个文件对应一个嵌入式软硬件平台
+
+* 其中<VENDOR>部分, 一般是指明嵌入式平台的软件OS提供方, 如`mxchip`, `ubuntu`, `win7`等. 另外, 这也会导致构建系统到`$(IMPORT_DIR)/<VENDOR>`目录下寻找预编译库的二进制库文件和头文件
+* 其中<MODEL>部分, 一般是标明嵌入式平台的具体硬件型号, 如`mtk7687`, `qcom4004`等, 不过也可以写上其它信息, 因为构建系统不会去理解它, 比如`mingw32`, `x86-64`等
+
+> 例如`config.mxchip.3080c`文件, 如果在`make reconfig`的时候被选择, 则会导致:
+
+* 构建系统在`import/mxchip/`目录下寻找预编译库的二进制库文件和头文件
+* 构建系统使用该文件内的变量指导编译行为, 具体来说, 可以根据说明使用如下变量
+
+| 变量                  | 说明                                      |
+|-----------------------|-------------------------------------------|
+| `CONFIG_ENV_CFLAGS`   | 指定全局的`CFLAGS`编译选项, 传给`compiler`, 例如`CONFIG_ENV_CFLAGS += -DDEBUG` |
+| `CONFIG_ENV_LDFLAGS`  | 指定全局的`LDFLAGS`链接选项, 传给`linker`, 例如`CONFIG_ENV_LDFLAGS += -lcrypto` |
+| `CROSS_PREFIX`        | 指定交叉编译工具链共有的前缀, 例如`CROSS_PREFIX := arm-none-eabi-`, 会导致构建系统使用`arm-none-eabi-gcc`和`arm-none-eabi-ar`, 以及`arm-none-eabi-strip`等 |
+| `OVERRIDE_CC`         | 当交叉工具链没有共有的前缀或者前缀不符合`prefix+gcc|ar|strip`类型时, 例如`armcc`, 可用`OVERRIDE_CC = armcc`单独指定C编译器 |
+| `OVERRIDE_AR`         | 当交叉工具链没有共有的前缀或者前缀不符合`prefix+gcc|ar|strip`类型时, 例如`armar`, 可用`OVERRIDE_AR = armar`单独指定库压缩器 |
+| `OVERRIDE_STRIP`      | 当交叉工具链没有共有的前缀或者前缀不符合`prefix+gcc|ar|strip`类型时, 例如`armcc`没有对应的strip程序, 可用`OVERRIDE_STRIP = true`单独指定strip程序不执行 |
+
+## 定制单元测试
+
+如果你的工程含有配合构建系统的单元测试用例, 则可以在顶层`makefile`中添写类似如下语句, 告诉构建系统在`make test`命令中执行它们做单元测试, 并统计源码覆盖率
+
+    UTEST_PROG := utils-tests
+
+> 以上面的`LITE-utils`为例, 其中的`utils-tests`就是它的单元测试程序, 这是在构建单元`testsuites`中产生的一个`Linux`下可执行程序
+
+    $ cat testsuites/iot.mk -n
+         1  TARGET      := utils-tests
+         2  DEPENDS     += external/cut src
+         3  HDR_REFS    := src
+         4
+         5  LDFLAGS     += -llite-utils -llite-log -llite-cut
+
+为什么如上的一个简单`iot.mk`片段文件, 就能指导构建系统生成可执行程序`utils-tests`, 可以访问[**构建单元说明**](https://code.aliyun.com/edward.yangx/public-docs/wikis/build/build-system-units)

+ 130 - 0
iotkit-embedded/build-rules/docs/Build-System-Units.md

@@ -0,0 +1,130 @@
+# 构建单元说明
+
+## 定义
+
+* 片段文件: 用来指导某个具体的文件夹下源码应如何获取和编译以及链接的makefile文本片段, 基本只包含变量的赋值
+* 默认的片段文件是名为`iot.mk`的文本文件, 可以在工程顶层目录`project.mk`里, 用`MAKE_SEGMENT := <new>`更改片段文件名
+* 从工程顶层目录以下, 每一个含有`iot.mk`的子目录, 都被构建系统认为是一个构建单元
+
+> 举例来说:
+
+> 假设在/path/to/project/project.mk文件中有
+> 
+>     MAKE_SEGEMENT := build.mk
+ 
+> 那么, 如下的目录排布
+> 
+>     /path/to/project/bar/build.mk
+>     /path/to/project/foo/sub1/build.mk
+>     /path/to/project/foo/sub2/build.mk
+>     /path/to/project/mmm/nnn/ppp/qqq/build.mk
+ 
+> 会导致
+> 
+>     bar
+>     foo/sub1
+>     foo/sub2
+>     mmm/nnn/ppp/qqq
+ 
+> 都被认为是构建单元, 可以用类似`make bar`, `make foo/bar1`这样的命令单独编译, 也可以调试完成后通过修改顶层`makefile`集成到工程中
+
+## 工作过程
+
+对整个工程进行构建的过程基本是遍历每个构建单元逐个构建, 而对每个构建单元的构建过程是:
+
+* 构造编译的临时目录, 例如 `.O/bar` 目录, 对应源码 `bar` 构建单元
+* 在编译的临时目录中动态生成或更新`makefile`和源代码
+* 切换到临时目录中, 编译源代码, 产生目标代码
+
+## 开发过程
+
+增加一个新的构建单元可以按如下步骤进行:
+
+* 创建新单元对应的目录, 比如
+
+        mkdir foo/bar
+
+* 创建该单元的片段文件, 比如
+
+        vi foo/bar/iot.mk
+        1 LIBA_TARGET := libfoobar.a
+
+* 为该单元添加一些源码文件, 比如
+
+        cp .../*.c foo/bar/
+
+* 这时, 在工程文件中运行`make reconfig`, 告诉构建系统新增了一个单元, 这个单元就可以被独立编译了
+
+        make reconfig
+        make foo/bar
+
+* 单独的编译和运行没问题之后, 修改工程的`makefile`, 使这个新单元也加入到工程中
+
+        vi makefile
+        ...
+        ...
+        SUBDIRS += foo/bar
+        ...
+        ...
+
+## 编写片段文件
+
+**简化编译的设计思想就是使每一个模块的开发者, 基本只需要编写片段文件就能构建自己的功能模块**
+
+**而片段文件之所以能够起到简化的效果, 是因为它基本上只是一些"变量赋值"语句的集合, 编写它, 几乎可以不需要学习任何语言的任何语法**
+
+---
+以下是在片段文件中可以使用的变量名:
+
+### 输出相关
+
+| 变量名            | 用处                                                                                          |
+|-------------------|-----------------------------------------------------------------------------------------------|
+| ORIGIN            | 如果你的模块希望按自己独特的方式编译, 比如`./configure ...; make; ...`, 需要设置此变量为1 |
+| LIBSO_TARGET      | 设置本单元被编译出的`Linux`动态库文件名, 对它赋值导致系统帮助你产生`*.so`共享库文件 | 
+| LIBA_TARGET       | 设置本单元被编译出的静态库文件名, 对它赋值导致系统帮助你产生`*.a`静态库文件 |
+| TARGET            | 设置本单元被编译出的可执行程序文件名, 对它赋值导致系统帮助你产生`Linux`下的可执行程序 |
+| KMOD_TARGET       | 设置本单元被编译出的内核模块文件名, 对它赋值导致系统帮助你产生`Linux`下的`*.ko`内核模块 |
+
+**以上变量至少要有一个被设置, 这样构建系统才知道构建的输出是什么, 至多则可以同时被设置, 例如同时产生静态库文件和可执行程序, 甚至内核模块等**
+
+### 输入相关
+
+| 变量名            | 用处                                                                                          |
+|-------------------|-----------------------------------------------------------------------------------------------|
+| LIB_SRCS          | 可选, 列出哪些`*.c`文件被编译成`*.a`或者`*.so` |
+| SRCS              | 可选, 列出哪些`*.c`文件被编译成可执行程序 |
+| EXTRA_SRCS        | 可选, 列出哪些源文件需要在开始编译之前被复制到临时的编译目录 |
+| CFLAGS            | 可选, 列出需要特别应用在本模块上的编译选项 |
+| LDFLAGS           | 可选, 列出需要特别应用在本模块上的链接选项 |
+
+### 组合相关
+
+| 变量名            | 用处                                                                                          |
+|-------------------|-----------------------------------------------------------------------------------------------|
+| HDR_REFS          | 可选, 如果你的模块引用了其它模块的头文件, 那么需要设置这个变量, 列出被引用模块在工程里的相对路径 |
+| DEPENDS           | 可选, 如果你的模块需要在其它模块构建完成后才能编译, 那么需要设置这个变量, 列出被依赖模块在工程里的相对路径 |
+
+### 高级用法
+
+| 变量名            | 用处                                                                                          |
+|-------------------|-----------------------------------------------------------------------------------------------|
+| PKG_SOURCE        | 可选, 表示源码来自`*.c`之外的形式, 例如压缩包文件, 或者独立的git仓库等 |
+| PKG_BRANCH        | 可选, 仅在`PKG_SOURCE`是git仓库的时候才有意义, 指定使用该仓库的哪个分支作为源码输入 |
+| PKG_REVISION      | 可选, 仅在`PKG_SOURCE`是git仓库的时候才有意义, 指定使用该仓库的哪个分支上的哪个`commit`或者`tag` |
+| PKG_UPSTREAM      | 可选, 仅在`PKG_SOURCE`是git仓库的时候才有意义, 指定使用哪个云端的git仓库地址来更新本地git仓库 |
+
+
+### 其它
+
+#### 产生多个可执行程序
+
+* 如果你的模块希望产生单个的可执行程序, 那么对变量`TARGET`和`SRCS`赋值就可以了, 但如果希望产生多个可执行程序, 比如
+
+        TARGET = prog1 prog2 prog3
+
+* 那么需要用`SRCS_<name>`变量对这多个可执行程序分别设定他们的源文件, 比如
+
+        SRCS_prog1 = prog1.c
+        SRCS_prog2 = prog2.c library_A.c
+        SRCS_prog3 = prog3.c library_A.c library_B.c

+ 23 - 0
iotkit-embedded/build-rules/docs/Help.md

@@ -0,0 +1,23 @@
+常用命令
+---
+
+| 命令                  | 解释                                                                              |
+|-----------------------|-----------------------------------------------------------------------------------|
+| `make distclean`      | **清除一切编译过程产生的中间文件, 使当前目录仿佛和刚刚clone下来一样**             |
+| `make [all]`          | **使用默认的平台配置文件开始编译**                                                |
+| `make reconfig`       | **弹出多平台选择菜单, 用户可按数字键选择, 然后根据相应的硬件平台配置开始编译**    |
+| `make config`         | **显示当前被选择的平台配置文件**                                                  |
+| `make help`           | **打印帮助文本**                                                                  |
+| `make env`            | **打印当前编译的选项和它们的值**                                                  |
+| `make <directory>`    | **单独编译被<directory>指定的目录, 或者叫编译单元**                               |
+
+高级命令
+---
+
+| 命令                  | 解释                                                                              |
+|-----------------------|-----------------------------------------------------------------------------------|
+| `make repo-list`      | 列出当前可以更新的组件列表, 所谓组件是跨项目的功能模块, 有独立的`git`仓库         |
+| `make repo-update`    | 根据输入更新所有组件或单个被选择的组件, 从线上获取其最新的`git`仓库               |
+| `make test`           | 如果当前项目有编写单元测试主程序和单元测试例, 则执行UT, 统计通过率和覆盖率        |
+
+o 访问 https://code.aliyun.com/edward.yangx/public-docs/wikis/home 可获得编译系统线上最新和最全的帮助文档

+ 172 - 0
iotkit-embedded/build-rules/funcs.mk

@@ -0,0 +1,172 @@
+define Dump_Var
+	NUM=`echo "$(strip $($(1)))"|awk '{ print NF }'`; \
+	if (( $${NUM} \> 1 )); then \
+	    printf -- "-----------------------------------------------------------------\n"; \
+	    printf "%-24s| %s\n" ". $(1)" `echo "$(strip $($(1)))"|cut -d' ' -f1|$(SED) 's/^ *//'`; \
+	    for i in `echo "$(strip $($(1)))"|cut -d' ' -f2-`; do \
+	        printf "%-24s| %s\n" "" "$${i}"; \
+	    done; \
+	    printf -- "-----------------------------------------------------------------\n"; \
+	else \
+	    printf "%-24s| %s\n" ". $(1)" "$(strip $($(1)))"; \
+	fi;
+endef
+
+ifneq (,$(Q))
+define Inspect_Env
+endef
+else
+define Inspect_Env
+	@printf -- "-----------------------------------------------------------------\n"
+	@printf "%-20s| %s\n" ". BUILDING_TARGET" "$@"
+	@printf -- "-----------------------------------------------------------------\n"
+	@printf "%-20s| %s\n" ". BUILDING_DEPEND" "$(filter-out FORCE,$^)"
+	@printf -- "-----------------------------------------------------------------\n"
+	@$(foreach var,$(1),$(call Dump_Var,$(var)))
+	@printf -- "-----------------------------------------------------------------\n"
+endef
+endif
+
+# 31, red. 32, green. 33, yellow. 34, blue. 35, magenta. 36, cyan. 37, white.
+define Brief_Log
+( \
+	if [ "$1" = "CC" ]; then \
+	    if echo "$@"|grep -q "\.so$$"; then \
+	        COLOR_MARK="\033[1;32m"; \
+	    elif echo "$@"|grep -q "\.ko$$"; then \
+	        COLOR_MARK="\033[1;35m"; \
+	    else \
+	        COLOR_MARK="\033[1;36m"; \
+	    fi \
+	elif [ "$1" = "AR" ]; then \
+	    COLOR_MARK="\033[1;33m"; \
+	elif [ "$1" = "LD" ]; then \
+	    COLOR_MARK="\033[1;31m"; \
+	elif [ "$1" = "ST" ]; then \
+	    COLOR_MARK="\033[0;33m"; \
+	fi; \
+    echo -ne "$${COLOR_MARK}"; \
+	if [ "$2" = "" ]; then \
+	    FIRST_DEP="$(firstword $(filter-out FORCE,$?))"; \
+	    SPACE_BAR="                                   "; \
+	    if [ "$${FIRST_DEP}" != "" ]; then \
+	        FIRST_DEP="$$(basename $${FIRST_DEP})"; \
+	    fi; \
+	    printf "\r%-32s%s%s\n" "[$1] $$(echo -n "$$(basename $@)" | cut -c1-20)" "<= $${FIRST_DEP} $${SPACE_BAR}"; \
+	else \
+	    printf "\r%-32s%s%s\n" "[$1] $$(echo -n "$(2)" | cut -c1-20)" "<= $${FIRST_DEP} $${SPACE_BAR}"; \
+	fi; \
+	for i in $(wordlist 2,100,$(filter-out FORCE,$?)); do \
+	    if [ "$$(echo $${i}|cut -c1)" != "/" ]; then \
+	        printf "%-32s%s\n" "" "   $$(basename $${i})"; \
+	    fi \
+	done; \
+	echo -ne "\033[0m"; \
+)
+endef
+
+define Copy_Headers
+	$(Q) \
+	if [ "$(strip $(1))" != "" ]; then \
+	    mkdir -p $(2)/$(3); \
+	    for hdr in $(1); do \
+	        if [ $${PWD}/$${hdr} -nt $(2)/$(3)/$${hdr} ]; then \
+	            mkdir -p $(2)/$(3)/$$(dirname $${hdr}); \
+	            cp -f $${hdr} $(2)/$(3)/$$(dirname $${hdr}); \
+	        fi; \
+	    done \
+	fi
+endef
+
+define Update_Extra_Srcs
+( \
+	for ELEM in $(strip $(1)); do \
+	    DST=$(OUTPUT_DIR)/$(2)/$$(basename $${ELEM}); \
+	    if [ $${ELEM} -nt $${DST} ]; then \
+	        cp -Lf $${ELEM} $${DST}; \
+	    fi; \
+	done \
+)
+endef
+
+define Require_Build
+( \
+    [ "$(PKG_SWITCH_$(1))" != "y" ] && \
+        echo "FALSE" && exit; \
+\
+    [ "$(LIBA_TARGET_$(1))" != "" ] && \
+    $(foreach L,$(LIBA_TARGET_$(1)),[ -f $(IMPORT_VDRDIR)/$(PREBUILT_LIBDIR)/$(L) ] && ) \
+            echo "FALSE" && exit; \
+\
+    [ "$(LIBSO_TARGET_$(1))" != "" ] && \
+    [ -f $(IMPORT_VDRDIR)/$(PREBUILT_LIBDIR)/$(LIBSO_TARGET_$(1)) ] && \
+            echo "FALSE" && exit; \
+\
+    echo "TRUE"; \
+)
+endef
+
+define Build_Depends
+( \
+    set -o pipefail && \
+    for i in $(DEPENDS_$(1)); do \
+        STAMP=$(STAMP_DIR)/$$(echo $${i}|$(SED) 's:/:~:g').build.done; \
+        if [ -f $${STAMP} ]; then \
+            continue; \
+        fi; \
+        $(MAKE) --no-print-directory $${i} \
+            $(if $(Q),,2>&1|tee -a $(OUTPUT_DIR)/$${i}/$(COMPILE_LOG)) \
+            $(if $(Q),,2>&1|tee -a $(OUTPUT_DIR)/$(COMPILE_LOG)); \
+        RETVAL=$$?; \
+        if [ $${RETVAL} != 0 ]; then \
+            exit $${RETVAL}; \
+        fi; \
+    done \
+\
+)
+endef
+
+#
+#	    ($(foreach d,$(COMP_LIB_COMPONENTS), \
+#
+#	        $(RECURSIVE_MAKE) pre-build target-$(d) && \
+#	        $(MAKE) --no-print-directory -C $(OUTPUT_DIR)/$(d) $(LIBA_TARGET_$(d)) \
+#	            $(if $(Q),,2>&1|tee -a $(OUTPUT_DIR)/$(d)/$(COMPILE_LOG)) \
+#	            $(if $(Q),,2>&1|tee -a $(OUTPUT_DIR)/$(COMPILE_LOG)) \
+#	        ; \
+#
+#	        if [ $$? != 0 ]; then \
+#
+# KEEP SEPA-LIBS:
+#
+# rm -f $(SYSROOT_LIB)/$(firstword $(LIBA_TARGET_$(d))) $(SYSROOT_LIB)/$(firstword $(LIBSO_TARGET_$(d))) 2>/dev/null; \
+#
+
+ifdef COMP_LIB
+define Build_CompLib
+( \
+    if  [ "$(strip $(1))" = "FORCE" ] || \
+        [ "$$(echo $(LDFLAGS_$(strip $(1)))|grep -wo -- '-l$(COMP_LIB_NAME)')" != "" ]; then \
+    ( \
+        $(foreach d,$(COMP_LIB_COMPONENTS), \
+            [ -f $(STAMP_DIR)/$(subst /,~,$(d)).build.done ] || \
+            set -o pipefail && \
+            $(MAKE) --no-print-directory -C $(OUTPUT_DIR)/$(d) $(firstword $(LIBA_TARGET_$(d))) $(firstword $(LIBSO_TARGET_$(d))) && set +x; \
+            RETVAL=$$?; \
+            if [ $${RETVAL} != 0 ]; then \
+                exit $${RETVAL}; \
+            fi; \
+        ) \
+    ); \
+    if  [ ! -f $(SYSROOT_LIB)/$(COMP_LIB) ]; then \
+        $(call Info_CompLib,$(COMP_LIB_NAME),$(COMP_LIB_OBJS)); \
+    fi; \
+    $(call Finalize_CompLib,$(COMP_LIB_OBJS),$(SYSROOT_LIB),$(COMP_LIB_NAME)); \
+    fi \
+)
+endef
+else
+define Build_CompLib
+true
+endef
+endif

+ 23 - 0
iotkit-embedded/build-rules/hooks/pre-commit

@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed.
+# Called by "git commit" with no arguments.  The hook should
+# exit with non-zero status after issuing an appropriate message if
+# it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-commit".
+
+for i in `git status -s | awk '{ print $NF }'`; do
+    j=$(echo $(basename $i)|cut -d'.' -f2)
+    if [ "$j" = "c" -o "$j" = "h" -o "$j" = "md" -o "$j" = "mk" ]; then
+        if [ "$(find $i -perm /111 2>/dev/null)" != "" ]; then
+            chmod a-x $i
+            echo "[chmod] $i"
+            if [ "$(git status --short $i|cut -c1)" = "M" ]; then
+                git add $i
+            fi
+        fi
+    else
+        echo "[skip ] $i"
+    fi
+done

+ 2426 - 0
iotkit-embedded/build-rules/misc/Doxyfile.tpl

@@ -0,0 +1,2426 @@
+# Doxyfile 1.8.11
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = TBD
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         = TBD
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = .
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
+# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
+
+FILE_PATTERNS          = *.h
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = NO
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: NO.
+
+# CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+# CLANG_OPTIONS          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES

+ 2 - 0
iotkit-embedded/build-rules/misc/config.generic.default

@@ -0,0 +1,2 @@
+CONFIG_ENV_CFLAGS   += -Wall
+CONFIG_ENV_CFLAGS   += --coverage

+ 159 - 0
iotkit-embedded/build-rules/misc/cut.c

@@ -0,0 +1,159 @@
+#include "cut.h"
+
+struct cut_runtime cut;
+
+static void _filter(int argc, char **argv)
+{
+    int i = 0;
+    struct cut_case *c = NULL;
+    if (argc == 2 && 0 == strcmp(argv[1], "all")) {
+        return;
+    }
+
+    for (i = 0; i < cut.ccnt_total; i++) {
+        c = cut.clist[i];
+        if ((argc == 2 && (NULL == strstr(c->sname, argv[1]))) ||
+            (argc == 3 && (NULL == strstr(c->sname, argv[1]) || NULL == strstr(c->cname, argv[2])))) {
+            cut.clist[i]->skip = 1;
+            cut.ccnt_skip++;
+        }
+    }
+}
+
+static void _usage(const char *me)
+{
+    cut_printf("Usage: %s [OPTION] S-FILTER [C-FILTER]\n\n" \
+               "OPTION:\n" \
+               "  --debug:      debug into cases\n" \
+               "  --list:       list cases\n" \
+               "  --count:      print case count\n" \
+               "\n" \
+               "S-FILTER:    suite name filter, e.g. '%s all' means run all suites\n" \
+               "C-FILTER:    case name filter\n", me, me);
+}
+
+static int _debug_opt = 0;
+static int _parse_arg(int argc, char **argv)
+{
+    if (argc >= 2) {
+        if (0 == strcmp(argv[1], "--list")) {
+            int i = 0;
+            int cnt = 0;
+            for (i = 0; i < cut.ccnt_total; i++) {
+                struct cut_case *c = cut.clist[i];
+                if (argc == 2 ||
+                    (argc == 3 && 0 == strcmp(argv[2], "all")) ||
+                    (argc == 3 && NULL != strstr(c->sname, argv[2])) ||
+                    (argc == 4 && NULL != strstr(c->sname, argv[2]) && NULL != strstr(c->cname, argv[3]))) {
+                    cut_printf("  [%02d] %s.%s\n", ++cnt, c->sname, c->cname);
+                }
+            }
+            cut_printf("\n");
+            cut_printf("In total %d case(s), matched %d case(s)\n", cut.ccnt_total, cnt);
+            cut_printf("\n");
+            return 0;
+        }
+        if (0 == strcmp(argv[1], "--count")) {
+            cut_printf("total %d case(s).\n", cut.ccnt_total);
+            return 0;
+        }
+        if (0 == strcmp(argv[1], "--help")) {
+            _usage(argv[0]);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+int cut_main(int argc, char **argv)
+{
+    int         i = 0, j = 0, cnt = 0;
+    char        tmpbuf[128];
+    char       *pos;
+
+    if (0 == _parse_arg(argc, argv)) {
+        return 0;
+    }
+
+    if (argc >= 2 && !strcmp(argv[1], "--debug")) {
+        _debug_opt = 1;
+        argc --;
+        argv ++;
+    }
+
+    _filter(argc, argv);
+
+    for (; i < cut.ccnt_total; i++) {
+        pos = tmpbuf;
+
+        cut.ccur = cut.clist[i];
+        if (cut.ccur->skip) {
+            continue;
+        }
+
+        memset(tmpbuf, 0, sizeof(tmpbuf));
+        pos += cut_snprintf(pos,
+                            sizeof(tmpbuf),
+                            "TEST [%02d/%02d] %s.%s ",
+                            ++cnt,
+                            cut.ccnt_total - cut.ccnt_skip,
+                            cut.ccur->sname,
+                            cut.ccur->cname);
+        for (j = 80 - strlen(tmpbuf); j >= 0; --j) {
+            pos += sprintf(pos, "%s", ".");
+        }
+        if (_debug_opt) {
+            pos += sprintf(pos, " [%sEXEC%s]\n", COL_YEL, COL_DEF);
+            cut_printf("%s", tmpbuf);
+            pos -= 19;
+        }
+        TRY {
+            if (cut.ccur->setup)
+            {
+                cut.ccur->setup(cut.ccur->data);
+            }
+            cut.ccur->run((struct cut_case *)(cut.ccur->data));
+            if (cut.ccur->teardown)
+            {
+                cut.ccur->teardown(cut.ccur->data);
+            }
+
+            pos += sprintf(pos, " [%sSUCC%s]\n", COL_GRE, COL_DEF);
+            cut_printf("%s", tmpbuf);
+
+            cut.ccnt_pass++;
+            continue;
+        }
+        EXCEPT {
+
+            pos += sprintf(pos, " [%sFAIL%s]\n", COL_RED, COL_DEF);
+            cut_printf("%s", tmpbuf);
+
+            cut.ccnt_fail++;
+            continue;
+        }
+    }
+
+    cut_printf("===========================================================================\n");
+    if (cut.ccnt_fail > 0) {
+        cut_printf("FAIL LIST:\n");
+        for (i = 0; i < cut.ccnt_fail; i++) {
+            cut_printf("  [%02d] %s\n", i + 1, cut.cerrmsg[i]);
+            cut_free(cut.cerrmsg[i]);
+        }
+        cut_printf("---------------------------------------------------------------------------\n");
+    }
+    cut_printf("SUMMARY:\n" \
+               "     TOTAL:    %d\n" \
+               "   SKIPPED:    %d\n" \
+               "   MATCHED:    %d\n" \
+               "      PASS:    %d\n" \
+               "    FAILED:    %d\n", cut.ccnt_total, cut.ccnt_skip,
+               cut.ccnt_total - cut.ccnt_skip, cut.ccnt_pass, cut.ccnt_fail);
+    cut_printf("===========================================================================\n");
+
+    return cut.ccnt_fail;
+
+}
+

+ 247 - 0
iotkit-embedded/build-rules/misc/cut.h

@@ -0,0 +1,247 @@
+#ifndef __CUT_H__
+#define __CUT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <string.h>
+#include <assert.h>
+
+#define CUT_CASE_MAX_CNT        (200)
+#define CUT_MSG_MAX_LEN         (256)
+
+#define cut_printf              printf
+#define cut_snprintf            snprintf
+#define cut_malloc              malloc
+#define cut_free                free
+
+extern int cut_main(int argc, char **argv);
+extern struct cut_runtime cut;
+
+struct cut_case {
+    const char *sname;
+    const char *cname;
+    void *data;
+    void (*run)(void *);
+    void (*setup)(void *);
+    void (*teardown)(void *);
+    int skip;
+};
+
+struct cut_runtime {
+    jmp_buf jmpbuf;
+    int     scnt_total;
+    int     ccnt_total;
+    int     ccnt_pass;
+    int     ccnt_fail;
+    int     ccnt_skip;
+    struct  cut_case *clist[CUT_CASE_MAX_CNT];
+    struct  cut_case *ccur;
+    char    *cerrmsg[CUT_CASE_MAX_CNT];
+};
+
+#define CUT_CASE_RUNNER(sname, cname)  cut_##sname##_##cname##_run
+#define CUT_CASE_NAME(sname, cname)    cut_##sname##_##cname
+#define CUT_CASE_DATA(sname)           cut_##sname##_data
+#define CUT_CASE_SETUP(sname)          cut_##sname##_setup
+#define CUT_CASE_TEARDOWN(sname)       cut_##sname##_teardown
+
+#define DATA(sname) \
+    struct CUT_CASE_DATA(sname)
+
+#define SETUP(sname) \
+    static void CUT_CASE_SETUP(sname)(struct CUT_CASE_DATA(sname) *data)
+
+#define TEARDOWN(sname) \
+    static void CUT_CASE_TEARDOWN(sname)(struct CUT_CASE_DATA(sname) *data)
+
+
+/*
+ * @brief: construct a test case structor and a test case runner
+ * @sname: suite name
+ * @cname: case name
+ * e.g.
+    CASE(mysuite, mycase1) {
+        // do something here
+        ASSERT_TRUE(1);
+    }
+ */
+#define CASE(sname, cname) \
+    static void CUT_CASE_RUNNER(sname, cname)(void *null); \
+    static struct cut_case CUT_CASE_NAME(sname, cname) = \
+            { \
+              #sname, #cname, NULL, CUT_CASE_RUNNER(sname, cname), NULL, NULL, 0}; \
+    static void CUT_CASE_RUNNER(sname, cname)(void *null)
+
+/*
+ * @brief: construct a test case structor and a test case runner
+ *         with case_data/setup/teardown for each case.
+ * @sname: suite name
+ * @cname: case name
+ * e.g.
+    CASE_DATA(mysuite) {
+        int errmsg;
+        char *errcode;
+    };
+
+    CASE_SETUP(mysuite) {
+        data->errcode = 0;
+        data->errmsg = (char*)malloc(100);
+    }
+
+    CASE_TEARDOWN(mysuite) {
+        if(data->errmsg) {
+            free(data->errmsg);
+            data->errmsg = NULL;
+        }
+    }
+
+    CASEs(mysuite, mycase1) {
+        data->errcode = 1;
+        strcpy(data->errmsg, "timeout error");
+        ASSERT_TRUE(1);
+    }
+ */
+#define CASEs(sname, cname)                                                        \
+    static struct CUT_CASE_DATA(sname) CUT_CASE_DATA(sname);                       \
+    static void CUT_CASE_RUNNER(sname, cname)(struct CUT_CASE_DATA(sname) * data); \
+    static struct cut_case CUT_CASE_NAME(sname, cname) = \
+            { \
+              #sname, #cname, &CUT_CASE_DATA(sname), (void(*)(void*))CUT_CASE_RUNNER(sname, cname),      \
+              (void(*)(void*))CUT_CASE_SETUP(sname), (void(*)(void*))CUT_CASE_TEARDOWN(sname), 0}; \
+    \
+    static void CUT_CASE_RUNNER(sname, cname)(struct CUT_CASE_DATA(sname) * data)
+
+/*
+ * @brief: construct a test suite by adding test case(s)
+ * @sname: suite name
+ * e.g.
+    SUITE(mysuite) = {
+        ADD_CASE(mysuite, mycase1),
+        ADD_CASE(mysuite, mycase2),
+        ADD_CASE_NULL
+    };
+ */
+#define SUITE(sname) struct cut_case *cut_suite_##sname[]
+
+/*
+ * @brief: add a test case into a test suite
+ * @sname: suite name
+ * @cname: case name
+ */
+#define ADD_CASE(sname, cname)   &CUT_CASE_NAME(sname, cname)
+#define ADD_CASE_NULL            (struct cut_case*)(NULL)
+
+/*
+ * @brief: add a test suite into case list
+ * @sname: suite name
+ */
+#define ADD_SUITE(sname)                                  \
+    do {                                                  \
+        int i = 0;                                        \
+        extern struct cut_case *cut_suite_##sname[];      \
+        struct cut_case *c = cut_suite_##sname[i];        \
+        if (cut.ccnt_total >= CUT_CASE_MAX_CNT) {         \
+            cut_printf("reaches maximum case count:%d\n", \
+                       CUT_CASE_MAX_CNT);                 \
+            break;                                        \
+        }                                                 \
+        while (c) {                                       \
+            *(cut.clist + cut.ccnt_total++) = c;          \
+            c = *(cut_suite_##sname + (++i));             \
+        }                                                 \
+    } while (0)
+
+
+#define TRY                if (0 == setjmp(cut.jmpbuf))
+#define EXCEPT             else
+#define RAISE_EXCEPTION_WITH_MSG(msg)                          \
+    do {                                                       \
+        int ret = 0, i = cut.ccnt_fail;                        \
+        cut.cerrmsg[i] = (char*)cut_malloc(CUT_MSG_MAX_LEN);   \
+        assert(cut.cerrmsg[i] != NULL);                        \
+        memset(cut.cerrmsg[i], 0, CUT_MSG_MAX_LEN);            \
+        ret = cut_snprintf(cut.cerrmsg[i],                     \
+                           CUT_MSG_MAX_LEN - 1,                \
+                           "%s.%s in %s(%d) expected %s",      \
+                           cut.ccur->sname, cut.ccur->cname,   \
+                           __FILE__, __LINE__, msg);           \
+        if (ret >= CUT_MSG_MAX_LEN)                            \
+            cut_snprintf(cut.cerrmsg[i] + CUT_MSG_MAX_LEN - 4, \
+                         4, "...");                            \
+        longjmp(cut.jmpbuf, 1);                                \
+    } while (0)
+
+#define ASSERT_TRUE(cond)                       \
+    do {                                        \
+        if (!(cond))                            \
+            RAISE_EXCEPTION_WITH_MSG("[True]"); \
+    } while (0)
+
+#define ASSERT_INT(expected, compare, actual)                                     \
+    do {                                                                          \
+        if (!((expected)compare(actual)))                                         \
+            RAISE_EXCEPTION_WITH_MSG("[" #expected " " #compare " " #actual "]"); \
+    } while (0)
+
+#define ASSERT_STR(expected, compare, actual)                                     \
+    do {                                                                          \
+        if (!(strcmp((expected), (actual)) compare 0))                            \
+            RAISE_EXCEPTION_WITH_MSG("[" #expected " " #compare " " #actual "]"); \
+    } while (0)
+
+#define ASSERT_IN(expected1, actual, expected2)                                       \
+    do {                                                                              \
+        if ((actual) < (expected1) || (actual) > (expected2))                         \
+            RAISE_EXCEPTION_WITH_MSG("[" #expected1 " <= " #actual " <= " #expected2 "]"); \
+    } while (0)
+
+#define ASSERT_NSTR(expected, compare, actual, len)                                     \
+    do {                                                                          \
+        if (!(strncmp((expected), (actual), (len)) compare 0))                            \
+            RAISE_EXCEPTION_WITH_MSG("[" #expected " " #compare " " #actual "]"); \
+    } while (0)
+
+
+#define ASSERT_FAIL()                               RAISE_EXCEPTION_WITH_MSG("[should not be here]")
+#define ASSERT_FALSE(cond)                          ASSERT_TRUE(!(cond))
+#define ASSERT_NULL(ptr)                            ASSERT_INT(ptr, ==, NULL)
+#define ASSERT_NOT_NULL(ptr)                        ASSERT_INT(ptr, !=, NULL)
+#define ASSERT_EQ(actual, expected)                 ASSERT_INT(actual, ==, expected)
+#define ASSERT_NE(actual, expected)                 ASSERT_INT(actual, !=, expected)
+#define ASSERT_GT(actual, expected)                 ASSERT_INT(actual,  >, expected)
+#define ASSERT_GE(actual, expected)                 ASSERT_INT(actual, >=, expected)
+#define ASSERT_LT(actual, expected)                 ASSERT_INT(actual,  <, expected)
+#define ASSERT_LE(actual, expected)                 ASSERT_INT(actual, <=, expected)
+#define ASSERT_STR_EQ(actual, expected)             ASSERT_STR(actual, ==, expected)
+#define ASSERT_STR_NE(actual, expected)             ASSERT_STR(actual, !=, expected)
+#define ASSERT_STR_GT(actual, expected)             ASSERT_STR(actual,  >, expected)
+#define ASSERT_STR_LT(actual, expected)             ASSERT_STR(actual,  <, expected)
+#define ASSERT_NSTR_EQ(actual, expected, len)       ASSERT_NSTR(actual, ==, expected, len)
+#define ASSERT_NSTR_NE(actual, expected, len)       ASSERT_NSTR(actual, !=, expected, len)
+#define ASSERT_NSTR_GT(actual, expected, len)       ASSERT_NSTR(actual,  >, expected, len)
+#define ASSERT_NSTR_LT(actual, expected, len)       ASSERT_NSTR(actual,  <, expected, len)
+
+/*
+ * see http://stackoverflow.com/questions/3585846/color-text-in-terminal-applications-in-unix
+ */
+#define COL_DEF "\x1B[0m"
+#define COL_RED "\x1B[1;31m"
+#define COL_GRE "\x1B[1;32m"
+#define COL_YEL "\x1B[1;33m"
+#define COL_BLU "\x1B[1;34m"
+#define COL_MAG "\x1B[1;35m"
+#define COL_CYN "\x1B[1;36m"
+#define COL_WHE "\x1B[1;37m"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUT_H__ */
+

+ 194 - 0
iotkit-embedded/build-rules/pre-build.sh

@@ -0,0 +1,194 @@
+#! /bin/bash
+if [ "$(uname)" = "Darwin" ]; then
+    SED=gsed
+else
+    SED=sed
+fi
+
+function Trace()
+{
+    if [ "${VERBOSE_PRE_BLD}" != "" ]; then
+        echo "$1" 1>&2
+    fi
+}
+
+function Update_Sources()
+{
+    if [ -f ${BLD_DIR}/${STAMP_UNPACK} ]; then
+        Trace "Skipped @ ${BLD_DIR}/${STAMP_UNPACK}"
+        return 0
+    fi
+    if [ "${PKG_SWITCH}" = "" ]; then
+        Trace "Warning @ CONFIG_${MODULE} = '${PKG_SWITCH}'"
+    fi
+
+    Trace "MODULE_NAME:     [${MODULE}]"
+    Trace "SRC_DIR:         [${SRC_DIR}]"
+    Trace "BLD_DIR:         [${BLD_DIR}]"
+    Trace "PACKAGE_DIR:     [${PACKAGE_DIR}]"
+    Trace "PKG_SOURCE:      [${PKG_SOURCE}]"
+    Trace "PKG_BRANCH:      [${PKG_BRANCH}]"
+    Trace "PKG_REVISION:    [${PKG_REVISION}]"
+    Trace "PKG_UPSTREAM:    [${PKG_UPSTREAM}]"
+
+    for i in $(find -L ${MODULE} -type d -not -path "*.git*"|${SED} "s:${MODULE}/*::1"|${SED} '/^$/d'); do
+        mkdir -p ${BLD_DIR}/${i}
+    done
+
+    if [ "${PKG_SOURCE}" != "" ] && [ -d ${PACKAGE_DIR}/${PKG_SOURCE} ]; then
+        GIT_BASENAME=$(basename ${PKG_SOURCE})
+        GIT_NAME_LEN=$(echo -n "${GIT_BASENAME}"|wc -c|awk '{ print $1 }')
+        GIT_OFFSET=$(( GIT_NAME_LEN - 3 ))
+        GIT_MOD_NAME=$(echo "${GIT_BASENAME}" | cut -c"1-$(( GIT_OFFSET-1 ))"|awk '{ print $1 }')
+        GIT_POSTFIX=$(echo "${GIT_BASENAME}" | cut -c"${GIT_OFFSET}-${GIT_NAME_LEN}"|awk '{ print $1 }')
+        Trace "GIT_POSTFIX:     [${GIT_POSTFIX}]"
+        Trace "GIT_MOD_NAME:    [${GIT_MOD_NAME}]"
+    fi
+    set +x
+
+    if [ "${GIT_POSTFIX}" = ".git" ]; then
+        GIT_COPY=${MODULE}/${GIT_MOD_NAME}
+        DEV_COPY_BASE=${TOP_DIR}.pkgs
+        Trace "GIT_COPY:        [${GIT_COPY}]"
+        Trace "DEV_COPY_BASE:   [${DEV_COPY_BASE}]"
+
+        eval "${CMDSET_X}"
+        mkdir -p ${DEV_COPY_BASE}
+        cd ${DEV_COPY_BASE}
+        if [ ! -d ${GIT_MOD_NAME} ]; then
+            git clone ${OPTION_Q} ${PACKAGE_DIR}/${PKG_SOURCE} ${GIT_MOD_NAME} \
+                $([ "${PKG_BRANCH}" = "" ] || echo "-b ${PKG_BRANCH}")
+            if [ "${PKG_UPSTREAM}" != "" ]; then
+                cd ${GIT_MOD_NAME};
+                git remote add upstream ${PKG_UPSTREAM}
+                cd ${OLDPWD};
+            fi
+        fi
+
+        if [ "${PKG_REVISION}" != "" ]; then
+            cd ${GIT_MOD_NAME} && git reset ${OPTION_Q} --hard ${PKG_REVISION} && cd ${OLDPWD}
+        else
+            cd ${GIT_MOD_NAME}
+            git pull ${OPTION_Q} origin ${PKG_BRANCH} || exit 1
+        fi
+
+        cd ${TOP_DIR}
+        rm -fr ${SRC_DIR}/${GIT_MOD_NAME}
+        ln -sf ${DEV_COPY_BASE}/${GIT_MOD_NAME} ${SRC_DIR}/${GIT_MOD_NAME}
+        touch ${BLD_DIR}/${STAMP_UNPACK}
+        PKG_SOURCE=""
+        set +x
+
+        SRC_ELEM=$(ls ${SRC_DIR}|grep -v ${HD_MAKEFILE}|grep -v ${MAKE_SEGMENT})
+        BLD_ELEM=$(ls ${BLD_DIR}|grep -v ${HD_MAKEFILE}|grep -v ${MAKE_SEGMENT})
+        if [ "${BLD_ELEM}" = "" ]; then
+            for iter in ${SRC_ELEM}; do
+                Trace "Bulk [${SRC_DIR}/${iter} => ${BLD_DIR}"
+#                cp -Lrf ${SRC_DIR}/${iter} ${BLD_DIR}
+            done
+            return 0
+        fi
+    fi
+
+#    for FILE in \
+#        $(find -L ${SRC_DIR}/ -type f -o -type l -name "*.[ch]" -o -name "*.mk" -o -name "*.cpp") \
+#        $(find ${SRC_DIR}/ -maxdepth 1 -name "*.patch" -o -name "lib*.a" -o -name "lib*.so") \
+#        $([ "" != "${PKG_SOURCE}" ] && [ -d ${PACKAGE_DIR}/${PKG_SOURCE} ] && find ${PACKAGE_DIR}/${PKG_SOURCE}/ -type f -o -type l) \
+#    ; \
+#    do
+#        if  [ "" != "${PKG_SOURCE}" ] && \
+#            [ -d ${PKG_SOURCE} ] && \
+#            [ "$(dirname ${FILE})" != "${TOP_DIR}/${MODULE}" ]; then
+#            SUBD=$(echo $(dirname ${FILE})|${SED} "s:$(dirname ${PKG_SOURCE})::")
+#            SUBD=$(echo ${SUBD}|${SED} "s:${SRC_DIR}::")
+#        else
+#            SUBD=$(echo $(dirname ${FILE})|${SED} "s:${SRC_DIR}::")
+#            SUBD=$(echo ${SUBD}|${SED} "s:${PACKAGE_DIR}/*::")
+#        fi
+#
+#        COPY_DIR=${OUTPUT_DIR}/${MODULE}/${SUBD}
+#        mkdir -p ${COPY_DIR}
+#        COPY_BASE=$(basename ${FILE})
+#        FILE_COPY=${COPY_DIR}/${COPY_BASE}
+#        # grep -q "\.git" <<< ${FILE} || Trace "Check: ${FILE}: ${FILE_COPY}"
+#
+#        if [ ! -e ${FILE_COPY} -o \
+#             ${FILE} -nt ${FILE_COPY} ]; then
+#             mkdir -p ${BLD_DIR}/${FILE_DIR}
+#             cp -f ${FILE} ${FILE_COPY}
+#        fi
+#    done
+
+}
+
+function Update_Makefile()
+{
+    BLD_MFILE=${BLD_DIR}/${HD_MAKEFILE}
+
+    if  [ ${BLD_MFILE} -nt ${SRC_DIR}/${MAKE_SEGMENT} ] && \
+        [ ${BLD_MFILE} -nt ${STAMP_BLD_ENV} ]; then
+        return 0;
+    fi
+
+    rm -f ${BLD_MFILE}
+
+    echo "MODULE_NAME := ${MODULE}" >> ${BLD_MFILE}
+    cat ${STAMP_BLD_ENV} >> ${BLD_MFILE}
+
+    cat << EOB >> ${BLD_MFILE}
+
+include \$(RULE_DIR)/settings.mk
+include \$(CONFIG_TPL)
+
+all:
+
+EOB
+
+    cp -f ${SRC_DIR}/${MAKE_SEGMENT} ${BLD_DIR}/${MAKE_SEGMENT}
+
+    cat ${BLD_DIR}/${MAKE_SEGMENT} >> ${BLD_MFILE}
+    ${SED} -i 's/clean:/clean : clean-prepare/g' ${BLD_MFILE}
+
+    cat << EOB >> ${BLD_MFILE}
+
+env:
+	@echo ""
+	@printf -- "-----------------------------------------------------------------\n"
+	@\$(foreach var,\$(SHOW_ENV_VARS),\$(call Dump_Var,\$(var)))
+	@printf -- "-----------------------------------------------------------------\n"
+	@echo ""
+
+include \$(RULE_DIR)/rules.mk
+EOB
+
+    Trace "Updated: ${BLD_MFILE}"
+}
+
+if [ "$#" != "1" -a "$#" != "2" ]; then exit 12; fi
+
+MODULE=${1}
+BLD_DIR=${OUTPUT_DIR}/${MODULE}
+SRC_DIR=${TOP_DIR}/${MODULE}
+
+if [ ! -d ${SRC_DIR} ]; then
+    exit 0
+fi
+
+if [ "${VERBOSE_PRE_BLD}" != "" ]; then
+    OPTION_V="-v"
+    CMDSET_X="set -x"
+else
+    OPTION_Q="-q"
+fi
+
+mkdir -p ${BLD_DIR}
+
+MSG=$(printf "%-28s%s" "${MODULE}" "[..]")
+echo -ne "\r                                                    "
+echo -ne "\033[0;37;0;44m""\r[..] o ${MSG}""\033[0;m"
+Trace ""
+
+if [ "$#" = "1" ]; then
+    Update_Sources
+fi
+Update_Makefile

+ 173 - 0
iotkit-embedded/build-rules/rules.mk

@@ -0,0 +1,173 @@
+include  $(RULE_DIR)/settings.mk
+sinclude $(CONFIG_TPL)
+include  $(RULE_DIR)/funcs.mk
+
+TOPDIR_NAME     := $(shell $(SHELL_DBG) basename $(TOP_DIR)|grep -m 1 -o \[-_a-zA-Z\]*[a-zA-Z])
+LIBOBJ_TMPDIR   := $(OUTPUT_DIR)/lib$(TOPDIR_NAME).objs
+
+SYSROOT_BIN     := $(OUTPUT_DIR)${bindir}
+SYSROOT_INC     := $(OUTPUT_DIR)${incdir}
+SYSROOT_LIB     := $(OUTPUT_DIR)${libdir}
+CONFIG_VENDOR   := $(shell grep -m 1 "VENDOR *:" $(CONFIG_TPL) 2>/dev/null|awk '{ print $$NF }')
+IMPORT_VDRDIR   := $(IMPORT_DIR)/$(CONFIG_VENDOR)
+
+HOST_ARCH_BITS  := $(shell [ "$$(uname -m)" = "x86_64" ] && echo -n "64" || echo -n "32")
+PREBUILT_LIBDIR := $(if $(strip $(filter 64,$(HOST_ARCH_BITS)) $(CROSS_PREFIX)),libs,32bit-libs)
+PREBUILT_BINDIR := $(if $(strip $(filter 64,$(HOST_ARCH_BITS)) $(CROSS_PREFIX)),bin,32bit-bin)
+
+CONFIG_VSP_WEBSITE  ?= http://gitlab.alibaba-inc.com/yusheng.yx/alink-vendor-support-package
+
+ifeq ($(shell uname), Linux)
+RPATH_CFLAGS    += -Wl,-rpath='$$''ORIGIN/../lib'
+endif
+
+# CFLAGS contains '$' causes ./configure failure in ORIGIN packages
+#
+# Instead of:
+#
+# ifeq ($(shell uname), Linux)
+# CFLAGS += -Wl,-rpath='$$''ORIGIN/../lib'
+# CFLAGS := $(sort $(CFLAGS))
+# endif
+#
+# Write @ package's makefile:
+#
+# ./configure \
+#     CFLAGS='$(CFLAGS) -Wl,-rpath='\''$$$$'\''ORIGIN/../lib' \
+#     --prefix=...
+#
+# To pass in RPATH related link flags
+
+COMP_LIB_NAME   := $(subst lib,,$(subst .so,,$(subst .a,,$(COMP_LIB))))
+COMP_LIB_OBJS    = $(foreach d,$(COMP_LIB_COMPONENTS),$(LIBOBJ_TMPDIR)/$(d)/*.o)
+RECURSIVE_MAKE  := $(MAKE) $(if $(TOP_Q),-s) -C $(TOP_DIR) -f $(TOP_MAKEFILE)
+ALL_SUB_DIRS    := $(shell find -L $(TOP_DIR) ! -path "$(OUTPUT_DIR)/*" -name "$(MAKE_SEGMENT)" 2>/dev/null \
+                           | $(SED) 's:$(TOP_DIR)[/]*::;s:[/]*$(MAKE_SEGMENT)::')
+
+SHOW_ENV_VARS   := \
+    MODULE_NAME SUBDIRS PKG_NAME PKG_RPATH PKG_SOURCE PKG_SWITCH_V PKG_SWITCH \
+    HOST_ARCH_BITS PREBUILT_LIBDIR RPATH_CFLAGS \
+    CROSS_PREFIX DEPENDS CFLAGS CCLD LDFLAGS \
+    CC LD AR STRIP OBJCOPY COMP_LIB COMP_LIB_COMPONENTS \
+    MAKE_ENV_VARS DEFAULT_BLD \
+    LIBA_TARGET LIBSO_TARGET TARGET KMOD_TARGET \
+    SRCS OBJS LIB_SRCS LIB_OBJS LIB_HDRS_DIR LIB_HEADERS EXTRA_SRCS \
+    $(foreach M,$(LIBA_TARGET),LIB_SRCS_$(subst .a,,$(subst lib,,$(M)))) \
+    INTERNAL_INCLUDES TOP_DIR PRJ_NAME PRJ_VERSION \
+    IMPORT_DIR IMPORT_VDRDIR CONFIG_DIR PACKAGE_DIR EXTERNAL_INCLUDES \
+    CONFIG_LIB_EXPORT OBJCOPY_FLAGS CONFIG_VENDOR COVERAGE_PROGS COVERAGE_CMD \
+
+ifndef CONFIG_LIB_EXPORT
+ifeq (y,$(strip $(CONFIG_EMB_GATEWAY_SDK)))
+CONFIG_LIB_EXPORT := dynamic
+else
+ifeq (y,$(strip $(CONFIG_EMB_BASIC_SDK)))
+CONFIG_LIB_EXPORT := static
+else
+ifeq (y,$(strip $(CONFIG_EMB_ROUTER_SDK)))
+CONFIG_LIB_EXPORT := dynamic
+endif # ROUTER
+endif # BASIC
+endif # GATEWAY
+else
+ifneq (static,$(CONFIG_LIB_EXPORT))
+ifneq (dynamic,$(CONFIG_LIB_EXPORT))
+$(error CONFIG_LIB_EXPORT($(CONFIG_LIB_EXPORT)) is neither 'static' or 'dynamic')
+endif # dynamic
+endif # static
+endif # CONFIG_LIB_EXPORT
+
+ifneq (,$(shell ls $(STAMP_BLD_VAR) 2>/dev/null))
+ifeq (,$(filter reconfig distclean,$(MAKECMDGOALS)))
+ifeq (0,$(strip $(shell $(SED) '/[-_/a-zA-Z0-9]* = ..*/d' $(STAMP_BLD_VAR)|wc -l)))
+include $(STAMP_BLD_VAR)
+endif
+endif
+endif
+
+.PHONY: all clean FORCE
+
+ifdef SUBDIRS
+include $(RULE_DIR)/_rules-top.mk
+include $(RULE_DIR)/_rules-prefix.mk
+include $(RULE_DIR)/_rules-repo.mk
+
+CROSS_CANDIDATES := CC CXX AR LD STRIP OBJCOPY
+export CC       := $(if $(OVERRIDE_CC),     $(OVERRIDE_CC),     $(CROSS_PREFIX)gcc)
+export CXX      := $(if $(OVERRIDE_CXX),    $(OVERRIDE_CXX),    $(CROSS_PREFIX)g++)
+export AR       := $(if $(OVERRIDE_AR),     $(OVERRIDE_AR),     $(CROSS_PREFIX)ar)
+export LD       := $(if $(OVERRIDE_LD),     $(OVERRIDE_LD),     $(CROSS_PREFIX)ld)
+export OBJCOPY  := $(if $(OVERRIDE_OBJCOPY),$(OVERRIDE_OBJCOPY),$(CROSS_PREFIX)objcopy)
+
+ifneq (,$(OVERRIDE_STRIP))
+export STRIP    := $(OVERRIDE_STRIP)
+else
+ifneq (,$(CROSS_PREFIX))
+export STRIP    := $(CROSS_PREFIX)strip
+else
+export STRIP    := true
+endif
+endif
+
+ifeq (gcc,$(strip $(CC)))
+export STRIP    := strip
+endif
+
+ifneq (,$(filter -m32,$(strip $(CFLAGS))))
+PREBUILT_LIBDIR := 32bit-libs
+PREBUILT_BINDIR := 32bit-bin
+endif
+
+include $(RULE_DIR)/_rules-dist.mk
+include $(RULE_DIR)/_rules-complib.mk
+include $(RULE_DIR)/_rules-submods.mk
+
+env:
+	$(Q)echo ""
+	$(Q)printf -- "-----------------------------------------------------------------\n"
+	$(Q)$(foreach var,$(SHOW_ENV_VARS),$(call Dump_Var,$(var)))
+	$(Q)printf -- "-----------------------------------------------------------------\n"
+	$(Q)echo ""
+
+else    # ifdef SUBDIRS
+
+PKG_RPATH   := $(shell echo $(CURDIR)|$(SED) 's:$(OUTPUT_DIR)/*::g')
+PKG_NAME    ?= $(shell basename $(CURDIR))
+PKG_SOURCE  ?= $(shell [ -d $(PACKAGE_DIR) ] && find $(PACKAGE_DIR) -name "$(PKG_NAME)*" | head -1)
+
+DEPENDS     += $(DEPENDS_$(MODULE_NAME))
+DEPENDS     := $(sort $(strip $(DEPENDS)))
+
+ifdef CONFIG_SWITCH
+PKG_SWITCH_V = $(CONFIG_SWITCH)
+else
+PKG_SWITCH_V := CONFIG_$(PKG_RPATH)
+endif
+PKG_SWITCH = $($(PKG_SWITCH_V))
+
+ifdef ORIGIN
+
+include $(RULE_DIR)/_rules-origin.mk
+
+else    # ifdef ORIGIN
+
+ifneq (,$(filter -m32,$(strip $(CFLAGS))))
+PREBUILT_LIBDIR := 32bit-libs
+PREBUILT_BINDIR := 32bit-bin
+endif
+
+include $(RULE_DIR)/_rules-flat.mk
+
+endif   # ifdef ORIGIN
+
+include $(RULE_DIR)/_rules-modinfo.mk
+
+endif   # ifdef SUBDIRS
+
+sinclude $(STAMP_POST_RULE)
+
+ifdef UTEST_PROG
+COVERAGE_LIST += \"./$(strip $(UTEST_PROG) --list)\"
+COVERAGE_LIST += \"./$(strip $(UTEST_PROG))\"
+include $(RULE_DIR)/_rules-coverage.mk
+endif

+ 40 - 0
iotkit-embedded/build-rules/scripts/add_license.sh

@@ -0,0 +1,40 @@
+#! /bin/bash
+
+TEXT=(
+    "Copyright (c) 2014-2016 Alibaba Group. All rights reserved."
+    "License-Identifier: Apache-2.0"
+    ""
+    "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."
+    ""
+)
+
+TOTAL_LINE=${#TEXT[@]}
+i=$(( TOTAL_LINE - 1 ))
+
+sed -i "1i\ */" $1
+while (( i >= 0 )); do
+    j=$(eval echo '${TEXT['$i']}')
+
+    if [ "$j" = "" ]; then
+        sed -i "1i\ *" $1
+    else
+        if [ "$(echo $j|awk '{ print NF }')" = "1" ] && [ "$(echo $j | cut -c1-7)" = "http://" ]; then
+            sed -i "1i\ *    $j" $1
+        else
+            sed -i "1i\ * $j" $1
+        fi
+    fi
+
+    i=$(( i - 1 ))
+done
+sed -i "1i\/*" $1

+ 10 - 0
iotkit-embedded/build-rules/scripts/del_license.sh

@@ -0,0 +1,10 @@
+#! /bin/bash
+
+START_LINE=$(head -3 $1|grep -n '^ *\/\*'|cut -d':' -f1)
+END_LINE=$(grep -m 1 -n '^ *\*\/' $1|cut -d':' -f1)
+echo "[${START_LINE},${END_LINE}]"
+
+if [ "${START_LINE}" != "" ] && [ "${END_LINE}" != "" ]; then
+    sed -i "${START_LINE},${END_LINE}d" $1
+    echo "LICENSE REMOVED: $1"
+fi

+ 25 - 0
iotkit-embedded/build-rules/scripts/exe_coverage_progs.sh

@@ -0,0 +1,25 @@
+#! /bin/bash
+set -e
+
+if [ "${OUTPUT_DIR}" = "" ] || [ ! -d ${OUTPUT_DIR} ]; then exit 1; fi
+
+cd ${OUTPUT_DIR}/usr/bin
+
+echo ""
+
+iter=0
+while (( iter < ${#PROGS[@]} )); do
+    UT_CMD=$(eval echo '${PROGS['${iter}']}')
+    UT_PROG=$(echo ${UT_CMD}|cut -d' ' -f1)
+
+    echo "[${iter}] RUNNING '${UT_CMD}' with '${UT_PROG}'"|grep --color ".*"
+    echo ""
+
+    if [ -f ${UT_PROG} ]; then
+        ${UT_CMD}
+    else
+        echo "${UT_CMD} SPECIFIED BUT ${UT_PROG} NOT FOUND"|grep --color ".*"
+    fi
+
+    iter=$(( iter + 1 ))
+done

+ 82 - 0
iotkit-embedded/build-rules/scripts/gen_lcov_report.sh

@@ -0,0 +1,82 @@
+#! /bin/bash
+set -e
+
+if [ $# != 1 ]; then exit 1; fi
+if [ "$(uname)" = "Darwin" ]; then
+    SED=gsed
+else
+    SED=sed
+fi
+
+LCOV_DIR=$1
+SRC_NAME_LENGTH=28
+DIR_NAME_LENGTH=16
+COVERAGE_HIGH=90
+COVERAGE_MID=75
+
+echo ""
+echo "Processing [${LCOV_DIR}] for Coverage Brief"
+echo ""
+#
+#      sdk-example / example.c               : [100.00%]  (7/7)            [100.00%]  (1/1)
+#
+echo -ne "\033[1;36m"
+printf "%${DIR_NAME_LENGTH}s   %-${SRC_NAME_LENGTH}s: %-24s %-20s\n\n" \
+    "Directory" \
+    "Source File" \
+    "Line Coverage" \
+    "Function Coverage"
+echo -ne "\033[0m"
+
+REPORT_LIST=$(find ${LCOV_DIR} -mindepth 2 -name "index.html")
+for R in ${REPORT_LIST}; do
+    SOURCE_LIST=$(grep "coverFile" ${R} | awk -F '<' '{ print $3 }' | cut -d'>' -f2)
+    for S in ${SOURCE_LIST}; do
+        STATS=$(grep -A 7 "${S}</a>" ${R} | ${SED} -n '6p;8p'|grep -o -E '[0-9]+')
+        DIR_NAME=$(echo "$(dirname ${R}|xargs basename)" | cut -c1-15)
+        SRC_NAME=$(echo "${S}" | cut -c"1-$(( SRC_NAME_LENGTH -1 ))")
+        COVER_LINE=$(echo ${STATS}|cut -d' ' -f1)
+        TOTAL_LINE=$(echo ${STATS}|cut -d' ' -f2)
+        COVER_FUNC=$(echo ${STATS}|cut -d' ' -f3)
+        TOTAL_FUNC=$(echo ${STATS}|cut -d' ' -f4)
+
+        LINE_PERCENT="$(echo "scale=2; ${COVER_LINE} * 100 / ${TOTAL_LINE}"|bc -l)%"
+        FUNC_PERCENT="$(echo "scale=2; ${COVER_FUNC} * 100 / ${TOTAL_FUNC}"|bc -l)%"
+
+        printf \
+            "%-8s %${DIR_NAME_LENGTH}s / %-${SRC_NAME_LENGTH}s: [ %s ] (%s/%s) \t [ %s ] (%s/%s)\n" \
+            ${LINE_PERCENT} \
+            ${DIR_NAME} \
+            ${SRC_NAME} \
+            ${LINE_PERCENT} \
+            ${COVER_LINE} \
+            ${TOTAL_LINE} \
+            ${FUNC_PERCENT} \
+            ${COVER_FUNC} \
+            ${TOTAL_FUNC}
+    done
+done \
+    | sort -nr \
+    | cut -d' ' -f2- \
+    | awk -v SRC_LEN=${SRC_NAME_LENGTH} -v DIR_LEN=${DIR_NAME_LENGTH} \
+          -v HIGH=${COVERAGE_HIGH} -v MID=${COVERAGE_MID} \
+            '{
+                split($6, arr, ".");
+
+                if (arr[1] >= HIGH)
+                    printf("\033[1;32m");
+                else if (arr[1] >= MID)
+                    printf("\033[1;35m");
+                else
+                    printf("\033[1;31m");
+
+                printf("%" DIR_LEN "s / %-" SRC_LEN "s: [ %-8s] %-12s [ %-8s] %-12s\n",
+                       $1, $3, $6, $8, $10, $12);
+            }'
+
+#
+# 1           2 3         4 5 6       7 8     9 10      11 12
+# sdk-example / example.c : [ 100.00% ] (7/7) [ 100.00% ]  (1/1)
+#
+echo ""
+exit 0

+ 65 - 0
iotkit-embedded/build-rules/scripts/ops_repository.sh

@@ -0,0 +1,65 @@
+#! /bin/bash
+
+if [ $# != 2 ]; then echo "$# != 2"; exit 1; fi
+if [ ! -f $1 ]; then echo "$1 not exist"; exit 2; fi
+
+if [ "$(uname)" = "Darwin" ]; then
+    SED=gsed
+else
+    SED=sed
+fi
+
+BLDV=$1
+CMDV=$2
+
+if [ "${CMDV}" = "list" ]; then
+    grep "^PKG_UPSTREAM_[-/_a-zA-Z0-9]*" ${BLDV} \
+        | ${SED} 's/^PKG_UPSTREAM_\([^ ]*\) = \(.*\)$/[\1] \2/g'
+fi
+
+REPO_LIST=$( \
+    grep "^PKG_UPSTREAM_[-/_a-zA-Z0-9]*" ${BLDV} \
+        | ${SED} 's/^PKG_UPSTREAM_\([^ ]*\) = \(.*\)$/[\1] \2/g' \
+        | cut -d' ' -f1 \
+        | ${SED} 's/\[//g;s/\]//g;' \
+)
+
+if [ "${CMDV}" = "update" ]; then
+    echo "Select repository to be updated, type 1 to update all repositories"|grep --color ".*"
+    echo ""
+    select O in "ALL REPOS" ${REPO_LIST}; do
+        echo ""
+        echo "Updating $O ..."|grep --color ".*"
+        echo ""
+        break
+    done
+
+    if [ "${O}" = "ALL REPOS" ]; then
+        O=""
+    fi
+    REPOS=$(grep -o "^PKG_UPSTREAM_[-/_a-zA-Z0-9]*" ${BLDV}|grep "${O}"|sort -u|${SED} 's:PKG_UPSTREAM_::')
+    for R in ${REPOS}; do
+        UPSTREAM=$(grep -m 1 "^PKG_UPSTREAM_${R}" ${BLDV}|awk '{ print $NF }')
+        SOURCE=$(grep -m 1 "^PKG_SOURCE_${R}" ${BLDV}|awk '{ print $NF }')
+        BRANCH=$(grep -m 1 "^PKG_BRANCH_${R}" ${BLDV}|awk '{ print $NF }')
+        [ "${BRANCH}" = "" ] && BRANCH="master"
+
+        echo "[ ${SOURCE} ] <= : ${UPSTREAM} :: ${BRANCH}"
+        set -x
+        cd ${PACKAGE_DIR}
+        rm -rf ${SOURCE}
+
+        # --single-branch might doesn't exist for git <= 1.7.9.5
+        #
+        # git clone -q --bare -b ${BRANCH} --single-branch ${UPSTREAM} ${SOURCE}
+        git clone -q --bare -b ${BRANCH} ${UPSTREAM} ${SOURCE}
+        rm -rf ${SOURCE}/hooks/
+        mkdir -p ${SOURCE}/hooks/
+        touch ${SOURCE}/hooks/.gitkeep
+        touch ${SOURCE}/refs/{heads,tags}/.gitkeep
+
+        rm -rf ${TOP_DIR}.pkgs/${SOURCE/.git}
+        cd ${OLDPWD}
+        set +x
+    done
+fi

+ 64 - 0
iotkit-embedded/build-rules/scripts/stats_static_lib.sh

@@ -0,0 +1,64 @@
+#! /bin/bash
+
+TARGET=$1
+TEMPD=$(mktemp -d -t STATD-XXXX)
+TEMPF=$(mktemp -t STATF-XXXX)
+
+# echo "TARGET = ${TARGET}"
+# echo "STAGED = ${STAGED}"
+# echo "TEMPD = ${TEMPD}"
+
+if [ ! -f ${TARGET} ] || [ ! -d ${STAGED} ]; then
+    echo "Invalid Env"
+    exit 1
+fi
+
+cp ${TARGET} ${TEMPD}
+cd ${TEMPD}
+ar xf $(basename ${TARGET})
+rm -f $(basename ${TARGET})
+${STRIP} -S *.o > /dev/null 2>&1
+
+for obj in $(ls *.o); do
+    dir=$(find ${STAGED} -name ${obj}|xargs dirname|xargs basename)
+    printf "%-12s %-32s %s\n" ${dir} ${obj} $(du -b ${obj}|awk '{ print $1 }')
+done | sort > ${TEMPF}
+
+MODS=$(cat ${TEMPF}|awk '{ print $1 }'|sort -u)
+
+TOTAL=$(cat ${TEMPF}|awk '{ sum += $3 } END { print sum }')
+# echo "TOTAL = ${TOTAL}"
+
+SMODS=$( \
+for mod in ${MODS}; do \
+    MSIZE=$(grep "^${mod}" ${TEMPF}|awk '{ sum += $3 } END { print sum }'); \
+    printf "%-8s %s\n" \
+        $(awk -v a=${MSIZE} -v b=${TOTAL} 'BEGIN { printf("%.2f%%\n", a/b*100); }') \
+        "${mod}"; \
+done | sort -nr | awk '{ print $2 }' \
+)
+
+echo ""
+for mod in ${SMODS}; do
+    MSIZE=$(grep "^${mod}" ${TEMPF}|awk '{ sum += $3 } END { print sum }')
+    OBJS=$(grep "^${mod}" ${TEMPF}|awk '{ print $2 }')
+    for obj in ${OBJS}; do
+        FSIZE=$(grep "\<${obj}\>" ${TEMPF}|awk '{ print $3 }')
+        printf "     %-8s %28s | %-8s %8s %-8s\n" \
+            $(awk -v a=${FSIZE} -v b=${MSIZE} 'BEGIN { printf("%.2f%%\n", a/b*100); }') \
+            "${obj}" "${mod}" "${FSIZE} /" "${MSIZE}"
+    done | sort -nr
+    echo "    -----------------------------------------------------------------"
+done
+
+echo ""
+for mod in ${MODS}; do
+    MSIZE=$(grep "^${mod}" ${TEMPF}|awk '{ sum += $3 } END { print sum }')
+    printf "     %-8s %-32s %16s\n" \
+        $(awk -v a=${MSIZE} -v b=${TOTAL} 'BEGIN { printf("%.2f%%\n", a/b*100); }') \
+        "[ ${mod} ]" "${MSIZE} Bytes"
+done | sort -nr
+
+cd ${OLDPWD}
+rm -rf ${TEMPD}
+rm -f ${TEMPF}

+ 83 - 0
iotkit-embedded/build-rules/settings.mk

@@ -0,0 +1,83 @@
+# Basic Settings
+#
+SHELL           := /bin/bash
+TOP_DIR         ?= $(CURDIR)
+
+ifeq (Darwin,$(strip $(shell uname)))
+SED             := gsed
+STRIP_DBGOPT    :=
+else
+SED             := sed
+STRIP_DBGOPT    := --strip-debug
+endif
+
+# Settings of input directory and file
+#
+RULE_DIR        ?= $(TOP_DIR)/build-rules
+CONFIG_DIR      ?= $(TOP_DIR)/configs
+SCRIPT_DIR      ?= $(TOP_DIR)/scripts
+PACKAGE_DIR     ?= $(TOP_DIR)/packages
+IMPORT_DIR      ?= $(TOP_DIR)/import
+MAKE_SEGMENT    ?= iot.mk
+
+ifeq ($(shell [ ! -d $(CONFIG_DIR) ] && echo y),y)
+DEFAULT_BLD     := $(RULE_DIR)/misc/config.generic.default
+endif
+
+# Settings of project information
+PRJ_NAME        ?= LITE-build.prj
+PRJ_VERSION     ?= LITE-build.ver
+
+# Settings of output directory
+#
+CONFIG_TPL      := $(TOP_DIR)/.config
+OUTPUT_DIR      ?= $(TOP_DIR)/.O
+DIST_DIR        ?= $(TOP_DIR)/output
+LCOV_DIR        ?= Coverage
+FINAL_DIR       ?= $(DIST_DIR)/release
+
+# Setting of directory for flat modules
+#
+bindir          = /usr/bin
+libdir          = /usr/lib
+incdir          = /usr/include
+
+# Setting of build process control
+#
+COMPILE_LOG     := compile.log
+WARNING_LOG     := warnings.log
+HD_MAKEFILE     := makefile
+TOP_MAKEFILE    := makefile
+
+STAMP_PRJ_CFG   := $(OUTPUT_DIR)/.just.configured
+STAMP_BLD_ENV   := $(OUTPUT_DIR)/.sub-build.env
+STAMP_BLD_VAR   := $(OUTPUT_DIR)/.sub-build.vars
+STAMP_UNPACK    := .unpack.done
+STAMP_CONFIG    := .config.done
+STAMP_BUILD     := .build.done
+STAMP_INSTALL   := .install.done
+STAMP_POSTINS   := .post.install.done
+STAMP_SHIELD    := .shield.done
+STAMP_POST_RULE := $(OUTPUT_DIR)/.post-rules.mk
+STAMP_DIR       := $(OUTPUT_DIR)/stamps
+
+ifdef DEBUG
+AUTO_HEADER_Q   :=
+ORIGIN_Q        :=
+SHELL_DBG       := set -x;
+Q               :=
+TOP_Q           :=
+else
+Q               := @
+TOP_Q           := @
+endif
+
+ifdef DEBUG_SHELL
+SHELL_DBG       := set -x;
+endif
+
+# Setting of directory for origin modules
+#
+export INSTALL_DIR     = $(OUTPUT_DIR)/usr
+export INSTALL_BIN_DIR = $(INSTALL_DIR)/bin
+export INSTALL_LIB_DIR = $(INSTALL_DIR)/lib

+ 6 - 0
iotkit-embedded/cmake/modules/iotx-sdk-version.cmake

@@ -0,0 +1,6 @@
+set(iotx_sdk_version_major 1)
+set(iotx_sdk_version_minor 1)
+set(iotx_sdk_version_patch 0)
+
+set(iotx_sdk_version "${iotx_sdk_version_major}.${iotx_sdk_version_minor}.${iotx_sdk_version_patch}")
+

+ 21 - 0
iotkit-embedded/doc/config.mdm9206.sim7000c

@@ -0,0 +1,21 @@
+CONFIG_ENV_CFLAGS += \
+    --cpu=Cortex-A7 \
+    -O1 \
+    --diag_suppress=9931 \
+    --gnu \
+    --arm_only \
+    --diag_error=warning \
+    --protect_stack \
+    --apcs=/interwork \
+    -DSIM7000C_DAM
+
+OVERRIDE_CC             := armcc
+OVERRIDE_AR             := armar
+
+CONFIG_src/shadow       :=
+CONFIG_src/coap         :=
+CONFIG_src/ota          :=
+CONFIG_src/tls          :=
+CONFIG_src/sdk-tests    :=
+CONFIG_sample           :=
+CONFIG_src/platform     :=

+ 6 - 0
iotkit-embedded/doc/export.sdk.demo/coap.mk

@@ -0,0 +1,6 @@
+all ::
+	$(CC) $(CFLAGS) -o ext.coap coap-example.c $(LDFLAGS)
+
+clean ::
+	rm -vf ext.coap
+

+ 13 - 0
iotkit-embedded/doc/export.sdk.demo/head.mk

@@ -0,0 +1,13 @@
+.PHONY: all
+
+CC          := gcc
+
+CFLAGS      := -I../include
+CFLAGS      += -I../include/iot-sdk
+CFLAGS      += -I../include/mbedtls
+
+LDFLAGS     := -L../lib
+LDFLAGS     += -liot_sdk -liot_platform
+LDFLAGS     += -Bstatic -liot_tls
+LDFLAGS     += -lgcov
+

+ 16 - 0
iotkit-embedded/doc/export.sdk.demo/head_id2.mk

@@ -0,0 +1,16 @@
+.PHONY: all
+
+CC          := gcc
+
+CFLAGS      := -I../include
+CFLAGS      += -I../include/iot-sdk
+CFLAGS      += -I../include/mbedtls
+CFLAGS      += -DMQTT_ID2_AUTH
+
+LDFLAGS     := -L../lib
+LDFLAGS     += -liot_sdk -liot_platform
+LDFLAGS     += -ltfs_online -liot-tfs
+LDFLAGS     += -Bstatic -liot_tls
+LDFLAGS     += -liot_sdk -liot_platform
+LDFLAGS     += -lgcov
+

Some files were not shown because too many files changed in this diff