Browse Source

[add] support joylink

Signed-off-by: liuxinaliang <liuxianliang@rt-thread.com>
liuxinaliang 5 years ago
parent
commit
4e54badd43
100 changed files with 25991 additions and 2 deletions
  1. 52 0
      .gitignore
  2. 201 0
      LICENSE
  3. 260 2
      README.md
  4. 66 0
      SConscript
  5. BIN
      docs/figures/ap_config.jpg
  6. BIN
      docs/figures/ap_env.jpg
  7. BIN
      docs/figures/joylink_start.jpg
  8. BIN
      docs/figures/key_manage.jpg
  9. BIN
      docs/figures/key_manage1.jpg
  10. BIN
      docs/figures/ota_add.jpg
  11. BIN
      docs/figures/ota_app.jpg
  12. BIN
      docs/figures/ota_info.jpg
  13. BIN
      docs/figures/ota_start.jpg
  14. BIN
      docs/figures/product_key.jpg
  15. BIN
      docs/figures/qr_code.jpg
  16. BIN
      docs/figures/softap.jpg
  17. BIN
      docs/figures/softap_connect.jpg
  18. BIN
      docs/figures/thunderconfig.jpg
  19. BIN
      docs/figures/uuid.jpg
  20. BIN
      docs/figures/wifi_connect.jpg
  21. 1 0
      joylink/BUGS
  22. 8 0
      joylink/COPYING
  23. 32 0
      joylink/Makefile
  24. 49 0
      joylink/Makefile.rule
  25. 27 0
      joylink/README
  26. 3 0
      joylink/README.md
  27. 126 0
      joylink/RELEASENOTES
  28. 50 0
      joylink/agent/Makefile
  29. 1543 0
      joylink/agent/joylink_adapter_net.c
  30. 324 0
      joylink/agent/joylink_adapter_net.h
  31. 930 0
      joylink/agent/joylink_agent.c
  32. 167 0
      joylink/agent/joylink_agent.h
  33. 318 0
      joylink/agent/joylink_agent_devs.c
  34. 110 0
      joylink/agent/joylink_agent_devs.h
  35. 531 0
      joylink/agent/joylink_agent_gw_2_cloud.c
  36. 353 0
      joylink/agent/joylink_agent_json.c
  37. 66 0
      joylink/agent/joylink_agent_json.h
  38. 246 0
      joylink/agent/tags
  39. 204 0
      joylink/agent/test.c
  40. 46 0
      joylink/auth/Makefile
  41. 1548 0
      joylink/auth/joylink3_auth_uECC.c
  42. 350 0
      joylink/auth/joylink3_auth_uECC.h
  43. 1248 0
      joylink/auth/joylink3_auth_uECC_curve-specific.inc
  44. 67 0
      joylink/auth/joylink3_auth_uECC_platform-specific.inc
  45. 107 0
      joylink/auth/joylink3_auth_uECC_types.h
  46. 172 0
      joylink/auth/joylink3_auth_uECC_vli.h
  47. 725 0
      joylink/auth/joylink_aes.c
  48. 87 0
      joylink/auth/joylink_aes.h
  49. 75 0
      joylink/auth/joylink_auth_crc.c
  50. 19 0
      joylink/auth/joylink_auth_crc.h
  51. 197 0
      joylink/auth/joylink_auth_md5.c
  52. 15 0
      joylink/auth/joylink_auth_md5.h
  53. 2809 0
      joylink/auth/joylink_auth_uECC.c
  54. 319 0
      joylink/auth/joylink_auth_uECC.h
  55. 28 0
      joylink/auth/joylink_crypt.c
  56. 20 0
      joylink/auth/joylink_crypt.h
  57. 16 0
      joylink/auth/test.c
  58. 47 0
      joylink/config/Makefile
  59. 334 0
      joylink/config/joylink_config_handle.c
  60. 24 0
      joylink/config/joylink_config_handle.h
  61. 433 0
      joylink/config/joylink_probe.c
  62. 87 0
      joylink/config/joylink_probe.h
  63. 565 0
      joylink/config/joylink_smart_config.c
  64. 119 0
      joylink/config/joylink_smart_config.h
  65. 90 0
      joylink/config/joylink_smart_config.htxt
  66. 565 0
      joylink/config/joylink_smart_config.txt
  67. 44 0
      joylink/config/joylink_smnt_adp.h
  68. 120 0
      joylink/config/joylink_syshdr.h
  69. 131 0
      joylink/config/joylink_thunder.h
  70. 1587 0
      joylink/config/joylink_thunder_slave_sdk.c
  71. 140 0
      joylink/config/joylink_thunder_slave_sdk.h
  72. 158 0
      joylink/config/joylink_wlan_probe.h
  73. 47 0
      joylink/example/Makefile
  74. 180 0
      joylink/example/joylink_dev.h
  75. 524 0
      joylink/example/joylink_extern.c
  76. 62 0
      joylink/example/joylink_extern.h
  77. 208 0
      joylink/example/joylink_extern_json.c
  78. 59 0
      joylink/example/joylink_extern_json.h
  79. 533 0
      joylink/example/joylink_extern_ota.c
  80. 61 0
      joylink/example/joylink_extern_ota.h
  81. 440 0
      joylink/example/joylink_extern_sub_dev.c
  82. 142 0
      joylink/example/joylink_extern_sub_dev.h
  83. 81 0
      joylink/example/joylink_extern_user.c
  84. 34 0
      joylink/example/joylink_extern_user.h
  85. 69 0
      joylink/joylink/Makefile
  86. 427 0
      joylink/joylink/joylink.h
  87. 346 0
      joylink/joylink/joylink_cloud_log.c
  88. 15 0
      joylink/joylink/joylink_cloud_log.h
  89. 497 0
      joylink/joylink/joylink_dev_active.c
  90. 14 0
      joylink/joylink/joylink_dev_active.h
  91. 777 0
      joylink/joylink/joylink_dev_lan.c
  92. 509 0
      joylink/joylink/joylink_dev_sdk.c
  93. 1021 0
      joylink/joylink/joylink_dev_server.c
  94. 992 0
      joylink/joylink/joylink_dev_timer.c
  95. 177 0
      joylink/joylink/joylink_dev_timer.h
  96. 228 0
      joylink/joylink/joylink_join_packet.c
  97. 46 0
      joylink/joylink/joylink_join_packet.h
  98. 113 0
      joylink/joylink/joylink_log.h
  99. 334 0
      joylink/joylink/joylink_packets.c
  100. 96 0
      joylink/joylink/joylink_packets.h

+ 52 - 0
.gitignore

@@ -0,0 +1,52 @@
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf

+ 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.

+ 260 - 2
README.md

@@ -1,2 +1,260 @@
-# joylink
-Joylink Cloud SDK for IoT platform
+# Joylink 京东云接入指南
+
+## 1. 介绍
+
+joylink 京东小京鱼 IoT 开放平台(以下简称京东云) 可以为京东平台产品提供一体化的智能解决方案,包括 App、云服务、数据运算、增值服务等,使得该产品可以和京东云平台上其他品牌产品实现相互连接,为用户提供更好的使用体验 。
+
+joylink 软件包是 RT-Thread 系统基于 joylink v2.0.19 版本移植的用于连接京东云 IoT 平台的软件包,该软件包目前完成功能:
+
+- 设备激活上线;
+- 自定义数据收发功能;
+
+
+### 1.2 依赖
+
+- RT-Thread 4.0.1 +
+
+- [cJSON 软件包](https://github.com/RT-Thread-packages/cJSON)
+
+- [EasyFlash 软件包](https://github.com/armink-rtt-pkgs/EasyFlash)
+
+- RTC 设备支持
+
+
+## 2. 软件包使用
+
+下面分三个部分介绍京东云接入和软件包使用流程:
+
+- 云端准备流程;
+
+- 参数配置和移植流程;
+
+- 软件包运行流程;
+
+### 2.1 云端准备流程
+
+**1. 账号注册登录**
+
+京东云平台地址:https://jdwhale.jd.com
+
+可以使用个人京东账号登录,也可以注册企业账号登录,建议注册使用企业账号。
+
+**2. 创建产品**
+
+参考官方 [创建产品说明](https://smartdev.jd.com/docCenterDoc/view/2/101/95400002/95900004#topMaoDot) ,创建成功之后需要获取并记录产品 **UUID** 和 **Product Key(公钥)**,用于后面设备的激活和认证过程。
+
+如下图所示为创建产品基本参数,当前创建的产品类型为**智能手环**:
+
+![UUID](docs/figures/uuid.jpg)
+
+![Product Key](docs/figures/product_key.jpg)
+
+**3. 通过 MAC 地址生成设备密钥**
+
+创建产品之后,正常应该是创建新设备,京东云提供 **设备密钥管理** 机制,通过表格传入的设备 **MAC 地址**生成该 MAC 地址设备特有的**Private Key(设备私钥)**,用于设备激活认证。
+
+
+进入`设备密钥管理`, 选中上面创建的产品,点击右边 `密钥管理`, 点击 `导入 MAC 地址`,按照 MAC 地址表格模板填写 MAC 地址,点击  `导入`。导入成功之后,再次点击进入 `密钥管理`,可以查看密钥列表,如下所示:
+
+![设备 MAC 地址导入](docs/figures/key_manage.jpg)
+
+![设备私钥导出](docs/figures/key_manage1.jpg)
+
+至此,针对每一个设备,获取到了四个重要的属性信息,分别是:
+
+- **UUID**:产品唯一标识
+- **Product Key**:产品公钥
+- **MAC**:设备硬件地址
+- **Device Key**:设备私钥
+
+### 2.2 参数配置流程
+
+通过上述云端准备流程获取产品相关信息,之后可以在 menuconfig 中配置信息, menuconfig 配置如下:
+
+```shell
+[*] Joylink: Joylink IoT SDK poting for RT-Thread
+    [ ]  Enable OTA update feature
+    [ ]  Enable network configure feature
+    [ ]  Enable thunderconfig mode
+         Output LOG level (DEBUG)  --->
+         Sample product type (Heater)  --->
+    [*]  Enable automatic initialize
+    (uuid) Device uuid
+    (public_key) Device public key
+    (private_key) Device private key
+    Version (latest)  --->
+```
+
+- **Enable OTA update feature**:配置开启 OTA 功能支持;同时需要自行移植
+- **Enable network configure feature**:配置配网方式支持,目前有两种:softap、thunderconfig;同时需要自行移植
+- **Enable softap mode**: 开启手机热点配网功能支持;同时需要自行移植
+- **Enable thunderconfig mode**:开启叮咚/京鱼座音箱配网功能支持;同时需要自行移植
+- **Output LOG level**:配置日志等级,目前支持等级:DEBUG、WARN、ERROR、INFO、NOTICE、FATAL
+- **Sample product type**:配置示例类型,目前支持两种:Heater、Wristband
+- **Enable automatic initialize**:配置开启云端自启动功能支持 
+- **Device uuid**:配置示例产品 UUID
+- **Device public key**:配置示例产品公钥
+- **Device private key**:配置示例设备私钥(该设备 MAC 地址对应私钥)
+
+### 软件包运行流程
+
+下载编译运行成功,设备上电,连接网络成功,若想要设备在云端上线需要  **小京鱼 APP** 配合设备完成设备激活过程。
+
+**1. 下载安装小京鱼 APP**
+
+小京鱼 APP 下载地址:https://smartdev.jd.com/docCenterDownload/download/156100001
+
+下载完成,使用创建产品和设备的京东账号登录。
+
+**2. 设备二维码生成**
+
+每个设备对应一个二维码,用于设备的联网和激活认证,在 `产品管理`->`销售信息` -> `二维码`处生成,如下图所示:
+
+![生成二维码](docs/figures/qr_code.jpg)
+
+需要注意的一点,**只有在产品基本信息填写完整的情况下,二维码才能正常显示**。
+
+
+**3. 云端启动**
+
+设备第一次上线进入配网模式,默认开启 softap 配网方式,如下图所示:
+
+![启动 softap 配网](./docs/figures/softap.jpg)
+
+**4. SoftAP 配网功能**
+
+目前设备默认配网方式为 SoftAP 配网, SoftAP 配网支持**设备自行激活绑定**的绑定策略,设备在配网之前需要在云端配置设备配网信息,具体 softap 配网方式使用流程如下:
+
+- **设置产品配网方式**
+
+  ![设置配网方式](docs/figures/ap_config.jpg)
+
+  产品管理,基本信息界面,设置配网方式为`SoftAP`(有些模块不支持该配网方式,这里使用联盛德 W600模块),设置激活绑定策略为`设备自行激活`;
+
+  获取当前产品 AP 名称为 `JDQuNuanQi6316`,用于 ENV 选项配置。
+
+- **配置工程参数**
+
+  使用 ENV 工具,配置 SoftAP 配网模式,配置使用的 AP 名称。
+
+  ![ENV 配置](docs/figures/ap_env.jpg)
+
+- **使用 APP 配网**
+
+  手机连接设备需要连接配置的 WIFI,进入小京鱼 APP,点击设备又上角加上 “+” 号,扫描产品生成的二维码,设备进入配网。配网完成,设备提示`配网成功`,之后设备进入自动激活过程,激活完成手机 APP 中能查看配网成功的设备。
+
+  注:如果 APP 提示`配网失败`,需要 FinSH 中执行 `joylink_stop` 停止配网,再执行 `joylink_start` 命令再次进入配网,手机重新扫描配网。
+
+  softap 网成功如下图所示:
+
+  ![softap 配网成功](docs/figures/softap_connect.jpg)
+
+
+**5. thunderconfig 配网**
+
+除了 softap 配网,京东云还支持叮咚/京鱼座音箱配网,需要 menuconfig 配置中开启 `thunderconfig mode` 配网模式支持,并且叮咚/京鱼座音箱固件版本为最新版本(需要联系京东云官方支持确定音箱版本是否支持音箱配网)。
+
+首先通过小京鱼 APP 给叮咚/京鱼座音箱配网,使音箱设备连接 WIFI,然后让设备进入待配网模式,设备默认使用 softap 配网方式,可以在 FinSH 中执行 `joylink_mod_change` 命令切换配网状态为 thunderconfig 配网。然后通过语音唤醒音箱配网功能,设备端会收到音箱发送的配网信息并自动连接网络。示例使用音箱设备为`京鱼座 A1 音箱`,音箱固件版本为 `206`,设备 thunderconfig 配网连接日志如下所示:
+
+![音箱配网](./docs/figures/thunderconfig.jpg)
+
+**6. 设备上线**
+
+配网成功之后,设备自动上线,设备上线后云端可以通过获取的设备 **Feed ID** 查看设备在线情况,也可以查看设备日志等信息。
+
+设备端激活完成之后,可以向云端发送自定义的 JSON 数据格式,如果没有数据发送,设备端也会定期发送心跳数据检查连接状态。
+
+**7. OTA 升级功能**
+
+menuconfig 配置中如果开启 `Enable OTA update feature`   选项,则产品支持固件 OTA 空中升级功能。
+
+OTA 升级主要分为如下几个步骤:
+
+- **更新设备分区表**
+    更新设备分区表
+
+- **本地生成最新固件**
+
+   OTA 功能配置完成,编译生成最新固件,joylink 软件包固件升级只支持后缀为 `.bin` 文件,如果工程中生成的可用于固件升级的文件是其他后缀名称,需要将文件修改为 `.bin` 后缀用于后面云端固件上传。
+
+- **上传固件到云端**
+
+  固件准备完成之后,需要上传最新固件到云端,选择`产品管理` -> `固件升级` -> `添加固件`:
+
+  ![添加固件](docs/figures/ota_add.jpg)
+
+  然后进入添加固件界面,选择版本号为`标准` 或 `自定义`,输入自定义版本信息;然后点击 `添加文件`,选择刚才生成的`realthread_upload.bin` 文件上传;然后添加 APP展示信息,可以使用推荐的默认文案,最后点击`保存`按键上传固件。
+
+  ![上传固件](docs/figures/ota_info.jpg)
+
+  **注意**:产品第一次上传固件默认为基础版本,不做固件更新,如果想要在 APP 中显示有新版本更新,则**产品固件列表中必须有两个或两个以上固件**。
+
+- **APP 端下发 OTA 升级控制**
+
+  云端上传固件完成之后,APP 端会显示有最新固件可以升级,如下所示:
+
+  ![APP OTA 控制](docs/figures/ota_app.jpg)
+
+- **设备端固件升级**
+
+  APP 点击开始升级之后,会向设备端下发 OTA 升级信息,设备接收到之后开始进入设备升级,升级流程如图所示:
+
+  ![OTA 启动](docs/figures/ota_start.jpg)
+
+- **重启设备完成 OTA 升级**
+
+  设备端 OTA 文件下载完成, APP 上提示 `固件升级成功,待设备重启后即可使用!`,重启设备进入 Bootloader 固件更新,固件升级完成。
+
+**8. 更多命令支持**
+
+FinSH 中执行 `joylink_stop` 命令,用于关闭 joylink 云端连接。如果开启 Wristband 类型产品示例支持,执行` joylink_band_set` 命令,用于设置产品对应信息。
+
+```shell
+msh />joylink_band_set sport 1  // 设备手环产品信息
+[DEBUG][packages\joylink-latest\samples\joylink_sample_band.c][joylink_dev_user_data_set][85]
+set wristband device sport status(1).
+msh />
+msh />joylink_band_set sleep 2 
+[DEBUG][packages\joylink-latest\samples\joylink_sample_band.c][joylink_dev_user_data_set][90]
+set wristband device sleep status(2).
+msh />
+msh />joylink_band_set physique 3
+[DEBUG][packages\joylink-latest\samples\joylink_sample_band.c][joylink_dev_user_data_set][95]
+set wristband device physique status(3).
+....
+[INFO][packages\joylink-latest\samples\joylink_sample_band.c][joylink_dev_get_snap_shot_with_retcode][343] // 拼接当前设备信息到云端
+------>{
+	"code":	0,
+	"streams":	[{
+			"stream_id":	"Sport",
+			"current_value":	"1"
+		}, {
+			"stream_id":	"Sleep",
+			"current_value":	"2"
+		}, {
+			"stream_id":	"Physique",
+			"current_value":	"3"
+		}]
+}:len:199
+
+[DEBUG][packages\joylink-latest\joylink\joylink\joylink_dev_server.c][joylink_server_upload_req][330]
+send to server len:224:ret:224   // 上传设置的当前设备信息到云端
+...
+```
+
+## 3. 注意事项
+
+- 开启示例功能,需要在源码中修改三个配置参数,且针对不同设备参数不同。
+- 如果 `产品管理`->`销售信息`中不显示 二维码,需要先补全产品基本信息。
+- OTA 功能默认关闭,功能实现需要自行移植
+- 配网功能默认关闭,功能实现需要自行移植
+- EASYFLASH 的移植部分需要自行完成 [EASYFLASH](https://github.com/armink-rtt-pkgs/EasyFlash)
+- 现已在联盛德 w60X 等设备上全面支持了配网和 OTA 功能,如需更多功能支持请联系官网商务
+
+## 参考资料
+
+- 京东云官网:https://jdwhale.jd.com/
+- 京东云官方文档中心:https://smartdev.jd.com/docCenterDoc/index
+- 京东云下载中心:https://smartdev.jd.com/docCenterDownload/list/2
+- 京东云 C 语言设备开发流程:https://smartdev.jd.com/docCenterDoc/view/2/102/152800001/152800002#topMaoDot
+

+ 66 - 0
SConscript

@@ -0,0 +1,66 @@
+from building import *
+
+cwd  = GetCurrentDir()
+
+path  = [cwd + '/joylink']
+path += [cwd + '/joylink/joylink']
+path += [cwd + '/joylink/auth']
+path += [cwd + '/joylink/json']
+path += [cwd + '/joylink/list']
+path += [cwd + '/joylink/config']
+if GetDepend(['JOYLINK_USING_SOFTAP']):
+    path += [cwd + '/joylink/softap']
+
+src  = Glob('joylink/joylink/*.c')
+SrcRemove(src, "joylink/joylink/test.c")
+SrcRemove(src, "joylink/joylink/joylink_cloud_log.c")
+SrcRemove(src, "joylink/joylink/joylink_dev_active.c")
+
+src += Glob('joylink/auth/*.c')
+SrcRemove(src, "joylink/auth/test.c")
+
+src += Glob('joylink/list/*.c')
+SrcRemove(src, "joylink/list/test.c")
+
+src += Glob('joylink/json/joylink_json.c')
+src += Glob('joylink/json/joylink_json_sub_dev.c')
+
+src += Glob('joylink/config/*.c')
+SrcRemove(src, "joylink/config/joylink_config_handle.c")
+SrcRemove(src, "joylink/config/joylink_smart_config.c")
+SrcRemove(src, "joylink/config/joylink_thunder_slave_sdk.c")
+
+# sample files
+if GetDepend(['JOYLINK_USING_SAMPLES_BAND']):
+    src += Glob('samples/joylink_sample_band.c')
+
+if GetDepend(['JOYLINK_USING_SAMPLES_HEATER']):
+    src += Glob('samples/joylink_sample_heater.c')
+
+# smartconfig files
+if GetDepend(['JOYLINK_USING_SMARTCONFIG']):
+    src += Glob('joylink/config/joylink_smart_config.c')
+
+# thunder slave files
+if GetDepend(['JOYLINK_USING_THUNDER_SLAVE']):
+    src += Glob('joylink/config/joylink_thunder_slave_sdk.c')
+    
+# softap files
+if GetDepend(['JOYLINK_USING_SOFTAP']):
+    src += Glob('joylink/joylink/joylink_cloud_log.c')
+    src += Glob('joylink/joylink/joylink_dev_active.c')
+
+CPPDEFINES = ['__RT_THREAD__']
+CPPDEFINES += ['_GET_HOST_BY_NAME_']
+
+if GetDepend(['JOYLINK_USING_SOFTAP']):
+    CPPDEFINES += ['_IS_DEV_REQUEST_ACTIVE_SUPPORTED_']
+
+group = DefineGroup('joylink', src, depend = ['PKG_USING_JOYLINK'], CPPPATH = path, CPPDEFINES = CPPDEFINES)
+
+list = os.listdir(cwd)
+for item in list:
+    if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
+        group = group + SConscript(os.path.join(item, 'SConscript'))
+
+Return('group')

BIN
docs/figures/ap_config.jpg


BIN
docs/figures/ap_env.jpg


BIN
docs/figures/joylink_start.jpg


BIN
docs/figures/key_manage.jpg


BIN
docs/figures/key_manage1.jpg


BIN
docs/figures/ota_add.jpg


BIN
docs/figures/ota_app.jpg


BIN
docs/figures/ota_info.jpg


BIN
docs/figures/ota_start.jpg


BIN
docs/figures/product_key.jpg


BIN
docs/figures/qr_code.jpg


BIN
docs/figures/softap.jpg


BIN
docs/figures/softap_connect.jpg


BIN
docs/figures/thunderconfig.jpg


BIN
docs/figures/uuid.jpg


BIN
docs/figures/wifi_connect.jpg


+ 1 - 0
joylink/BUGS

@@ -0,0 +1 @@
+Plese check https://github.com/joylink/issues

+ 8 - 0
joylink/COPYING

@@ -0,0 +1,8 @@
+Copyright (c) 2015-2050, JD Smart All rights reserved.  
+Redistribution and use in source forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the name of joylink nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+ LTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 32 - 0
joylink/Makefile

@@ -0,0 +1,32 @@
+include ./Makefile.rule
+
+DEPS= auth json list example joylink config softap
+
+STATICLIBS = $(wildcard $(TARGET_LIB)/*.a)
+SDKLIBNAME = libjoylinksdk.a
+
+all: ${DEPS} sdk_lib jt
+
+clean: ${DEPS} 
+
+distclean: ${DEPS}
+	${RM} ${TARGET_LIB}/*
+
+${DEPS}: 
+	make -C $@ $(MAKECMDGOALS) 
+
+jt:
+	make jt -C joylink
+
+sdk_lib:
+	@for name in $(STATICLIBS); \
+	do              \
+	${AR} x "$$name";           \
+	if [ "$$name" != "$(TARGET_LIB)/libjoylinksdk.a" ]; then ${RM} "$$name" ; fi;\
+	done                
+	@${AR} -crs ${SDKLIBNAME} *.o
+	@${RANLIB} ${SDKLIBNAME} 
+	@${RM} *.o
+	@${MV} ${SDKLIBNAME} $(TARGET_LIB)
+
+.PHONY:all clean distclean ${DEPS} jt sdk_lib

+ 49 - 0
joylink/Makefile.rule

@@ -0,0 +1,49 @@
+ARCH=x86
+CHIP=
+
+#=======  EDITER =============
+PROJECT_ROOT_PATH:=/home/lizw/workspace/joylink_dev_sdk_2.0
+
+#======= TARGET =======
+TARGET_BIN=${PROJECT_ROOT_PATH}/target/bin
+
+#======= PLAT FROM =============
+ifeq (${CHIP}, )  
+PLATFORM=${ARCH}
+else
+PLATFORM=${ARCH}_${CHIP}
+endif
+
+include ${PROJECT_ROOT_PATH}/scripts/${PLATFORM}.mk
+INCLUDES+= -I${PROJECT_ROOT_PATH}
+INCLUDES+= -I${PROJECT_ROOT_PATH}/example/
+INCLUDES+= -I${PROJECT_ROOT_PATH}/config/
+INCLUDES+= -I${PROJECT_ROOT_PATH}/softap/
+
+TARGET_LIB=${PROJECT_ROOT_PATH}/target/lib
+
+#====== COMMON ======
+
+RM = rm -rf
+CP = cp -rf
+MV = mv -f
+
+LIBS += -lm 
+
+CFLAGS += -D_SAVE_FILE_
+
+#DEV_REQ_ACTIVE_EN=no
+DEV_REQ_ACTIVE_EN=yes
+ifeq (${DEV_REQ_ACTIVE_EN}, yes)  
+CFLAGS += -D_IS_DEV_REQUEST_ACTIVE_SUPPORTED_
+endif
+
+
+DEBUG=y
+ifeq ($(DEBUG), y)
+CFLAGS += -D_GET_HOST_BY_NAME_
+else
+CFLAGS += -O2
+endif
+
+#=======================

+ 27 - 0
joylink/README

@@ -0,0 +1,27 @@
+Where to find complete joylink documentation?
+-------------------------------------------
+
+This README is just a fast "quick start" document. You can find more detailed
+documentation at http://www.jdsmart.com/joylink/
+
+Building joylink_dev_sdk
+--------------
+
+joylink_dev_sdk can be compiled and used on Linux, OSX, OpenBSD, NetBSD, FreeBSD.
+We support big endian and little endian architectures.
+
+It may compile on Linux. 
+
+step 1:
+    % ./once.sh               /* once.sh can set the path as your project dir in Makefile.rule */ 
+
+step 2:
+    % make distclean          /* Clear all the files generated by the compiler */
+
+step 3:
+    % make
+
+step 4:
+    % sudo ./target/bin/jt    /* run the program */
+
+Enjoy!

+ 3 - 0
joylink/README.md

@@ -0,0 +1,3 @@
+joylink_dev_sdk_2.0
+====
+joylink 2.0 dev sdk

+ 126 - 0
joylink/RELEASENOTES

@@ -0,0 +1,126 @@
+VERSION:2.0.7
+HEAD:35fe9dd7501bf5754b8e7e5951ac527926dcd159
+DATE:04/24/18
+
+--------------------------------------------------------------------------------
+
+Upgrade urgency levels:
+
+LOW:      No need to upgrade unless there are new features you want to use.
+MODERATE: Program an upgrade of the server, but it's not urgent.
+HIGH:     There is a critical bug that may affect a subset of users. Upgrade!
+CRITICAL: There is a critical bug affecting MOST USERS. Upgrade ASAP.
+
+--------------------------------------------------------------------------------
+--[ joylink 1.3.3 ] Release date: 
+
+# UPGRADE URGENCY: LOW for joylink. 
+
+* [NEW] No. 
+* [FIX] Add CID firmwareVersion modelCode in func joylink_package_scan 
+* [FIX] Add productuuid in func joylink_parse_write_key 
+=======================
+
+** IMPORTANT ** 
+
+
+--[ joylink 1.3.3 ] Release date: 
+
+# UPGRADE URGENCY: LOW for joylink. 
+
+* [NEW] No. 
+* [FIX] joylink_json.c:joylink_parse_scan, add  cJSON_Delete(pJson);
+* [FIX] joylink_json.c:joylink_package_scan, del cJson_CreateArry;
+=======================
+
+** IMPORTANT ** 
+
+--------------------------------------------------------------------------------
+--[ joylink 1.3.2 ] Release date: 
+
+# UPGRADE URGENCY: LOW for joylink. 
+
+* [NEW] No. 
+* [FIX] Add sdk/lua/example.lua sdk/lua/only_trans.lua 
+* [FIX] Change var name in joylink.h     
+=======================
+
+** IMPORTANT ** 
+
+--------------------------------------------------------------------------------
+--[ joylink 1.3.1 ] Release date: 
+
+# UPGRADE URGENCY: LOW for joylink. 
+
+* [NEW] Add big package cut and send ,but code is for debug. 
+
+* [FIX] 
+=======================
+
+** IMPORTANT ** 
+
+--------------------------------------------------------------------------------
+
+--[ joylink 1.3.0 ] Release date: 
+
+# UPGRADE URGENCY: CRITICAL for joylink. 
+
+* [FIX] Fix the error of joylink_parse_lan_write_key()
+
+* [FIX] Change .jlp.trantype = 0, to .jlp.trantype = 1
+
+Migrating from 1.2 to 1.3
+=========================
+
+joylink_dev_sdk 1.2 is mostly a strict subset of 1.3. However there are a few things
+that you should be aware of:
+
+The following default attr changed:
+
+    * .jlp.trantype = 1, means suport lua script.
+--------------------------------------------------------------------------------
+
+joylink_dev_sdk 1.2 release notes
+=======================
+
+** IMPORTANT ** Check the 'Migrating from 1.1 to 1.2' section at the end of
+                this file for information about what changed between 1.1 and
+                1.2 and how this may affect your application.
+
+--------------------------------------------------------------------------------
+Upgrade urgency levels:
+
+LOW:      No need to upgrade unless there are new features you want to use.
+MODERATE: Program an upgrade of the server, but it's not urgent.
+HIGH:     There is a critical bug that may affect a subset of users. Upgrade!
+CRITICAL: There is a critical bug affecting MOST USERS. Upgrade ASAP.
+--------------------------------------------------------------------------------
+
+--[ joylink 1.2.0 ] Release date: 14 Jul 2014
+
+# UPGRADE URGENCY: LOW for joylink , this is a features enhancement
+                   release mostly. 
+
+* [FIX] Recive data that's len bigger than 1400 from server. (steven)
+
+* [NEW] The new OTA feature. (yangnan)
+
+Migrating from 1.1 to 1.2
+=========================
+
+joylink_dev_sdk 1.1 is mostly a strict subset of 1.2. However there are a few things
+that you should be aware of:
+
+The following commands changed behavior:
+
+    * XXXX.
+    * YYYY.
+--------------------------------------------------------------------------------
+
+Credits: 
+Thanks to all the contributors and the amazing
+community we have.
+
+See commit messages for more joylink_dev_sdk.
+
+Cheers!

+ 50 - 0
joylink/agent/Makefile

@@ -0,0 +1,50 @@
+include ../Makefile.rule 
+HEADERS = $(wildcard *.h)
+ORG_SOURCES = $(wildcard *.c)
+OUT_SRC = test.c 
+
+SOURCES=$(filter-out ${OUT_SRC}, ${ORG_SOURCES})
+OBJS = $(patsubst %.c, %.o, $(SOURCES))
+
+LIBNAME = $(strip ${shell pwd |xargs basename})
+
+INCLUDES += -I${PROJECT_ROOT_PATH}/json
+INCLUDES += -I${PROJECT_ROOT_PATH}/list
+INCLUDES += -I${PROJECT_ROOT_PATH}/joylink
+
+STATIC_LIBS += ${TARGET_LIB}/libauth.a
+STATIC_LIBS += ${TARGET_LIB}/libjson.a
+STATIC_LIBS += ${TARGET_LIB}/liblist.a
+#STATIC_LIBS += ${TARGET_LIB}/libjoylinksdk.a
+
+STATIC_LIBS += 
+LIBS += -lm  
+
+ifeq (${ARCH}, x86)  
+all:${OBJS} liba libso
+else
+all:${OBJS} liba 
+endif
+
+.SUFFIXES: .c .o
+.c.o:
+	${CC} ${CFLAGS} -c $(INCLUDES) ${STATIC_LIBS} $(LIBS) $*.c
+
+liba:${OBJS}
+	${AR} -crs lib${LIBNAME}.a ${OBJS}
+	${MV} lib${LIBNAME}.a ${TARGET_LIB}
+
+libso:${OBJS}
+	${CC}  ${OBJS} -shared -fPIC -o lib${LIBNAME}.so
+	${MV} lib${LIBNAME}.so ${TARGET_LIB} 
+
+test:${OBJS}
+	${CC} -DLIB_TEST ${OBJS} test.c -o $@ ${CFLAGS} ${INCLUDES}  ${TARGET_LIB}/libjoylinksdk.a ${LIBS} 
+
+clean:
+	${RM} *.o *.so *.a test
+
+distclean:clean
+	${RM} ./*.a ./*.so ${TARGET_LIB}/lib${LIBNAME}.*
+
+.PHONY:all clean test jt

+ 1543 - 0
joylink/agent/joylink_adapter_net.c

@@ -0,0 +1,1543 @@
+/*Copyright (c) 2015-2050, JD Smart All rights reserved.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License. */
+
+#include <stdint.h>
+#if defined(__MTK_7687__)
+#include "lwip/netdb.h"
+#include "lwip/inet.h"
+#include "lwip/netif.h"
+#include "lwip/stats.h"
+#include "lwip/tcp.h"
+#include "lwip/sockets.h"
+#elif defined(__REALTEK_8711__)
+#include "lwip/sockets.h"
+#include "lwip/netdb.h"
+#include "lwip/inet.h"
+#include "lwip/netif.h"
+#include "lwip/stats.h"
+#include "lwip/tcp.h"
+#elif defined(__ESP32__)
+#include "lwip/sockets.h"
+#include "lwip/netdb.h"
+#include "lwip/inet.h"
+#include "lwip/netif.h"
+#include "lwip/stats.h"
+#include "lwip/tcp.h"
+#elif defined(__MICOKIT_3166__)
+#include "lwip/netdb.h"
+#include "lwip/inet.h"
+#include "sockets.h"
+#include "lwip/arch.h"
+#include "interface.h"
+
+#elif defined(__MW300__)
+#include "lwip/sockets.h"
+#include "lwip/netdb.h"
+#include <stdint.h>
+#elif defined(__QC_4010__)
+#include "basetypes.h"
+#include "socket_api.h"
+#include "timetype.h"
+#include "qcom_time.h"
+#elif defined(__OV_788__)
+#include "includes.h" 
+#include "libpdk.h"
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <time.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+#endif
+
+#if  defined(__OV_788__)
+#include "joylink_net.h"
+#else
+#include <string.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#endif
+
+#include "joylink_adapter_net.h"
+#include "joylink_ret_code.h"
+#include "joylink_log.h"
+#include "joylink.h"
+
+#ifndef __LINUX__
+uint8_t s_host_ipv4[32] = {0};
+#endif
+
+#define E_OK            E_RET_OK
+#define E_ERROR         E_RET_ERROR
+
+static void 
+joylink_adapter_net_set_error(char *err, const char *fmt, ...)
+{
+#if defined(__QC_4010__) || defined(__OV_788__)
+    printf("\njoylink_net_set_error:not support va_list on qc4010.\n");
+#else
+    va_list ap;
+
+    if (!err) return;
+    va_start(ap, fmt);
+    vsnprintf(err, ANET_ERR_LEN, fmt, ap);
+    va_end(ap);
+#endif
+}
+
+int32_t 
+joylink_adapter_net_non_block(char *err, int32_t fd)
+{
+#if defined(__MICOKIT_3166__) || defined(__QC_4010__) || defined(__OV_788__)
+
+	printf("not support non block now\n");
+	return ANET_ERR;
+#else
+    int32_t flags;
+
+    /* Set the socket non-blocking.
+     * Note that fcntl(2) for F_GETFL and F_SETFL can't be
+     * interrupted by a signal. */
+#if defined (__MTK_7687__) || defined(__MW300__) || defined(__REALTEK_8711__) || defined(__ESP32__)
+	if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
+#else
+    if ((flags = fcntl(fd, F_GETFL)) == -1)
+#endif	
+	{
+        joylink_adapter_net_set_error(err, "fcntl(F_GETFL): %s", strerror(errno));
+        return ANET_ERR;
+    }
+    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
+        joylink_adapter_net_set_error(err, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno));
+        return ANET_ERR;
+    }
+    return ANET_OK;
+
+#endif
+}
+
+/* Set TCP keep alive option to detect dead peers. The interval option
+ * is only used for Linux as we are using Linux-specific APIs to set
+ * the probe send time, interval, and count. */
+int32_t 
+joylink_adapter_net_keep_alive(char *err, int32_t fd, int32_t interval)
+{
+#if defined(__OV_788__)
+	printf("not support non block now\n");
+    return ANET_OK;
+#else
+    int32_t val = 1;
+
+    if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){
+        joylink_adapter_net_set_error(err, "setsockopt SO_KEEPALIVE: %s", strerror(errno));
+        return ANET_ERR;
+    }
+
+#ifdef __linux__
+    /* Default settings are more or less garbage, with the keepalive time
+     * set to 7200 by default on Linux. Modify settings to make the feature
+     * actually useful. */
+
+    /* Send first probe after interval. */
+    val = interval;
+    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) {
+        joylink_adapter_net_set_error(err, "setsockopt TCP_KEEPIDLE: %s\n", strerror(errno));
+        return ANET_ERR;
+    }
+
+    /* Send next probes after the specified interval. Note that we set the
+     * delay as interval / 3, as we send three probes before detecting
+     * an error (see the next setsockopt call). */
+    val = interval/3;
+    if (val == 0) val = 1;
+    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) {
+        joylink_adapter_net_set_error(err, "setsockopt TCP_KEEPINTVL: %s\n", strerror(errno));
+        return ANET_ERR;
+    }
+
+    /* Consider the socket in error state after three we send three ACK
+     * probes without getting a reply. */
+    val = 3;
+    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) {
+        joylink_adapter_net_set_error(err, "setsockopt TCP_KEEPCNT: %s\n", strerror(errno));
+        return ANET_ERR;
+    }
+#endif
+
+    return ANET_OK;
+#endif /* __OV_788__*/
+}
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: fd
+ * @Param: val
+ *
+ * @Returns: 
+ */
+static int32_t 
+joylink_adapter_net_set_tcp_no_delay(char *err, int32_t fd, int32_t val)
+{
+#if defined(__OV_788__)
+    printf("no delay is not support in ov788.");
+    return ANET_ERR;
+#else
+#if defined(__QC_4010__)
+    if (setsockopt(fd, SOL_SOCKET, TCP_NODELAY, &val, sizeof(val)) == -1) {
+#else
+    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) == -1) {
+#endif
+        joylink_adapter_net_set_error(err, "setsockopt TCP_NODELAY: %s", strerror(errno));
+        return ANET_ERR;
+    }
+    return ANET_OK;
+#endif /*ov_788*/
+}
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: fd
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_enable_tcp_no_delay(char *err, int32_t fd)
+{
+    return joylink_adapter_net_set_tcp_no_delay(err, fd, 1);
+}
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: fd
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_disable_tcp_no_delay(char *err, int32_t fd)
+{
+    return joylink_adapter_net_set_tcp_no_delay(err, fd, 0);
+}
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: fd
+ * @Param: buffsize
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_set_send_buf(char *err, int32_t fd, int32_t buffsize)
+{
+#if defined(__OV_788__)
+    printf("not support:set_sent_buf\n");
+    return ANET_ERR;
+#else
+    if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffsize, sizeof(buffsize)) == -1)
+    {
+        joylink_adapter_net_set_error(err, "setsockopt SO_SNDBUF: %s", strerror(errno));
+        return ANET_ERR;
+    }
+    return ANET_OK;
+#endif /* ov_788 */
+}
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: fd
+ *
+ * @Returns: 
+ */
+int32_t
+joylink_adapter_net_tcp_keep_alive(char *err, int32_t fd)
+{
+#if defined(__OV_788__)
+    printf("not support:tcp_keep_alive\n");
+    return ANET_ERR;
+#else
+    int32_t yes = 1;
+    if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) == -1) {
+        joylink_adapter_net_set_error(err, "setsockopt SO_KEEPALIVE: %s", strerror(errno));
+        return ANET_ERR;
+    }
+    return ANET_OK;
+#endif /* ov_788 */
+}
+
+/* joylink_adapter_net_generic_resolve() is called by joylink_adapter_net_resolve() and joylink_adapter_net_resolve_ip() to
+ * do the actual work. It resolves the hostname "host" and set the string
+ * representation of the IP address into the buffer pointed by "ipbuf".
+ *
+ * If flags is set to ANET_IP_ONLY the function only resolves hostnames
+ * that are actually already IPv4 or IPv6 addresses. This turns the function
+ * into a validating / normalizing function. */
+int32_t
+joylink_adapter_net_generic_resolve(char *err, char *host, char *ipbuf, int32_t ipbuf_len,
+                       int32_t flags)
+{
+#if defined(__QC_4010__) || defined(__OV_788__)
+    printf("__QC_4010__:struct addrinfo not support\n");
+    return ANET_ERR;
+#else
+    struct addrinfo hints, *info;
+    int32_t rv;
+
+    memset(&hints,0,sizeof(hints));
+    
+    #if defined(__MICOKIT_3166__) || defined(__MW300__) || defined(__QC_4010__) || defined(__REALTEK_8711__)
+    printf("__MICOKIT_3166__:ANET IP ONLY not support\n");
+    #else
+    if (flags & ANET_IP_ONLY) hints.ai_flags = AI_NUMERICHOST;
+    #endif
+	hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;  /* specify socktype to avoid dups */
+
+    if ((rv = getaddrinfo(host, NULL, &hints, &info)) != 0) {
+		joylink_adapter_net_set_error(err, "getaddrinfo:%d", rv);
+        return ANET_ERR;
+    }
+    if (info->ai_family == AF_INET) {
+        struct sockaddr_in *sa = (struct sockaddr_in *)info->ai_addr;
+#if defined(__MW300__)
+        inet_ntop(AF_INET, (ip_addr_t *) &(sa->sin_addr), ipbuf, ipbuf_len);
+#else
+        #if defined(__REALTEK_8711__)
+        extern char * joylink_adapter_inet_ntoa(struct in_addr in_a);
+        if (ipbuf) {
+            char *temp_ip = joylink_adapter_inet_ntoa(sa->sin_addr);
+            memcpy(ipbuf,  temp_ip, strlen(temp_ip));
+        }
+        #else
+            inet_ntop(AF_INET, &sa->sin_addr, ipbuf, ipbuf_len);
+        #endif
+#endif
+    } 
+	else 
+	{
+		#ifndef __LINUX__
+		printf("__MICOKIT_3166__:not support ipv6\n");
+		#else
+		struct sockaddr_in6 *sa = (struct sockaddr_in6 *)info->ai_addr;
+        inet_ntop(AF_INET6, &(sa->sin6_addr), ipbuf, ipbuf_len);
+		#endif
+    }
+
+    freeaddrinfo(info);
+    return ANET_OK;
+#endif
+}
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: host
+ * @Param: ipbuf
+ * @Param: ipbuf_len
+ *
+ * @Returns: 
+ */
+int32_t
+joylink_adapter_net_resolve(char *err, char *host, char *ipbuf, int32_t ipbuf_len) {
+    return joylink_adapter_net_generic_resolve(err,host,ipbuf,ipbuf_len,ANET_NONE);
+}
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: host
+ * @Param: ipbuf
+ * @Param: ipbuf_len
+ *
+ * @Returns: 
+ */
+int32_t
+joylink_adapter_net_resolve_ip(char *err, char *host, char *ipbuf, int32_t ipbuf_len) {
+    return joylink_adapter_net_generic_resolve(err,host,ipbuf,ipbuf_len,ANET_IP_ONLY);
+}
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: fd
+ *
+ * @Returns: 
+ */
+static int32_t 
+joylink_adapter_net_set_reuse_addr(char *err, int32_t fd) {
+#if defined(__OV_788__)
+    printf("net_set_reuse_addr is not support\n"); 
+        return ANET_ERR;
+#else
+    int32_t yes = 1;
+    /* Make sure connection-intensive things like the redis benckmark
+     * will be able to close/open sockets a zillion of times */
+    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
+        joylink_adapter_net_set_error(err, "setsockopt SO_REUSEADDR: %s", strerror(errno));
+        return ANET_ERR;
+    }
+    return ANET_OK;
+#endif /*  ov_788 */
+}
+
+/**
+ * brief: 
+ *
+ * @Param: s
+ *
+ * @Returns: 
+ */
+static int32_t
+joylink_adapter_net_check_connect(int32_t s)
+{
+#if defined(__OV_788__)
+    return 0;
+#else
+    fd_set r_set;
+    struct timeval tm;
+
+    FD_ZERO(&r_set);
+    FD_SET(s, &r_set);
+
+    tm.tv_sec = 3;
+    tm.tv_usec = 0;
+
+    if (select(s + 1, NULL, &r_set, NULL, &tm) < 0) {
+        log_error("select error");
+        close(s);
+        return -1;
+    }
+
+    if (FD_ISSET(s, &r_set)) {
+        int32_t err = -1;
+        socklen_t len = sizeof(int32_t);
+        if (getsockopt(s, SOL_SOCKET, SO_ERROR ,&err, &len) < 0 ) {
+            log_error("getsockopt error");
+            close(s);
+            return -2;
+        }
+        if (err) {
+            log_error("err:%d, errno:%d", err, errno);
+            errno = err;    //ENETUNREACH(101):Network is unreachable
+            close(s);
+            return -3;
+        }
+    }
+    return 0;
+#endif
+}
+
+/**
+ *FIXME zhongxuan
+ */
+#define ANET_CONNECT_NONE 0
+#define ANET_CONNECT_NONBLOCK 1
+
+#if defined(__MTK_7687__)
+static int32_t 
+joylink_adapter_net_tcp_generic_connect(char *err, const char *addr, int32_t port, int32_t flags)
+{
+    int32_t s = ANET_ERR;   
+    
+    /* Try to create the socket and to connect it.
+     * If we fail in the socket() call, or on connect(), we retry with
+     * the next entry in servinfo. */
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1){
+            log_error("socket:%d", s);
+            goto error;
+        }
+    if (joylink_adapter_net_set_reuse_addr(err,s) == ANET_ERR) {
+        log_error("socket:%d", s);
+        goto error;
+    }
+    if (flags & ANET_CONNECT_NONBLOCK && joylink_adapter_net_non_block(err,s) != ANET_OK) {
+        log_error("ANET_CONNECT_NONBLOCK:%d", s);
+        goto error;
+     }
+
+    struct sockaddr_in in;
+    memset(&in, 0, sizeof(in));
+    in.sin_family = AF_INET;
+
+    in.sin_port = htons(port);
+    in.sin_addr.s_addr = joylink_adapter_inet_addr(addr);
+    
+    if (connect(s, (struct sockaddr*)&in, sizeof(struct sockaddr_in)) == -1) {
+        /* If the socket is non-blocking, it is ok for connect() to
+         * return an EINPROGRESS error here. */
+        if (errno == EINPROGRESS && flags & ANET_CONNECT_NONBLOCK) {            
+            if (0 == joylink_adapter_net_check_connect(s)){
+                log_error("connect:%d", s);
+                goto end;    
+            }
+            
+        }
+        close(s);
+        s = ANET_ERR; 
+
+        joylink_adapter_net_set_error(err, "connect: %s", strerror(errno));
+        log_error("socket:%d, errno:%d, %s", s, errno, err);
+    }    
+
+    /* If we ended an iteration of the for loop without errors, we
+     * have a connected socket. Let's return to the caller. */
+    goto end;   
+    
+error:
+    if (s != ANET_ERR) {
+        close(s);
+        s = ANET_ERR;
+    }
+end:    
+    return s;
+}
+#elif defined(__OV_788__)
+static int32_t 
+joylink_adapter_net_tcp_generic_connect(char *err, const char *addr, int32_t port, int32_t flags)
+{
+    int32_t s = ANET_ERR;   
+    
+    if ((s = tsock_init(TSOCK_TCP, 0, 0)) == -1){
+            log_error("socket:%d", s);
+            goto error;
+    }
+
+    struct sockaddr_in in;
+    memset(&in, 0, sizeof(in));
+    in.sin_family = AF_INET;
+
+    in.sin_port = htons(port);
+    in.sin_addr.s_addr = joylink_adapter_inet_addr(addr);
+    
+    if (tsock_connect(s, (uip_ipaddr_t*)&(in.sin_addr), in.sin_port) == -1) {
+        if (0 == joylink_adapter_net_check_connect(s)){
+            log_error("connect:%d", s);
+            goto end;    
+        }
+            
+        tsock_close(s);
+        s = ANET_ERR; 
+
+        log_error("socket:%d", s);
+    }    
+
+    /* If we ended an iteration of the for loop without errors, we
+     * have a connected socket. Let's return to the caller. */
+    goto end;   
+    
+error:
+    if (s != ANET_ERR) {
+        tsock_close(s);
+        s = ANET_ERR;
+    }
+end:    
+    return s;
+}
+#else
+static int32_t 
+joylink_adapter_net_tcp_generic_connect(char *err, const char *addr, int32_t port, int32_t flags)
+{
+#if defined(__QC_4010__)
+    printf("__QC_4010__:struct addrinfo not support\n");
+    return ANET_ERR;
+#else
+    int32_t s = ANET_ERR, rv;
+    char portstr[6];  /* strlen("65535") + 1; */
+    struct addrinfo hints, *servinfo, *p;
+
+    snprintf(portstr,sizeof(portstr),"%d",port);
+    memset(&hints,0,sizeof(hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+
+    if ((rv = getaddrinfo(addr,portstr,&hints,&servinfo)) != 0) {
+	    joylink_adapter_net_set_error(err, "getaddrinfo:%d", rv);
+        return ANET_ERR;
+    }
+    for (p = servinfo; p != NULL; p = p->ai_next) {
+        /* Try to create the socket and to connect it.
+         * If we fail in the socket() call, or on connect(), we retry with
+         * the next entry in servinfo. */
+        if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
+            continue;
+        if (joylink_adapter_net_set_reuse_addr(err,s) == ANET_ERR) goto error;
+        if (flags & ANET_CONNECT_NONBLOCK && joylink_adapter_net_non_block(err,s) != ANET_OK)
+            goto error;
+        if (connect(s, p->ai_addr, p->ai_addrlen) == -1) {
+            /* If the socket is non-blocking, it is ok for connect() to
+             * return an EINPROGRESS error here. */
+            if (errno == EINPROGRESS && flags & ANET_CONNECT_NONBLOCK) {
+                if (0 == joylink_adapter_net_check_connect(s)){
+                    goto end;    
+                }
+                
+            }
+            close(s);
+            s = ANET_ERR;
+            continue;
+        }
+
+        /* If we ended an iteration of the for loop without errors, we
+         * have a connected socket. Let's return to the caller. */
+        goto end;
+    }
+    if (p == NULL) {
+        joylink_adapter_net_set_error(err, "creating socket: %s", strerror(errno));
+        log_error("errno:%d, %s", errno, err);
+    }
+
+error:
+    if (s != ANET_ERR) {
+        close(s);
+        s = ANET_ERR;
+    }
+end:
+    freeaddrinfo(servinfo);
+    return s;
+#endif
+}
+#endif
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: addr
+ * @Param: port
+ *
+ * @Returns: 
+ */
+int32_t
+joylink_adapter_net_tcp_connect(char *err, const char *addr, int32_t port)
+{
+    return joylink_adapter_net_tcp_generic_connect(err, addr,port,ANET_CONNECT_NONE);
+}
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: addr
+ * @Param: port
+ *
+ * @Returns: 
+ */
+int32_t
+joylink_adapter_net_tcp_non_block_connect(char *err, char *addr, int32_t port)
+{
+    return joylink_adapter_net_tcp_generic_connect(err,addr,port,ANET_CONNECT_NONBLOCK);
+}
+
+int32_t
+joylink_adapter_net_read_no_check_out(int32_t fd, char *buf, int32_t count)
+{
+    return read(fd,buf,count);
+}
+
+/* Like read(2) but make sure 'count' is read before to return
+ * (unless error or EOF condition is encountered) */
+int32_t
+joylink_adapter_net_read(int32_t fd, char *buf, int32_t count)
+{
+    int32_t nread, totlen = 0;
+    while(totlen != count) {
+#if defined(__OV_788__)
+	nread = tsock_recv(fd, buf, count-totlen); 
+#else
+        nread = read(fd,buf,count-totlen);
+#endif
+        if (nread == 0) return totlen;
+        if (nread == -1) return -1;
+        totlen += nread;
+        buf += nread;
+    }
+    return totlen;
+}
+
+extern void joylink_cloud_set_st(int32_t value);
+
+/* Like write(2) but make sure 'count' is read before to return
+ * (unless error is encountered) */
+int32_t
+joylink_adapter_net_write(int32_t fd, char *buf, int32_t count)
+{
+    int32_t nwritten, totlen = 0;
+    while(totlen != count) {
+#if defined(__OV_788__)
+        nwritten = tsock_send(fd, buf, count-totlen);
+#else
+        nwritten = write(fd,buf,count-totlen);
+#endif
+        if (nwritten == 0) return totlen;
+        if (nwritten == -1) return -1;
+        totlen += nwritten;
+        buf += nwritten;
+    }
+    return totlen;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: buf
+ * @Param: size
+ *
+ * @Returns: 
+ */
+int32_t
+joylink_adapter_net_send(int32_t fd, char *buf, int32_t size)
+{
+    if(fd < 0){
+        printf("------------- XXXXX fd is -1 XXXXXXXX\n");
+        return E_ERROR;
+    }
+    int32_t count = 0;
+    int32_t ret = E_ERROR;
+SEND:
+    log_info("fd:%d, size:%d", fd, size);
+#if defined(__OV_788__)
+    ret  = tsock_send(fd, buf, size);
+#else
+    ret = send(fd, buf, size, 0);
+#endif
+    count++;
+    if (ret >= 0) {
+        if (ret == size) {
+            log_info("net send OK : %d", size);
+            return size;
+        }
+        if (ret < size) {
+            log_info("net send OK : %d", ret);
+            int32_t ret_l = joylink_adapter_net_send(fd, buf + ret, size - ret);
+            if (ret_l == (size - ret)) {
+                log_info("net send OK : %d", size);
+                return size;
+            } else {
+#if defined(__OV_788__)
+                tsock_close(fd);
+#else
+                close(fd);
+#endif
+                return ret_l;
+            }
+        }
+    } else {
+#if defined(__QC_4010__) || defined(__OV_788__)
+         log_error("unknown error! errno:%d", ret);
+#else
+        switch(errno){
+            case EINTR:         //Interrupted system call
+                log_error("interrupted system call");
+                close(fd);
+                break;
+            case EAGAIN:        //Try again
+                log_info("count:%d", count);
+                if (count <= 3) {
+#if defined(__MICOKIT_3166__) || defined(__MW300__) || defined(__ESP32__)
+#elif defined(__MTK_7687__)
+                    os_sleep(0, 10);
+#else
+                    usleep(10);
+#endif
+                    goto SEND;    
+                } else {
+                    /*close fd, set st*/
+                    log_error("retry send 10 times, net send error");
+                    close(fd);
+                }
+                break;
+            case EBADF:         //Bad file number
+                log_error("bad file number");
+                close(fd);
+                break;
+            default:
+                log_error("unknown error! errno:%d, %s", errno, strerror(errno));
+                close(fd);
+        }    
+#endif
+    }
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: buf
+ * @Param: size
+ *
+ * @Returns: 
+ */
+int32_t
+joylink_adapter_net_recv(int32_t fd, char *buf, int32_t size)
+{
+    int32_t count  = 0;
+    int32_t ret = E_ERROR;
+
+SEND:
+#if defined(__OV_788__)
+    ret = tsock_recv(fd, buf, size);
+#else
+    ret = recv(fd, buf, size, 0);
+#endif
+    count++;
+    if (ret > 0) {
+        if (ret == size) {
+            /*log_info("net recv OK : %d", size);*/
+            return size;
+        }
+        if (ret < size) {
+            /*log_info("net recv OK : %d", ret);*/
+            int32_t ret_l = joylink_adapter_net_recv(fd, buf + ret, size - ret);
+            if (ret_l == (size - ret)) {
+                /*log_info("net recv OK : %d", size);*/
+                return size;
+            } else {
+#if defined(__OV_788__)
+                tsock_close(fd);
+#else
+                close(fd);
+#endif
+                return ret_l;
+            }
+        }
+    } else if (ret == 0) {
+#if defined(__OV_788__)
+                tsock_close(fd);
+#else
+                close(fd);
+#endif
+        log_error("tcp is disconnected");
+        return E_ERROR;
+    } else if (ret < 0) {
+#if defined(__QC_4010__) || defined(__OV_788__)
+         log_error("unknown error! errno:%d", ret);
+#else
+        switch(errno){
+            case EINTR:         //Interrupted system call
+                break;
+            case EAGAIN:        //Try again
+                if (count <= 10) {
+                    sleep(1);
+                    goto SEND;    
+                } else {
+                    /*close fd*/
+                    log_error("timeout 10s, net recv error");
+                    close(fd);
+                }
+                break;
+            case EBADF:         //Bad file number
+                close(fd);
+                break;
+            default:
+                log_error("unknown error! errno:%d, %s", errno, strerror(errno));
+                close(fd);
+        }
+#endif
+    }
+    return ret;
+}
+
+/**
+ * [joylink_adapter_net_recv_with_time] 
+ *
+ * @param: [fd]
+ * @param: [buf]
+ * @param: [size]
+ * @param: [usec]
+ * @param: [sec]
+ *
+ * @returns: 
+ */
+int32_t
+joylink_adapter_net_recv_with_time(int32_t fd, char *buf, int32_t size, int32_t usec, int32_t sec)
+{
+    struct timeval select_time_out;
+    fd_set  read_fds;
+    int32_t ret;
+
+    FD_ZERO(&read_fds);
+    select_time_out.tv_usec = usec;
+    select_time_out.tv_sec = (long)sec;
+
+#if defined(__OV_788__)
+    ret = select(&read_fds, NULL, NULL, &select_time_out);
+#else
+    ret = select(fd + 1, &read_fds, NULL, NULL, &select_time_out);
+#endif
+    if (ret < 0){
+        log_error("select err: %d!\r\n", ret);
+    }else if (ret == 0){
+        log_error("select err timeout: %d!\r\n", ret);
+    }else if (ret > 0){
+        return joylink_adapter_net_recv(fd, buf, size);
+    }
+
+    return E_ERROR;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: s
+ * @Param: sa
+ * @Param: len
+ * @Param: backlog
+ *
+ * @Returns: 
+ */
+static int32_t 
+joylink_net_listen(char *err, int32_t s, struct sockaddr *sa, socklen_t len, int32_t backlog) {
+	
+#if defined(__OV_788__)
+    struct sockaddr_in *in = (struct sockaddr_in *)sa;
+    if (tsock_bind(s, in->sin_port) == -1) {
+        log_error(err, "bind: %d", s);
+        tsock_close(s);
+#else
+    if (bind(s,sa,len) == -1) {
+        joylink_adapter_net_set_error(err, "bind: %s", strerror(errno));
+        close(s);
+#endif
+        return ANET_ERR;
+    }
+
+#if defined(__OV_788__)
+    if (tsock_listen(s, backlog) == -1) {
+        log_error(err, "listen: %d", s);
+        tsock_close(s);
+        return ANET_ERR;
+    }
+#else
+if (listen(s, backlog) == -1) {
+        joylink_adapter_net_set_error(err, "listen: %s", strerror(errno));
+        close(s);
+        return ANET_ERR;
+    }
+#endif
+    return ANET_OK;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: s
+ *
+ * @Returns: 
+ */
+static int32_t 
+joylink_adapter_net_v6_only(char *err, int32_t s) 
+{
+#ifndef __LINUX__
+	printf("__MICOKIT_3166__:not support IPV6\n");
+	return ANET_ERR;
+#else
+	int32_t yes = 1;
+    if (setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,&yes,sizeof(yes)) == -1) {
+        joylink_adapter_net_set_error(err, "setsockopt: %s", strerror(errno));
+        close(s);
+        return ANET_ERR;
+    }
+    return ANET_OK;
+#endif
+}
+
+#if defined(__LINUX__)
+static int32_t 
+_joylink_net_tcp_server(char *err, int32_t port, char *bindaddr, int32_t af, int32_t backlog)
+{
+#if defined(__QC_4010__)
+    printf("__QC_4010__:struct addrinfo not support\n");
+    return ANET_ERR;
+#else
+    int32_t s, rv;
+    char _port[6];  /* strlen("65535") */
+    struct addrinfo hints, *servinfo, *p;
+
+    snprintf(_port,6,"%d",port);
+
+    memset(&hints,0,sizeof(hints));
+    hints.ai_family = af;
+    hints.ai_socktype = SOCK_STREAM;
+    /*AI_PASSIVE == 0x0001*/
+	hints.ai_flags = 0x0001;
+
+    if ((rv = getaddrinfo(bindaddr, _port, &hints, &servinfo)) != 0) {
+        joylink_adapter_net_set_error(err, "getaddrinfo:%d", rv);
+        return ANET_ERR;
+    }
+
+    for (p = servinfo; p != NULL; p = p->ai_next) {
+        if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
+            continue;
+#if defined(__LINUX__) || defined(__LINUX_UB2__) 
+        if (af == AF_INET6 && joylink_adapter_net_v6_only(err,s) == ANET_ERR) goto error;
+#endif
+		if (joylink_adapter_net_set_reuse_addr(err,s) == ANET_ERR) goto error;
+        if (joylink_net_listen(err,s,p->ai_addr,p->ai_addrlen,backlog) == ANET_ERR) goto error;
+
+        goto end;
+    }
+    if (p == NULL) {
+        joylink_adapter_net_set_error(err, "unable to bind socket");
+        goto error;
+    }
+
+error:
+    s = ANET_ERR;
+end:
+    freeaddrinfo(servinfo);
+    return s;
+#endif
+}
+#else
+static int32_t 
+_joylink_net_tcp_server(char *err, int32_t port, char *bindaddr, int32_t af, int32_t backlog)
+{
+	int32_t fd = -1;
+	struct sockaddr_in sin;
+
+    memset(&sin, 0, sizeof(sin));                
+    sin.sin_family      = AF_INET;
+    sin.sin_port        = htons(port);
+#if !defined(__OV_788__)
+    sin.sin_addr.s_addr = htonl(INADDR_ANY);
+#endif
+
+#if defined(__OV_788__)
+	fd = tsock_init(TSOCK_TCP_LISTEN, 0, 0);
+#else
+	fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+#endif
+	if(fd < 0){
+		LOG_ERROR_RET("tcp socket failed");
+	}
+
+#if defined(__OV_788__)
+	if(tsock_bind(fd, sin.sin_port) < 0){
+		tsock_close(fd);
+#else
+	if(bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0){
+		close(fd);
+#endif
+		fd = -1;
+		LOG_ERROR_RET("tcp bind failed");
+	}
+	
+#if defined(__OV_788__)
+	if(tsock_listen(fd, 6) < 0){
+		tsock_close(fd);
+#else
+	if(listen(fd, 6) < 0){
+		close(fd);
+#endif
+		fd = -1;
+		LOG_ERROR_RET("tcp listen failed");
+	}
+RET:
+	return fd;
+}
+#endif
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: port
+ * @Param: bindaddr
+ * @Param: backlog
+ *
+ * @Returns: 
+ */
+int32_t
+joylink_adapter_net_tcp_server(char *err, int32_t port, char *bindaddr, int32_t backlog)
+{
+    return _joylink_net_tcp_server(err, port, bindaddr, AF_INET, backlog);
+}
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: port
+ * @Param: bindaddr
+ * @Param: backlog
+ *
+ * @Returns: 
+ */
+int32_t
+joylink_adapter_net_tcp6_server(char *err, int32_t port, char *bindaddr, int32_t backlog)
+{
+    #ifndef __LINUX__
+	printf("__MICOKIT_3166__:not support IPV6\n");
+	return ANET_ERR;
+	#else
+	return _joylink_net_tcp_server(err, port, bindaddr, AF_INET6, backlog);
+	#endif
+}
+static int32_t joylink_net_generic_accept(char *err, int32_t s, struct sockaddr *sa, socklen_t *len) {
+    int32_t fd;
+    while(1) {
+#if defined(__OV_788__)
+        struct sockaddr_in *in = (struct sockaddr_in*)sa;
+        fd = tsock_accept(s);        
+        memset(in, 0, sizeof(struct sockaddr_in));
+        memcpy(&in->sin_addr, ((struct tsock*)s)->ripaddr, sizeof(in->sin_addr));
+        in->sin_port = ((struct tsock*)s)->rport;
+#else
+        fd = accept(s,sa,len);        
+#endif
+        if (fd == -1) {
+#if defined(__QC_4010__) || defined(__OV_788__)
+#else
+            if (errno == EINTR)
+                continue;
+            else {
+                joylink_adapter_net_set_error(err, "accept: %s", strerror(errno));
+                return ANET_ERR;
+            }
+#endif
+        }
+        break;
+    }
+    return fd;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: s
+ * @Param: ip
+ * @Param: ip_len
+ * @Param: port
+ *
+ * @Returns: 
+ */
+int32_t
+joylink_net_tcp_accept(char *err, int32_t s, char *ip, int32_t ip_len, int32_t *port) {
+    int32_t fd;
+#if defined(__REALTEK_8711__)
+    struct sockaddr sa;
+#elif defined(__OV_788__)
+    struct sockaddr_in sa;
+#else
+    struct sockaddr_storage sa;
+#endif
+    socklen_t salen = sizeof(sa);
+    if ((fd = joylink_net_generic_accept(err,s,(struct sockaddr*)&sa,&salen)) == -1){
+        log_error("joylink_net_generic_accept fd:%d, %d", fd, salen);
+        return ANET_ERR;
+    }
+
+#if defined(__REALTEK_8711__) 
+    if (sa.sa_family == AF_INET) {
+#elif defined(__OV_788__)
+    if (sa.sin_family == AF_INET) {
+#else
+    if (sa.ss_family == AF_INET) {
+#endif
+        struct sockaddr_in *si = (struct sockaddr_in *)&sa;
+#if defined(__QC_4010__) || defined(__REALTEK_8711__) || defined(__OV_788__) | defined(__MTK_7687__)
+        extern char * joylink_adapter_inet_ntoa(struct in_addr in_a);
+        if (ip) {
+            char *temp_ip = joylink_adapter_inet_ntoa(si->sin_addr);
+            memcpy(ip,  temp_ip, strlen(temp_ip));
+        }
+#else
+        if (ip) inet_ntop(AF_INET,(void*)&(si->sin_addr),ip,ip_len);
+#endif
+        if (port) *port = ntohs(si->sin_port);
+    } else {
+    	#ifndef __LINUX__
+		#else
+        struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)&sa;
+        if (ip) inet_ntop(AF_INET6,(void*)&(s6->sin6_addr),ip,ip_len);
+        if (port) *port = ntohs(s6->sin6_port);
+		#endif
+    }
+    return fd;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: ip
+ * @Param: ip_len
+ * @Param: port
+ *
+ * @Returns: 
+ */
+int32_t
+joylink_net_peer_to_string(int32_t fd, char *ip, int32_t ip_len, int32_t *port) {
+#if defined(__REALTEK_8711__)
+    struct sockaddr sa;
+#elif defined(__OV_788__)
+    struct sockaddr_in sa;
+#else
+    struct sockaddr_storage sa;
+#endif
+    socklen_t salen = sizeof(sa);
+
+#if defined(__OV_788__)
+    memset(&sa, 0, sizeof(struct sockaddr_in));
+    memcpy(&sa.sin_addr, ((struct tsock*)fd)->ripaddr, sizeof(sa.sin_addr));
+    sa.sin_port = ((struct tsock*)fd)->rport;
+#else
+    if (getpeername(fd,(struct sockaddr*)&sa,&salen) == -1) {
+        if (port) *port = 0;
+        ip[0] = '?';
+        ip[1] = '\0';
+        return -1;
+    }
+#endif
+
+#if defined(__REALTEK_8711__)
+    if (sa.sa_family == AF_INET) {
+#elif defined(__OV_788__)
+    if (sa.sin_family == AF_INET) {
+#else
+    if (sa.ss_family == AF_INET) {
+#endif
+        struct sockaddr_in *s = (struct sockaddr_in *)&sa;
+#if defined(__REALTEK_8711__)|| defined(__OV_788__)
+        extern char * joylink_adapter_inet_ntoa(struct in_addr in_a);
+        if (ip) {
+            char *temp_ip = joylink_adapter_inet_ntoa(s->sin_addr);
+            memcpy(ip,  temp_ip, strlen(temp_ip));
+        }
+#else
+        if (ip) inet_ntop(AF_INET,(void*)&(s->sin_addr),ip,ip_len);
+#endif
+        if (port) *port = ntohs(s->sin_port);
+    } 
+    else 
+    {
+        #ifndef __LINUX__
+        #else
+        struct sockaddr_in6 *s = (struct sockaddr_in6 *)&sa;
+        if (ip) inet_ntop(AF_INET6,(void*)&(s->sin6_addr),ip,ip_len);
+        if (port) *port = ntohs(s->sin6_port);
+        #endif
+    }
+    return 0;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: ip
+ * @Param: ip_len
+ * @Param: port
+ *
+ * @Returns: 
+ */
+int32_t
+joylink_net_sock_name(int32_t fd, char *ip, int32_t ip_len, int32_t *port) {
+#if defined(__REALTEK_8711__)
+    struct sockaddr sa;
+#elif defined(__OV_788__)
+    struct sockaddr_in sa;
+#else
+    struct sockaddr_storage sa;
+#endif
+    socklen_t salen = sizeof(sa);
+
+#if defined(__OV_788__)
+    memset(&sa, 0, sizeof(struct sockaddr_in));
+    memcpy(&sa.sin_addr, ((struct tsock*)fd)->ripaddr, sizeof(sa.sin_addr));
+    sa.sin_port = ((struct tsock*)fd)->rport;
+#else
+    if (getsockname(fd,(struct sockaddr*)&sa,&salen) == -1) {
+        if (port) *port = 0;
+        ip[0] = '?';
+        ip[1] = '\0';
+        return -1;
+    }
+#endif
+
+#if defined(__REALTEK_8711__)
+    if (sa.sa_family == AF_INET) {
+#elif defined(__OV_788__)
+    if (sa.sin_family == AF_INET) {
+#else
+    if (sa.ss_family == AF_INET) {
+#endif
+        struct sockaddr_in *s = (struct sockaddr_in *)&sa;
+#if defined(__REALTEK_8711__) || defined(__OV_788__)
+        extern char * joylink_adapter_inet_ntoa(struct in_addr in_a);
+        if (ip) {
+            char *temp_ip = joylink_adapter_inet_ntoa(s->sin_addr);
+            memcpy(ip,  temp_ip, strlen(temp_ip));
+        }
+#else
+        if (ip) inet_ntop(AF_INET,(void*)&(s->sin_addr),ip,ip_len);
+#endif
+        if (port) *port = ntohs(s->sin_port);
+    } 
+    else 
+    {
+#ifndef __LINUX__
+#else
+      struct sockaddr_in6 *s = (struct sockaddr_in6 *)&sa;
+        if (ip) inet_ntop(AF_INET6,(void*)&(s->sin6_addr),ip,ip_len);
+        if (port) *port = ntohs(s->sin6_port);
+#endif
+    }
+    return 0;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: cp
+ * @Param: ap
+ *
+ * @Returns: 
+ */
+int  
+joylink_adapter_inet_aton(const char *cp, struct in_addr *ap)
+{
+    int dots = 0;
+	#if defined(__MICOKIT_3166__) || defined(__REALTEK_8711__) || defined(__OV_788__)
+	register unsigned long acc = 0, addr = 0;
+
+	#else
+    register u_long acc = 0, addr = 0;
+	#endif
+    do {
+        register char cc = *cp;
+
+        switch (cc) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+                acc = acc * 10 + (cc - '0');
+                break;
+
+            case '.':
+                if (++dots > 3) {
+                    return 0;
+                }
+                /* Fall through */
+
+            case '\0':
+                if (acc > 255) {
+                    return 0;
+                }
+                addr = addr << 8 | acc;
+                acc = 0;
+                break;
+
+            default:
+                return 0;
+        }
+    } while (*cp++) ;
+
+    /* Normalize the address */
+    if (dots < 3) {
+        addr <<= 8 * (3 - dots) ;
+    }
+
+    /* Store it if requested */
+    if (ap) {
+        ap->s_addr = htonl(addr);
+    }
+
+    return 1;    
+}
+
+/*int inet_aton(const char *cp, struct in_addr *inp);*/
+
+         /*in_addr_t joylink_adapter_inet_addr(const char *cp);*/
+/* 
+  * Ascii internet address interpretation routine. 
+  * The value returned is in network order. 
+  */ 
+/*  */ 
+unsigned long 
+joylink_adapter_inet_addr(const char *cp)
+{ 
+#if defined(__LINUX__) || defined(__MICOKIT_3166__)
+    return inet_addr(cp);
+#else
+    struct in_addr val;
+
+    if (joylink_adapter_inet_aton(cp, &val))
+        return (val.s_addr);
+    return (INADDR_NONE);
+#endif
+} 
+  
+/**
+ * brief: 
+ *
+ * @Param: in_a
+ *
+ * @Returns: 
+ */
+char *  
+joylink_adapter_inet_ntoa(struct in_addr in_a)
+{
+#if defined(__LINUX__) || defined(__MICOKIT_3166__)
+    return inet_ntoa(in_a);
+#else
+    static char buffer[16];
+    memset(buffer, 0, sizeof(buffer));
+    
+    uint32_t tm = 0;
+    memcpy(&tm, &in_a, 4);
+    unsigned char *bytes = (unsigned char *) &tm;
+    snprintf( buffer, sizeof (buffer), "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3] );
+    return buffer;
+#endif
+}
+
+/**
+ * brief: 
+ *
+ * @Param: nfds
+ * @Param: readfds
+ * @Param: writefds
+ * @Param: exceptfds
+ * @Param: timeout
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_select(int nfds, fd_set *readfds, fd_set *writefds,
+                fd_set *exceptfds, struct timeval *timeout)
+{
+#if defined(__OV_788__)
+    return select(readfds, writefds, exceptfds, timeout);
+#else
+    return select(nfds, readfds, writefds, exceptfds, timeout);
+#endif
+}
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_close(int32_t fd)
+{
+#if defined(__OV_788__)
+    return tsock_close(fd);
+#else
+    return close(fd);
+#endif
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_udp_socket()
+{
+#if defined(__MICOKIT_3166__) || defined(__MW300__)
+	return socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+#elif defined(__QC_4010__) || defined(__REALTEK_8711__)
+	return socket(AF_INET,SOCK_DGRAM, 0);
+#elif defined(__OV_788__)
+	return tsock_init(TSOCK_UDP, 0, 0);
+#else
+	return socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
+#endif  
+}
+
+#if defined(__ANDROID__) || defined(__IOS__)
+E_JL_RETCODE 
+joylink_adapter_multi_net_get_ip(char* ipv4, const uint32_t max_size)
+{
+    int i = 0, buf_size = 512;
+    int sock_fd = -1;
+    struct ifreq *ifreq;
+    struct ifconf ifconf;
+    char *buf = (char *)malloc(buf_size);
+    char *sin_addr = NULL;
+    E_JL_RETCODE ret = E_ERROR;
+
+    ifconf.ifc_len = buf_size;
+    ifconf.ifc_buf = buf;
+    if((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
+        log_error("socket create failed");
+        goto RET;
+    }
+    ioctl(sock_fd, SIOCGIFCONF, &ifconf);
+
+    ifreq = (struct ifreq *)buf;
+    i = ifconf.ifc_len / sizeof(struct ifreq);
+    int count = 0;
+    for(count = 0; (count < 5 && i > 0); i--){
+        sin_addr = inet_ntoa(((struct sockaddr_in*)&(ifreq->ifr_addr))->sin_addr);
+        log_debug("ip addr:%s", sin_addr);
+        if(strcmp(sin_addr, "127.0.0.1") && (strcmp(sin_addr, ""))){
+            strncpy(ipv4, sin_addr, max_size);
+            ret = E_OK;
+            break;
+        }else{
+            count++;
+            ifreq++;
+            continue;
+        }
+    }
+RET:
+    if(NULL != buf){
+        free(buf);
+    }
+    if(sock_fd > 0){
+        close(sock_fd);
+    }
+
+    return ret;
+}
+#endif

+ 324 - 0
joylink/agent/joylink_adapter_net.h

@@ -0,0 +1,324 @@
+/*Copyright (c) 2015-2050, JD Smart All rights reserved.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License. */
+
+#ifndef JOYLINK_ADAPTER_NET_TCP_H
+#define JOYLINK_ADAPTER_NET_TCP_H 
+
+#include <stdint.h>
+
+#define ANET_OK                     0
+#define ANET_ERR                    -1
+#define ANET_ERR_LEN                256
+
+/* Flags used with certain functions. */
+#define ANET_NONE                   0
+#define ANET_IP_ONLY (1<<0)
+
+#if defined(__sun)
+#define AF_LOCAL AF_UNIX
+#endif
+
+#include "joylink_ret_code.h"
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: addr
+ * @Param: port
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_tcp_connect(char *err, const char *addr, int32_t port);
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: addr
+ * @Param: port
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_tcp_non_block_connect(char *err, char *addr, int32_t port);
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: port
+ * @Param: bindaddr
+ * @Param: backlog
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_tcp_server(char *err, int32_t port, char *bindaddr, int32_t backlog);
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: port
+ * @Param: bindaddr
+ * @Param: backlog
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_tcp6_server(char *err, int32_t port, char *bindaddr, int32_t backlog);
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: serversock
+ * @Param: ip
+ * @Param: ip_len
+ * @Param: port
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_net_tcp_accept(char *err, int32_t serversock, char *ip, int32_t ip_len, int32_t *port);
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: fd
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_tcp_keep_alive(char *err, int32_t fd);
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: serversock
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_net_unix_accept(char *err, int32_t serversock);
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: fd
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_non_block(char *err, int32_t fd);
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: fd
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_enable_tcp_no_delay(char *err, int32_t fd);
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: fd
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_disable_tcp_no_delay(char *err, int32_t fd);
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: ip
+ * @Param: ip_len
+ * @Param: port
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_net_peer_to_string(int32_t fd, char *ip, int32_t ip_len, int32_t *port);
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: fd
+ * @Param: int32_terval
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_keep_alive(char *err, int32_t fd, int32_t int32_terval);
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: ip
+ * @Param: ip_len
+ * @Param: port
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_net_sock_name(int32_t fd, char *ip, int32_t ip_len, int32_t *port);
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: host
+ * @Param: ipbuf
+ * @Param: ipbuf_len
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_resolve(char *err, char *host, char *ipbuf, int32_t ipbuf_len);
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: host
+ * @Param: ipbuf
+ * @Param: ipbuf_len
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_resolve_ip(char *err, char *host, char *ipbuf, int32_t ipbuf_len);
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: buf
+ * @Param: size
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_send(int32_t fd, char *buf, int32_t size);
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: buf
+ * @Param: size
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_recv(int32_t fd, char *buf, int32_t size);
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: buf
+ * @Param: count
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_read(int32_t fd, char *buf, int32_t count);
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: buf
+ * @Param: count
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_write(int32_t fd, char *buf, int32_t count);
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: buf
+ * @Param: size
+ * @Param: usec
+ * @Param: sec
+ *
+ * @Returns: 
+ */
+int32_t
+joylink_adapter_net_recv_with_time(int32_t fd, char *buf, int32_t size, int32_t usec, int32_t sec);
+
+/**
+ * brief: 
+ *
+ * @Param: err
+ * @Param: fd
+ * @Param: buffsize
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_set_send_buf(char *err, int32_t fd, int32_t buffsize);
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_net_close(int32_t fd);
+
+
+/**
+ * brief: 
+ *
+ * @Param: nfds
+ * @Param: readfds
+ * @Param: writefds
+ * @Param: exceptfds
+ * @Param: timeout
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_select(int nfds, fd_set *readfds, fd_set *writefds,
+                fd_set *exceptfds, struct timeval *timeout);
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int32_t 
+joylink_adapter_udp_socket();
+
+#endif

+ 930 - 0
joylink/agent/joylink_agent.c

@@ -0,0 +1,930 @@
+/* --------------------------------------------------
+ * @brief: 
+ *
+ * @version: 1.0
+ *
+ *
+ * @author: 
+ * --------------------------------------------------
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <arpa/inet.h>
+#include "joylink_agent.h"
+#include "joylink_agent_devs.h"
+#include "joylink_log.h"
+#include "joylink_agent_json.h"
+
+typedef struct {
+    int32_t fd;
+    int32_t st;
+    int32_t cloud_thread_run;
+    char eabled;
+    pthread_t ntid;
+}jl_agent_cloud_mg_t;
+
+static jl_agent_cloud_mg_t _g_c_mg, * _g_p_cmg = &_g_c_mg;
+
+extern int 
+joylink_dencypt_server_req(
+        JLPacketParam_t *pParam, 
+        const uint8_t *pIn, 
+        int length, 
+        uint8_t* pOut, int maxlen, char*  feedid);
+
+#ifdef _AGENT_GW_ 
+pthread_mutex_t    agent_devs_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+/**
+ * brief: 
+ */
+void joylink_agent_devs_lock() 		
+{
+#ifdef _AGENT_GW_ 
+    pthread_mutex_lock(&agent_devs_lock);
+#endif
+}
+
+/**
+ * brief: 
+ */
+void joylink_agent_devs_unlock() 		
+{
+#ifdef _AGENT_GW_ 
+    pthread_mutex_unlock(&agent_devs_lock);
+#endif
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+static jl_agent_cloud_mg_t*
+joylink_agent_cloud_mg(void)
+{
+    return &_g_c_mg;
+}
+
+/**
+ * [joylink_agent_cloud_init]
+ */
+E_JLRetCode_t
+joylink_agent_cloud_init(void)
+{
+    jl_agent_cloud_mg_t init_c_mg = { -1, 0, 1, 1};
+    memcpy(_g_p_cmg, &init_c_mg, sizeof(jl_agent_cloud_mg_t));
+
+    char err[512] = {0};
+    int socket = joylink_adapter_net_tcp_server(err, JL_AGENT_GW_PORT, 
+            NULL, JL_AGENT_GW_CLIENT_MAX);
+
+    if(socket < 0){
+        log_error("agent cloud tcp socket create error.");
+        return E_RET_ERROR;
+    }
+
+    _g_p_cmg->fd = socket;
+
+    return E_RET_OK;
+}
+
+/**
+ * [joylink_agent_cloud_finit]
+ */
+void 
+joylink_agent_cloud_finit(void)
+{
+    log_debug("=====finit cloud data: init st; close fd, set it to -1=====");
+    _g_c_mg.st = 0;
+    if (_g_c_mg.fd > 0) {
+        joylink_adapter_net_close(_g_c_mg.fd);
+    }
+    _g_c_mg.fd = -1;
+    log_debug("=====finit cloud data end=====");
+    
+    return;
+}
+
+E_JLRetCode_t
+joylink_agent_make_session_key(char *skey)
+{
+    char sk[32] = "01234567890123456789012345678901";
+    memcpy(skey, sk, 32);
+    return E_RET_OK;
+}
+
+int
+joylink_agent_dev_rsp()
+{
+    int ret = -1;
+    int time_v;
+    int len;
+    char data[JL_MAX_PACKET_LEN] = {0};
+
+    ret = joylink_dev_get_snap_shot(data + 4, JL_MAX_PACKET_LEN - 4);
+
+    if(ret > 0){
+        time_v = time(NULL);
+        memcpy(data, &time_v, 4);
+
+        len = joylink_encypt_server_rsp(
+                _g_pdev->send_buff,
+                JL_MAX_PACKET_LEN, PT_UPLOAD,
+                _g_pdev->jlp.sessionKey, 
+                (uint8_t*)&data,
+                ret + 4);
+
+        if(len > 0 && len < JL_MAX_PACKET_LEN){
+            ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+            if(ret < 0){
+                log_error("send error ret:%d", ret);
+            }
+            log_debug("send to server len:%d:ret:%d\n", len, ret);
+        }else{
+            log_error("send data too big or packe error:ret:%d", ret);
+        }
+    }
+
+    return ret;
+}
+
+int 
+joylink_agent_cloud_rsp_packet(
+        uint8_t* pBuf, 
+        int buflen, 
+        E_PacketType cmd, 
+        uint8_t* pOpt, 
+        int optLen, 
+        uint8_t* key, 
+        const uint8_t* payload, 
+        int payloadLen)
+{
+	JLPacketHead_t head = {
+		.magic = 0x123455CC,
+		.optlen = 0,
+		.payloadlen = 0,
+		.version = 1,
+		.type = (char)cmd,
+		.total = 0,
+		.index = 0,
+		.enctype = (char)1,
+		.reserved = 0,
+		.crc = 0		// Todo:У??CRC
+	};
+
+	int len = 0;
+	uint8_t* pOut = pBuf + sizeof(JLPacketHead_t) + optLen;
+    
+    /*1 packet opt*/
+    if((NULL != pOpt) && (optLen > 0)){
+        memcpy(pOut, pOpt, optLen);
+        head.optlen = optLen;
+    }
+    /*2 enctype type*/
+    switch (cmd) {
+        case PT_AUTH:
+            head.enctype = ET_ACCESSKEYAES;
+            break;
+        default:
+            head.enctype = ET_SESSIONKEYAES;
+            break;
+    }
+
+    /*3 encrypt payload*/
+    /*4 packet payload*/
+    len = device_aes_encrypt(
+            key, 16,
+            key + 16,
+            (uint8_t*)payload,
+            payloadLen,
+            pOut, buflen);
+
+    head.payloadlen = len;
+    pOut += len;
+
+    /*5 crc*/
+	len = pOut - pBuf;
+	head.crc = CRC16(pBuf + sizeof(JLPacketHead_t), 
+            len - sizeof(JLPacketHead_t));
+
+    /*6 packet head*/
+	memcpy(pBuf, &head, sizeof(head));
+    
+    /*7 return all packet len*/
+	return len;
+}
+
+/*
+ * agent dev >> agent GW
+ * tcp
+ * 
+ */
+E_JLRetCode_t
+joylink_agent_dev_cloud_auth_hand(int32_t fd, char* feedid, uint32_t d_rand, 
+        uint8_t *payload, int32_t s_len, char* auth_org)
+{
+    /**
+     *1 check random  
+     *2 create session key
+     *3 packet rsp
+     *4 send to rsp
+     *5 update session key and fd to agent dev
+     */
+    int ret = E_RET_ERROR;
+    int len = 0;
+    char auth_rsp[4 + 4 + 32] = {0};
+    char buff[JL_MAX_PACKET_LEN] = {0};
+
+    JLAuth_t *pAuth = (JLAuth_t *)payload;
+    JLAuthRsp_t *pRsp = (JLAuthRsp_t*)auth_rsp;
+
+    if(d_rand != pAuth->random_unm){
+        log_error("agent dev auth random is error");
+        goto ERROR; 
+    }
+
+    pRsp->timestamp = time(NULL); 
+    pRsp->random_unm = 3;
+    joylink_agent_make_session_key((char *)pRsp->session_key);
+
+    AgentDev_t *p = joylink_agent_dev_get(feedid);
+    if(p == NULL){
+        log_error("agent dev get is error");
+        goto ERROR;
+    }
+    len = joylink_agent_cloud_rsp_packet(
+                (uint8_t*)buff, 
+                sizeof(buff), 
+                PT_AUTH, 
+                (uint8_t*) &pRsp->random_unm, 
+                4, 
+                (uint8_t*)p->accesskey, 
+                (const uint8_t*)auth_rsp, 
+                sizeof(auth_rsp));
+    if(len < 0){
+        log_error("packet error");
+        goto ERROR;
+    }
+
+    ret = send(fd, buff, len, 0);
+    if(ret < 0){
+        log_error("send error ret:%d", ret);
+        goto ERROR;
+    }
+
+    memcpy(p->sessionkey, pRsp->session_key, 32);
+    memcpy(p->auth, auth_org, 16);
+    p->random = pAuth->random_unm;
+
+    p->fd = fd;
+    ST_AGENT_AUTH_SET(p->agent_st);
+    log_debug("send to server len:%d:ret:%d:%d\n", 
+            len, ret, p->agent_st);
+ERROR:
+    return ret;
+}
+
+/*
+ * agent dev >> agent GW
+ * tcp
+ * 
+ */
+E_JLRetCode_t
+joylink_agent_dev_cloud_HB_hand(int32_t fd, uint8_t *payload, 
+        int32_t s_len)
+{
+    /**
+     *1 get HB
+     *2 packet rsp
+     *3 send to rsp
+     *4 update HB agent dev
+     */
+    int ret = E_RET_ERROR;
+    int len = 0;
+    char buff[JL_MAX_PACKET_LEN] = {0};
+
+    JLHearBeat_t *hb = (JLHearBeat_t*)payload;
+    JLHearBeatRst_t hbrsp;
+
+    hbrsp.timestamp = time(NULL);
+    hbrsp.code = 0;
+
+    AgentDev_t * p = joylink_agent_get_dev_by_fd(fd);
+    if(p == NULL){
+        log_error("agent dev get is error");
+        goto ERROR;
+    }
+    len = joylink_agent_cloud_rsp_packet(
+                (uint8_t*)buff, 
+                sizeof(buff), 
+                PT_BEAT, 
+                NULL, 
+                0, 
+                (uint8_t*)p->sessionkey, 
+                (const uint8_t*)&hbrsp, 
+                sizeof(hbrsp));
+    if(len < 0){
+        log_error("packet error");
+        goto ERROR;
+    }
+
+    ret = send(fd, buff, len, 0);
+    if(ret < 0){
+        log_error("send error ret:%d", ret);
+        goto ERROR;
+    }
+    memcpy(&p->hb, hb, sizeof(JLHearBeat_t));
+    log_debug("rssi:%d verion:%d\n", hb->rssi, hb->verion);
+    ST_AGENT_HB_SET(p->agent_st);
+    log_debug("send to server len:%d:ret:%d\n", len, ret);
+ERROR:
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: payload
+ * @Param: s_len
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_dev_cloud_upload_hand(int32_t fd, uint8_t *payload, 
+        int32_t s_len)
+{
+    /**
+     *1 get UPLOAD 
+     *2 packet rsp
+     *3 send to rsp
+     *4 update UPLOAD to agent dev
+     */
+    int ret = E_RET_ERROR;
+    int len = 0;
+    char buff[JL_MAX_PACKET_LEN] = {0};
+
+    JLHearBeatRst_t hbrsp;
+
+    hbrsp.timestamp = time(NULL);
+    hbrsp.code = 0;
+
+    AgentDev_t * p = joylink_agent_get_dev_by_fd(fd);
+    if(p == NULL){
+        log_error("agent dev get is error");
+        goto ERROR;
+    }
+    len = joylink_agent_cloud_rsp_packet(
+                (uint8_t*)buff, 
+                sizeof(buff), 
+                PT_UPLOAD, 
+                NULL, 
+                0, 
+                (uint8_t*)p->sessionkey, 
+                (const uint8_t*)&hbrsp, 
+                sizeof(hbrsp));
+    if(len < 0){
+        log_error("packet error");
+        goto ERROR;
+    }
+
+    ret = send(fd, buff, len, 0);
+    if(ret < 0){
+        log_error("send error ret:%d", ret);
+        goto ERROR;
+    }
+    if(p->snap != NULL){
+        free(p->snap);
+    }
+    if(NULL == (p->snap = (char*)malloc(s_len * 2 + 1))){
+        log_error("malloc error");
+    }else{
+        memset(p->snap, 0, s_len * 2 + 1);
+        joylink_util_byte2hexstr(payload, s_len, p->snap, s_len * 2);
+    }
+    ST_AGENT_SNAP_SET(p->agent_st);
+    log_debug("snap:%s\n", payload);
+    log_debug("send to server len:%d:ret:%d\n", len, ret);
+ERROR:
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: payload
+ * @Param: s_len
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_dev_cloud_ota_up_hand(int32_t fd, 
+        uint8_t *payload, 
+        int32_t s_len)
+{
+    /**
+     *1 packet rsp
+     *2 send to rsp
+     */
+    int ret = E_RET_ERROR;
+    int len = 0;
+    char buff[JL_MAX_PACKET_LEN] = {0};
+    char data[JL_MAX_PACKET_LEN] = {0};
+
+    *((int32_t*)(data)) = (int)time(NULL);
+    sprintf(data + 4, "{\"code\":%d, \"msg\":\"%s\"}", 0, "sucess");
+
+    AgentDev_t * p = joylink_agent_get_dev_by_fd(fd);
+    if(p == NULL){
+        log_error("agent dev get is error");
+        goto ERROR;
+    }
+    len = joylink_agent_cloud_rsp_packet(
+                (uint8_t*)buff, 
+                sizeof(buff), 
+                PT_UPLOAD, 
+                NULL, 
+                0, 
+                (uint8_t*)p->sessionkey, 
+                (const uint8_t*)data, 
+                strlen(data + 4) + 4);
+    if(len < 0){
+        log_error("packet error");
+        goto ERROR;
+    }
+
+    ret = send(fd, buff, len, 0);
+    if(ret < 0){
+        log_error("send error ret:%d", ret);
+        goto ERROR;
+    }
+    log_debug("send to server len:%d:ret:%d\n", len, ret);
+
+ERROR:
+    return ret;
+}
+
+/************ TCP SERVER *************/
+/**
+ * [joylink_agent_cloud_fd] 
+ *
+ * @returns: 
+ */
+int32_t
+joylink_agent_cloud_fd()
+{
+    return _g_p_cmg->fd; 
+}
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: rec_buff
+ * @Param: max
+ *
+ * @Returns: 
+ */
+int
+joylink_agent_tcp_recv(char fd, char *rec_buff, int max)
+{
+    JLPacketHead_t head;
+    bzero(&head, sizeof(head));
+    E_PT_REV_ST_t st = E_PT_REV_ST_MAGIC;
+    int ret;
+    
+    do{
+        switch(st){
+            case E_PT_REV_ST_MAGIC:
+                ret = recv(fd, &head.magic, sizeof(head.magic), 0);
+                if(head.magic == 0x123455CC){
+                    st = E_PT_REV_ST_HEAD;
+                }
+                break;
+            case E_PT_REV_ST_HEAD:
+                ret = recv(fd, &head.optlen, sizeof(head) - sizeof(head.magic), 0);
+                if(ret > 0){
+                    st = E_PT_REV_ST_DATA;
+                }
+                break;
+            case E_PT_REV_ST_DATA:
+                if(head.optlen + head.payloadlen < max - sizeof(head)){
+                    ret = recv(fd, rec_buff + sizeof(head), head.optlen + head.payloadlen , 0);
+                    if(ret > 0){
+                        memcpy(rec_buff, &head, sizeof(head));
+                        ret = ret + sizeof(head);
+                        st = E_PT_REV_ST_END;
+                    }
+
+                }else{
+                    ret = -1;
+                    log_fatal("recev buff is too small");
+                }
+                break;
+            default:
+                break;
+        }
+    }while(ret>0 && st != E_PT_REV_ST_END);
+
+    if (ret == -1 || ret == 0){
+        return -1;
+    }
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ */
+void
+joylink_agent_dev_req_proc(int fd)
+{
+    uint8_t recBuffer[JL_MAX_PACKET_LEN * 8 ] = { 0 };
+    uint8_t recPainText[JL_MAX_PACKET_LEN * 8 + 16] = { 0 };
+    char feedid[JL_MAX_FEEDID_LEN] = {0};
+    char auth_org[16] = {0};
+    uint32_t d_rand = 0;
+    int ret;
+    JLPacketParam_t param;
+
+    memset(&param, 0, sizeof(param));
+
+    ret = joylink_agent_tcp_recv(fd, (char*)recBuffer, sizeof(recBuffer));
+    if (ret == -1 || ret == 0){
+        close(fd);
+        joylink_agent_dev_clear_fd_by_fd(fd);
+        log_info("client close!:%d\r\n", ret);
+        return;
+    }
+    
+	JLPacketHead_t* pPack = (JLPacketHead_t*)recBuffer;
+    log_debug("pack type:%d", pPack->type);
+
+    if(PT_AUTH == pPack->type){
+        if(pPack->optlen < 4){
+            log_error("pPack->optlen is error optlen:%d", pPack->optlen);
+            return;
+        }
+        memcpy(feedid, recBuffer + sizeof(JLPacketHead_t), pPack->optlen - 4);
+        memcpy(&d_rand, recBuffer + sizeof(JLPacketHead_t) + pPack->optlen - 4, 4);
+        memcpy(auth_org, recBuffer + sizeof(JLPacketHead_t) + pPack->optlen, 16);
+
+        log_debug("auth feedid:%s", feedid);
+        log_debug("auth payload len:%d", pPack->payloadlen);
+    }else{
+        if(E_RET_OK != joylink_agent_get_feedid_by_fd(fd, feedid)){
+            log_error("Find feedid by fd error:%d", fd);
+            return;
+        }
+    }
+   
+    ret = joylink_dencypt_server_req(&param, recBuffer, ret, 
+            recPainText, sizeof(recPainText), feedid);
+
+    if (ret < 1){
+        log_debug("dencypt erorr ret");
+        return;
+    }
+
+    log_info("Server org ctrl type:%d:", param.type);
+    switch (param.type){
+        case PT_AUTH:
+            log_debug("Dev AUTH is get");
+            joylink_agent_dev_cloud_auth_hand(fd, feedid, d_rand, recPainText, ret, auth_org);
+            /*joylink_agent_auth_req();*/
+            break;
+        case PT_BEAT:
+            log_debug("Dev HB is get");
+            joylink_agent_dev_cloud_HB_hand(fd, recPainText, ret);
+            /*joylink_agent_HB_req();*/
+            break;
+        case PT_UPLOAD:
+            joylink_agent_dev_cloud_upload_hand(fd, recPainText, ret);
+            log_debug("Dev UP_UPLOAD is get");
+            /*joylink_agent_snap_req();*/
+            break;
+        case PT_OTA_UPLOAD:
+            log_debug("Dev PT_OTA_UPLOAD is get");
+            /*send ack to dev*/
+            joylink_agent_dev_cloud_ota_up_hand(fd, recPainText, ret);
+            /*send ota st to cloud*/
+            joylink_agent_ota_st_to_cloud_req(recPainText, ret);
+            break;
+        default:
+            log_debug("Unknow param type.\r\n");
+            break;
+    }
+}
+
+/**
+ * brief: 
+ *
+ * @Param: gw_fd
+ */
+static void
+joylink_agent_cloud_server_proc(int32_t gw_fd)
+{
+    int32_t fd;
+    char c_ip[128] = {0};
+    char err[128] = {0};
+    int32_t c_port;
+    int32_t ret; 
+
+    /*1 accept client */
+    fd = joylink_net_tcp_accept(err, gw_fd, c_ip, sizeof(c_ip), &c_port);
+
+    log_debug("--------------accept fd:%d, ip:%s", fd, c_ip);
+
+    if(fd > 0){
+        joylink_agent_dev_req_proc(fd);
+    }
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+void *
+joylink_agent_cloud_loop(void* data)
+{
+    struct timeval select_time_out;
+    int32_t fds[AGENT_DEV_MAX + 1];
+    int32_t max_fd = 0;
+    int32_t cloud_fd = 0;
+    int32_t fd_cnt = 0;
+    int32_t i;
+    int32_t ret;
+
+    joylink_agent_cloud_init();
+    _g_p_cmg->cloud_thread_run = 1;
+
+    jl_agent_cloud_mg_t *pcmgv = (jl_agent_cloud_mg_t*)data;
+    while(_g_p_cmg->cloud_thread_run){
+        fd_set  read_fds;
+        FD_ZERO(&read_fds);
+        
+        cloud_fd = joylink_agent_cloud_fd();
+        fds[0] = cloud_fd;
+
+        fd_cnt = joylink_agent_devs_get_fds(&fds[1]);
+        if(fd_cnt > 0){
+            fd_cnt = fd_cnt + 1; 
+        }else{
+            fd_cnt = 1;
+        }
+
+
+        for(i = 0; i < fd_cnt; i++){
+            if (fds[i] > 0) {
+                FD_SET(fds[i], &read_fds);    
+                max_fd = max_fd > fds[i]? max_fd : fds[i];
+            }
+        }
+
+        /*select for msg.*/
+        select_time_out.tv_usec = 500 * 1000L;
+        select_time_out.tv_sec = (long)0;
+
+        ret = joylink_adapter_select(max_fd + 1, 
+                &read_fds, NULL, NULL, &select_time_out);
+        log_info("select ret: %d", ret);
+
+        if (ret < 0){
+            log_error("select err: %d!\r\n", ret);
+        }else if (ret > 0){
+            if (FD_ISSET(cloud_fd, &read_fds)) {
+                joylink_agent_cloud_server_proc(cloud_fd);
+            }
+            for(i = 1; i < fd_cnt; i++){
+                if (FD_ISSET(fds[i], &read_fds)) {
+
+                    joylink_agent_devs_lock();
+                    joylink_agent_dev_req_proc(fds[i]);
+                    joylink_agent_devs_unlock();
+
+                }
+            }
+        }
+
+    }
+
+    return NULL;
+}
+
+/**
+ * brief: 
+ */
+void
+joylink_agent_gw_thread_start()
+{
+    if(0 != pthread_create(&_g_p_cmg->ntid, NULL, joylink_agent_cloud_loop, (void*)_g_p_cmg)){
+        log_error("cloud thread create err!\n");
+    }
+}
+
+/**
+ * brief: 
+ */
+void
+joylink_agent_gw_thread_stop()
+{
+    _g_p_cmg->cloud_thread_run = 0;
+    pthread_cancel(_g_p_cmg->ntid);
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: sin_recv
+ * @Param: addrlen
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t 
+joylink_agent_proc_dev_add(uint8_t *src, struct sockaddr_in *sin_recv, socklen_t addrlen)
+{
+    int len = 0;
+    int num = 0;
+    int i;
+    char data[JL_MAX_PACKET_LEN] = {0};
+
+    JLAddAgentDev_t *devs = NULL;
+    if(NULL == (devs = joylink_agent_parse_dev_add(src, &num))){
+        log_error("parse error");
+        return E_RET_ERROR;
+    }
+
+    for(i = 0; i < num; i++){
+        log_debug("agent dev:%s", devs[i].feedid);
+        joylink_agent_dev_add(devs[i].feedid, devs[i].ackey);
+    }
+
+    if(devs != NULL){
+        free(devs);
+    }
+
+    *((int*)data) = time(NULL);
+    sprintf(data + 4, "{\"code\":%d, \"msg\":\"%s\"}", 0, "sucesss");
+    log_info("rsp data:%s:len:%d", data + 4, len);
+
+    len = joylink_encrypt_lan_basic(
+            _g_pdev->send_buff, 
+            JL_MAX_PACKET_LEN,
+            ET_ACCESSKEYAES,
+            PT_SUB_ADD,
+            (uint8_t *)_g_pdev->jlp.localkey, 
+            (const uint8_t*)data, 
+            strlen(data + 4) + 4);
+
+    if(len <= 0 || len > JL_MAX_PACKET_LEN){
+        log_error("packet error ret:%d", len);
+    }else{
+        len = sendto(_g_pdev->lan_socket, 
+                _g_pdev->send_buff, len, 0,
+                (SOCKADDR*)sin_recv, addrlen);
+
+        if(len < 0){
+            log_error("send error");
+        }
+        log_info("send ret:%d",len);
+    }
+
+    return E_RET_OK;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: sin_recv
+ * @Param: addrlen
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t 
+joylink_agent_proc_dev_del(uint8_t *src, struct sockaddr_in *sin_recv, socklen_t addrlen)
+{
+    int len = 0;
+    int num = 0;
+    int i;
+    char data[JL_MAX_PACKET_LEN] = {0};
+
+    JLAddAgentDev_t *devs = NULL;
+    if(NULL == (devs = joylink_agent_parse_dev_del(src, &num))){
+        log_error("parse error");
+        return E_RET_ERROR;
+    }
+
+    for(i = 0; i < num; i++){
+        joylink_agent_dev_del(devs[i].feedid);
+    }
+
+    if(devs != NULL){
+        free(devs);
+    }
+
+    *((int*)data) = time(NULL);
+    sprintf(data + 4, "{\"code\":%d, \"msg\":\"%s\"}", 0, "sucesss");
+    log_info("rsp data:%s:len:%d", data + 4, len);
+
+    len = joylink_encrypt_lan_basic(
+            _g_pdev->send_buff, 
+            JL_MAX_PACKET_LEN,
+            ET_ACCESSKEYAES,
+            PT_SUB_ADD,
+            (uint8_t *)_g_pdev->jlp.localkey, 
+            (const uint8_t*)data, 
+            strlen(data + 4) + 4);
+
+    if(len <= 0 || len > JL_MAX_PACKET_LEN){
+        log_error("packet error ret:%d", len);
+    }else{
+        len = sendto(_g_pdev->lan_socket, 
+                _g_pdev->send_buff, len, 0,
+                (SOCKADDR*)sin_recv, addrlen);
+
+        if(len < 0){
+            log_error("send error");
+        }
+        log_info("send ret:%d",len);
+    }
+
+    return E_RET_OK;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: sin_recv
+ * @Param: addrlen
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t 
+joylink_agent_proc_get_dev_list(uint8_t *src, struct sockaddr_in *sin_recv, socklen_t addrlen)
+{
+    int len = 0;
+    int num = 0;
+    int i;
+    char data[JL_MAX_PACKET_LEN] = {0};
+    char *p = NULL;
+
+    *((int*)data) = time(NULL);
+
+    p = joylink_agent_json_packet_dev_list(0, "success");
+    if(strlen(p) > sizeof(data)){
+        sprintf(data + 4, "{\"code\":%d, \"msg\":\"%s\"}", 
+                -1, "dev list too many to packet.");
+    }else{
+        memcpy(data + 4, p, strlen(p));
+        free(p);
+    }
+
+    log_info("rsp data:%s:len:%d", data + 4, len);
+    len = joylink_encrypt_lan_basic(
+            _g_pdev->send_buff, 
+            JL_MAX_PACKET_LEN,
+            ET_ACCESSKEYAES,
+            PT_AGENT_GET_DEV_LIST,
+            (uint8_t *)_g_pdev->jlp.localkey, 
+            (const uint8_t*)data, 
+            strlen(data + 4) + 4);
+
+    if(len <= 0 || len > JL_MAX_PACKET_LEN){
+        log_error("packet error ret:%d", len);
+    }else{
+        len = sendto(_g_pdev->lan_socket, 
+                _g_pdev->send_buff, len, 0,
+                (SOCKADDR*)sin_recv, addrlen);
+
+        if(len < 0){
+            log_error("send error");
+        }
+        log_info("send ret:%d",len);
+    }
+
+    return E_RET_OK;
+}
+
+void
+joylink_agent_req_cloud_proc()
+{
+    joylink_agent_auth_req();
+    joylink_agent_HB_req();
+    joylink_agent_snap_req();
+}

+ 167 - 0
joylink/agent/joylink_agent.h

@@ -0,0 +1,167 @@
+#ifndef __JD_AGENT_H_
+#define __JD_AGENT_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C"{
+#endif /* __cplusplus */
+
+#include "joylink.h"
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+
+#pragma pack(1)
+
+/************** APP -> AGENT GW ************/
+typedef struct {
+	char feedid[JL_MAX_FEEDID_LEN];
+	char accesskey[33];
+}AgentDevAdd_t;
+
+typedef struct {
+	char feedid[JL_MAX_FEEDID_LEN];
+}AgentDevDel_t;
+
+/************** AGENT GW -> Cloud ************/
+typedef struct {
+	int devs_len;
+	unsigned int timestamp;
+	char* devs;
+}AgentAuthReq_t;
+
+typedef struct {
+	unsigned int timestamp;
+	int code;
+	char error_devs[];
+}AgentAuthRsp_t;
+
+typedef struct {
+	int devs_len;
+	unsigned int timestamp;
+	char* devs;
+}AgentHBReq_t;
+
+typedef struct {
+	unsigned int timestamp;
+	int code;
+}AgentHBRsp_t;
+
+typedef struct {
+	int snaps_len;
+	unsigned int timestamp;
+	char* snaps;
+}AgentSnapsReq_t;
+
+typedef struct {
+	unsigned int timestamp;
+	int code;
+}AgentSnapsRsp_t;
+
+/**************  Cloud -> Agent GW ************/
+
+#pragma pack()
+
+typedef struct {
+    int32_t fd;
+    int32_t st;
+	char accesskey[JL_MAX_ACKEY_LEN];
+	char sessionkey[JL_MAX_SESSION_KEY_LEN];
+	char feedid[JL_MAX_FEEDID_LEN];
+
+    JLHearBeat_t hb;
+    char *snap;
+    int32_t snap_len;
+    char auth[16];
+    int32_t random;
+    int agent_st;
+}AgentDev_t;
+
+#define JL_AGENT_GW_PORT                (33000)
+#define JL_AGENT_GW_CLIENT_MAX          (20)
+
+#define IS_AGENT_AUTH_SET(agent_st)     (agent_st & 0x01)
+#define IS_AGENT_HB_SET(agent_st)       (agent_st & 0x02)
+#define IS_AGENT_SNAP_SET(agent_st)     (agent_st & 0x04)
+
+#define ST_AGENT_AUTH_SET(agent_st)     (agent_st = agent_st | 0x00000001)
+#define ST_AGENT_HB_SET(agent_st)       (agent_st = agent_st | 0x02)
+#define ST_AGENT_SNAP_SET(agent_st)     (agent_st = agent_st | 0x04)
+
+#define ST_AGENT_AUTH_CLR(agent_st)     (agent_st = agent_st & (~0x01))
+#define ST_AGENT_HB_CLR(agent_st)       (agent_st = agent_st & (~0x02))
+#define ST_AGENT_SNAP_CLR(agent_st)     (agent_st = agent_st & (~0x04))
+
+/********* funs ***********/
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: src
+ * @Param: len
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_cloud_auth_hand(int32_t fd, uint8_t *src, int32_t len);
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: sin_recv
+ * @Param: addrlen
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t 
+joylink_agent_proc_dev_add(uint8_t *src, struct sockaddr_in *sin_recv, socklen_t addrlen);
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: sin_recv
+ * @Param: addrlen
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t 
+joylink_agent_proc_dev_del(uint8_t *src, struct sockaddr_in *sin_recv, socklen_t addrlen);
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: sin_recv
+ * @Param: addrlen
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t 
+joylink_agent_proc_get_dev_list(uint8_t *src, struct sockaddr_in *sin_recv, socklen_t addrlen);
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: payload
+ * @Param: s_len
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_dev_cloud_ota_up_hand(int32_t fd, 
+        uint8_t *payload, 
+        int32_t s_len);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif

+ 318 - 0
joylink/agent/joylink_agent_devs.c

@@ -0,0 +1,318 @@
+/* --------------------------------------------------
+ * @brief: 
+ *
+ * @version: 1.0
+ *
+ *
+ * @author: 
+ * --------------------------------------------------
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "joylink_agent.h"
+#include "joylink_agent_devs.h"
+#include "joylink_log.h"
+#include "joylink.h"
+
+AgentDev_t _g_adevs[AGENT_DEV_MAX];
+
+pthread_mutex_t    devs_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#ifdef _SAVE_FILE_
+    char  *devs_info_file = "devs_info.txt";
+#endif
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_devs_load(void)
+{
+    /**TO DO
+     *MUST load AgentDevs from flash when application run.
+     */
+
+#ifdef _SAVE_FILE_
+    FILE *infile;
+    infile = fopen(devs_info_file, "wr+");
+    int i;
+    for(i = 0; i< AGENT_DEV_MAX; i++){
+        fread(&_g_adevs[i], sizeof(AgentDev_t), 1, infile);
+        _g_adevs[i].fd = 0;
+    }
+    fclose(infile);
+#endif
+
+    return E_RET_OK;
+}
+
+E_JLRetCode_t
+joylink_agent_devs_save_file(void)
+{
+    /**TO DO
+     *MUST load AgentDevs from flash when application run.
+     */
+
+#ifdef _SAVE_FILE_
+    log_info("sava to files");
+    FILE *outfile;
+    outfile = fopen(devs_info_file, "wb" );
+    fwrite(_g_adevs, sizeof(_g_adevs), 1, outfile);
+    fclose(outfile);
+#endif
+
+    return E_RET_OK;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: feedid
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_dev_del(char *feedid)
+{
+    /**TO DO
+     *MUST sync to flash
+     */
+
+    int32_t i;
+    for(i = 0; i < AGENT_DEV_MAX; i++){
+        if(!strcmp(_g_adevs[i].feedid, feedid)){
+            memset(&_g_adevs[i], 0, sizeof(AgentDev_t));
+            /**
+             * !!!!!!!!!!! sync to flash !!!!!!!!!!!!
+             * */
+            joylink_agent_devs_save_file();
+            return E_RET_OK;
+        }
+    }
+    log_error("agent devs no find:%s", feedid);
+    return E_RET_ERROR;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: pad
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_dev_upd(char *feedid, AgentDev_t *pad)
+{
+    /**TO DO
+     *MUST sync to flash
+     */
+    int32_t i;
+    for(i = 0; i < AGENT_DEV_MAX; i++){
+        if(!strcmp(_g_adevs[i].feedid, feedid)){
+            memcpy(&_g_adevs[i], pad, sizeof(AgentDev_t));
+            /**
+             * !!!!!!!!!!! sync to flash !!!!!!!!!!!!
+             * */
+            return E_RET_OK;
+        }
+    }
+
+    log_error("agent devs no find:%s", pad->feedid);
+    joylink_agent_devs_save_file();
+    return E_RET_ERROR;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: pad
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_dev_upd_to_flash(char *feedid)
+{
+    /**TO DO
+     *MUST sync to flash
+     */
+    int32_t i;
+    for(i = 0; i < AGENT_DEV_MAX; i++){
+        if(!strcmp(_g_adevs[i].feedid, feedid)){
+            /**
+             * !!!!!!!!!!! sync to flash !!!!!!!!!!!!
+             * */
+            return E_RET_OK;
+        }
+    }
+
+    log_error("agent devs no find:%s", feedid);
+    joylink_agent_devs_save_file();
+    return E_RET_ERROR;
+}
+/**
+ * brief: 
+ *
+ * @Param: feedid
+ * @Param: o_pad
+ *
+ * @Returns: 
+ */
+AgentDev_t *
+joylink_agent_dev_get(char *feedid)
+{
+    int32_t i;
+    for(i = 0; i < AGENT_DEV_MAX; i++){
+        if(!strcmp(_g_adevs[i].feedid, feedid)){
+            return &_g_adevs[i];
+        }
+    }
+    log_error("agent devs no find:%s", feedid);
+    return NULL;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: pad
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_dev_add(char feedid[JL_MAX_FEEDID_LEN], char ackey[JL_MAX_ACKEY_LEN])
+{
+    /**TO DO
+     *MUST sync to flash
+     */
+    int32_t i;
+    AgentDev_t *p = NULL; 
+    p = joylink_agent_dev_get(feedid);
+    if(NULL != p){
+        memcpy(p->accesskey, ackey, JL_MAX_ACKEY_LEN);
+        return E_RET_OK;
+    }
+    for(i = 0; i < AGENT_DEV_MAX; i++){
+        if(!strcmp(_g_adevs[i].feedid, "")){
+            memcpy(&_g_adevs[i].feedid, feedid, JL_MAX_FEEDID_LEN);
+            memcpy(&_g_adevs[i].accesskey, ackey, JL_MAX_ACKEY_LEN);
+            /**
+             * !!!!!!!!!!! sync to flash !!!!!!!!!!!!
+             * */
+            joylink_agent_devs_save_file();
+            return E_RET_OK;
+        }
+    }
+    log_error("agent devs no space");
+
+    return E_RET_ERROR;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: feedid[JL_MAX_FEEDID_LEN]
+ * @Param: ackey[JL_MAX_ACKEY_LEN]
+ * @Param: sessionkey[JL_MAX_ACKEY_LEN]
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_dev_get_keys(char feedid[JL_MAX_FEEDID_LEN], 
+                      char ackey[JL_MAX_ACKEY_LEN],
+                      char sessionkey[JL_MAX_SESSION_KEY_LEN])
+{
+    AgentDev_t * ad = joylink_agent_dev_get(feedid);
+    if(NULL != ad){
+        memcpy(ackey, ad->accesskey, JL_MAX_ACKEY_LEN);
+        memcpy(sessionkey, ad->sessionkey, JL_MAX_SESSION_KEY_LEN);
+        return E_RET_OK;
+    }
+    return E_RET_ERROR;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: fds[AGENT_DEV_MAX]
+ *
+ * @Returns: 
+ */
+int
+joylink_agent_devs_get_fds(int fds[AGENT_DEV_MAX])
+{
+    int32_t i;
+    int32_t j = 0;
+    for(i = 0; i < AGENT_DEV_MAX; i++){
+        /**
+         * FIXME fd > 0 must adapter to SOC
+         * */
+        if(_g_adevs[i].fd > 0){
+            fds[j++] = _g_adevs[i].fd;
+        }
+    }
+    return j;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: feedid[JL_MAX_FEEDID_LEN]
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_get_feedid_by_fd(int fd, char feedid[JL_MAX_FEEDID_LEN])
+{
+    int32_t i;
+    for(i = 0; i < AGENT_DEV_MAX; i++){
+        if(_g_adevs[i].fd == fd){
+            memcpy(feedid,  _g_adevs[i].feedid, JL_MAX_FEEDID_LEN);
+            return E_RET_OK;
+        }
+    }
+
+    return E_RET_ERROR;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ *
+ * @Returns: 
+ */
+AgentDev_t *
+joylink_agent_get_dev_by_fd(int fd)
+{
+    int32_t i;
+    for(i = 0; i < AGENT_DEV_MAX; i++){
+        if(_g_adevs[i].fd == fd){
+            return &_g_adevs[i];
+        }
+    }
+
+    return NULL;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_dev_clear_fd_by_fd(int fd)
+{
+    AgentDev_t * p = joylink_agent_get_dev_by_fd(fd);
+    if(NULL != p){
+        p->fd = 0;  
+        return E_RET_OK;
+    }
+
+    return E_RET_ERROR;
+}

+ 110 - 0
joylink/agent/joylink_agent_devs.h

@@ -0,0 +1,110 @@
+#ifndef __JD_AGENT_DEVS_H_
+#define __JD_AGENT_DEVS_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C"{
+#endif /* __cplusplus */
+
+#include "joylink.h"
+#include "joylink_agent.h"
+
+#define AGENT_DEV_MAX               (10)
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_devs_load(void);
+
+/**
+ * brief: 
+ *
+ * @Param: pad
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_dev_add(char feedid[JL_MAX_FEEDID_LEN], 
+        char ackey[JL_MAX_ACKEY_LEN]);
+
+/**
+ * brief: 
+ *
+ * @Param: feedid
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_dev_del(char *feedid);
+
+/**
+ * brief: 
+ *
+ * @Param: pad
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_dev_upd(char *feedid, AgentDev_t *pad);
+
+/**
+ * brief: 
+ *
+ * @Param: feedid
+ * @Param: o_pad
+ *
+ * @Returns: 
+ */
+AgentDev_t *
+joylink_agent_dev_get(char *feedid);
+
+/**
+ * brief: 
+ *
+ * @Param: fds[AGENT_DEV_MAX]
+ *
+ * @Returns: 
+ */
+int
+joylink_agent_devs_get_fds(int fds[AGENT_DEV_MAX]);
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ *
+ * @Returns: 
+ */
+AgentDev_t *
+joylink_agent_get_dev_by_fd(int fd);
+/**
+ * brief: 
+ *
+ * @Param: fd
+ * @Param: feedid[JL_MAX_FEEDID_LEN]
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_get_feedid_by_fd(int fd, char feedid[JL_MAX_FEEDID_LEN]);
+
+/**
+ * brief: 
+ *
+ * @Param: fd
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_dev_clear_fd_by_fd(int fd);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif

+ 531 - 0
joylink/agent/joylink_agent_gw_2_cloud.c

@@ -0,0 +1,531 @@
+/* --------------------------------------------------
+ * @brief: 
+ *
+ * @version: 1.0
+ *
+ *
+ * @author: 
+ * --------------------------------------------------
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "joylink_agent.h"
+#include "joylink_agent_devs.h"
+#include "joylink_agent_json.h"
+#include "joylink_log.h"
+
+extern void 
+joylink_cloud_fd_lock();
+
+extern void 
+joylink_cloud_fd_unlock();
+
+extern char *
+joylink_package_ota_fff_upload();
+
+extern char * 
+joylink_agent_create_cloud_auth_json_req_f();
+
+extern void 
+joylink_agent_devs_lock();
+
+extern void 
+joylink_agent_devs_unlock();
+
+/**
+ * brief: 
+ *
+ * @Param: msg
+ * @Param: msg_len
+ * @Param: cmd
+ *
+ * @Returns: 
+ */
+
+extern E_JLBOOL_t
+is_joylink_server_st_work();
+
+E_JLRetCode_t
+joylink_agent_package_and_send(char* msg, int32_t msg_len, int32_t cmd)
+{
+    if(NULL == msg || msg_len <= 0){
+        log_error("Param error");
+        return E_RET_ERROR;
+    }
+    int ret = E_RET_ERROR;
+    char *data = NULL;
+
+    if(!is_joylink_server_st_work()){
+        log_error("cloud is not work");
+        return E_RET_ERROR;
+    }
+
+    if(NULL == (data = (char*)malloc(msg_len + 32))){
+        log_error("malloc is error");
+        return E_RET_ERROR;
+    }
+
+    ret = joylink_encypt_server_rsp(
+            (uint8_t*)data,
+            msg_len + 32, 
+            cmd,
+            _g_pdev->jlp.sessionKey, 
+            (uint8_t*)msg,
+            msg_len);
+
+    if(ret < 0){
+        log_error("packe error:ret:%d", ret);
+    }else{
+        joylink_cloud_fd_lock();
+        ret = send(_g_pdev->server_socket, data, ret, 0);
+        log_info("VVVVVVVVVVV:send ret:%d", ret);
+        joylink_cloud_fd_unlock();
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }else{
+            ret = E_RET_OK;
+        }
+    }
+RET:
+    if(NULL != data){
+        free(data);
+    }
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_auth_req()
+{
+    /*
+     *1 get agent devs data
+     *2 packet data as msg
+     *3 encypt and send 
+     */
+    char * p_json = joylink_agent_create_cloud_auth_json_req_f();
+    if(NULL == p_json){
+        return E_RET_ERROR;
+    }
+    char *p = (char*)malloc(strlen(p_json) + 4); 
+    if(NULL != p){
+        int32_t *pi = (int*)p;
+        *pi = time(NULL);
+        memcpy(p + 4, p_json, strlen(p_json));
+        log_debug("auth json len:%d: text:%s:", (int)strlen(p_json),  p_json);
+        joylink_agent_package_and_send(p, strlen(p_json) + 4, PT_AGENT_AUTH);
+        free(p_json);
+        free(p);
+    }
+    return E_RET_OK;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: len
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_auth_rsps(char *src, int len)
+{
+    /*
+     *1 check the code 
+     */
+    AgentAuthRsp_t *p = (AgentAuthRsp_t *)src;
+    log_info("AGENT AUTH rsp: time:%d, code:%d", p->timestamp, p->code);
+
+    if(p->code != E_RET_OK && len > 0){
+        log_debug("error feedids:%s", p->error_devs);
+    }
+    return E_RET_OK;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_HB_req()
+{
+    /*
+     *1 get agent devs data
+     *2 packet data as msg
+     *3 encypt and send 
+     */
+
+    char * p_json = NULL;
+    p_json = joylink_agent_create_cloud_hb_json_req();
+    if(NULL == p_json){
+        return E_RET_ERROR;
+    }
+    char *p = (char*)malloc(strlen(p_json) + 4); 
+    if(NULL != p){
+        int32_t *pi = (int*)p;
+        *pi = time(NULL);
+        memcpy(p + 4, p_json, strlen(p_json));
+        log_debug("auth json len:%d: text:%s:", (int)strlen(p_json),  p_json);
+        joylink_agent_package_and_send(p, strlen(p_json) + 4, PT_AGENT_HB);
+        free(p_json);
+        free(p);
+    }
+    return E_RET_OK;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: len
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_HB_rsps(char *src, int len)
+{
+    /*
+     *1 check the code 
+     */
+    AgentHBRsp_t *p = NULL;
+    p = (AgentHBRsp_t *)src;
+    if(p->code != 0){
+        log_error("HB rsps error");
+    }
+    log_info("AGENT HB rsp: time:%d, code:%d", p->timestamp, p->code);
+
+    return E_RET_OK;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_snap_req()
+{
+    /*
+     *1 get agent devs data
+     *2 packet data as msg
+     *3 encypt and send 
+     */
+    char * p_json = NULL; 
+    p_json = joylink_agent_create_cloud_snap_json_req();
+    if(NULL == p_json){
+        return E_RET_ERROR;
+    }
+    char *p = (char*)malloc(strlen(p_json) + 4); 
+    if(NULL != p){
+        int32_t *pi = (int*)p;
+        *pi = time(NULL);
+        memcpy(p + 4, p_json, strlen(p_json));
+        log_debug("auth json len:%d: text:%s:", (int)strlen(p_json),  p_json);
+        joylink_agent_package_and_send(p, strlen(p_json) + 4, PT_AGENT_UPLOAD);
+        free(p_json);
+        free(p);
+    }
+    return E_RET_OK;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: len
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_snap_rsps(char *src, int len)
+{
+    /*
+     *1 check the code 
+     */
+    AgentSnapsRsp_t *p = NULL;
+    p = (AgentSnapsRsp_t*)src;
+
+    if(p->code != 0){
+        log_error("AGENT SNAP rsps error");
+    }
+
+    log_info("AGENT SNAP rsp: time:%d, code:%d", p->timestamp, p->code);
+
+    return E_RET_OK;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_agent_ota_st_to_cloud_req(char* src, int ret)
+{
+    joylink_agent_package_and_send(src, ret, PT_UPLOAD);
+
+    return E_RET_OK;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: recPainText
+ * @Param: src_len
+ * @Param: o_result
+ * @Param: o_len
+ */
+E_JLRetCode_t
+joylink_agent_dev_ctrl(uint8_t* recPainText, int32_t src_len, uint8_t* o_result, int32_t o_max, int32_t *o_len)
+{
+    /**
+     *1 get feedid
+     *2 encrypt dev msg
+     *3 send dev msg
+     *4 wait msg ack
+     *5 decrypt dev ack  
+     */
+    int ret = E_RET_ERROR;
+    int len = 0;
+    char data[JL_MAX_PACKET_LEN * 10] = {0};
+    char feedid[33] = {0};
+    JLPacketParam_t param;
+
+    memcpy(feedid, recPainText, 32);
+    memset(&param, 0, sizeof(param));
+
+    /*joylink_agent_devs_lock();*/
+
+     /*1 get feedid*/
+    AgentDev_t * p = joylink_agent_dev_get(feedid);
+    if(p == NULL){
+        log_error("agent dev get is error");
+        goto ERROR;
+    }
+
+    log_info("AGENT_CTRL:%s", recPainText + 32 + 4);
+     /*2 encrypt as dev msg*/
+    len = joylink_agent_cloud_rsp_packet(
+                (uint8_t*)data, 
+                sizeof(data), 
+                PT_SERVERCONTROL, 
+                NULL, 
+                0, 
+                (uint8_t*)p->sessionkey, 
+                (const uint8_t*)(recPainText + 32), 
+                src_len - 32);
+    if(len < 0){
+        log_error("packet error");
+        goto ERROR;
+    }
+
+     /*3 send dev msg*/
+    ret = send(p->fd, data, len, 0);
+    if(ret < 0){
+        log_error("send error ret:%d", ret);
+        goto ERROR;
+    }
+
+     /*4 wait msg ack*/
+    memset(data, 0, sizeof(data));
+    ret = joylink_agent_tcp_recv(p->fd, (char*)data, sizeof(data));
+    if (ret == -1 || ret == 0){
+        close(p->fd);
+        log_info("Server close, Reconnect!\r\n");
+        goto ERROR;
+    }
+
+     /*5 decrypt dev ack*/
+    ret = joylink_dencypt_server_req(&param, data, ret, 
+            o_result, o_max, feedid);
+
+    if (ret < 1){
+        log_debug("dencypt erorr ret");
+        goto ERROR;
+    }
+
+    *o_len = ret;
+    /*joylink_agent_devs_unlock();*/
+    return  E_RET_OK;
+ERROR:
+    /*joylink_agent_devs_unlock();*/
+    return E_RET_ERROR;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: recPainText
+ * @Param: src_len
+ */
+void
+joylink_agent_server_ctrl(uint8_t* recPainText, int32_t src_len)
+{
+    /**
+     *1 send msg to dev and get result
+     *2 packge result as agent result
+     *3 send result to cloud
+     */
+
+    int ret = -1;
+    int len;
+    char data[JL_MAX_PACKET_LEN * 10] = {0};
+    char *p = NULL;
+
+    log_debug("Control from server:%s:len:%d\n",
+            recPainText + 12 + 32, (int)strlen((char*)(recPainText + 12 + 32)));
+   
+    printf("CCCC:start:%ld", time(NULL));
+    fflush(stdout);
+    joylink_agent_devs_lock();
+    /*
+     *1 send msg to dev and get result
+     */
+    if(E_RET_OK != joylink_agent_dev_ctrl((char *)recPainText, src_len, data + 32, sizeof(data), &len)){
+        log_error("agent server ctrl error");
+    }else{
+        /*
+         *2 packge result as agent result
+         */
+        /*copy feedid*/
+        memcpy(data, recPainText, 32); 
+        len += 32;
+    }
+    joylink_agent_devs_unlock();
+    printf("CCCC:end:%ld", time(NULL));
+
+    /*len + encypt tail len 32*/
+    if(len + 32 > sizeof(_g_pdev->send_buff)){
+        p = (char*)malloc(len + 32);
+        memset(p, 0, len + 32);
+    }else{
+        p = _g_pdev->send_buff;
+    }
+
+    len = joylink_encypt_server_rsp(p, len + 32, 
+            PT_AGENT_DEV_CTRL, _g_pdev->jlp.sessionKey, 
+            (uint8_t*)data, len);
+
+    if(len > 0){
+        if(0 > (ret = send(_g_pdev->server_socket, p, len, 0))){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+}
+
+/**
+ * brief: 
+ *
+ * @Param: recPainText
+ * @Param: src_len
+ */
+void
+joylink_agent_cloud_ota_to_dev(char * feedid, 
+        uint8_t* recPainText, int32_t src_len,
+        uint8_t* o_result, int32_t o_max, int32_t *o_len)
+{
+    int ret = E_RET_ERROR;
+    int len = 0;
+    char data[JL_MAX_PACKET_LEN] = {0};
+    JLPacketParam_t param;
+
+    memset(&param, 0, sizeof(param));
+
+    joylink_agent_devs_lock();
+
+     /*1 get feedid*/
+    AgentDev_t * p = joylink_agent_dev_get(feedid);
+    if(p == NULL){
+        log_error("agent dev get is error");
+        goto ERROR;
+    }
+
+    log_info("CLOUD OTA INFO:%s", recPainText + 4);
+     /*2 encrypt as dev msg*/
+    len = joylink_agent_cloud_rsp_packet(
+                (uint8_t*)data, 
+                sizeof(data), 
+                PT_OTA_ORDER, 
+                NULL, 
+                0, 
+                (uint8_t*)p->sessionkey, 
+                (const uint8_t*)(recPainText), 
+                src_len);
+    if(len < 0){
+        log_error("packet error");
+        goto ERROR;
+    }
+
+     /*3 send dev msg*/
+    ret = send(p->fd, data, len, 0);
+    if(ret < 0){
+        log_error("send error ret:%d", ret);
+        goto ERROR;
+    }
+
+     /*4 wait msg ack*/
+    memset(data, 0, sizeof(data));
+    ret = joylink_agent_tcp_recv(p->fd, (char*)data, sizeof(data));
+    if (ret == -1 || ret == 0){
+        close(p->fd);
+        log_info("dev fd close!\r\n");
+        goto ERROR;
+    }
+
+     /*5 decrypt dev ack*/
+    ret = joylink_dencypt_server_req(&param, data, ret, 
+            o_result, o_max, feedid);
+
+    if (ret < 1){
+        log_debug("dencypt erorr ret");
+        goto ERROR;
+    }
+
+    *o_len = ret;
+    joylink_agent_devs_unlock();
+    return  E_RET_OK;
+ERROR:
+    joylink_agent_devs_unlock();
+    return E_RET_ERROR;
+}
+
+/**
+ *1 Package request msg to cloud
+ *2 Send msg to cloud
+ *3 Handle the cloud rsponse
+ */
+void
+joylink_agent_cloud_rsp(int32_t type, char * src, int32_t src_len)
+{
+    switch (type){
+        case PT_AGENT_AUTH:
+            log_debug("PT_AGENT_AUTH RSP");
+            joylink_agent_auth_rsps(src, src_len);
+            break;
+        case PT_AGENT_HB:
+            log_debug("PT_AGENT_HB RSP");
+            joylink_agent_HB_rsps(src, src_len);
+            break;
+        case PT_AGENT_UPLOAD:
+            joylink_agent_snap_rsps(src, src_len);
+            log_debug("PT_AGENT_UPLOAD");
+            break;
+        case PT_AGENT_DEV_CTRL:
+            log_debug("PT_AGENT_DEV_CTRL");
+            joylink_agent_server_ctrl(src, src_len);
+            break;
+        default:
+            log_debug("Unknow param type.\r\n");
+            break;
+    }
+}

+ 353 - 0
joylink/agent/joylink_agent_json.c

@@ -0,0 +1,353 @@
+/* --------------------------------------------------
+ * @brief: 
+ *
+ * @version: 1.0
+ *
+ *
+ * @author: 
+ * --------------------------------------------------
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cJSON.h"
+
+#include "joylink_json.h"
+#include "joylink_agent.h"
+#include "joylink_agent_devs.h"
+#include "joylink_agent_json.h"
+#include "joylink_log.h"
+
+extern AgentDev_t _g_adevs[AGENT_DEV_MAX];
+
+extern int 
+joylink_util_byte2hexstr(const uint8_t *pBytes, int srcLen, uint8_t *pDstStr, int dstLen);
+
+/**
+ * brief: 
+ *
+ * @Param: pMsg
+ * @Param: out_num
+ *
+ * @Returns: 
+ */
+JLAddAgentDev_t*
+joylink_agent_parse_dev_add(const uint8_t* pMsg, int* out_num)
+{
+    if(NULL == pMsg || NULL == out_num){
+        log_error("--->:ERROR: pMsg is NULL\n");
+        return NULL;
+    }
+    int32_t count;
+    cJSON * pSub;
+    cJSON * pJson = NULL;
+    cJSON * pRoot = cJSON_Parse((char *)pMsg);
+    JLAddAgentDev_t* devs = NULL;
+
+    if(NULL == pRoot){
+        log_error("--->:cJSON_Parse is error:%s\n", pMsg);
+        goto ERROR;
+    }
+
+    pJson = cJSON_GetObjectItem(pRoot, "list");
+    count = cJSON_GetArraySize(pJson);
+    devs = (JLAddAgentDev_t*)malloc(sizeof(JLAddAgentDev_t) * count);
+
+    if(NULL == devs){
+        log_error("--->:malloc error\n");
+        goto ERROR;
+    }
+    memset(devs, 0, sizeof(JLAddAgentDev_t) * count);
+
+    int i;
+    for( i = 0; i < count; i++){
+        pSub = cJSON_GetArrayItem(pJson, i);
+        if(NULL == pSub){
+            continue;
+        }
+        cJSON *pData= cJSON_GetObjectItem(pSub, "feedid");
+        if(NULL == pData){
+            continue;
+        }
+		strcpy((char*)(devs[i].feedid), pData->valuestring);
+        pData = cJSON_GetObjectItem(pSub, "ackey");
+        if(NULL == pData){
+            continue;
+        }
+		strcpy((char*)(devs[i].ackey), pData->valuestring);
+    }
+
+    *out_num = i;
+ERROR:
+    if(NULL != pJson){
+        cJSON_Delete(pJson);
+    }
+    return devs;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: pMsg
+ * @Param: out_num
+ *
+ * @Returns: 
+ */
+JLAddAgentDev_t*
+joylink_agent_parse_dev_del(const uint8_t* pMsg, int* out_num)
+{
+    if(NULL == pMsg || NULL == out_num){
+        log_error("--->:ERROR: pMsg is NULL\n");
+        return NULL;
+    }
+    int32_t count;
+    cJSON * pSub;
+    cJSON * pJson = NULL;
+    cJSON * pRoot = cJSON_Parse((char *)pMsg);
+    JLAddAgentDev_t* devs = NULL;
+
+    if(NULL == pRoot){
+        log_error("--->:cJSON_Parse is error:%s\n", pMsg);
+        goto ERROR;
+    }
+
+    pJson = cJSON_GetObjectItem(pRoot, "list");
+    if(NULL == pJson){
+        log_error("--->:cJSON_Parse is error:%s\n", pMsg);
+        goto ERROR;
+    }
+    count = cJSON_GetArraySize(pJson);
+    devs = (JLAddAgentDev_t*)malloc(sizeof(JLAddAgentDev_t) * count);
+    if(NULL == devs){
+        log_error("--->:malloc error\n");
+        goto ERROR;
+    }
+    memset(devs, 0, sizeof(JLAddAgentDev_t) * count);
+    int i;
+    if(count > 0){
+        for(i = 0; i < count; i++){ 
+            cJSON *pv;
+            pv = cJSON_GetArrayItem(pJson, i);
+            if(NULL != pv){
+                strcpy((char*)(devs[i].feedid), pv->valuestring);
+            }
+        }
+    }
+    *out_num = i;
+ERROR:
+    if(NULL != pRoot){
+        cJSON_Delete(pRoot);
+    }
+    return devs;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+char * 
+joylink_agent_create_cloud_auth_json_req_f()
+{
+    cJSON *arrary; 
+    unsigned int i; 
+    int j = 0;
+    char *out = NULL; 
+    char auth_str[128];
+  
+    int count = AGENT_DEV_MAX;
+    cJSON **js_devs = (cJSON **)malloc(sizeof(cJSON *) * count); 
+    if(js_devs == NULL){
+        goto RET;
+    }
+    if(NULL == (arrary = cJSON_CreateArray())){
+        free(js_devs);
+        goto RET;
+    }
+
+    for(i = 0; i < count; i ++){
+        if(!IS_AGENT_AUTH_SET(_g_adevs[i].agent_st)){
+            continue;
+        }
+        js_devs[j] =cJSON_CreateObject();
+        if(NULL != js_devs[j]){
+            cJSON_AddItemToArray(arrary, js_devs[j]);
+            cJSON_AddStringToObject(js_devs[j], "feedid", _g_adevs[i].feedid);
+            cJSON_AddNumberToObject(js_devs[j], "random", _g_adevs[i].random);
+
+            memset(auth_str, 0, sizeof(auth_str));
+            joylink_util_byte2hexstr((uint8_t*)&_g_adevs[j].auth, sizeof(_g_adevs[i].auth), 
+                        (uint8_t*)auth_str, sizeof(auth_str));
+            cJSON_AddStringToObject(js_devs[j], "cloud_auth_hexstr", auth_str);
+        }
+        ST_AGENT_AUTH_CLR(_g_adevs[i].agent_st);
+        j++;
+    }
+
+    if(j > 0){
+        out=cJSON_Print(arrary);  
+        log_debug("------ json len:%d:%s", (int)strlen(out),  out);
+    }
+    cJSON_Delete(arrary);
+    free(js_devs);
+RET:
+    return out;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+char * 
+joylink_agent_create_cloud_hb_json_req()
+{
+    cJSON *arrary; 
+    unsigned int i; 
+    int j = 0;
+    char *out = NULL; 
+    char auth_str[128];
+  
+    int count = AGENT_DEV_MAX;
+    cJSON **js_devs = (cJSON **)malloc(sizeof(cJSON *) * count); 
+    if(js_devs == NULL){
+        goto RET;
+    }
+    if(NULL == (arrary = cJSON_CreateArray())){
+        free(js_devs);
+        goto RET;
+    }
+
+    for(i = 0; i < count; i ++){
+        if(!IS_AGENT_HB_SET(_g_adevs[i].agent_st)){
+            continue;
+        }
+        js_devs[j] =cJSON_CreateObject();
+        if(NULL != js_devs[j]){
+            cJSON_AddItemToArray(arrary, js_devs[j]);
+            cJSON_AddStringToObject(js_devs[j], "feedid", _g_adevs[i].feedid);
+            cJSON_AddNumberToObject(js_devs[j], "version", _g_adevs[i].hb.verion);
+            cJSON_AddNumberToObject(js_devs[j], "rssi", _g_adevs[i].hb.rssi);
+        }
+        ST_AGENT_HB_CLR(_g_adevs[i].agent_st);
+        j++;
+    }
+
+    if(j > 0){
+        out=cJSON_Print(arrary);  
+        log_debug("------ json len:%d:%s", (int)strlen(out),  out);
+    }
+
+    cJSON_Delete(arrary);
+    free(js_devs);
+RET:
+    return (char*)out;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+char * 
+joylink_agent_create_cloud_snap_json_req()
+{
+    cJSON *arrary; 
+    unsigned int i; 
+    int j = 0;
+    char *out = NULL; 
+    char auth_str[128];
+  
+    int count = AGENT_DEV_MAX;
+    cJSON **js_devs = (cJSON **)malloc(sizeof(cJSON *) * count); 
+    if(js_devs == NULL){
+        goto RET;
+    }
+    if(NULL == (arrary = cJSON_CreateArray())){
+        free(js_devs);
+        goto RET;
+    }
+
+    for(i = 0; i < count; i ++){
+        if(!IS_AGENT_SNAP_SET(_g_adevs[i].agent_st)){
+            continue;
+        }
+        js_devs[j] =cJSON_CreateObject();
+        if(NULL != js_devs[j]){
+            cJSON_AddItemToArray(arrary, js_devs[j]);
+            cJSON_AddStringToObject(js_devs[j], "feedid", _g_adevs[i].feedid);
+            cJSON_AddStringToObject(js_devs[j], "snap_hex_str", _g_adevs[i].snap);
+            char tb[1024] = {0};
+
+            joylink_util_hexStr2bytes(_g_adevs[i].snap, 
+                    tb, sizeof(tb));
+
+            log_info("SNAP:%s", tb + 4);
+        }
+        ST_AGENT_SNAP_CLR(_g_adevs[i].agent_st);
+        j++;
+    }
+
+    if(j > 0){
+        out=cJSON_Print(arrary);  
+        log_debug("------ json len:%d:%s", (int)strlen(out),  out);
+    }
+    cJSON_Delete(arrary);
+    free(js_devs);
+RET:
+    return out;
+}
+
+extern void suffix_object(cJSON *prev,cJSON *item);
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+char * 
+joylink_agent_json_packet_dev_list(int32_t ret_code, char* ret_msg)
+{
+    cJSON *arrary; 
+    unsigned int i; 
+    int j = 0;
+    char *out = NULL; 
+    char auth_str[128];
+    int count = AGENT_DEV_MAX;
+
+    cJSON *root = NULL;
+
+    root = cJSON_CreateObject();
+    if(NULL == root){
+        goto RET;
+    }
+
+    if(NULL == (arrary = cJSON_CreateArray())){
+        goto RET;
+    }
+
+    cJSON_AddNumberToObject(root, "code", ret_code);
+    cJSON_AddStringToObject(root, "msg", ret_msg); 
+    cJSON_AddItemToObject(root,"list", arrary);
+
+    char fs[AGENT_DEV_MAX][33];
+    for(i = 0; i < count; i ++){
+        if(!strcmp(_g_adevs[i].feedid, "")){
+            continue;
+        }
+        memset(fs[i], 0, 33);
+        strcpy(fs[j], _g_adevs[i].feedid);
+        j++;
+    }
+    cJSON *n = NULL, *p = NULL;
+    for(i=0; i<j ;i++){
+        n=cJSON_CreateString(fs[i]);
+        if(!i)arrary->child=n;else suffix_object(p,n);
+        p=n;
+    }
+
+    out=cJSON_Print(root);  
+    cJSON_Delete(root);
+    log_debug("------ json len:%d:%s", (int)strlen(out),  out);
+RET:
+    return out;
+}

+ 66 - 0
joylink/agent/joylink_agent_json.h

@@ -0,0 +1,66 @@
+#ifndef __JD_AGENT_JSON_H_
+#define __JD_AGENT_JSON_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C"{
+#endif /* __cplusplus */
+
+
+#include "joylink.h"
+/**
+ * brief: 
+ *
+ * @Param: sdev
+ * @Param: count
+ *
+ * @Returns: 
+ */
+char * 
+joylink_agent_create_cloud_auth_json_req();
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+char * 
+joylink_agent_create_cloud_hb_json_req();
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+char * 
+joylink_agent_create_cloud_snap_json_req();
+
+/**
+ * brief: 
+ *
+ * @Param: pMsg
+ * @Param: out_num
+ *
+ * @Returns: 
+ */
+JLAddAgentDev_t*
+joylink_agent_parse_dev_del(const uint8_t* pMsg, int* out_num);
+
+/**
+ * brief: 
+ *
+ * @Param: pMsg
+ * @Param: out_num
+ *
+ * @Returns: 
+ */
+JLAddAgentDev_t*
+joylink_agent_parse_dev_add(const uint8_t* pMsg, int* out_num);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif

+ 246 - 0
joylink/agent/tags

@@ -0,0 +1,246 @@
+!_TAG_FILE_FORMAT	2	/extended format; --format=1 will not append ;" to lines/
+!_TAG_FILE_SORTED	1	/0=unsorted, 1=sorted, 2=foldcase/
+!_TAG_PROGRAM_AUTHOR	Darren Hiebert	/dhiebert@users.sourceforge.net/
+!_TAG_PROGRAM_NAME	Exuberant Ctags	//
+!_TAG_PROGRAM_URL	http://ctags.sourceforge.net	/official site/
+!_TAG_PROGRAM_VERSION	5.9~svn20110310	//
+AF_LOCAL	joylink_adapter_net.h	29;"	d
+AGENT_DEV_MAX	joylink_agent_devs.h	15;"	d
+ANET_CONNECT_NONBLOCK	joylink_adapter_net.c	465;"	d	file:
+ANET_CONNECT_NONE	joylink_adapter_net.c	464;"	d	file:
+ANET_ERR	joylink_adapter_net.h	21;"	d
+ANET_ERR_LEN	joylink_adapter_net.h	22;"	d
+ANET_IP_ONLY	joylink_adapter_net.h	26;"	d
+ANET_NONE	joylink_adapter_net.h	25;"	d
+ANET_OK	joylink_adapter_net.h	20;"	d
+AgentAuthReq_t	joylink_agent.h	/^}AgentAuthReq_t;$/;"	t	typeref:struct:__anon4
+AgentAuthRsp_t	joylink_agent.h	/^}AgentAuthRsp_t;$/;"	t	typeref:struct:__anon5
+AgentDevAdd_t	joylink_agent.h	/^}AgentDevAdd_t;$/;"	t	typeref:struct:__anon2
+AgentDevDel_t	joylink_agent.h	/^}AgentDevDel_t;$/;"	t	typeref:struct:__anon3
+AgentDev_t	joylink_agent.h	/^}AgentDev_t;$/;"	t	typeref:struct:__anon10
+AgentHBReq_t	joylink_agent.h	/^}AgentHBReq_t;$/;"	t	typeref:struct:__anon6
+AgentHBRsp_t	joylink_agent.h	/^}AgentHBRsp_t;$/;"	t	typeref:struct:__anon7
+AgentSnapsReq_t	joylink_agent.h	/^}AgentSnapsReq_t;$/;"	t	typeref:struct:__anon8
+AgentSnapsRsp_t	joylink_agent.h	/^}AgentSnapsRsp_t;$/;"	t	typeref:struct:__anon9
+E_ERROR	joylink_adapter_net.c	91;"	d	file:
+E_OK	joylink_adapter_net.c	90;"	d	file:
+HEADERS	Makefile	/^HEADERS = $(wildcard *.h)$/;"	m
+IS_AGENT_AUTH_SET	joylink_agent.h	83;"	d
+IS_AGENT_HB_SET	joylink_agent.h	84;"	d
+IS_AGENT_SNAP_SET	joylink_agent.h	85;"	d
+JL_AGENT_GW_CLIENT_MAX	joylink_agent.h	81;"	d
+JL_AGENT_GW_PORT	joylink_agent.h	80;"	d
+JOYLINK_ADAPTER_NET_TCP_H	joylink_adapter_net.h	16;"	d
+LIBNAME	Makefile	/^LIBNAME = $(strip ${shell pwd |xargs basename})$/;"	m
+OBJS	Makefile	/^OBJS = $(patsubst %.c, %.o, $(SOURCES))$/;"	m
+ORG_SOURCES	Makefile	/^ORG_SOURCES = $(wildcard *.c)$/;"	m
+OUT_SRC	Makefile	/^OUT_SRC = test.c $/;"	m
+SOURCES	Makefile	/^SOURCES=$(filter-out ${OUT_SRC}, ${ORG_SOURCES})$/;"	m
+ST_AGENT_AUTH_CLR	joylink_agent.h	91;"	d
+ST_AGENT_AUTH_SET	joylink_agent.h	87;"	d
+ST_AGENT_HB_CLR	joylink_agent.h	92;"	d
+ST_AGENT_HB_SET	joylink_agent.h	88;"	d
+ST_AGENT_SNAP_CLR	joylink_agent.h	93;"	d
+ST_AGENT_SNAP_SET	joylink_agent.h	89;"	d
+__JD_AGENT_DEVS_H_	joylink_agent_devs.h	2;"	d
+__JD_AGENT_H_	joylink_agent.h	2;"	d
+__JD_AGENT_JSON_H_	joylink_agent_json.h	2;"	d
+__anon10::accesskey	joylink_agent.h	/^	char accesskey[JL_MAX_ACKEY_LEN];$/;"	m	struct:__anon10	access:public
+__anon10::agent_st	joylink_agent.h	/^    int agent_st;$/;"	m	struct:__anon10	access:public
+__anon10::auth	joylink_agent.h	/^    char auth[16];$/;"	m	struct:__anon10	access:public
+__anon10::fd	joylink_agent.h	/^    int32_t fd;$/;"	m	struct:__anon10	access:public
+__anon10::feedid	joylink_agent.h	/^	char feedid[JL_MAX_FEEDID_LEN];$/;"	m	struct:__anon10	access:public
+__anon10::hb	joylink_agent.h	/^    JLHearBeat_t hb;$/;"	m	struct:__anon10	access:public
+__anon10::random	joylink_agent.h	/^    int32_t random;$/;"	m	struct:__anon10	access:public
+__anon10::sessionkey	joylink_agent.h	/^	char sessionkey[JL_MAX_SESSION_KEY_LEN];$/;"	m	struct:__anon10	access:public
+__anon10::snap	joylink_agent.h	/^    char *snap;$/;"	m	struct:__anon10	access:public
+__anon10::snap_len	joylink_agent.h	/^    int32_t snap_len;$/;"	m	struct:__anon10	access:public
+__anon10::st	joylink_agent.h	/^    int32_t st;$/;"	m	struct:__anon10	access:public
+__anon1::cloud_thread_run	joylink_agent.c	/^    int32_t cloud_thread_run;$/;"	m	struct:__anon1	file:	access:public
+__anon1::eabled	joylink_agent.c	/^    char eabled;$/;"	m	struct:__anon1	file:	access:public
+__anon1::fd	joylink_agent.c	/^    int32_t fd;$/;"	m	struct:__anon1	file:	access:public
+__anon1::ntid	joylink_agent.c	/^    pthread_t ntid;$/;"	m	struct:__anon1	file:	access:public
+__anon1::st	joylink_agent.c	/^    int32_t st;$/;"	m	struct:__anon1	file:	access:public
+__anon2::accesskey	joylink_agent.h	/^	char accesskey[33];$/;"	m	struct:__anon2	access:public
+__anon2::feedid	joylink_agent.h	/^	char feedid[JL_MAX_FEEDID_LEN];$/;"	m	struct:__anon2	access:public
+__anon3::feedid	joylink_agent.h	/^	char feedid[JL_MAX_FEEDID_LEN];$/;"	m	struct:__anon3	access:public
+__anon4::devs	joylink_agent.h	/^	char* devs;$/;"	m	struct:__anon4	access:public
+__anon4::devs_len	joylink_agent.h	/^	int devs_len;$/;"	m	struct:__anon4	access:public
+__anon4::timestamp	joylink_agent.h	/^	unsigned int timestamp;$/;"	m	struct:__anon4	access:public
+__anon5::code	joylink_agent.h	/^	int code;$/;"	m	struct:__anon5	access:public
+__anon5::error_devs	joylink_agent.h	/^	char error_devs[];$/;"	m	struct:__anon5	access:public
+__anon5::timestamp	joylink_agent.h	/^	unsigned int timestamp;$/;"	m	struct:__anon5	access:public
+__anon6::devs	joylink_agent.h	/^	char* devs;$/;"	m	struct:__anon6	access:public
+__anon6::devs_len	joylink_agent.h	/^	int devs_len;$/;"	m	struct:__anon6	access:public
+__anon6::timestamp	joylink_agent.h	/^	unsigned int timestamp;$/;"	m	struct:__anon6	access:public
+__anon7::code	joylink_agent.h	/^	int code;$/;"	m	struct:__anon7	access:public
+__anon7::timestamp	joylink_agent.h	/^	unsigned int timestamp;$/;"	m	struct:__anon7	access:public
+__anon8::snaps	joylink_agent.h	/^	char* snaps;$/;"	m	struct:__anon8	access:public
+__anon8::snaps_len	joylink_agent.h	/^	int snaps_len;$/;"	m	struct:__anon8	access:public
+__anon8::timestamp	joylink_agent.h	/^	unsigned int timestamp;$/;"	m	struct:__anon8	access:public
+__anon9::code	joylink_agent.h	/^	int code;$/;"	m	struct:__anon9	access:public
+__anon9::timestamp	joylink_agent.h	/^	unsigned int timestamp;$/;"	m	struct:__anon9	access:public
+_g_adevs	joylink_agent_devs.c	/^AgentDev_t _g_adevs[AGENT_DEV_MAX];$/;"	v
+_g_c_mg	joylink_agent.c	/^static jl_agent_cloud_mg_t _g_c_mg, * _g_p_cmg = &_g_c_mg;$/;"	v	file:
+_g_p_cmg	joylink_agent.c	/^static jl_agent_cloud_mg_t _g_c_mg, * _g_p_cmg = &_g_c_mg;$/;"	v	file:
+_joylink_net_tcp_server	joylink_adapter_net.c	/^_joylink_net_tcp_server(char *err, int32_t port, char *bindaddr, int32_t af, int32_t backlog)$/;"	f	file:	signature:(char *err, int32_t port, char *bindaddr, int32_t af, int32_t backlog)
+accesskey	joylink_agent.h	/^	char accesskey[33];$/;"	m	struct:__anon2	access:public
+accesskey	joylink_agent.h	/^	char accesskey[JL_MAX_ACKEY_LEN];$/;"	m	struct:__anon10	access:public
+agent_st	joylink_agent.h	/^    int agent_st;$/;"	m	struct:__anon10	access:public
+auth	joylink_agent.h	/^    char auth[16];$/;"	m	struct:__anon10	access:public
+cloud_thread_run	joylink_agent.c	/^    int32_t cloud_thread_run;$/;"	m	struct:__anon1	file:	access:public
+code	joylink_agent.h	/^	int code;$/;"	m	struct:__anon5	access:public
+code	joylink_agent.h	/^	int code;$/;"	m	struct:__anon7	access:public
+code	joylink_agent.h	/^	int code;$/;"	m	struct:__anon9	access:public
+devs	joylink_agent.h	/^	char* devs;$/;"	m	struct:__anon4	access:public
+devs	joylink_agent.h	/^	char* devs;$/;"	m	struct:__anon6	access:public
+devs_len	joylink_agent.h	/^	int devs_len;$/;"	m	struct:__anon4	access:public
+devs_len	joylink_agent.h	/^	int devs_len;$/;"	m	struct:__anon6	access:public
+devs_lock	joylink_agent_devs.c	/^pthread_mutex_t    devs_lock = PTHREAD_MUTEX_INITIALIZER;$/;"	v
+eabled	joylink_agent.c	/^    char eabled;$/;"	m	struct:__anon1	file:	access:public
+error_devs	joylink_agent.h	/^	char error_devs[];$/;"	m	struct:__anon5	access:public
+fd	joylink_agent.c	/^    int32_t fd;$/;"	m	struct:__anon1	file:	access:public
+fd	joylink_agent.h	/^    int32_t fd;$/;"	m	struct:__anon10	access:public
+fd_lock	joylink_agent.c	/^pthread_mutex_t    fd_lock = PTHREAD_MUTEX_INITIALIZER;$/;"	v
+feedid	joylink_agent.h	/^	char feedid[JL_MAX_FEEDID_LEN];$/;"	m	struct:__anon10	access:public
+feedid	joylink_agent.h	/^	char feedid[JL_MAX_FEEDID_LEN];$/;"	m	struct:__anon2	access:public
+feedid	joylink_agent.h	/^	char feedid[JL_MAX_FEEDID_LEN];$/;"	m	struct:__anon3	access:public
+hb	joylink_agent.h	/^    JLHearBeat_t hb;$/;"	m	struct:__anon10	access:public
+jl_agent_cloud_mg_t	joylink_agent.c	/^}jl_agent_cloud_mg_t;$/;"	t	typeref:struct:__anon1	file:
+joylink_adapter_inet_addr	joylink_adapter_net.c	/^joylink_adapter_inet_addr(const char *cp)$/;"	f	signature:(const char *cp)
+joylink_adapter_inet_aton	joylink_adapter_net.c	/^joylink_adapter_inet_aton(const char *cp, struct in_addr *ap)$/;"	f	signature:(const char *cp, struct in_addr *ap)
+joylink_adapter_inet_ntoa	joylink_adapter_net.c	/^joylink_adapter_inet_ntoa(struct in_addr in_a)$/;"	f	signature:(struct in_addr in_a)
+joylink_adapter_multi_net_get_ip	joylink_adapter_net.c	/^joylink_adapter_multi_net_get_ip(char* ipv4, const uint32_t max_size)$/;"	f	signature:(char* ipv4, const uint32_t max_size)
+joylink_adapter_net_check_connect	joylink_adapter_net.c	/^joylink_adapter_net_check_connect(int32_t s)$/;"	f	file:	signature:(int32_t s)
+joylink_adapter_net_close	joylink_adapter_net.c	/^joylink_adapter_net_close(int32_t fd)$/;"	f	signature:(int32_t fd)
+joylink_adapter_net_close	joylink_adapter_net.h	/^joylink_adapter_net_close(int32_t fd);$/;"	p	signature:(int32_t fd)
+joylink_adapter_net_disable_tcp_no_delay	joylink_adapter_net.c	/^joylink_adapter_net_disable_tcp_no_delay(char *err, int32_t fd)$/;"	f	signature:(char *err, int32_t fd)
+joylink_adapter_net_disable_tcp_no_delay	joylink_adapter_net.h	/^joylink_adapter_net_disable_tcp_no_delay(char *err, int32_t fd);$/;"	p	signature:(char *err, int32_t fd)
+joylink_adapter_net_enable_tcp_no_delay	joylink_adapter_net.c	/^joylink_adapter_net_enable_tcp_no_delay(char *err, int32_t fd)$/;"	f	signature:(char *err, int32_t fd)
+joylink_adapter_net_enable_tcp_no_delay	joylink_adapter_net.h	/^joylink_adapter_net_enable_tcp_no_delay(char *err, int32_t fd);$/;"	p	signature:(char *err, int32_t fd)
+joylink_adapter_net_generic_resolve	joylink_adapter_net.c	/^joylink_adapter_net_generic_resolve(char *err, char *host, char *ipbuf, int32_t ipbuf_len,$/;"	f	signature:(char *err, char *host, char *ipbuf, int32_t ipbuf_len, int32_t flags)
+joylink_adapter_net_keep_alive	joylink_adapter_net.c	/^joylink_adapter_net_keep_alive(char *err, int32_t fd, int32_t interval)$/;"	f	signature:(char *err, int32_t fd, int32_t interval)
+joylink_adapter_net_keep_alive	joylink_adapter_net.h	/^joylink_adapter_net_keep_alive(char *err, int32_t fd, int32_t int32_terval);$/;"	p	signature:(char *err, int32_t fd, int32_t int32_terval)
+joylink_adapter_net_non_block	joylink_adapter_net.c	/^joylink_adapter_net_non_block(char *err, int32_t fd)$/;"	f	signature:(char *err, int32_t fd)
+joylink_adapter_net_non_block	joylink_adapter_net.h	/^joylink_adapter_net_non_block(char *err, int32_t fd);$/;"	p	signature:(char *err, int32_t fd)
+joylink_adapter_net_read	joylink_adapter_net.c	/^joylink_adapter_net_read(int32_t fd, char *buf, int32_t count)$/;"	f	signature:(int32_t fd, char *buf, int32_t count)
+joylink_adapter_net_read	joylink_adapter_net.h	/^joylink_adapter_net_read(int32_t fd, char *buf, int32_t count);$/;"	p	signature:(int32_t fd, char *buf, int32_t count)
+joylink_adapter_net_read_no_check_out	joylink_adapter_net.c	/^joylink_adapter_net_read_no_check_out(int32_t fd, char *buf, int32_t count)$/;"	f	signature:(int32_t fd, char *buf, int32_t count)
+joylink_adapter_net_recv	joylink_adapter_net.c	/^joylink_adapter_net_recv(int32_t fd, char *buf, int32_t size)$/;"	f	signature:(int32_t fd, char *buf, int32_t size)
+joylink_adapter_net_recv	joylink_adapter_net.h	/^joylink_adapter_net_recv(int32_t fd, char *buf, int32_t size);$/;"	p	signature:(int32_t fd, char *buf, int32_t size)
+joylink_adapter_net_recv_with_time	joylink_adapter_net.c	/^joylink_adapter_net_recv_with_time(int32_t fd, char *buf, int32_t size, int32_t usec, int32_t sec)$/;"	f	signature:(int32_t fd, char *buf, int32_t size, int32_t usec, int32_t sec)
+joylink_adapter_net_recv_with_time	joylink_adapter_net.h	/^joylink_adapter_net_recv_with_time(int32_t fd, char *buf, int32_t size, int32_t usec, int32_t sec);$/;"	p	signature:(int32_t fd, char *buf, int32_t size, int32_t usec, int32_t sec)
+joylink_adapter_net_resolve	joylink_adapter_net.c	/^joylink_adapter_net_resolve(char *err, char *host, char *ipbuf, int32_t ipbuf_len) {$/;"	f	signature:(char *err, char *host, char *ipbuf, int32_t ipbuf_len)
+joylink_adapter_net_resolve	joylink_adapter_net.h	/^joylink_adapter_net_resolve(char *err, char *host, char *ipbuf, int32_t ipbuf_len);$/;"	p	signature:(char *err, char *host, char *ipbuf, int32_t ipbuf_len)
+joylink_adapter_net_resolve_ip	joylink_adapter_net.c	/^joylink_adapter_net_resolve_ip(char *err, char *host, char *ipbuf, int32_t ipbuf_len) {$/;"	f	signature:(char *err, char *host, char *ipbuf, int32_t ipbuf_len)
+joylink_adapter_net_resolve_ip	joylink_adapter_net.h	/^joylink_adapter_net_resolve_ip(char *err, char *host, char *ipbuf, int32_t ipbuf_len);$/;"	p	signature:(char *err, char *host, char *ipbuf, int32_t ipbuf_len)
+joylink_adapter_net_send	joylink_adapter_net.c	/^joylink_adapter_net_send(int32_t fd, char *buf, int32_t size)$/;"	f	signature:(int32_t fd, char *buf, int32_t size)
+joylink_adapter_net_send	joylink_adapter_net.h	/^joylink_adapter_net_send(int32_t fd, char *buf, int32_t size);$/;"	p	signature:(int32_t fd, char *buf, int32_t size)
+joylink_adapter_net_set_error	joylink_adapter_net.c	/^joylink_adapter_net_set_error(char *err, const char *fmt, ...)$/;"	f	file:	signature:(char *err, const char *fmt, ...)
+joylink_adapter_net_set_reuse_addr	joylink_adapter_net.c	/^joylink_adapter_net_set_reuse_addr(char *err, int32_t fd) {$/;"	f	file:	signature:(char *err, int32_t fd)
+joylink_adapter_net_set_send_buf	joylink_adapter_net.c	/^joylink_adapter_net_set_send_buf(char *err, int32_t fd, int32_t buffsize)$/;"	f	signature:(char *err, int32_t fd, int32_t buffsize)
+joylink_adapter_net_set_send_buf	joylink_adapter_net.h	/^joylink_adapter_net_set_send_buf(char *err, int32_t fd, int32_t buffsize);$/;"	p	signature:(char *err, int32_t fd, int32_t buffsize)
+joylink_adapter_net_set_tcp_no_delay	joylink_adapter_net.c	/^joylink_adapter_net_set_tcp_no_delay(char *err, int32_t fd, int32_t val)$/;"	f	file:	signature:(char *err, int32_t fd, int32_t val)
+joylink_adapter_net_tcp6_server	joylink_adapter_net.c	/^joylink_adapter_net_tcp6_server(char *err, int32_t port, char *bindaddr, int32_t backlog)$/;"	f	signature:(char *err, int32_t port, char *bindaddr, int32_t backlog)
+joylink_adapter_net_tcp6_server	joylink_adapter_net.h	/^joylink_adapter_net_tcp6_server(char *err, int32_t port, char *bindaddr, int32_t backlog);$/;"	p	signature:(char *err, int32_t port, char *bindaddr, int32_t backlog)
+joylink_adapter_net_tcp_connect	joylink_adapter_net.c	/^joylink_adapter_net_tcp_connect(char *err, const char *addr, int32_t port)$/;"	f	signature:(char *err, const char *addr, int32_t port)
+joylink_adapter_net_tcp_connect	joylink_adapter_net.h	/^joylink_adapter_net_tcp_connect(char *err, const char *addr, int32_t port);$/;"	p	signature:(char *err, const char *addr, int32_t port)
+joylink_adapter_net_tcp_generic_connect	joylink_adapter_net.c	/^joylink_adapter_net_tcp_generic_connect(char *err, const char *addr, int32_t port, int32_t flags)$/;"	f	file:	signature:(char *err, const char *addr, int32_t port, int32_t flags)
+joylink_adapter_net_tcp_keep_alive	joylink_adapter_net.c	/^joylink_adapter_net_tcp_keep_alive(char *err, int32_t fd)$/;"	f	signature:(char *err, int32_t fd)
+joylink_adapter_net_tcp_keep_alive	joylink_adapter_net.h	/^joylink_adapter_net_tcp_keep_alive(char *err, int32_t fd);$/;"	p	signature:(char *err, int32_t fd)
+joylink_adapter_net_tcp_non_block_connect	joylink_adapter_net.c	/^joylink_adapter_net_tcp_non_block_connect(char *err, char *addr, int32_t port)$/;"	f	signature:(char *err, char *addr, int32_t port)
+joylink_adapter_net_tcp_non_block_connect	joylink_adapter_net.h	/^joylink_adapter_net_tcp_non_block_connect(char *err, char *addr, int32_t port);$/;"	p	signature:(char *err, char *addr, int32_t port)
+joylink_adapter_net_tcp_server	joylink_adapter_net.c	/^joylink_adapter_net_tcp_server(char *err, int32_t port, char *bindaddr, int32_t backlog)$/;"	f	signature:(char *err, int32_t port, char *bindaddr, int32_t backlog)
+joylink_adapter_net_tcp_server	joylink_adapter_net.h	/^joylink_adapter_net_tcp_server(char *err, int32_t port, char *bindaddr, int32_t backlog);$/;"	p	signature:(char *err, int32_t port, char *bindaddr, int32_t backlog)
+joylink_adapter_net_v6_only	joylink_adapter_net.c	/^joylink_adapter_net_v6_only(char *err, int32_t s) $/;"	f	file:	signature:(char *err, int32_t s)
+joylink_adapter_net_write	joylink_adapter_net.c	/^joylink_adapter_net_write(int32_t fd, char *buf, int32_t count)$/;"	f	signature:(int32_t fd, char *buf, int32_t count)
+joylink_adapter_net_write	joylink_adapter_net.h	/^joylink_adapter_net_write(int32_t fd, char *buf, int32_t count);$/;"	p	signature:(int32_t fd, char *buf, int32_t count)
+joylink_adapter_select	joylink_adapter_net.c	/^joylink_adapter_select(int nfds, fd_set *readfds, fd_set *writefds,$/;"	f	signature:(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
+joylink_adapter_select	joylink_adapter_net.h	/^joylink_adapter_select(int nfds, fd_set *readfds, fd_set *writefds,$/;"	p	signature:(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
+joylink_adapter_udp_socket	joylink_adapter_net.c	/^joylink_adapter_udp_socket()$/;"	f
+joylink_adapter_udp_socket	joylink_adapter_net.h	/^joylink_adapter_udp_socket();$/;"	p	signature:()
+joylink_agent_HB_req	joylink_agent_gw_2_cloud.c	/^joylink_agent_HB_req()$/;"	f
+joylink_agent_HB_rsps	joylink_agent_gw_2_cloud.c	/^joylink_agent_HB_rsps(char *src, int len)$/;"	f	signature:(char *src, int len)
+joylink_agent_auth_req	joylink_agent_gw_2_cloud.c	/^joylink_agent_auth_req()$/;"	f
+joylink_agent_auth_rsps	joylink_agent_gw_2_cloud.c	/^joylink_agent_auth_rsps(char *src, int len)$/;"	f	signature:(char *src, int len)
+joylink_agent_cloud_auth_hand	joylink_agent.h	/^joylink_agent_cloud_auth_hand(int32_t fd, uint8_t *src, int32_t len);$/;"	p	signature:(int32_t fd, uint8_t *src, int32_t len)
+joylink_agent_cloud_fd	joylink_agent.c	/^joylink_agent_cloud_fd()$/;"	f
+joylink_agent_cloud_finit	joylink_agent.c	/^joylink_agent_cloud_finit(void)$/;"	f	signature:(void)
+joylink_agent_cloud_init	joylink_agent.c	/^joylink_agent_cloud_init(void)$/;"	f	signature:(void)
+joylink_agent_cloud_loop	joylink_agent.c	/^joylink_agent_cloud_loop(void* data)$/;"	f	signature:(void* data)
+joylink_agent_cloud_mg	joylink_agent.c	/^joylink_agent_cloud_mg(void)$/;"	f	file:	signature:(void)
+joylink_agent_cloud_rsp	joylink_agent_gw_2_cloud.c	/^joylink_agent_cloud_rsp(char * src, int32_t src_len)$/;"	f	signature:(char * src, int32_t src_len)
+joylink_agent_cloud_rsp_packet	joylink_agent.c	/^joylink_agent_cloud_rsp_packet($/;"	f	signature:( uint8_t* pBuf, int buflen, E_PacketType cmd, uint8_t* pOpt, int optLen, uint8_t* key, const uint8_t* payload, int payloadLen)
+joylink_agent_cloud_server_proc	joylink_agent.c	/^joylink_agent_cloud_server_proc(int32_t gw_fd)$/;"	f	file:	signature:(int32_t gw_fd)
+joylink_agent_create_cloud_auth_json_req	joylink_agent_json.h	/^joylink_agent_create_cloud_auth_json_req();$/;"	p	signature:()
+joylink_agent_create_cloud_auth_json_req_f	joylink_agent_gw_2_cloud.c	/^joylink_agent_create_cloud_auth_json_req_f();$/;"	p	file:
+joylink_agent_create_cloud_auth_json_req_f	joylink_agent_json.c	/^joylink_agent_create_cloud_auth_json_req_f()$/;"	f
+joylink_agent_create_cloud_hb_json_req	joylink_agent_json.c	/^joylink_agent_create_cloud_hb_json_req()$/;"	f
+joylink_agent_create_cloud_hb_json_req	joylink_agent_json.h	/^joylink_agent_create_cloud_hb_json_req();$/;"	p	signature:()
+joylink_agent_create_cloud_snap_json_req	joylink_agent_json.c	/^joylink_agent_create_cloud_snap_json_req()$/;"	f
+joylink_agent_create_cloud_snap_json_req	joylink_agent_json.h	/^joylink_agent_create_cloud_snap_json_req();$/;"	p	signature:()
+joylink_agent_dev_add	joylink_agent_devs.c	/^joylink_agent_dev_add(char feedid[JL_MAX_FEEDID_LEN], char ackey[JL_MAX_ACKEY_LEN])$/;"	f	signature:(char feedid[JL_MAX_FEEDID_LEN], char ackey[JL_MAX_ACKEY_LEN])
+joylink_agent_dev_add	joylink_agent_devs.h	/^joylink_agent_dev_add(char feedid[JL_MAX_FEEDID_LEN], $/;"	p	signature:(char feedid[JL_MAX_FEEDID_LEN], char ackey[JL_MAX_ACKEY_LEN])
+joylink_agent_dev_cloud_HB_hand	joylink_agent.c	/^joylink_agent_dev_cloud_HB_hand(int32_t fd, uint8_t *payload, $/;"	f	signature:(int32_t fd, uint8_t *payload, int32_t s_len)
+joylink_agent_dev_cloud_auth_hand	joylink_agent.c	/^joylink_agent_dev_cloud_auth_hand(int32_t fd, char* feedid, uint32_t d_rand, $/;"	f	signature:(int32_t fd, char* feedid, uint32_t d_rand, uint8_t *payload, int32_t s_len, char* auth_org)
+joylink_agent_dev_cloud_upload_hand	joylink_agent.c	/^joylink_agent_dev_cloud_upload_hand(int32_t fd, uint8_t *payload, $/;"	f	signature:(int32_t fd, uint8_t *payload, int32_t s_len)
+joylink_agent_dev_del	joylink_agent_devs.c	/^joylink_agent_dev_del(char *feedid)$/;"	f	signature:(char *feedid)
+joylink_agent_dev_del	joylink_agent_devs.h	/^joylink_agent_dev_del(char *feedid);$/;"	p	signature:(char *feedid)
+joylink_agent_dev_get	joylink_agent_devs.c	/^joylink_agent_dev_get(char *feedid)$/;"	f	signature:(char *feedid)
+joylink_agent_dev_get	joylink_agent_devs.h	/^joylink_agent_dev_get(char *feedid);$/;"	p	signature:(char *feedid)
+joylink_agent_dev_get_keys	joylink_agent_devs.c	/^joylink_agent_dev_get_keys(char feedid[JL_MAX_FEEDID_LEN], $/;"	f	signature:(char feedid[JL_MAX_FEEDID_LEN], char ackey[JL_MAX_ACKEY_LEN], char sessionkey[JL_MAX_SESSION_KEY_LEN])
+joylink_agent_dev_req_proc	joylink_agent.c	/^joylink_agent_dev_req_proc(int fd)$/;"	f	signature:(int fd)
+joylink_agent_dev_rsp	joylink_agent.c	/^joylink_agent_dev_rsp()$/;"	f
+joylink_agent_dev_upd	joylink_agent_devs.c	/^joylink_agent_dev_upd(char *feedid, AgentDev_t *pad)$/;"	f	signature:(char *feedid, AgentDev_t *pad)
+joylink_agent_dev_upd	joylink_agent_devs.h	/^joylink_agent_dev_upd(char *feedid, AgentDev_t *pad);$/;"	p	signature:(char *feedid, AgentDev_t *pad)
+joylink_agent_devs_get_fds	joylink_agent_devs.c	/^joylink_agent_devs_get_fds(int fds[AGENT_DEV_MAX])$/;"	f	signature:(int fds[AGENT_DEV_MAX])
+joylink_agent_devs_get_fds	joylink_agent_devs.h	/^joylink_agent_devs_get_fds(int fds[AGENT_DEV_MAX]);$/;"	p	signature:(int fds[AGENT_DEV_MAX])
+joylink_agent_devs_load	joylink_agent_devs.c	/^joylink_agent_devs_load(void)$/;"	f	signature:(void)
+joylink_agent_devs_load	joylink_agent_devs.h	/^joylink_agent_devs_load(void);$/;"	p	signature:(void)
+joylink_agent_get_dev_by_fd	joylink_agent_devs.c	/^joylink_agent_get_dev_by_fd(int fd)$/;"	f	signature:(int fd)
+joylink_agent_get_dev_by_fd	joylink_agent_devs.h	/^joylink_agent_get_dev_by_fd(int fd);$/;"	p	signature:(int fd)
+joylink_agent_get_feedid_by_fd	joylink_agent_devs.c	/^joylink_agent_get_feedid_by_fd(int fd, char feedid[JL_MAX_FEEDID_LEN])$/;"	f	signature:(int fd, char feedid[JL_MAX_FEEDID_LEN])
+joylink_agent_get_feedid_by_fd	joylink_agent_devs.h	/^joylink_agent_get_feedid_by_fd(int fd, char feedid[JL_MAX_FEEDID_LEN]);$/;"	p	signature:(int fd, char feedid[JL_MAX_FEEDID_LEN])
+joylink_agent_gw_thread_start	joylink_agent.c	/^joylink_agent_gw_thread_start()$/;"	f
+joylink_agent_gw_thread_start	test.c	/^joylink_agent_gw_thread_start();$/;"	p	file:
+joylink_agent_gw_thread_stop	joylink_agent.c	/^joylink_agent_gw_thread_stop()$/;"	f
+joylink_agent_make_session_key	joylink_agent.c	/^joylink_agent_make_session_key(char *skey)$/;"	f	signature:(char *skey)
+joylink_agent_package_and_send	joylink_agent_gw_2_cloud.c	/^joylink_agent_package_and_send(char* msg, int32_t msg_len, int32_t cmd)$/;"	f	signature:(char* msg, int32_t msg_len, int32_t cmd)
+joylink_agent_snap_req	joylink_agent_gw_2_cloud.c	/^joylink_agent_snap_req()$/;"	f
+joylink_agent_snap_rsps	joylink_agent_gw_2_cloud.c	/^joylink_agent_snap_rsps(char *src, int len)$/;"	f	signature:(char *src, int len)
+joylink_agent_tcp_recv	joylink_agent.c	/^joylink_agent_tcp_recv(char fd, char *rec_buff, int max)$/;"	f	signature:(char fd, char *rec_buff, int max)
+joylink_cloud_set_st	joylink_adapter_net.c	/^extern void joylink_cloud_set_st(int32_t value);$/;"	p	file:	signature:(int32_t value)
+joylink_dencypt_server_req	joylink_agent.c	/^joylink_dencypt_server_req($/;"	p	file:	signature:( JLPacketParam_t *pParam, const uint8_t *pIn, int length, uint8_t* pOut, int maxlen, char* feedid)
+joylink_net_generic_accept	joylink_adapter_net.c	/^static int32_t joylink_net_generic_accept(char *err, int32_t s, struct sockaddr *sa, socklen_t *len) {$/;"	f	file:	signature:(char *err, int32_t s, struct sockaddr *sa, socklen_t *len)
+joylink_net_listen	joylink_adapter_net.c	/^joylink_net_listen(char *err, int32_t s, struct sockaddr *sa, socklen_t len, int32_t backlog) {$/;"	f	file:	signature:(char *err, int32_t s, struct sockaddr *sa, socklen_t len, int32_t backlog)
+joylink_net_peer_to_string	joylink_adapter_net.c	/^joylink_net_peer_to_string(int32_t fd, char *ip, int32_t ip_len, int32_t *port) {$/;"	f	signature:(int32_t fd, char *ip, int32_t ip_len, int32_t *port)
+joylink_net_peer_to_string	joylink_adapter_net.h	/^joylink_net_peer_to_string(int32_t fd, char *ip, int32_t ip_len, int32_t *port);$/;"	p	signature:(int32_t fd, char *ip, int32_t ip_len, int32_t *port)
+joylink_net_sock_name	joylink_adapter_net.c	/^joylink_net_sock_name(int32_t fd, char *ip, int32_t ip_len, int32_t *port) {$/;"	f	signature:(int32_t fd, char *ip, int32_t ip_len, int32_t *port)
+joylink_net_sock_name	joylink_adapter_net.h	/^joylink_net_sock_name(int32_t fd, char *ip, int32_t ip_len, int32_t *port);$/;"	p	signature:(int32_t fd, char *ip, int32_t ip_len, int32_t *port)
+joylink_net_tcp_accept	joylink_adapter_net.c	/^joylink_net_tcp_accept(char *err, int32_t s, char *ip, int32_t ip_len, int32_t *port) {$/;"	f	signature:(char *err, int32_t s, char *ip, int32_t ip_len, int32_t *port)
+joylink_net_tcp_accept	joylink_adapter_net.h	/^joylink_net_tcp_accept(char *err, int32_t serversock, char *ip, int32_t ip_len, int32_t *port);$/;"	p	signature:(char *err, int32_t serversock, char *ip, int32_t ip_len, int32_t *port)
+joylink_net_unix_accept	joylink_adapter_net.h	/^joylink_net_unix_accept(char *err, int32_t serversock);$/;"	p	signature:(char *err, int32_t serversock)
+joylink_package_ota_fff_upload	joylink_agent_gw_2_cloud.c	/^joylink_package_ota_fff_upload();$/;"	p	file:
+joylink_packet_server_hb_xxx_req	test.c	/^joylink_packet_server_hb_xxx_req(void);$/;"	p	file:	signature:(void)
+joylink_server_st_init	test.c	/^joylink_server_st_init()$/;"	f	file:
+joylink_util_byte2hexstr	joylink_agent_json.c	/^joylink_util_byte2hexstr(const uint8_t *pBytes, int srcLen, uint8_t *pDstStr, int dstLen);$/;"	p	file:	signature:(const uint8_t *pBytes, int srcLen, uint8_t *pDstStr, int dstLen)
+main	test.c	/^int main(int argc , char **argv)$/;"	f	signature:(int argc , char **argv)
+ntid	joylink_agent.c	/^    pthread_t ntid;$/;"	m	struct:__anon1	file:	access:public
+random	joylink_agent.h	/^    int32_t random;$/;"	m	struct:__anon10	access:public
+s_host_ipv4	joylink_adapter_net.c	/^uint8_t s_host_ipv4[32] = {0};$/;"	v
+sessionkey	joylink_agent.h	/^	char sessionkey[JL_MAX_SESSION_KEY_LEN];$/;"	m	struct:__anon10	access:public
+snap	joylink_agent.h	/^    char *snap;$/;"	m	struct:__anon10	access:public
+snap_len	joylink_agent.h	/^    int32_t snap_len;$/;"	m	struct:__anon10	access:public
+snaps	joylink_agent.h	/^	char* snaps;$/;"	m	struct:__anon8	access:public
+snaps_len	joylink_agent.h	/^	int snaps_len;$/;"	m	struct:__anon8	access:public
+st	joylink_agent.c	/^    int32_t st;$/;"	m	struct:__anon1	file:	access:public
+st	joylink_agent.h	/^    int32_t st;$/;"	m	struct:__anon10	access:public
+test_adevs	test.c	/^void test_adevs()$/;"	f
+test_adevs_init	test.c	/^void test_adevs_init()$/;"	f
+test_send	test.c	/^void test_send()$/;"	f
+timestamp	joylink_agent.h	/^	unsigned int timestamp;$/;"	m	struct:__anon4	access:public
+timestamp	joylink_agent.h	/^	unsigned int timestamp;$/;"	m	struct:__anon5	access:public
+timestamp	joylink_agent.h	/^	unsigned int timestamp;$/;"	m	struct:__anon6	access:public
+timestamp	joylink_agent.h	/^	unsigned int timestamp;$/;"	m	struct:__anon7	access:public
+timestamp	joylink_agent.h	/^	unsigned int timestamp;$/;"	m	struct:__anon8	access:public
+timestamp	joylink_agent.h	/^	unsigned int timestamp;$/;"	m	struct:__anon9	access:public

+ 204 - 0
joylink/agent/test.c

@@ -0,0 +1,204 @@
+/* --------------------------------------------------
+ * @file: test.c
+ *
+ * @brief: 
+ *
+ * @version: 1.0
+ *
+ * @date: 10/08/2015 09:28:27 AM
+ *
+ * --------------------------------------------------
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+
+#include "joylink_json.h"
+#include "joylink_agent.h"
+#include "joylink_agent_devs.h"
+
+extern void
+joylink_agent_gw_thread_start();
+
+extern int 
+joylink_packet_server_hb_xxx_req(void);
+
+/**
+ * brief: 
+ */
+static void 
+joylink_server_st_init()
+{
+    int ret = -1;
+    struct sockaddr_in saServer; 
+    bzero(&saServer, sizeof(saServer)); 
+
+    saServer.sin_family = AF_INET;
+
+    /*saServer.sin_port = htons(_g_pdev->jlp.server_port);*/
+    saServer.sin_port = htons( JL_AGENT_GW_PORT);
+
+    saServer.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+    _g_pdev->server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (_g_pdev->server_socket < 0 ){
+        log_error("socket() failed!\n");
+        return;
+    }
+    ret = connect(_g_pdev->server_socket, 
+            (struct sockaddr *)&saServer,
+            sizeof(saServer));
+
+    if(ret < 0){
+        log_error("connect() server failed!\n");
+        close(_g_pdev->server_socket);
+        _g_pdev->server_st = 0;
+    }else{
+        _g_pdev->server_st = 1;
+    }
+    _g_pdev->hb_lost_count = 0;
+}
+
+void test_send()
+{
+    int ret;
+    int len = 0; 
+
+    joylink_server_st_init();
+
+    len = joylink_packet_server_hb_xxx_req();
+
+    ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+    if(ret < 0){
+        log_error("send error ret:%d", ret);
+    }
+    log_debug("HB----->");
+}
+
+void test_adevs_init()
+{
+    AgentDev_t ad; 
+    memset(&ad, 0, sizeof(ad));
+    
+    memcpy(ad.feedid, _g_pdev->jlp.feedid, JL_MAX_FEEDID_LEN);
+    memcpy(ad.accesskey, _g_pdev->jlp.accesskey, JL_MAX_FEEDID_LEN);
+    joylink_agent_dev_add(ad.feedid, ad.accesskey);
+    AgentDev_t *p = joylink_agent_dev_get(ad.feedid);
+
+    log_debug("after add :%s:%s", p->feedid, p->accesskey);
+}
+
+void test_adevs()
+{
+    AgentDev_t ad = {.feedid = "feedid111111111", .accesskey= "ffffff"};
+
+    AgentDev_t ab;
+    memset(&ab, 0, sizeof(ab));
+    memcpy(&ab, &ad, sizeof(AgentDev_t));
+
+    joylink_agent_dev_add(ad.feedid, ad.accesskey);
+
+    AgentDev_t *p = joylink_agent_dev_get(ad.feedid);
+
+    log_debug("after add :%s:%s", p->feedid, p->accesskey);
+   
+    strcpy(ad.feedid, "666666");
+    joylink_agent_dev_upd(ab.feedid, &ad);
+
+    p = joylink_agent_dev_get(ad.feedid);
+    if(p != NULL){
+        log_debug("after update :%s:%s", p->feedid, p->accesskey);
+    }else{
+        log_debug("after update get error"); 
+    }
+
+    joylink_agent_dev_del(ad.feedid);
+
+    p = joylink_agent_dev_get(ad.feedid);
+    if(p == NULL){
+        log_debug("after del no found agent dev");
+    }
+}
+
+extern JLAddAgentDev_t*
+joylink_agent_parse_dev_add(const uint8_t* pMsg, int* out_num);
+
+void test_add_agent_dev()
+{
+    char* ts = "[{\"feedid\":\"1ffff\",\"ackey\":\"1keyfff\"}, {\"feedid\":\"2ffff\",\"ackey\":\"2keyfff\"}]";
+    int32_t num = 0;
+
+    int i;
+    for(i=0; i < num; i++){
+        /*log_debug("---:feedid:%s\nackey:%s", p[i].feedid, p[i].ackey);*/
+    }
+
+}
+
+void test_file_save()
+{
+    JLPInfo_t jlp[10];
+    JLPInfo_t fjlp[10];
+
+    memset(&jlp, 0, sizeof(jlp));
+    memset(&fjlp, 0, sizeof(fjlp));
+
+    strcpy(jlp[1].feedid, "my feedid");
+    log_debug("before save file:%s", jlp[1].feedid);
+
+
+    char  *file = "joylink_info.txt";
+    FILE *outfile, *infile;
+
+    outfile = fopen(file, "wb" );
+
+    fwrite(jlp, sizeof(jlp), 1, outfile );
+    fclose(outfile);
+
+    infile = fopen(file, "rb");
+    int i;
+    for(i = 0; i< 10; i++){
+        fread(&fjlp[i], sizeof(JLPInfo_t), 1, infile);
+    }
+    fclose(infile);
+
+    log_debug("after save file:%s", fjlp[1].feedid);
+}
+
+
+/* Create a bunch of objects as demonstration. */
+int main(int argc , char **argv)
+{
+    if(argc < 2){
+        log_error("USAG:%s server/client", argv[0]);
+        exit(-1);
+    }
+
+    if(!strcmp("server", argv[1])){
+        test_adevs_init();
+        joylink_agent_gw_thread_start();
+        while(1){
+            sleep(1);
+        }
+    }
+
+    if(!strcmp("client", argv[1])){
+        test_send();
+    }
+
+    if(!strcmp("test", argv[1])){
+        /*test_adevs();*/
+        /*log_debug("sssssssss:%d", sizeof(JLAuthRsp_t));*/
+        /*test_adevs_init();*/
+        /*test_add_agent_dev();*/
+        test_file_save();
+    }
+
+    return 0;
+}

+ 46 - 0
joylink/auth/Makefile

@@ -0,0 +1,46 @@
+include ../Makefile.rule
+
+HEADERS = $(wildcard *.h)
+ORG_SOURCES = $(wildcard *.c)
+OUT_SRC = test.c
+
+SOURCES=$(filter-out ${OUT_SRC}, ${ORG_SOURCES})
+OBJS = $(patsubst %.c, %.o, $(SOURCES))
+
+LIBNAME = $(strip ${shell pwd |xargs basename})
+
+INCLUDES += -I${PROJECT_ROOT_PATH}/json 
+INCLUDES += -I${PROJECT_ROOT_PATH}/example
+INCLUDES += -I${PROJECT_ROOT_PATH}/joylink
+
+STATIC_LIBS +=
+LIBS += 
+
+ifeq (${ARCH}, x86)  
+all:${OBJS} liba libso
+else
+all:${OBJS} liba 
+endif
+
+.SUFFIXES: .c .o
+.c.o:
+	${CC} ${CFLAGS} -c $(INCLUDES) ${STATIC_LIBS} $(LIBS) $*.c
+
+liba:${OBJS}
+	${AR} -crs lib${LIBNAME}.a ${OBJS}
+	${MV} lib${LIBNAME}.a ${TARGET_LIB}
+
+libso:${OBJS}
+	${CC}  ${OBJS} -shared -fPIC -o lib${LIBNAME}.so
+	${MV} lib${LIBNAME}.so ${TARGET_LIB} 
+
+test:
+	${CC} -DLIB_TEST test.c ${OBJS} -o $@ ${CFLAGS} ${INCLUDES} ${STATIC_LIBS} ${LIBS} 
+
+clean:
+	${RM} *.o *.so *.a test
+
+distclean:clean
+	${RM} ./*.a ./*.so ${TARGET_LIB}/lib${LIBNAME}.*
+
+.PHONY:all clean test

+ 1548 - 0
joylink/auth/joylink3_auth_uECC.c

@@ -0,0 +1,1548 @@
+/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
+
+#include "joylink3_auth_uECC.h"
+#include "joylink3_auth_uECC_vli.h"
+
+#ifndef uECC_RNG_MAX_TRIES
+    #define uECC_RNG_MAX_TRIES 64
+#endif
+
+#if uECC_ENABLE_VLI_API
+    #define uECC_VLI_API
+#else
+    #define uECC_VLI_API static
+#endif
+
+#define CONCATX(a, ...) a ## __VA_ARGS__
+#define CONCAT(a, ...) CONCATX(a, __VA_ARGS__)
+
+#define STRX(a) #a
+#define STR(a) STRX(a)
+
+#define EVAL(...)  EVAL1(EVAL1(EVAL1(EVAL1(__VA_ARGS__))))
+#define EVAL1(...) EVAL2(EVAL2(EVAL2(EVAL2(__VA_ARGS__))))
+#define EVAL2(...) EVAL3(EVAL3(EVAL3(EVAL3(__VA_ARGS__))))
+#define EVAL3(...) EVAL4(EVAL4(EVAL4(EVAL4(__VA_ARGS__))))
+#define EVAL4(...) __VA_ARGS__
+
+#define DEC_1  0
+#define DEC_2  1
+#define DEC_3  2
+#define DEC_4  3
+#define DEC_5  4
+#define DEC_6  5
+#define DEC_7  6
+#define DEC_8  7
+#define DEC_9  8
+#define DEC_10 9
+#define DEC_11 10
+#define DEC_12 11
+#define DEC_13 12
+#define DEC_14 13
+#define DEC_15 14
+#define DEC_16 15
+#define DEC_17 16
+#define DEC_18 17
+#define DEC_19 18
+#define DEC_20 19
+#define DEC_21 20
+#define DEC_22 21
+#define DEC_23 22
+#define DEC_24 23
+#define DEC_25 24
+#define DEC_26 25
+#define DEC_27 26
+#define DEC_28 27
+#define DEC_29 28
+#define DEC_30 29
+#define DEC_31 30
+#define DEC_32 31
+
+#define DEC(N) CONCAT(DEC_, N)
+
+#define SECOND_ARG(_, val, ...) val
+#define SOME_CHECK_0 ~, 0
+#define GET_SECOND_ARG(...) SECOND_ARG(__VA_ARGS__, SOME,)
+#define SOME_OR_0(N) GET_SECOND_ARG(CONCAT(SOME_CHECK_, N))
+
+#define EMPTY(...)
+#define DEFER(...) __VA_ARGS__ EMPTY()
+
+#define REPEAT_NAME_0() REPEAT_0
+#define REPEAT_NAME_SOME() REPEAT_SOME
+#define REPEAT_0(...)
+#define REPEAT_SOME(N, stuff) DEFER(CONCAT(REPEAT_NAME_, SOME_OR_0(DEC(N))))()(DEC(N), stuff) stuff
+#define REPEAT(N, stuff) EVAL(REPEAT_SOME(N, stuff))
+
+#define REPEATM_NAME_0() REPEATM_0
+#define REPEATM_NAME_SOME() REPEATM_SOME
+#define REPEATM_0(...)
+#define REPEATM_SOME(N, macro) macro(N) \
+    DEFER(CONCAT(REPEATM_NAME_, SOME_OR_0(DEC(N))))()(DEC(N), macro)
+#define REPEATM(N, macro) EVAL(REPEATM_SOME(N, macro))
+
+#include "joylink3_auth_uECC_platform-specific.inc"
+
+#if (uECC_WORD_SIZE == 1)
+    #if uECC_SUPPORTS_secp160r1
+        #define uECC_MAX_WORDS 21 /* Due to the size of curve_n. */
+    #endif
+    #if uECC_SUPPORTS_secp192r1
+        #undef uECC_MAX_WORDS
+        #define uECC_MAX_WORDS 24
+    #endif
+    #if uECC_SUPPORTS_secp224r1
+        #undef uECC_MAX_WORDS
+        #define uECC_MAX_WORDS 28
+    #endif
+    #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)
+        #undef uECC_MAX_WORDS
+        #define uECC_MAX_WORDS 32
+    #endif
+#elif (uECC_WORD_SIZE == 4)
+    #if uECC_SUPPORTS_secp160r1
+        #define uECC_MAX_WORDS 6 /* Due to the size of curve_n. */
+    #endif
+    #if uECC_SUPPORTS_secp192r1
+        #undef uECC_MAX_WORDS
+        #define uECC_MAX_WORDS 6
+    #endif
+    #if uECC_SUPPORTS_secp224r1
+        #undef uECC_MAX_WORDS
+        #define uECC_MAX_WORDS 7
+    #endif
+    #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)
+        #undef uECC_MAX_WORDS
+        #define uECC_MAX_WORDS 8
+    #endif
+#elif (uECC_WORD_SIZE == 8)
+    #if uECC_SUPPORTS_secp160r1
+        #define uECC_MAX_WORDS 3
+    #endif
+    #if uECC_SUPPORTS_secp192r1
+        #undef uECC_MAX_WORDS
+        #define uECC_MAX_WORDS 3
+    #endif
+    #if uECC_SUPPORTS_secp224r1
+        #undef uECC_MAX_WORDS
+        #define uECC_MAX_WORDS 4
+    #endif
+    #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)
+        #undef uECC_MAX_WORDS
+        #define uECC_MAX_WORDS 4
+    #endif
+#endif /* uECC_WORD_SIZE */
+
+#define BITS_TO_WORDS(num_bits) ((num_bits + ((uECC_WORD_SIZE * 8) - 1)) / (uECC_WORD_SIZE * 8))
+#define BITS_TO_BYTES(num_bits) ((num_bits + 7) / 8)
+
+struct uECC_Curve_t {
+    wordcount_t num_words;
+    wordcount_t num_bytes;
+    bitcount_t num_n_bits;
+    uECC_word_t p[uECC_MAX_WORDS];
+    uECC_word_t n[uECC_MAX_WORDS];
+    uECC_word_t G[uECC_MAX_WORDS * 2];
+    uECC_word_t b[uECC_MAX_WORDS];
+    void (*double_jacobian)(uECC_word_t * X1,
+                            uECC_word_t * Y1,
+                            uECC_word_t * Z1,
+                            uECC_Curve curve);
+#if uECC_SUPPORT_COMPRESSED_POINT
+    void (*mod_sqrt)(uECC_word_t *a, uECC_Curve curve);
+#endif
+    void (*x_side)(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve);
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+    void (*mmod_fast)(uECC_word_t *result, uECC_word_t *product);
+#endif
+};
+
+static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
+                                       const uECC_word_t *right,
+                                       wordcount_t num_words);
+
+#if (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \
+        uECC_PLATFORM == jl3_uECC_arm_thumb2)
+    #include "asm_arm.inc"
+#endif
+
+#if (uECC_PLATFORM == jl3_uECC_avr)
+    #include "asm_avr.inc"
+#endif
+
+#if default_RNG_defined
+static uECC_RNG_Function g_rng_function = &default_RNG;
+#else
+static uECC_RNG_Function g_rng_function = 0;
+#endif
+
+void jl3_uECC_set_rng(uECC_RNG_Function rng_function) {
+    g_rng_function = rng_function;
+}
+
+uECC_RNG_Function jl3_uECC_get_rng(void) {
+    return g_rng_function;
+}
+
+#if !asm_clear
+uECC_VLI_API void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words) {
+    wordcount_t i;
+    for (i = 0; i < num_words; ++i) {
+        vli[i] = 0;
+    }
+}
+#endif /* !asm_clear */
+
+/* Constant-time comparison to zero - secure way to compare long integers */
+/* Returns 1 if vli == 0, 0 otherwise. */
+uECC_VLI_API uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words) {
+    uECC_word_t bits = 0;
+    wordcount_t i;
+    for (i = 0; i < num_words; ++i) {
+        bits |= vli[i];
+    }
+    return (bits == 0);
+}
+
+/* Returns nonzero if bit 'bit' of vli is set. */
+uECC_VLI_API uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit) {
+    return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));
+}
+
+/* Counts the number of words in vli. */
+static wordcount_t vli_numDigits(const uECC_word_t *vli, const wordcount_t max_words) {
+    wordcount_t i;
+    /* Search from the end until we find a non-zero digit.
+       We do it in reverse because we expect that most digits will be nonzero. */
+    for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) {
+    }
+
+    return (i + 1);
+}
+
+/* Counts the number of bits required to represent vli. */
+uECC_VLI_API bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words) {
+    uECC_word_t i;
+    uECC_word_t digit;
+
+    wordcount_t num_digits = vli_numDigits(vli, max_words);
+    if (num_digits == 0) {
+        return 0;
+    }
+
+    digit = vli[num_digits - 1];
+    for (i = 0; digit; ++i) {
+        digit >>= 1;
+    }
+
+    return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);
+}
+
+/* Sets dest = src. */
+#if !asm_set
+uECC_VLI_API void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words) {
+    wordcount_t i;
+    for (i = 0; i < num_words; ++i) {
+        dest[i] = src[i];
+    }
+}
+#endif /* !asm_set */
+
+/* Returns sign of left - right. */
+static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
+                                       const uECC_word_t *right,
+                                       wordcount_t num_words) {
+    wordcount_t i;
+    for (i = num_words - 1; i >= 0; --i) {
+        if (left[i] > right[i]) {
+            return 1;
+        } else if (left[i] < right[i]) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/* Constant-time comparison function - secure way to compare long integers */
+/* Returns one if left == right, zero otherwise. */
+uECC_VLI_API uECC_word_t uECC_vli_equal(const uECC_word_t *left,
+                                        const uECC_word_t *right,
+                                        wordcount_t num_words) {
+    uECC_word_t diff = 0;
+    wordcount_t i;
+    for (i = num_words - 1; i >= 0; --i) {
+        diff |= (left[i] ^ right[i]);
+    }
+    return (diff == 0);
+}
+
+uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result,
+                                      const uECC_word_t *left,
+                                      const uECC_word_t *right,
+                                      wordcount_t num_words);
+
+/* Returns sign of left - right, in constant time. */
+uECC_VLI_API cmpresult_t uECC_vli_cmp(const uECC_word_t *left,
+                                      const uECC_word_t *right,
+                                      wordcount_t num_words) {
+    uECC_word_t tmp[uECC_MAX_WORDS];
+    uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words);
+    uECC_word_t equal = uECC_vli_isZero(tmp, num_words);
+    return (!equal - 2 * neg);
+}
+
+/* Computes vli = vli >> 1. */
+#if !asm_rshift1
+uECC_VLI_API void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words) {
+    uECC_word_t *end = vli;
+    uECC_word_t carry = 0;
+
+    vli += num_words;
+    while (vli-- > end) {
+        uECC_word_t temp = *vli;
+        *vli = (temp >> 1) | carry;
+        carry = temp << (uECC_WORD_BITS - 1);
+    }
+}
+#endif /* !asm_rshift1 */
+
+/* Computes result = left + right, returning carry. Can modify in place. */
+#if !asm_add
+uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result,
+                                      const uECC_word_t *left,
+                                      const uECC_word_t *right,
+                                      wordcount_t num_words) {
+    uECC_word_t carry = 0;
+    wordcount_t i;
+    for (i = 0; i < num_words; ++i) {
+        uECC_word_t sum = left[i] + right[i] + carry;
+        if (sum != left[i]) {
+            carry = (sum < left[i]);
+        }
+        result[i] = sum;
+    }
+    return carry;
+}
+#endif /* !asm_add */
+
+/* Computes result = left - right, returning borrow. Can modify in place. */
+#if !asm_sub
+uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result,
+                                      const uECC_word_t *left,
+                                      const uECC_word_t *right,
+                                      wordcount_t num_words) {
+    uECC_word_t borrow = 0;
+    wordcount_t i;
+    for (i = 0; i < num_words; ++i) {
+        uECC_word_t diff = left[i] - right[i] - borrow;
+        if (diff != left[i]) {
+            borrow = (diff > left[i]);
+        }
+        result[i] = diff;
+    }
+    return borrow;
+}
+#endif /* !asm_sub */
+
+#if !asm_mult || (uECC_SQUARE_FUNC && !asm_square) || \
+    (uECC_SUPPORTS_secp256k1 && (uECC_OPTIMIZATION_LEVEL > 0) && \
+        ((uECC_WORD_SIZE == 1) || (uECC_WORD_SIZE == 8)))
+static void muladd(uECC_word_t a,
+                   uECC_word_t b,
+                   uECC_word_t *r0,
+                   uECC_word_t *r1,
+                   uECC_word_t *r2) {
+#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128
+    uint64_t a0 = a & 0xffffffffull;
+    uint64_t a1 = a >> 32;
+    uint64_t b0 = b & 0xffffffffull;
+    uint64_t b1 = b >> 32;
+
+    uint64_t i0 = a0 * b0;
+    uint64_t i1 = a0 * b1;
+    uint64_t i2 = a1 * b0;
+    uint64_t i3 = a1 * b1;
+
+    uint64_t p0, p1;
+
+    i2 += (i0 >> 32);
+    i2 += i1;
+    if (i2 < i1) { /* overflow */
+        i3 += 0x100000000ull;
+    }
+
+    p0 = (i0 & 0xffffffffull) | (i2 << 32);
+    p1 = i3 + (i2 >> 32);
+
+    *r0 += p0;
+    *r1 += (p1 + (*r0 < p0));
+    *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0));
+#else
+    uECC_dword_t p = (uECC_dword_t)a * b;
+    uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
+    r01 += p;
+    *r2 += (r01 < p);
+    *r1 = r01 >> uECC_WORD_BITS;
+    *r0 = (uECC_word_t)r01;
+#endif
+}
+#endif /* muladd needed */
+
+#if !asm_mult
+uECC_VLI_API void uECC_vli_mult(uECC_word_t *result,
+                                const uECC_word_t *left,
+                                const uECC_word_t *right,
+                                wordcount_t num_words) {
+    uECC_word_t r0 = 0;
+    uECC_word_t r1 = 0;
+    uECC_word_t r2 = 0;
+    wordcount_t i, k;
+
+    /* Compute each digit of result in sequence, maintaining the carries. */
+    for (k = 0; k < num_words; ++k) {
+        for (i = 0; i <= k; ++i) {
+            muladd(left[i], right[k - i], &r0, &r1, &r2);
+        }
+        result[k] = r0;
+        r0 = r1;
+        r1 = r2;
+        r2 = 0;
+    }
+    for (k = num_words; k < num_words * 2 - 1; ++k) {
+        for (i = (k + 1) - num_words; i < num_words; ++i) {
+            muladd(left[i], right[k - i], &r0, &r1, &r2);
+        }
+        result[k] = r0;
+        r0 = r1;
+        r1 = r2;
+        r2 = 0;
+    }
+    result[num_words * 2 - 1] = r0;
+}
+#endif /* !asm_mult */
+
+#if uECC_SQUARE_FUNC
+
+#if !asm_square
+static void mul2add(uECC_word_t a,
+                    uECC_word_t b,
+                    uECC_word_t *r0,
+                    uECC_word_t *r1,
+                    uECC_word_t *r2) {
+#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128
+    uint64_t a0 = a & 0xffffffffull;
+    uint64_t a1 = a >> 32;
+    uint64_t b0 = b & 0xffffffffull;
+    uint64_t b1 = b >> 32;
+
+    uint64_t i0 = a0 * b0;
+    uint64_t i1 = a0 * b1;
+    uint64_t i2 = a1 * b0;
+    uint64_t i3 = a1 * b1;
+
+    uint64_t p0, p1;
+
+    i2 += (i0 >> 32);
+    i2 += i1;
+    if (i2 < i1)
+    { /* overflow */
+        i3 += 0x100000000ull;
+    }
+
+    p0 = (i0 & 0xffffffffull) | (i2 << 32);
+    p1 = i3 + (i2 >> 32);
+
+    *r2 += (p1 >> 63);
+    p1 = (p1 << 1) | (p0 >> 63);
+    p0 <<= 1;
+
+    *r0 += p0;
+    *r1 += (p1 + (*r0 < p0));
+    *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0));
+#else
+    uECC_dword_t p = (uECC_dword_t)a * b;
+    uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
+    *r2 += (p >> (uECC_WORD_BITS * 2 - 1));
+    p *= 2;
+    r01 += p;
+    *r2 += (r01 < p);
+    *r1 = r01 >> uECC_WORD_BITS;
+    *r0 = (uECC_word_t)r01;
+#endif
+}
+
+uECC_VLI_API void uECC_vli_square(uECC_word_t *result,
+                                  const uECC_word_t *left,
+                                  wordcount_t num_words) {
+    uECC_word_t r0 = 0;
+    uECC_word_t r1 = 0;
+    uECC_word_t r2 = 0;
+
+    wordcount_t i, k;
+
+    for (k = 0; k < num_words * 2 - 1; ++k) {
+        uECC_word_t min = (k < num_words ? 0 : (k + 1) - num_words);
+        for (i = min; i <= k && i <= k - i; ++i) {
+            if (i < k-i) {
+                mul2add(left[i], left[k - i], &r0, &r1, &r2);
+            } else {
+                muladd(left[i], left[k - i], &r0, &r1, &r2);
+            }
+        }
+        result[k] = r0;
+        r0 = r1;
+        r1 = r2;
+        r2 = 0;
+    }
+
+    result[num_words * 2 - 1] = r0;
+}
+#endif /* !asm_square */
+
+#else /* uECC_SQUARE_FUNC */
+
+#if uECC_ENABLE_VLI_API
+uECC_VLI_API void uECC_vli_square(uECC_word_t *result,
+                                  const uECC_word_t *left,
+                                  wordcount_t num_words) {
+    uECC_vli_mult(result, left, left, num_words);
+}
+#endif /* uECC_ENABLE_VLI_API */
+
+#endif /* uECC_SQUARE_FUNC */
+
+/* Computes result = (left + right) % mod.
+   Assumes that left < mod and right < mod, and that result does not overlap mod. */
+uECC_VLI_API void uECC_vli_modAdd(uECC_word_t *result,
+                                  const uECC_word_t *left,
+                                  const uECC_word_t *right,
+                                  const uECC_word_t *mod,
+                                  wordcount_t num_words) {
+    uECC_word_t carry = uECC_vli_add(result, left, right, num_words);
+    if (carry || uECC_vli_cmp_unsafe(mod, result, num_words) != 1) {
+        /* result > mod (result = mod + remainder), so subtract mod to get remainder. */
+        uECC_vli_sub(result, result, mod, num_words);
+    }
+}
+
+/* Computes result = (left - right) % mod.
+   Assumes that left < mod and right < mod, and that result does not overlap mod. */
+uECC_VLI_API void uECC_vli_modSub(uECC_word_t *result,
+                                  const uECC_word_t *left,
+                                  const uECC_word_t *right,
+                                  const uECC_word_t *mod,
+                                  wordcount_t num_words) {
+    uECC_word_t l_borrow = uECC_vli_sub(result, left, right, num_words);
+    if (l_borrow) {
+        /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,
+           we can get the correct result from result + mod (with overflow). */
+        uECC_vli_add(result, result, mod, num_words);
+    }
+}
+
+/* Computes result = product % mod, where product is 2N words long. */
+/* Currently only designed to work for curve_p or curve_n. */
+uECC_VLI_API void uECC_vli_mmod(uECC_word_t *result,
+                                uECC_word_t *product,
+                                const uECC_word_t *mod,
+                                wordcount_t num_words) {
+    uECC_word_t mod_multiple[2 * uECC_MAX_WORDS];
+    uECC_word_t tmp[2 * uECC_MAX_WORDS];
+    uECC_word_t *v[2] = {tmp, product};
+    uECC_word_t index;
+
+    /* Shift mod so its highest set bit is at the maximum position. */
+    bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) - uECC_vli_numBits(mod, num_words);
+    wordcount_t word_shift = shift / uECC_WORD_BITS;
+    wordcount_t bit_shift = shift % uECC_WORD_BITS;
+    uECC_word_t carry = 0;
+    uECC_vli_clear(mod_multiple, word_shift);
+    if (bit_shift > 0) {
+        for(index = 0; index < (uECC_word_t)num_words; ++index) {
+            mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry;
+            carry = mod[index] >> (uECC_WORD_BITS - bit_shift);
+        }
+    } else {
+        uECC_vli_set(mod_multiple + word_shift, mod, num_words);
+    }
+
+    for (index = 1; shift >= 0; --shift) {
+        uECC_word_t borrow = 0;
+        wordcount_t i;
+        for (i = 0; i < num_words * 2; ++i) {
+            uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow;
+            if (diff != v[index][i]) {
+                borrow = (diff > v[index][i]);
+            }
+            v[1 - index][i] = diff;
+        }
+        index = !(index ^ borrow); /* Swap the index if there was no borrow */
+        uECC_vli_rshift1(mod_multiple, num_words);
+        mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1);
+        uECC_vli_rshift1(mod_multiple + num_words, num_words);
+    }
+    uECC_vli_set(result, v[index], num_words);
+}
+
+/* Computes result = (left * right) % mod. */
+uECC_VLI_API void uECC_vli_modMult(uECC_word_t *result,
+                                   const uECC_word_t *left,
+                                   const uECC_word_t *right,
+                                   const uECC_word_t *mod,
+                                   wordcount_t num_words) {
+    uECC_word_t product[2 * uECC_MAX_WORDS];
+    uECC_vli_mult(product, left, right, num_words);
+    uECC_vli_mmod(result, product, mod, num_words);
+}
+
+uECC_VLI_API void uECC_vli_modMult_fast(uECC_word_t *result,
+                                        const uECC_word_t *left,
+                                        const uECC_word_t *right,
+                                        uECC_Curve curve) {
+    uECC_word_t product[2 * uECC_MAX_WORDS];
+    uECC_vli_mult(product, left, right, curve->num_words);
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+    curve->mmod_fast(result, product);
+#else
+    uECC_vli_mmod(result, product, curve->p, curve->num_words);
+#endif
+}
+
+#if uECC_SQUARE_FUNC
+
+#if uECC_ENABLE_VLI_API
+/* Computes result = left^2 % mod. */
+uECC_VLI_API void uECC_vli_modSquare(uECC_word_t *result,
+                                     const uECC_word_t *left,
+                                     const uECC_word_t *mod,
+                                     wordcount_t num_words) {
+    uECC_word_t product[2 * uECC_MAX_WORDS];
+    uECC_vli_square(product, left, num_words);
+    uECC_vli_mmod(result, product, mod, num_words);
+}
+#endif /* uECC_ENABLE_VLI_API */
+
+uECC_VLI_API void uECC_vli_modSquare_fast(uECC_word_t *result,
+                                          const uECC_word_t *left,
+                                          uECC_Curve curve) {
+    uECC_word_t product[2 * uECC_MAX_WORDS];
+    uECC_vli_square(product, left, curve->num_words);
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+    curve->mmod_fast(result, product);
+#else
+    uECC_vli_mmod(result, product, curve->p, curve->num_words);
+#endif
+}
+
+#else /* uECC_SQUARE_FUNC */
+
+#if uECC_ENABLE_VLI_API
+uECC_VLI_API void uECC_vli_modSquare(uECC_word_t *result,
+                                     const uECC_word_t *left,
+                                     const uECC_word_t *mod,
+                                     wordcount_t num_words) {
+    uECC_vli_modMult(result, left, left, mod, num_words);
+}
+#endif /* uECC_ENABLE_VLI_API */
+
+uECC_VLI_API void uECC_vli_modSquare_fast(uECC_word_t *result,
+                                          const uECC_word_t *left,
+                                          uECC_Curve curve) {
+    uECC_vli_modMult_fast(result, left, left, curve);
+}
+
+#endif /* uECC_SQUARE_FUNC */
+
+#define EVEN(vli) (!(vli[0] & 1))
+static void vli_modInv_update(uECC_word_t *uv,
+                              const uECC_word_t *mod,
+                              wordcount_t num_words) {
+    uECC_word_t carry = 0;
+    if (!EVEN(uv)) {
+        carry = uECC_vli_add(uv, uv, mod, num_words);
+    }
+    uECC_vli_rshift1(uv, num_words);
+    if (carry) {
+        uv[num_words - 1] |= HIGH_BIT_SET;
+    }
+}
+
+/* Computes result = (1 / input) % mod. All VLIs are the same size.
+   See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" */
+uECC_VLI_API void uECC_vli_modInv(uECC_word_t *result,
+                                  const uECC_word_t *input,
+                                  const uECC_word_t *mod,
+                                  wordcount_t num_words) {
+    uECC_word_t a[uECC_MAX_WORDS], b[uECC_MAX_WORDS], u[uECC_MAX_WORDS], v[uECC_MAX_WORDS];
+    cmpresult_t cmpResult;
+
+    if (uECC_vli_isZero(input, num_words)) {
+        uECC_vli_clear(result, num_words);
+        return;
+    }
+
+    uECC_vli_set(a, input, num_words);
+    uECC_vli_set(b, mod, num_words);
+    uECC_vli_clear(u, num_words);
+    u[0] = 1;
+    uECC_vli_clear(v, num_words);
+    while ((cmpResult = uECC_vli_cmp_unsafe(a, b, num_words)) != 0) {
+        if (EVEN(a)) {
+            uECC_vli_rshift1(a, num_words);
+            vli_modInv_update(u, mod, num_words);
+        } else if (EVEN(b)) {
+            uECC_vli_rshift1(b, num_words);
+            vli_modInv_update(v, mod, num_words);
+        } else if (cmpResult > 0) {
+            uECC_vli_sub(a, a, b, num_words);
+            uECC_vli_rshift1(a, num_words);
+            if (uECC_vli_cmp_unsafe(u, v, num_words) < 0) {
+                uECC_vli_add(u, u, mod, num_words);
+            }
+            uECC_vli_sub(u, u, v, num_words);
+            vli_modInv_update(u, mod, num_words);
+        } else {
+            uECC_vli_sub(b, b, a, num_words);
+            uECC_vli_rshift1(b, num_words);
+            if (uECC_vli_cmp_unsafe(v, u, num_words) < 0) {
+                uECC_vli_add(v, v, mod, num_words);
+            }
+            uECC_vli_sub(v, v, u, num_words);
+            vli_modInv_update(v, mod, num_words);
+        }
+    }
+    uECC_vli_set(result, u, num_words);
+}
+
+/* ------ Point operations ------ */
+
+#include "joylink3_auth_uECC_curve-specific.inc"
+
+/* Returns 1 if 'point' is the point at infinity, 0 otherwise. */
+#define EccPoint_isZero(point, curve) uECC_vli_isZero((point), (curve)->num_words * 2)
+
+/* Point multiplication algorithm using Montgomery's ladder with co-Z coordinates.
+From http://eprint.iacr.org/2011/338.pdf
+*/
+
+/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */
+static void apply_z(uECC_word_t * X1,
+                    uECC_word_t * Y1,
+                    const uECC_word_t * const Z,
+                    uECC_Curve curve) {
+    uECC_word_t t1[uECC_MAX_WORDS];
+
+    uECC_vli_modSquare_fast(t1, Z, curve);    /* z^2 */
+    uECC_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */
+    uECC_vli_modMult_fast(t1, t1, Z, curve);  /* z^3 */
+    uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */
+}
+
+/* P = (x1, y1) => 2P, (x2, y2) => P' */
+static void XYcZ_initial_double(uECC_word_t * X1,
+                                uECC_word_t * Y1,
+                                uECC_word_t * X2,
+                                uECC_word_t * Y2,
+                                const uECC_word_t * const initial_Z,
+                                uECC_Curve curve) {
+    uECC_word_t z[uECC_MAX_WORDS];
+    wordcount_t num_words = curve->num_words;
+    if (initial_Z) {
+        uECC_vli_set(z, initial_Z, num_words);
+    } else {
+        uECC_vli_clear(z, num_words);
+        z[0] = 1;
+    }
+
+    uECC_vli_set(X2, X1, num_words);
+    uECC_vli_set(Y2, Y1, num_words);
+
+    apply_z(X1, Y1, z, curve);
+    curve->double_jacobian(X1, Y1, z, curve);
+    apply_z(X2, Y2, z, curve);
+}
+
+/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
+   Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3)
+   or P => P', Q => P + Q
+*/
+static void XYcZ_add(uECC_word_t * X1,
+                     uECC_word_t * Y1,
+                     uECC_word_t * X2,
+                     uECC_word_t * Y2,
+                     uECC_Curve curve) {
+    /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
+    uECC_word_t t5[uECC_MAX_WORDS];
+    wordcount_t num_words = curve->num_words;
+
+    uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */
+    uECC_vli_modSquare_fast(t5, t5, curve);                  /* t5 = (x2 - x1)^2 = A */
+    uECC_vli_modMult_fast(X1, X1, t5, curve);                /* t1 = x1*A = B */
+    uECC_vli_modMult_fast(X2, X2, t5, curve);                /* t3 = x2*A = C */
+    uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */
+    uECC_vli_modSquare_fast(t5, Y2, curve);                  /* t5 = (y2 - y1)^2 = D */
+
+    uECC_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */
+    uECC_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */
+    uECC_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */
+    uECC_vli_modMult_fast(Y1, Y1, X2, curve);                /* t2 = y1*(C - B) */
+    uECC_vli_modSub(X2, X1, t5, curve->p, num_words); /* t3 = B - x3 */
+    uECC_vli_modMult_fast(Y2, Y2, X2, curve);                /* t4 = (y2 - y1)*(B - x3) */
+    uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */
+
+    uECC_vli_set(X2, t5, num_words);
+}
+
+/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
+   Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
+   or P => P - Q, Q => P + Q
+*/
+static void XYcZ_addC(uECC_word_t * X1,
+                      uECC_word_t * Y1,
+                      uECC_word_t * X2,
+                      uECC_word_t * Y2,
+                      uECC_Curve curve) {
+    /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
+    uECC_word_t t5[uECC_MAX_WORDS];
+    uECC_word_t t6[uECC_MAX_WORDS];
+    uECC_word_t t7[uECC_MAX_WORDS];
+    wordcount_t num_words = curve->num_words;
+
+    uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */
+    uECC_vli_modSquare_fast(t5, t5, curve);                  /* t5 = (x2 - x1)^2 = A */
+    uECC_vli_modMult_fast(X1, X1, t5, curve);                /* t1 = x1*A = B */
+    uECC_vli_modMult_fast(X2, X2, t5, curve);                /* t3 = x2*A = C */
+    uECC_vli_modAdd(t5, Y2, Y1, curve->p, num_words); /* t5 = y2 + y1 */
+    uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */
+
+    uECC_vli_modSub(t6, X2, X1, curve->p, num_words); /* t6 = C - B */
+    uECC_vli_modMult_fast(Y1, Y1, t6, curve);                /* t2 = y1 * (C - B) = E */
+    uECC_vli_modAdd(t6, X1, X2, curve->p, num_words); /* t6 = B + C */
+    uECC_vli_modSquare_fast(X2, Y2, curve);                  /* t3 = (y2 - y1)^2 = D */
+    uECC_vli_modSub(X2, X2, t6, curve->p, num_words); /* t3 = D - (B + C) = x3 */
+
+    uECC_vli_modSub(t7, X1, X2, curve->p, num_words); /* t7 = B - x3 */
+    uECC_vli_modMult_fast(Y2, Y2, t7, curve);                /* t4 = (y2 - y1)*(B - x3) */
+    uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = (y2 - y1)*(B - x3) - E = y3 */
+
+    uECC_vli_modSquare_fast(t7, t5, curve);                  /* t7 = (y2 + y1)^2 = F */
+    uECC_vli_modSub(t7, t7, t6, curve->p, num_words); /* t7 = F - (B + C) = x3' */
+    uECC_vli_modSub(t6, t7, X1, curve->p, num_words); /* t6 = x3' - B */
+    uECC_vli_modMult_fast(t6, t6, t5, curve);                /* t6 = (y2+y1)*(x3' - B) */
+    uECC_vli_modSub(Y1, t6, Y1, curve->p, num_words); /* t2 = (y2+y1)*(x3' - B) - E = y3' */
+
+    uECC_vli_set(X1, t7, num_words);
+}
+
+/* result may overlap point. */
+static void EccPoint_mult(uECC_word_t * result,
+                          const uECC_word_t * point,
+                          const uECC_word_t * scalar,
+                          const uECC_word_t * initial_Z,
+                          bitcount_t num_bits,
+                          uECC_Curve curve) {
+    /* R0 and R1 */
+    uECC_word_t Rx[2][uECC_MAX_WORDS];
+    uECC_word_t Ry[2][uECC_MAX_WORDS];
+    uECC_word_t z[uECC_MAX_WORDS];
+    bitcount_t i;
+    uECC_word_t nb;
+    wordcount_t num_words = curve->num_words;
+
+    uECC_vli_set(Rx[1], point, num_words);
+    uECC_vli_set(Ry[1], point + num_words, num_words);
+
+    XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z, curve);
+
+    for (i = num_bits - 2; i > 0; --i) {
+        nb = !uECC_vli_testBit(scalar, i);
+        XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve);
+        XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve);
+    }
+
+    nb = !uECC_vli_testBit(scalar, 0);
+    XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve);
+
+    /* Find final 1/Z value. */
+    uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */
+    uECC_vli_modMult_fast(z, z, Ry[1 - nb], curve);               /* Yb * (X1 - X0) */
+    uECC_vli_modMult_fast(z, z, point, curve);                    /* xP * Yb * (X1 - X0) */
+    uECC_vli_modInv(z, z, curve->p, num_words);            /* 1 / (xP * Yb * (X1 - X0)) */
+    /* yP / (xP * Yb * (X1 - X0)) */
+    uECC_vli_modMult_fast(z, z, point + num_words, curve);
+    uECC_vli_modMult_fast(z, z, Rx[1 - nb], curve); /* Xb * yP / (xP * Yb * (X1 - X0)) */
+    /* End 1/Z calculation */
+
+    XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve);
+    apply_z(Rx[0], Ry[0], z, curve);
+
+    uECC_vli_set(result, Rx[0], num_words);
+    uECC_vli_set(result + num_words, Ry[0], num_words);
+}
+
+static uECC_word_t regularize_k(const uECC_word_t * const k,
+                                uECC_word_t *k0,
+                                uECC_word_t *k1,
+                                uECC_Curve curve) {
+    wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
+    bitcount_t num_n_bits = curve->num_n_bits;
+    uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) ||
+        (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) &&
+         uECC_vli_testBit(k0, num_n_bits));
+    uECC_vli_add(k1, k0, curve->n, num_n_words);
+    return carry;
+}
+
+static uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
+                                               uECC_word_t *private,
+                                               uECC_Curve curve) {
+    uECC_word_t tmp1[uECC_MAX_WORDS];
+    uECC_word_t tmp2[uECC_MAX_WORDS];
+    uECC_word_t *p2[2] = {tmp1, tmp2};
+    uECC_word_t carry;
+
+    /* Regularize the bitcount for the private key so that attackers cannot use a side channel
+       attack to learn the number of leading zeros. */
+    carry = regularize_k(private, tmp1, tmp2, curve);
+
+    EccPoint_mult(result, curve->G, p2[!carry], 0, curve->num_n_bits + 1, curve);
+
+    if (EccPoint_isZero(result, curve)) {
+        return 0;
+    }
+    return 1;
+}
+
+#if uECC_WORD_SIZE == 1
+
+uECC_VLI_API void uECC_vli_nativeToBytes(uint8_t *bytes,
+                                         int num_bytes,
+                                         const uint8_t *native) {
+    wordcount_t i;
+    for (i = 0; i < num_bytes; ++i) {
+        bytes[i] = native[(num_bytes - 1) - i];
+    }
+}
+
+uECC_VLI_API void uECC_vli_bytesToNative(uint8_t *native,
+                                         const uint8_t *bytes,
+                                         int num_bytes) {
+    uECC_vli_nativeToBytes(native, num_bytes, bytes);
+}
+
+#else
+
+uECC_VLI_API void uECC_vli_nativeToBytes(uint8_t *bytes,
+                                         int num_bytes,
+                                         const uECC_word_t *native) {
+    wordcount_t i;
+    for (i = 0; i < num_bytes; ++i) {
+        unsigned b = num_bytes - 1 - i;
+        bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE));
+    }
+}
+
+uECC_VLI_API void uECC_vli_bytesToNative(uECC_word_t *native,
+                                         const uint8_t *bytes,
+                                         int num_bytes) {
+    wordcount_t i;
+    uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE);
+    for (i = 0; i < num_bytes; ++i) {
+        unsigned b = num_bytes - 1 - i;
+        native[b / uECC_WORD_SIZE] |=
+            (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE));
+    }
+}
+
+#endif /* uECC_WORD_SIZE */
+
+/* Generates a random integer in the range 0 < random < top.
+   Both random and top have num_words words. */
+uECC_VLI_API int uECC_generate_random_int(uECC_word_t *random,
+                                          const uECC_word_t *top,
+                                          wordcount_t num_words) {
+    uECC_word_t mask = (uECC_word_t)-1;
+    uECC_word_t tries;
+    bitcount_t num_bits = uECC_vli_numBits(top, num_words);
+
+    if (!g_rng_function) {
+        return 0;
+    }
+
+    for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
+        if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) {
+            return 0;
+	    }
+        random[num_words - 1] &= mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits));
+        if (!uECC_vli_isZero(random, num_words) &&
+		        uECC_vli_cmp(top, random, num_words) == 1) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+int jl3_uECC_make_key(uint8_t *public_key,
+                  uint8_t *private_key,
+                  uECC_Curve curve) {
+    uECC_word_t private[uECC_MAX_WORDS];
+    uECC_word_t public[uECC_MAX_WORDS * 2];
+    uECC_word_t tries;
+
+    for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
+        if (!uECC_generate_random_int(private, curve->n, BITS_TO_WORDS(curve->num_n_bits))) {
+            return 0;
+        }
+
+        if (EccPoint_compute_public_key(public, private, curve)) {
+            uECC_vli_nativeToBytes(private_key, BITS_TO_BYTES(curve->num_n_bits), private);
+            uECC_vli_nativeToBytes(public_key, curve->num_bytes, public);
+            uECC_vli_nativeToBytes(
+                public_key + curve->num_bytes, curve->num_bytes, public + curve->num_words);
+            return 1;
+        }
+    }
+    return 0;
+}
+
+int jl3_uECC_shared_secret(const uint8_t *public_key,
+                       const uint8_t *private_key,
+                       uint8_t *secret,
+                       uECC_Curve curve) {
+    uECC_word_t public[uECC_MAX_WORDS * 2];
+    uECC_word_t private[uECC_MAX_WORDS];
+    uECC_word_t tmp[uECC_MAX_WORDS];
+    uECC_word_t *p2[2] = {private, tmp};
+    uECC_word_t *initial_Z = 0;
+    uECC_word_t carry;
+    wordcount_t num_words = curve->num_words;
+    wordcount_t num_bytes = curve->num_bytes;
+
+    uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits));
+    uECC_vli_bytesToNative(public, public_key, num_bytes);
+    uECC_vli_bytesToNative(public + num_words, public_key + num_bytes, num_bytes);
+
+    /* Regularize the bitcount for the private key so that attackers cannot use a side channel
+       attack to learn the number of leading zeros. */
+    carry = regularize_k(private, private, tmp, curve);
+
+    /* If an RNG function was specified, try to get a random initial Z value to improve
+       protection against side-channel attacks. */
+    if (g_rng_function) {
+        if (!uECC_generate_random_int(p2[carry], curve->p, num_words)) {
+            return 0;
+        }
+        initial_Z = p2[carry];
+    }
+
+    EccPoint_mult(public, public, p2[!carry], initial_Z, curve->num_n_bits + 1, curve);
+    uECC_vli_nativeToBytes(secret, num_bytes, public);
+    return !EccPoint_isZero(public, curve);
+}
+
+#if uECC_SUPPORT_COMPRESSED_POINT
+void jl3_uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve) {
+    wordcount_t i;
+    for (i = 0; i < curve->num_bytes; ++i) {
+        compressed[i+1] = public_key[i];
+    }
+    compressed[0] = 2 + (public_key[curve->num_bytes * 2 - 1] & 0x01);
+}
+
+void jl3_uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve) {
+    uECC_word_t point[uECC_MAX_WORDS * 2];
+    uECC_word_t *y = point + curve->num_words;
+    uECC_vli_bytesToNative(point, compressed + 1, curve->num_bytes);
+    curve->x_side(y, point, curve);
+    curve->mod_sqrt(y, curve);
+
+    if ((y[0] & 0x01) != (compressed[0] & 0x01)) {
+        uECC_vli_sub(y, curve->p, y, curve->num_words);
+    }
+
+    uECC_vli_nativeToBytes(public_key, curve->num_bytes, point);
+    uECC_vli_nativeToBytes(public_key + curve->num_bytes, curve->num_bytes, y);
+}
+#endif /* uECC_SUPPORT_COMPRESSED_POINT */
+
+int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) {
+    uECC_word_t tmp1[uECC_MAX_WORDS];
+    uECC_word_t tmp2[uECC_MAX_WORDS];
+    wordcount_t num_words = curve->num_words;
+
+    /* The point at infinity is invalid. */
+    if (EccPoint_isZero(point, curve)) {
+        return 0;
+    }
+
+    /* x and y must be smaller than p. */
+    if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 ||
+            uECC_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) {
+        return 0;
+    }
+
+    uECC_vli_modSquare_fast(tmp1, point + num_words, curve);
+    curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */
+
+    /* Make sure that y^2 == x^3 + ax + b */
+    return (int)(uECC_vli_equal(tmp1, tmp2, num_words));
+}
+
+int jl3_uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve) {
+    uECC_word_t public[uECC_MAX_WORDS * 2];
+
+    uECC_vli_bytesToNative(public, public_key, curve->num_bytes);
+    uECC_vli_bytesToNative(
+        public + curve->num_words, public_key + curve->num_bytes, curve->num_bytes);
+    return uECC_valid_point(public, curve);
+}
+
+int jl3_uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) {
+    uECC_word_t private[uECC_MAX_WORDS];
+    uECC_word_t public[uECC_MAX_WORDS * 2];
+
+    uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits));
+
+    /* Make sure the private key is in the range [1, n-1]. */
+    if (uECC_vli_isZero(private, BITS_TO_WORDS(curve->num_n_bits))) {
+        return 0;
+    }
+
+    if (uECC_vli_cmp(curve->n, private, BITS_TO_WORDS(curve->num_n_bits)) != 1) {
+        return 0;
+    }
+
+    /* Compute public key. */
+    if (!EccPoint_compute_public_key(public, private, curve)) {
+        return 0;
+    }
+
+    uECC_vli_nativeToBytes(public_key, curve->num_bytes, public);
+    uECC_vli_nativeToBytes(
+        public_key + curve->num_bytes, curve->num_bytes, public + curve->num_words);
+    return 1;
+}
+
+
+/* -------- ECDSA code -------- */
+
+static void bits2int(uECC_word_t *native,
+                     const uint8_t *bits,
+                     unsigned bits_size,
+                     uECC_Curve curve) {
+    unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits);
+    unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits);
+    if (bits_size > num_n_bytes) {
+        bits_size = num_n_bytes;
+    }
+    uECC_vli_clear(native, num_n_words);
+    uECC_vli_bytesToNative(native, bits, bits_size);
+    if (bits_size * 8 <= (unsigned)curve->num_n_bits) {
+        return;
+    }
+    int shift = bits_size * 8 - curve->num_n_bits;
+    uECC_word_t carry = 0;
+    uECC_word_t *ptr = native + num_n_words;
+    while (ptr-- > native) {
+        uECC_word_t temp = *ptr;
+        *ptr = (temp >> shift) | carry;
+        carry = temp << (uECC_WORD_BITS - shift);
+    }
+
+    /* Reduce mod curve_n */
+    if (uECC_vli_cmp_unsafe(curve->n, native, num_n_words) != 1) {
+        uECC_vli_sub(native, native, curve->n, num_n_words);
+    }
+}
+
+static int uECC_sign_with_k(const uint8_t *private_key,
+                            const uint8_t *message_hash,
+                            unsigned hash_size,
+                            uECC_word_t *k,
+                            uint8_t *signature,
+                            uECC_Curve curve) {
+    uECC_word_t tmp[uECC_MAX_WORDS];
+    uECC_word_t s[uECC_MAX_WORDS];
+    uECC_word_t *k2[2] = {tmp, s};
+    uECC_word_t p[uECC_MAX_WORDS * 2];
+    uECC_word_t carry;
+    wordcount_t num_words = curve->num_words;
+    wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
+    bitcount_t num_n_bits = curve->num_n_bits;
+
+    /* Make sure 0 < k < curve_n */
+    if (uECC_vli_isZero(k, num_words) || uECC_vli_cmp(curve->n, k, num_n_words) != 1) {
+        return 0;
+    }
+
+    carry = regularize_k(k, tmp, s, curve);
+    EccPoint_mult(p, curve->G, k2[!carry], 0, num_n_bits + 1, curve);
+    if (uECC_vli_isZero(p, num_words)) {
+        return 0;
+    }
+
+    /* If an RNG function was specified, get a random number
+       to prevent side channel analysis of k. */
+    if (!g_rng_function) {
+        uECC_vli_clear(tmp, num_n_words);
+        tmp[0] = 1;
+    } else if (!uECC_generate_random_int(tmp, curve->n, num_n_words)) {
+        return 0;
+    }
+
+    /* Prevent side channel analysis of uECC_vli_modInv() to determine
+       bits of k / the private key by premultiplying by a random number */
+    uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */
+    uECC_vli_modInv(k, k, curve->n, num_n_words);       /* k = 1 / k' */
+    uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */
+
+    uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */
+
+    uECC_vli_bytesToNative(tmp, private_key, BITS_TO_BYTES(curve->num_n_bits)); /* tmp = d */
+    s[num_n_words - 1] = 0;
+    uECC_vli_set(s, p, num_words);
+    uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */
+
+    bits2int(tmp, message_hash, hash_size, curve);
+    uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */
+    uECC_vli_modMult(s, s, k, curve->n, num_n_words);  /* s = (e + r*d) / k */
+    if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) {
+        return 0;
+    }
+    uECC_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s);
+    return 1;
+}
+
+int jl3_uECC_sign(const uint8_t *private_key,
+              const uint8_t *message_hash,
+              unsigned hash_size,
+              uint8_t *signature,
+              uECC_Curve curve) {
+    uECC_word_t k[uECC_MAX_WORDS];
+    uECC_word_t tries;
+
+    for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
+        if (!uECC_generate_random_int(k, curve->n, BITS_TO_WORDS(curve->num_n_bits))) {
+            return 0;
+        }
+
+        if (uECC_sign_with_k(private_key, message_hash, hash_size, k, signature, curve)) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always
+   the same size as the hash result size. */
+static void HMAC_init(const jl3_uECC_HashContext *hash_context, const uint8_t *K) {
+    uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size;
+    unsigned i;
+    for (i = 0; i < hash_context->result_size; ++i)
+        pad[i] = K[i] ^ 0x36;
+    for (; i < hash_context->block_size; ++i)
+        pad[i] = 0x36;
+
+    hash_context->init_hash(hash_context);
+    hash_context->update_hash(hash_context, pad, hash_context->block_size);
+}
+
+static void HMAC_update(const jl3_uECC_HashContext *hash_context,
+                        const uint8_t *message,
+                        unsigned message_size) {
+    hash_context->update_hash(hash_context, message, message_size);
+}
+
+static void HMAC_finish(const jl3_uECC_HashContext *hash_context,
+                        const uint8_t *K,
+                        uint8_t *result) {
+    uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size;
+    unsigned i;
+    for (i = 0; i < hash_context->result_size; ++i)
+        pad[i] = K[i] ^ 0x5c;
+    for (; i < hash_context->block_size; ++i)
+        pad[i] = 0x5c;
+
+    hash_context->finish_hash(hash_context, result);
+
+    hash_context->init_hash(hash_context);
+    hash_context->update_hash(hash_context, pad, hash_context->block_size);
+    hash_context->update_hash(hash_context, result, hash_context->result_size);
+    hash_context->finish_hash(hash_context, result);
+}
+
+/* V = HMAC_K(V) */
+static void update_V(const jl3_uECC_HashContext *hash_context, uint8_t *K, uint8_t *V) {
+    HMAC_init(hash_context, K);
+    HMAC_update(hash_context, V, hash_context->result_size);
+    HMAC_finish(hash_context, K, V);
+}
+
+/* Deterministic signing, similar to RFC 6979. Differences are:
+    * We just use H(m) directly rather than bits2octets(H(m))
+      (it is not reduced modulo curve_n).
+    * We generate a value for k (aka T) directly rather than converting endianness.
+
+   Layout of hash_context->tmp: <K> | <V> | (1 byte overlapped 0x00 or 0x01) / <HMAC pad> */
+int jl3_uECC_sign_deterministic(const uint8_t *private_key,
+                            const uint8_t *message_hash,
+                            unsigned hash_size,
+                            const jl3_uECC_HashContext *hash_context,
+                            uint8_t *signature,
+                            uECC_Curve curve) {
+    uint8_t *K = hash_context->tmp;
+    uint8_t *V = K + hash_context->result_size;
+    wordcount_t num_bytes = curve->num_bytes;
+    wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
+    bitcount_t num_n_bits = curve->num_n_bits;
+    uECC_word_t tries;
+    unsigned i;
+    for (i = 0; i < hash_context->result_size; ++i) {
+        V[i] = 0x01;
+        K[i] = 0;
+    }
+
+    /* K = HMAC_K(V || 0x00 || int2octets(x) || h(m)) */
+    HMAC_init(hash_context, K);
+    V[hash_context->result_size] = 0x00;
+    HMAC_update(hash_context, V, hash_context->result_size + 1);
+    HMAC_update(hash_context, private_key, num_bytes);
+    HMAC_update(hash_context, message_hash, hash_size);
+    HMAC_finish(hash_context, K, K);
+
+    update_V(hash_context, K, V);
+
+    /* K = HMAC_K(V || 0x01 || int2octets(x) || h(m)) */
+    HMAC_init(hash_context, K);
+    V[hash_context->result_size] = 0x01;
+    HMAC_update(hash_context, V, hash_context->result_size + 1);
+    HMAC_update(hash_context, private_key, num_bytes);
+    HMAC_update(hash_context, message_hash, hash_size);
+    HMAC_finish(hash_context, K, K);
+
+    update_V(hash_context, K, V);
+
+    for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
+        uECC_word_t T[uECC_MAX_WORDS];
+        uint8_t *T_ptr = (uint8_t *)T;
+        wordcount_t T_bytes = 0;
+        for (;;) {
+            update_V(hash_context, K, V);
+            for (i = 0; i < hash_context->result_size; ++i) {
+                T_ptr[T_bytes++] = V[i];
+                if (T_bytes >= num_n_words * uECC_WORD_SIZE) {
+                    goto filled;
+                }
+            }
+        }
+    filled:
+        if ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8 > num_n_bits) {
+            uECC_word_t mask = (uECC_word_t)-1;
+            T[num_n_words - 1] &=
+                mask >> ((bitcount_t)(num_n_words * uECC_WORD_SIZE * 8 - num_n_bits));
+        }
+
+        if (uECC_sign_with_k(private_key, message_hash, hash_size, T, signature, curve)) {
+            return 1;
+        }
+
+        /* K = HMAC_K(V || 0x00) */
+        HMAC_init(hash_context, K);
+        V[hash_context->result_size] = 0x00;
+        HMAC_update(hash_context, V, hash_context->result_size + 1);
+        HMAC_finish(hash_context, K, K);
+
+        update_V(hash_context, K, V);
+    }
+    return 0;
+}
+
+static bitcount_t smax(bitcount_t a, bitcount_t b) {
+    return (a > b ? a : b);
+}
+
+int jl3_uECC_verify(const uint8_t *public_key,
+                const uint8_t *message_hash,
+                unsigned hash_size,
+                const uint8_t *signature,
+                uECC_Curve curve) {
+    uECC_word_t u1[uECC_MAX_WORDS], u2[uECC_MAX_WORDS];
+    uECC_word_t z[uECC_MAX_WORDS];
+    uECC_word_t public[uECC_MAX_WORDS * 2];
+    uECC_word_t sum[uECC_MAX_WORDS * 2];
+    uECC_word_t rx[uECC_MAX_WORDS];
+    uECC_word_t ry[uECC_MAX_WORDS];
+    uECC_word_t tx[uECC_MAX_WORDS];
+    uECC_word_t ty[uECC_MAX_WORDS];
+    uECC_word_t tz[uECC_MAX_WORDS];
+    const uECC_word_t *points[4];
+    const uECC_word_t *point;
+    bitcount_t num_bits;
+    bitcount_t i;
+    uECC_word_t r[uECC_MAX_WORDS], s[uECC_MAX_WORDS];
+    wordcount_t num_words = curve->num_words;
+    wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
+
+    rx[num_n_words - 1] = 0;
+    r[num_n_words - 1] = 0;
+    s[num_n_words - 1] = 0;
+
+    uECC_vli_bytesToNative(public, public_key, curve->num_bytes);
+    uECC_vli_bytesToNative(
+        public + num_words, public_key + curve->num_bytes, curve->num_bytes);
+    uECC_vli_bytesToNative(r, signature, curve->num_bytes);
+    uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes);
+
+    /* r, s must not be 0. */
+    if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) {
+        return 0;
+    }
+
+    /* r, s must be < n. */
+    if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 ||
+            uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) {
+        return 0;
+    }
+
+    /* Calculate u1 and u2. */
+    uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */
+    u1[num_n_words - 1] = 0;
+    bits2int(u1, message_hash, hash_size, curve);
+    uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */
+    uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */
+
+    /* Calculate sum = G + Q. */
+    uECC_vli_set(sum, public, num_words);
+    uECC_vli_set(sum + num_words, public + num_words, num_words);
+    uECC_vli_set(tx, curve->G, num_words);
+    uECC_vli_set(ty, curve->G + num_words, num_words);
+    uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */
+    XYcZ_add(tx, ty, sum, sum + num_words, curve);
+    uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */
+    apply_z(sum, sum + num_words, z, curve);
+
+    /* Use Shamir's trick to calculate u1*G + u2*Q */
+    points[0] = 0;
+    points[1] = curve->G;
+    points[2] = public;
+    points[3] = sum;
+    num_bits = smax(uECC_vli_numBits(u1, num_n_words),
+                    uECC_vli_numBits(u2, num_n_words));
+
+    point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) |
+                   ((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)];
+    uECC_vli_set(rx, point, num_words);
+    uECC_vli_set(ry, point + num_words, num_words);
+    uECC_vli_clear(z, num_words);
+    z[0] = 1;
+
+    for (i = num_bits - 2; i >= 0; --i) {
+        uECC_word_t index;
+        curve->double_jacobian(rx, ry, z, curve);
+
+        index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1);
+        point = points[index];
+        if (point) {
+            uECC_vli_set(tx, point, num_words);
+            uECC_vli_set(ty, point + num_words, num_words);
+            apply_z(tx, ty, z, curve);
+            uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */
+            XYcZ_add(tx, ty, rx, ry, curve);
+            uECC_vli_modMult_fast(z, z, tz, curve);
+        }
+    }
+
+    uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */
+    apply_z(rx, ry, z, curve);
+
+    /* v = x1 (mod n) */
+    if (uECC_vli_cmp_unsafe(curve->n, rx, num_n_words) != 1) {
+        uECC_vli_sub(rx, rx, curve->n, num_n_words);
+    }
+
+    /* Accept only if v == r. */
+    return (int)(uECC_vli_equal(rx, r, num_words));
+}
+
+#if uECC_ENABLE_VLI_API
+
+unsigned uECC_curve_num_words(uECC_Curve curve) {
+    return curve->num_words;
+}
+
+unsigned uECC_curve_num_bytes(uECC_Curve curve) {
+    return curve->num_bytes;
+}
+
+unsigned uECC_curve_num_bits(uECC_Curve curve) {
+    return curve->num_bytes * 8;
+}
+
+unsigned uECC_curve_num_n_words(uECC_Curve curve) {
+    return BITS_TO_WORDS(curve->num_n_bits);
+}
+
+unsigned uECC_curve_num_n_bytes(uECC_Curve curve) {
+    return BITS_TO_BYTES(curve->num_n_bits);
+}
+
+unsigned uECC_curve_num_n_bits(uECC_Curve curve) {
+    return curve->num_n_bits;
+}
+
+const uECC_word_t *uECC_curve_p(uECC_Curve curve) {
+    return curve->p;
+}
+
+const uECC_word_t *uECC_curve_n(uECC_Curve curve) {
+    return curve->n;
+}
+
+const uECC_word_t *uECC_curve_G(uECC_Curve curve) {
+    return curve->G;
+}
+
+const uECC_word_t *uECC_curve_b(uECC_Curve curve) {
+    return curve->b;
+}
+
+#if uECC_SUPPORT_COMPRESSED_POINT
+void uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve) {
+    curve->mod_sqrt(a, curve);
+}
+#endif
+
+void uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product, uECC_Curve curve) {
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+    curve->mmod_fast(result, product);
+#else
+    uECC_vli_mmod(result, product, curve->p, curve->num_words);
+#endif
+}
+
+void uECC_point_mult(uECC_word_t *result,
+                     const uECC_word_t *point,
+                     const uECC_word_t *scalar,
+                     uECC_Curve curve) {
+    uECC_word_t tmp1[uECC_MAX_WORDS];
+    uECC_word_t tmp2[uECC_MAX_WORDS];
+    uECC_word_t *p2[2] = {tmp1, tmp2};
+    uECC_word_t carry = regularize_k(scalar, tmp1, tmp2, curve);
+
+    EccPoint_mult(result, point, p2[!carry], 0, curve->num_n_bits + 1, curve);
+}
+
+#endif /* uECC_ENABLE_VLI_API */
+
+int jl3_uECC_verify_256r1(const uint8_t *public_key,
+                const uint8_t *message_hash,
+                unsigned hash_size,
+                const uint8_t *signature){
+    uint8_t dc_pubkey[64];
+    jl3_uECC_decompress(public_key, dc_pubkey, uECC_secp256r1());
+    return jl3_uECC_verify(dc_pubkey,
+                message_hash,
+                hash_size,
+                signature,
+                uECC_secp256r1());
+}

+ 350 - 0
joylink/auth/joylink3_auth_uECC.h

@@ -0,0 +1,350 @@
+/*Copyright (c) 2015-2050, JD Smart All rights reserved.
+
+  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. */
+
+/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
+
+#ifndef _UECC_H_
+#define _UECC_H_
+
+#include <stdint.h>
+
+/* Platform selection options.
+If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros.
+Possible values for uECC_PLATFORM are defined below: */
+#define uECC_arch_other 0
+#define uECC_x86        1
+#define uECC_x86_64     2
+#define uECC_arm        3
+#define uECC_arm_thumb  4
+#define jl3_uECC_arm_thumb2 5
+#define uECC_arm64      6
+#define jl3_uECC_avr        7
+
+/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes).
+If uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your
+platform. */
+
+/* Optimization level; trade speed for code size.
+   Larger values produce code that is faster but larger.
+   Currently supported values are 0 - 3; 0 is unusably slow for most applications. */
+#ifndef uECC_OPTIMIZATION_LEVEL
+    #define uECC_OPTIMIZATION_LEVEL 2
+#endif
+
+/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be
+used for (scalar) squaring instead of the generic multiplication function. This can make things
+faster somewhat faster, but increases the code size. */
+#ifndef uECC_SQUARE_FUNC
+    #define uECC_SQUARE_FUNC 0
+#endif
+
+/* Curve support selection. Set to 0 to remove that curve. */
+#ifndef uECC_SUPPORTS_secp160r1
+    #define uECC_SUPPORTS_secp160r1 1
+#endif
+#ifndef uECC_SUPPORTS_secp192r1
+    #define uECC_SUPPORTS_secp192r1 0
+#endif
+#ifndef uECC_SUPPORTS_secp224r1
+    #define uECC_SUPPORTS_secp224r1 0
+#endif
+#ifndef uECC_SUPPORTS_secp256r1
+    #define uECC_SUPPORTS_secp256r1 1
+#endif
+#ifndef uECC_SUPPORTS_secp256k1
+    #define uECC_SUPPORTS_secp256k1 0
+#endif
+
+/* Specifies whether compressed point format is supported.
+   Set to 0 to disable point compression/decompression functions. */
+#ifndef uECC_SUPPORT_COMPRESSED_POINT
+    #define uECC_SUPPORT_COMPRESSED_POINT 1
+#endif
+
+struct uECC_Curve_t;
+typedef const struct uECC_Curve_t * uECC_Curve;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if uECC_SUPPORTS_secp160r1
+uECC_Curve jl3_uECC_secp160r1(void);
+#endif
+#if uECC_SUPPORTS_secp192r1
+uECC_Curve uECC_secp192r1(void);
+#endif
+#if uECC_SUPPORTS_secp224r1
+uECC_Curve uECC_secp224r1(void);
+#endif
+#if uECC_SUPPORTS_secp256r1
+uECC_Curve uECC_secp256r1(void);
+#endif
+#if uECC_SUPPORTS_secp256k1
+uECC_Curve uECC_secp256k1(void);
+#endif
+
+/* uECC_RNG_Function type
+The RNG function should fill 'size' random bytes into 'dest'. It should return 1 if
+'dest' was filled with random data, or 0 if the random data could not be generated.
+The filled-in values should be either truly random, or from a cryptographically-secure PRNG.
+
+A correctly functioning RNG function must be set (using jl3_uECC_set_rng()) before calling
+jl3_uECC_make_key() or jl3_uECC_sign().
+
+Setting a correctly functioning RNG function improves the resistance to side-channel attacks
+for jl3_uECC_shared_secret() and jl3_uECC_sign_deterministic().
+
+A correct RNG function is set by default when building for Windows, Linux, or OS X.
+If you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom,
+you can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined
+RNG function; you must provide your own.
+*/
+typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size);
+
+/* jl3_uECC_set_rng() function.
+Set the function that will be used to generate random bytes. The RNG function should
+return 1 if the random data was generated, or 0 if the random data could not be generated.
+
+On platforms where there is no predefined RNG function (eg embedded platforms), this must
+be called before jl3_uECC_make_key() or jl3_uECC_sign() are used.
+
+Inputs:
+    rng_function - The function that will be used to generate random bytes.
+*/
+void jl3_uECC_set_rng(uECC_RNG_Function rng_function);
+
+/* jl3_uECC_get_rng() function.
+
+Returns the function that will be used to generate random bytes.
+*/
+uECC_RNG_Function jl3_uECC_get_rng(void);
+
+/* jl3_uECC_make_key() function.
+Create a public/private key pair.
+
+Outputs:
+    public_key  - Will be filled in with the public key. Must be at least 2 * the curve size
+                  (in bytes) long. For example, if the curve is secp256r1, public_key must be 64
+                  bytes long.
+    private_key - Will be filled in with the private key. Must be as long as the curve order; this
+                  is typically the same as the curve size, except for secp160r1. For example, if the
+                  curve is secp256r1, private_key must be 32 bytes long.
+
+                  For secp160r1, private_key must be 21 bytes long! Note that the first byte will
+                  almost always be 0 (there is about a 1 in 2^80 chance of it being non-zero).
+
+Returns 1 if the key pair was generated successfully, 0 if an error occurred.
+*/
+int jl3_uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve);
+
+/* jl3_uECC_shared_secret() function.
+Compute a shared secret given your secret key and someone else's public key.
+Note: It is recommended that you hash the result of jl3_uECC_shared_secret() before using it for
+symmetric encryption or HMAC.
+
+Inputs:
+    public_key  - The public key of the remote party.
+    private_key - Your private key.
+
+Outputs:
+    secret - Will be filled in with the shared secret value. Must be the same size as the
+             curve size; for example, if the curve is secp256r1, secret must be 32 bytes long.
+
+Returns 1 if the shared secret was generated successfully, 0 if an error occurred.
+*/
+int jl3_uECC_shared_secret(const uint8_t *public_key,
+                       const uint8_t *private_key,
+                       uint8_t *secret,
+                       uECC_Curve curve);
+
+#if uECC_SUPPORT_COMPRESSED_POINT
+/* jl3_uECC_compress() function.
+Compress a public key.
+
+Inputs:
+    public_key - The public key to compress.
+
+Outputs:
+    compressed - Will be filled in with the compressed public key. Must be at least
+                 (curve size + 1) bytes long; for example, if the curve is secp256r1,
+                 compressed must be 33 bytes long.
+*/
+void jl3_uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve);
+
+/* jl3_uECC_decompress() function.
+Decompress a compressed public key.
+
+Inputs:
+    compressed - The compressed public key.
+
+Outputs:
+    public_key - Will be filled in with the decompressed public key.
+*/
+void jl3_uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve);
+#endif /* uECC_SUPPORT_COMPRESSED_POINT */
+
+/* jl3_uECC_valid_public_key() function.
+Check to see if a public key is valid.
+
+Note that you are not required to check for a valid public key before using any other uECC
+functions. However, you may wish to avoid spending CPU time computing a shared secret or
+verifying a signature using an invalid public key.
+
+Inputs:
+    public_key - The public key to check.
+
+Returns 1 if the public key is valid, 0 if it is invalid.
+*/
+int jl3_uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve);
+
+/* jl3_uECC_compute_public_key() function.
+Compute the corresponding public key for a private key.
+
+Inputs:
+    private_key - The private key to compute the public key for
+
+Outputs:
+    public_key - Will be filled in with the corresponding public key
+
+Returns 1 if the key was computed successfully, 0 if an error occurred.
+*/
+int jl3_uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve);
+
+/* jl3_uECC_sign() function.
+Generate an ECDSA signature for a given hash value.
+
+Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to
+this function along with your private key.
+
+Inputs:
+    private_key  - Your private key.
+    message_hash - The hash of the message to sign.
+    hash_size    - The size of message_hash in bytes.
+
+Outputs:
+    signature - Will be filled in with the signature value. Must be at least 2 * curve size long.
+                For example, if the curve is secp256r1, signature must be 64 bytes long.
+
+Returns 1 if the signature generated successfully, 0 if an error occurred.
+*/
+int jl3_uECC_sign(const uint8_t *private_key,
+              const uint8_t *message_hash,
+              unsigned hash_size,
+              uint8_t *signature,
+              uECC_Curve curve);
+
+/* uECC_HashContext structure.
+This is used to pass in an arbitrary hash function to jl3_uECC_sign_deterministic().
+The structure will be used for multiple hash computations; each time a new hash
+is computed, init_hash() will be called, followed by one or more calls to
+update_hash(), and finally a call to finish_hash() to produce the resulting hash.
+
+The intention is that you will create a structure that includes uECC_HashContext
+followed by any hash-specific data. For example:
+
+typedef struct SHA256_HashContext {
+    uECC_HashContext uECC;
+    SHA256_CTX ctx;
+} SHA256_HashContext;
+
+void init_SHA256(uECC_HashContext *base) {
+    SHA256_HashContext *context = (SHA256_HashContext *)base;
+    SHA256_Init(&context->ctx);
+}
+
+void update_SHA256(uECC_HashContext *base,
+                   const uint8_t *message,
+                   unsigned message_size) {
+    SHA256_HashContext *context = (SHA256_HashContext *)base;
+    SHA256_Update(&context->ctx, message, message_size);
+}
+
+void finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) {
+    SHA256_HashContext *context = (SHA256_HashContext *)base;
+    SHA256_Final(hash_result, &context->ctx);
+}
+
+... when signing ...
+{
+    uint8_t tmp[32 + 32 + 64];
+    SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}};
+    jl3_uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature);
+}
+*/
+typedef struct jl3_uECC_HashContext {
+    void (*init_hash)(const struct jl3_uECC_HashContext *context);
+    void (*update_hash)(const struct jl3_uECC_HashContext *context,
+                        const uint8_t *message,
+                        unsigned message_size);
+    void (*finish_hash)(const struct jl3_uECC_HashContext *context, uint8_t *hash_result);
+    unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */
+    unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */
+    uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */
+} jl3_uECC_HashContext;
+
+/* jl3_uECC_sign_deterministic() function.
+Generate an ECDSA signature for a given hash value, using a deterministic algorithm
+(see RFC 6979). You do not need to set the RNG using jl3_uECC_set_rng() before calling
+this function; however, if the RNG is defined it will improve resistance to side-channel
+attacks.
+
+Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it to
+this function along with your private key and a hash context. Note that the message_hash
+does not need to be computed with the same hash function used by hash_context.
+
+Inputs:
+    private_key  - Your private key.
+    message_hash - The hash of the message to sign.
+    hash_size    - The size of message_hash in bytes.
+    hash_context - A hash context to use.
+
+Outputs:
+    signature - Will be filled in with the signature value.
+
+Returns 1 if the signature generated successfully, 0 if an error occurred.
+*/
+int jl3_uECC_sign_deterministic(const uint8_t *private_key,
+                            const uint8_t *message_hash,
+                            unsigned hash_size,
+                            const jl3_uECC_HashContext *hash_context,
+                            uint8_t *signature,
+                            uECC_Curve curve);
+
+/* jl3_uECC_verify() function.
+Verify an ECDSA signature.
+
+Usage: Compute the hash of the signed data using the same hash as the signer and
+pass it to this function along with the signer's public key and the signature values (r and s).
+
+Inputs:
+    public_key   - The signer's public key.
+    message_hash - The hash of the signed data.
+    hash_size    - The size of message_hash in bytes.
+    signature    - The signature value.
+
+Returns 1 if the signature is valid, 0 if it is invalid.
+*/
+int jl3_uECC_verify(const uint8_t *public_key,
+                const uint8_t *message_hash,
+                unsigned hash_size,
+                const uint8_t *signature,
+                uECC_Curve curve);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif /* _UECC_H_ */

+ 1248 - 0
joylink/auth/joylink3_auth_uECC_curve-specific.inc

@@ -0,0 +1,1248 @@
+/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
+
+#ifndef _UECC_CURVE_SPECIFIC_H_
+#define _UECC_CURVE_SPECIFIC_H_
+
+#define num_bytes_secp160r1 20
+#define num_bytes_secp192r1 24
+#define num_bytes_secp224r1 28
+#define num_bytes_secp256r1 32
+#define num_bytes_secp256k1 32
+
+#if (uECC_WORD_SIZE == 1)
+
+#define num_words_secp160r1 20
+#define num_words_secp192r1 24
+#define num_words_secp224r1 28
+#define num_words_secp256r1 32
+#define num_words_secp256k1 32
+
+#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) \
+    0x##a, 0x##b, 0x##c, 0x##d, 0x##e, 0x##f, 0x##g, 0x##h
+#define BYTES_TO_WORDS_4(a, b, c, d) 0x##a, 0x##b, 0x##c, 0x##d
+
+#elif (uECC_WORD_SIZE == 4)
+
+#define num_words_secp160r1 5
+#define num_words_secp192r1 6
+#define num_words_secp224r1 7
+#define num_words_secp256r1 8
+#define num_words_secp256k1 8
+
+#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##d##c##b##a, 0x##h##g##f##e
+#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a
+
+#elif (uECC_WORD_SIZE == 8)
+
+#define num_words_secp160r1 3
+#define num_words_secp192r1 3
+#define num_words_secp224r1 4
+#define num_words_secp256r1 4
+#define num_words_secp256k1 4
+
+#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##h##g##f##e##d##c##b##a##ull
+#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a##ull
+
+#endif /* uECC_WORD_SIZE */
+
+#if uECC_SUPPORTS_secp160r1 || uECC_SUPPORTS_secp192r1 || \
+    uECC_SUPPORTS_secp224r1 || uECC_SUPPORTS_secp256r1
+static void double_jacobian_default(uECC_word_t * X1,
+                                    uECC_word_t * Y1,
+                                    uECC_word_t * Z1,
+                                    uECC_Curve curve) {
+    /* t1 = X, t2 = Y, t3 = Z */
+    uECC_word_t t4[uECC_MAX_WORDS];
+    uECC_word_t t5[uECC_MAX_WORDS];
+    wordcount_t num_words = curve->num_words;
+
+    if (uECC_vli_isZero(Z1, num_words)) {
+        return;
+    }
+
+    uECC_vli_modSquare_fast(t4, Y1, curve);   /* t4 = y1^2 */
+    uECC_vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */
+    uECC_vli_modSquare_fast(t4, t4, curve);   /* t4 = y1^4 */
+    uECC_vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */
+    uECC_vli_modSquare_fast(Z1, Z1, curve);   /* t3 = z1^2 */
+
+    uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */
+    uECC_vli_modAdd(Z1, Z1, Z1, curve->p, num_words); /* t3 = 2*z1^2 */
+    uECC_vli_modSub(Z1, X1, Z1, curve->p, num_words); /* t3 = x1 - z1^2 */
+    uECC_vli_modMult_fast(X1, X1, Z1, curve);                /* t1 = x1^2 - z1^4 */
+
+    uECC_vli_modAdd(Z1, X1, X1, curve->p, num_words); /* t3 = 2*(x1^2 - z1^4) */
+    uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = 3*(x1^2 - z1^4) */
+    if (uECC_vli_testBit(X1, 0)) {
+        uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words);
+        uECC_vli_rshift1(X1, num_words);
+        X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);
+    } else {
+        uECC_vli_rshift1(X1, num_words);
+    }
+    /* t1 = 3/2*(x1^2 - z1^4) = B */
+
+    uECC_vli_modSquare_fast(Z1, X1, curve);                  /* t3 = B^2 */
+    uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - A */
+    uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - 2A = x3 */
+    uECC_vli_modSub(t5, t5, Z1, curve->p, num_words); /* t5 = A - x3 */
+    uECC_vli_modMult_fast(X1, X1, t5, curve);                /* t1 = B * (A - x3) */
+    uECC_vli_modSub(t4, X1, t4, curve->p, num_words); /* t4 = B * (A - x3) - y1^4 = y3 */
+
+    uECC_vli_set(X1, Z1, num_words);
+    uECC_vli_set(Z1, Y1, num_words);
+    uECC_vli_set(Y1, t4, num_words);
+}
+
+/* Computes result = x^3 + ax + b. result must not overlap x. */
+static void x_side_default(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) {
+    uECC_word_t _3[uECC_MAX_WORDS] = {3}; /* -a = 3 */
+    wordcount_t num_words = curve->num_words;
+
+    uECC_vli_modSquare_fast(result, x, curve);                             /* r = x^2 */
+    uECC_vli_modSub(result, result, _3, curve->p, num_words);       /* r = x^2 - 3 */
+    uECC_vli_modMult_fast(result, result, x, curve);                       /* r = x^3 - 3x */
+    uECC_vli_modAdd(result, result, curve->b, curve->p, num_words); /* r = x^3 - 3x + b */
+}
+#endif /* uECC_SUPPORTS_secp... */
+
+#if uECC_SUPPORT_COMPRESSED_POINT
+#if uECC_SUPPORTS_secp160r1 || uECC_SUPPORTS_secp192r1 || \
+    uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1
+/* Compute a = sqrt(a) (mod curve_p). */
+static void mod_sqrt_default(uECC_word_t *a, uECC_Curve curve) {
+    bitcount_t i;
+    uECC_word_t p1[uECC_MAX_WORDS] = {1};
+    uECC_word_t l_result[uECC_MAX_WORDS] = {1};
+    wordcount_t num_words = curve->num_words;
+    
+    /* When curve->p == 3 (mod 4), we can compute
+       sqrt(a) = a^((curve->p + 1) / 4) (mod curve->p). */
+    uECC_vli_add(p1, curve->p, p1, num_words); /* p1 = curve_p + 1 */
+    for (i = uECC_vli_numBits(p1, num_words) - 1; i > 1; --i) {
+        uECC_vli_modSquare_fast(l_result, l_result, curve);
+        if (uECC_vli_testBit(p1, i)) {
+            uECC_vli_modMult_fast(l_result, l_result, a, curve);
+        }
+    }
+    uECC_vli_set(a, l_result, num_words);
+}
+#endif /* uECC_SUPPORTS_secp... */
+#endif /* uECC_SUPPORT_COMPRESSED_POINT */
+
+#if uECC_SUPPORTS_secp160r1
+
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product);
+#endif
+
+static const struct uECC_Curve_t curve_secp160r1 = {
+    num_words_secp160r1,
+    num_bytes_secp160r1,
+    161, /* num_n_bits */
+    { BYTES_TO_WORDS_8(FF, FF, FF, 7F, FF, FF, FF, FF),
+        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
+        BYTES_TO_WORDS_4(FF, FF, FF, FF) },
+    { BYTES_TO_WORDS_8(57, 22, 75, CA, D3, AE, 27, F9),
+        BYTES_TO_WORDS_8(C8, F4, 01, 00, 00, 00, 00, 00),
+        BYTES_TO_WORDS_8(00, 00, 00, 00, 01, 00, 00, 00) },
+    { BYTES_TO_WORDS_8(82, FC, CB, 13, B9, 8B, C3, 68),
+        BYTES_TO_WORDS_8(89, 69, 64, 46, 28, 73, F5, 8E),
+        BYTES_TO_WORDS_4(68, B5, 96, 4A),
+
+        BYTES_TO_WORDS_8(32, FB, C5, 7A, 37, 51, 23, 04),
+        BYTES_TO_WORDS_8(12, C9, DC, 59, 7D, 94, 68, 31),
+        BYTES_TO_WORDS_4(55, 28, A6, 23) },
+    { BYTES_TO_WORDS_8(45, FA, 65, C5, AD, D4, D4, 81),
+        BYTES_TO_WORDS_8(9F, F8, AC, 65, 8B, 7A, BD, 54),
+        BYTES_TO_WORDS_4(FC, BE, 97, 1C) },
+    &double_jacobian_default,
+#if uECC_SUPPORT_COMPRESSED_POINT
+    &mod_sqrt_default,
+#endif
+    &x_side_default,
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+    &vli_mmod_fast_secp160r1
+#endif
+};
+
+uECC_Curve jl3_uECC_secp160r1(void) { return &curve_secp160r1; }
+
+#if (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp160r1)
+/* Computes result = product % curve_p
+    see http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf page 354
+    
+    Note that this only works if log2(omega) < log2(p) / 2 */
+static void omega_mult_secp160r1(uECC_word_t *result, const uECC_word_t *right);
+#if uECC_WORD_SIZE == 8
+static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) {
+    uECC_word_t tmp[2 * num_words_secp160r1];
+    uECC_word_t copy;
+    
+    uECC_vli_clear(tmp, num_words_secp160r1);
+    uECC_vli_clear(tmp + num_words_secp160r1, num_words_secp160r1);
+
+    omega_mult_secp160r1(tmp, product + num_words_secp160r1 - 1); /* (Rq, q) = q * c */
+    
+    product[num_words_secp160r1 - 1] &= 0xffffffff;
+    copy = tmp[num_words_secp160r1 - 1];
+    tmp[num_words_secp160r1 - 1] &= 0xffffffff;
+    uECC_vli_add(result, product, tmp, num_words_secp160r1); /* (C, r) = r + q */
+    uECC_vli_clear(product, num_words_secp160r1);
+    tmp[num_words_secp160r1 - 1] = copy;
+    omega_mult_secp160r1(product, tmp + num_words_secp160r1 - 1); /* Rq*c */
+    uECC_vli_add(result, result, product, num_words_secp160r1); /* (C1, r) = r + Rq*c */
+
+    while (uECC_vli_cmp_unsafe(result, curve_secp160r1.p, num_words_secp160r1) > 0) {
+        uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1);
+    }
+}
+
+static void omega_mult_secp160r1(uint64_t *result, const uint64_t *right) {
+    uint32_t carry;
+    unsigned i;
+    
+    /* Multiply by (2^31 + 1). */
+    carry = 0;
+    for (i = 0; i < num_words_secp160r1; ++i) {
+        uint64_t tmp = (right[i] >> 32) | (right[i + 1] << 32);
+        result[i] = (tmp << 31) + tmp + carry;
+        carry = (tmp >> 33) + (result[i] < tmp || (carry && result[i] == tmp));
+    }
+    result[i] = carry;
+}
+#else
+static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) {
+    uECC_word_t tmp[2 * num_words_secp160r1];
+    uECC_word_t carry;
+    
+    uECC_vli_clear(tmp, num_words_secp160r1);
+    uECC_vli_clear(tmp + num_words_secp160r1, num_words_secp160r1);
+
+    omega_mult_secp160r1(tmp, product + num_words_secp160r1); /* (Rq, q) = q * c */
+    
+    carry = uECC_vli_add(result, product, tmp, num_words_secp160r1); /* (C, r) = r + q */
+    uECC_vli_clear(product, num_words_secp160r1);
+    omega_mult_secp160r1(product, tmp + num_words_secp160r1); /* Rq*c */
+    carry += uECC_vli_add(result, result, product, num_words_secp160r1); /* (C1, r) = r + Rq*c */
+
+    while (carry > 0) {
+        --carry;
+        uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1);
+    }
+    if (uECC_vli_cmp_unsafe(result, curve_secp160r1.p, num_words_secp160r1) > 0) {
+        uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1);
+    }
+}
+#endif
+
+#if uECC_WORD_SIZE == 1
+static void omega_mult_secp160r1(uint8_t *result, const uint8_t *right) {
+    uint8_t carry;
+    uint8_t i;
+    
+    /* Multiply by (2^31 + 1). */
+    uECC_vli_set(result + 4, right, num_words_secp160r1); /* 2^32 */
+    uECC_vli_rshift1(result + 4, num_words_secp160r1); /* 2^31 */
+    result[3] = right[0] << 7; /* get last bit from shift */
+    
+    carry = uECC_vli_add(result, result, right, num_words_secp160r1); /* 2^31 + 1 */
+    for (i = num_words_secp160r1; carry; ++i) {
+        uint16_t sum = (uint16_t)result[i] + carry;
+        result[i] = (uint8_t)sum;
+        carry = sum >> 8;
+    }
+}
+#elif uECC_WORD_SIZE == 4
+static void omega_mult_secp160r1(uint32_t *result, const uint32_t *right) {
+    uint32_t carry;
+    unsigned i;
+    
+    /* Multiply by (2^31 + 1). */
+    uECC_vli_set(result + 1, right, num_words_secp160r1); /* 2^32 */
+    uECC_vli_rshift1(result + 1, num_words_secp160r1); /* 2^31 */
+    result[0] = right[0] << 31; /* get last bit from shift */
+    
+    carry = uECC_vli_add(result, result, right, num_words_secp160r1); /* 2^31 + 1 */
+    for (i = num_words_secp160r1; carry; ++i) {
+        uint64_t sum = (uint64_t)result[i] + carry;
+        result[i] = (uint32_t)sum;
+        carry = sum >> 32;
+    }
+}
+#endif /* uECC_WORD_SIZE */
+#endif /* (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp160r1) */
+
+#endif /* uECC_SUPPORTS_secp160r1 */
+
+#if uECC_SUPPORTS_secp192r1
+
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+static void vli_mmod_fast_secp192r1(uECC_word_t *result, uECC_word_t *product);
+#endif
+
+static const struct uECC_Curve_t curve_secp192r1 = {
+    num_words_secp192r1,
+    num_bytes_secp192r1,
+    192, /* num_n_bits */
+    { BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
+        BYTES_TO_WORDS_8(FE, FF, FF, FF, FF, FF, FF, FF),
+        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) },
+    { BYTES_TO_WORDS_8(31, 28, D2, B4, B1, C9, 6B, 14),
+        BYTES_TO_WORDS_8(36, F8, DE, 99, FF, FF, FF, FF),
+        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) },
+    { BYTES_TO_WORDS_8(12, 10, FF, 82, FD, 0A, FF, F4),
+        BYTES_TO_WORDS_8(00, 88, A1, 43, EB, 20, BF, 7C),
+        BYTES_TO_WORDS_8(F6, 90, 30, B0, 0E, A8, 8D, 18),
+
+        BYTES_TO_WORDS_8(11, 48, 79, 1E, A1, 77, F9, 73),
+        BYTES_TO_WORDS_8(D5, CD, 24, 6B, ED, 11, 10, 63),
+        BYTES_TO_WORDS_8(78, DA, C8, FF, 95, 2B, 19, 07) },
+    { BYTES_TO_WORDS_8(B1, B9, 46, C1, EC, DE, B8, FE),
+        BYTES_TO_WORDS_8(49, 30, 24, 72, AB, E9, A7, 0F),
+        BYTES_TO_WORDS_8(E7, 80, 9C, E5, 19, 05, 21, 64) },
+    &double_jacobian_default,
+#if uECC_SUPPORT_COMPRESSED_POINT
+    &mod_sqrt_default,
+#endif
+    &x_side_default,
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+    &vli_mmod_fast_secp192r1
+#endif
+};
+
+uECC_Curve uECC_secp192r1(void) { return &curve_secp192r1; }
+
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+/* Computes result = product % curve_p.
+   See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */
+#if uECC_WORD_SIZE == 1
+static void vli_mmod_fast_secp192r1(uint8_t *result, uint8_t *product) {
+    uint8_t tmp[num_words_secp192r1];
+    uint8_t carry;
+    
+    uECC_vli_set(result, product, num_words_secp192r1);
+    
+    uECC_vli_set(tmp, &product[24], num_words_secp192r1);
+    carry = uECC_vli_add(result, result, tmp, num_words_secp192r1);
+    
+    tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;
+    tmp[8] = product[24]; tmp[9] = product[25]; tmp[10] = product[26]; tmp[11] = product[27];
+    tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31];
+    tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35];
+    tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39];
+    carry += uECC_vli_add(result, result, tmp, num_words_secp192r1);
+    
+    tmp[0] = tmp[8] = product[40];
+    tmp[1] = tmp[9] = product[41];
+    tmp[2] = tmp[10] = product[42];
+    tmp[3] = tmp[11] = product[43];
+    tmp[4] = tmp[12] = product[44];
+    tmp[5] = tmp[13] = product[45];
+    tmp[6] = tmp[14] = product[46];
+    tmp[7] = tmp[15] = product[47];
+    tmp[16] = tmp[17] = tmp[18] = tmp[19] = tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;
+    carry += uECC_vli_add(result, result, tmp, num_words_secp192r1);
+    
+    while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) {
+        carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1);
+    }
+}
+#elif uECC_WORD_SIZE == 4
+static void vli_mmod_fast_secp192r1(uint32_t *result, uint32_t *product) {
+    uint32_t tmp[num_words_secp192r1];
+    int carry;
+    
+    uECC_vli_set(result, product, num_words_secp192r1);
+    
+    uECC_vli_set(tmp, &product[6], num_words_secp192r1);
+    carry = uECC_vli_add(result, result, tmp, num_words_secp192r1);
+    
+    tmp[0] = tmp[1] = 0;
+    tmp[2] = product[6];
+    tmp[3] = product[7];
+    tmp[4] = product[8];
+    tmp[5] = product[9];
+    carry += uECC_vli_add(result, result, tmp, num_words_secp192r1);
+    
+    tmp[0] = tmp[2] = product[10];
+    tmp[1] = tmp[3] = product[11];
+    tmp[4] = tmp[5] = 0;
+    carry += uECC_vli_add(result, result, tmp, num_words_secp192r1);
+    
+    while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) {
+        carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1);
+    }
+}
+#else
+static void vli_mmod_fast_secp192r1(uint64_t *result, uint64_t *product) {
+    uint64_t tmp[num_words_secp192r1];
+    int carry;
+    
+    uECC_vli_set(result, product, num_words_secp192r1);
+    
+    uECC_vli_set(tmp, &product[3], num_words_secp192r1);
+    carry = (int)uECC_vli_add(result, result, tmp, num_words_secp192r1);
+    
+    tmp[0] = 0;
+    tmp[1] = product[3];
+    tmp[2] = product[4];
+    carry += uECC_vli_add(result, result, tmp, num_words_secp192r1);
+    
+    tmp[0] = tmp[1] = product[5];
+    tmp[2] = 0;
+    carry += uECC_vli_add(result, result, tmp, num_words_secp192r1);
+    
+    while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) {
+        carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1);
+    }
+}
+#endif /* uECC_WORD_SIZE */
+#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */
+
+#endif /* uECC_SUPPORTS_secp192r1 */
+
+#if uECC_SUPPORTS_secp224r1
+
+#if uECC_SUPPORT_COMPRESSED_POINT
+static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve);
+#endif
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+static void vli_mmod_fast_secp224r1(uECC_word_t *result, uECC_word_t *product);
+#endif
+
+static const struct uECC_Curve_t curve_secp224r1 = {
+    num_words_secp224r1,
+    num_bytes_secp224r1,
+    224, /* num_n_bits */
+    { BYTES_TO_WORDS_8(01, 00, 00, 00, 00, 00, 00, 00),
+        BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF),
+        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
+        BYTES_TO_WORDS_4(FF, FF, FF, FF) },
+    { BYTES_TO_WORDS_8(3D, 2A, 5C, 5C, 45, 29, DD, 13),
+        BYTES_TO_WORDS_8(3E, F0, B8, E0, A2, 16, FF, FF),
+        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
+        BYTES_TO_WORDS_4(FF, FF, FF, FF) },
+    { BYTES_TO_WORDS_8(21, 1D, 5C, 11, D6, 80, 32, 34),
+        BYTES_TO_WORDS_8(22, 11, C2, 56, D3, C1, 03, 4A),
+        BYTES_TO_WORDS_8(B9, 90, 13, 32, 7F, BF, B4, 6B),
+        BYTES_TO_WORDS_4(BD, 0C, 0E, B7),
+
+        BYTES_TO_WORDS_8(34, 7E, 00, 85, 99, 81, D5, 44),
+        BYTES_TO_WORDS_8(64, 47, 07, 5A, A0, 75, 43, CD),
+        BYTES_TO_WORDS_8(E6, DF, 22, 4C, FB, 23, F7, B5),
+        BYTES_TO_WORDS_4(88, 63, 37, BD) },
+    { BYTES_TO_WORDS_8(B4, FF, 55, 23, 43, 39, 0B, 27),
+        BYTES_TO_WORDS_8(BA, D8, BF, D7, B7, B0, 44, 50),
+        BYTES_TO_WORDS_8(56, 32, 41, F5, AB, B3, 04, 0C),
+        BYTES_TO_WORDS_4(85, 0A, 05, B4) },
+    &double_jacobian_default,
+#if uECC_SUPPORT_COMPRESSED_POINT
+    &mod_sqrt_secp224r1,
+#endif
+    &x_side_default,
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+    &vli_mmod_fast_secp224r1
+#endif
+};
+
+uECC_Curve uECC_secp224r1(void) { return &curve_secp224r1; }
+
+
+#if uECC_SUPPORT_COMPRESSED_POINT
+/* Routine 3.2.4 RS;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+static void mod_sqrt_secp224r1_rs(uECC_word_t *d1,
+                                  uECC_word_t *e1,
+                                  uECC_word_t *f1,
+                                  const uECC_word_t *d0,
+                                  const uECC_word_t *e0,
+                                  const uECC_word_t *f0) {
+    uECC_word_t t[num_words_secp224r1];
+
+    uECC_vli_modSquare_fast(t, d0, &curve_secp224r1);                    /* t <-- d0 ^ 2 */
+    uECC_vli_modMult_fast(e1, d0, e0, &curve_secp224r1);                 /* e1 <-- d0 * e0 */
+    uECC_vli_modAdd(d1, t, f0, curve_secp224r1.p, num_words_secp224r1);  /* d1 <-- t  + f0 */
+    uECC_vli_modAdd(e1, e1, e1, curve_secp224r1.p, num_words_secp224r1); /* e1 <-- e1 + e1 */
+    uECC_vli_modMult_fast(f1, t, f0, &curve_secp224r1);                  /* f1 <-- t  * f0 */
+    uECC_vli_modAdd(f1, f1, f1, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- f1 + f1 */
+    uECC_vli_modAdd(f1, f1, f1, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- f1 + f1 */
+}
+
+/* Routine 3.2.5 RSS;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+static void mod_sqrt_secp224r1_rss(uECC_word_t *d1,
+                                   uECC_word_t *e1,
+                                   uECC_word_t *f1,
+                                   const uECC_word_t *d0,
+                                   const uECC_word_t *e0,
+                                   const uECC_word_t *f0,
+                                   const bitcount_t j) {
+    bitcount_t i;
+
+    uECC_vli_set(d1, d0, num_words_secp224r1); /* d1 <-- d0 */
+    uECC_vli_set(e1, e0, num_words_secp224r1); /* e1 <-- e0 */
+    uECC_vli_set(f1, f0, num_words_secp224r1); /* f1 <-- f0 */
+    for (i = 1; i <= j; i++) {
+        mod_sqrt_secp224r1_rs(d1, e1, f1, d1, e1, f1); /* RS (d1,e1,f1,d1,e1,f1) */
+    }
+}
+
+/* Routine 3.2.6 RM;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+static void mod_sqrt_secp224r1_rm(uECC_word_t *d2,
+                                  uECC_word_t *e2,
+                                  uECC_word_t *f2,
+                                  const uECC_word_t *c,
+                                  const uECC_word_t *d0,
+                                  const uECC_word_t *e0,
+                                  const uECC_word_t *d1,
+                                  const uECC_word_t *e1) {
+    uECC_word_t t1[num_words_secp224r1];
+    uECC_word_t t2[num_words_secp224r1];
+
+    uECC_vli_modMult_fast(t1, e0, e1, &curve_secp224r1); /* t1 <-- e0 * e1 */
+    uECC_vli_modMult_fast(t1, t1, c, &curve_secp224r1);  /* t1 <-- t1 * c */
+    /* t1 <-- p  - t1 */
+    uECC_vli_modSub(t1, curve_secp224r1.p, t1, curve_secp224r1.p, num_words_secp224r1);
+    uECC_vli_modMult_fast(t2, d0, d1, &curve_secp224r1);                 /* t2 <-- d0 * d1 */
+    uECC_vli_modAdd(t2, t2, t1, curve_secp224r1.p, num_words_secp224r1); /* t2 <-- t2 + t1 */
+    uECC_vli_modMult_fast(t1, d0, e1, &curve_secp224r1);                 /* t1 <-- d0 * e1 */
+    uECC_vli_modMult_fast(e2, d1, e0, &curve_secp224r1);                 /* e2 <-- d1 * e0 */
+    uECC_vli_modAdd(e2, e2, t1, curve_secp224r1.p, num_words_secp224r1); /* e2 <-- e2 + t1 */
+    uECC_vli_modSquare_fast(f2, e2, &curve_secp224r1);                   /* f2 <-- e2^2 */
+    uECC_vli_modMult_fast(f2, f2, c, &curve_secp224r1);                  /* f2 <-- f2 * c */
+    /* f2 <-- p  - f2 */
+    uECC_vli_modSub(f2, curve_secp224r1.p, f2, curve_secp224r1.p, num_words_secp224r1);
+    uECC_vli_set(d2, t2, num_words_secp224r1); /* d2 <-- t2 */
+}
+
+/* Routine 3.2.7 RP;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+static void mod_sqrt_secp224r1_rp(uECC_word_t *d1,
+                                  uECC_word_t *e1,
+                                  uECC_word_t *f1,
+                                  const uECC_word_t *c,
+                                  const uECC_word_t *r) {
+    wordcount_t i;
+    wordcount_t pow2i = 1;
+    uECC_word_t d0[num_words_secp224r1];
+    uECC_word_t e0[num_words_secp224r1] = {1}; /* e0 <-- 1 */
+    uECC_word_t f0[num_words_secp224r1];
+
+    uECC_vli_set(d0, r, num_words_secp224r1); /* d0 <-- r */
+    /* f0 <-- p  - c */
+    uECC_vli_modSub(f0, curve_secp224r1.p, c, curve_secp224r1.p, num_words_secp224r1);
+    for (i = 0; i <= 6; i++) {
+        mod_sqrt_secp224r1_rss(d1, e1, f1, d0, e0, f0, pow2i); /* RSS (d1,e1,f1,d0,e0,f0,2^i) */
+        mod_sqrt_secp224r1_rm(d1, e1, f1, c, d1, e1, d0, e0);  /* RM (d1,e1,f1,c,d1,e1,d0,e0) */
+        uECC_vli_set(d0, d1, num_words_secp224r1); /* d0 <-- d1 */
+        uECC_vli_set(e0, e1, num_words_secp224r1); /* e0 <-- e1 */
+        uECC_vli_set(f0, f1, num_words_secp224r1); /* f0 <-- f1 */
+        pow2i *= 2;
+    }
+}
+
+/* Compute a = sqrt(a) (mod curve_p). */
+/* Routine 3.2.8 mp_mod_sqrt_224; from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve) {
+    bitcount_t i;
+    uECC_word_t e1[num_words_secp224r1];
+    uECC_word_t f1[num_words_secp224r1];
+    uECC_word_t d0[num_words_secp224r1];
+    uECC_word_t e0[num_words_secp224r1];
+    uECC_word_t f0[num_words_secp224r1];
+    uECC_word_t d1[num_words_secp224r1];
+
+    /* s = a; using constant instead of random value */
+    mod_sqrt_secp224r1_rp(d0, e0, f0, a, a);           /* RP (d0, e0, f0, c, s) */
+    mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0);     /* RS (d1, e1, f1, d0, e0, f0) */
+    for (i = 1; i <= 95; i++) {
+        uECC_vli_set(d0, d1, num_words_secp224r1);          /* d0 <-- d1 */
+        uECC_vli_set(e0, e1, num_words_secp224r1);          /* e0 <-- e1 */
+        uECC_vli_set(f0, f1, num_words_secp224r1);          /* f0 <-- f1 */
+        mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0); /* RS (d1, e1, f1, d0, e0, f0) */
+        if (uECC_vli_isZero(d1, num_words_secp224r1)) {     /* if d1 == 0 */
+                break;
+        }
+    }
+    uECC_vli_modInv(f1, e0, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- 1 / e0 */
+    uECC_vli_modMult_fast(a, d0, f1, &curve_secp224r1);              /* a  <-- d0 / e0 */
+}
+#endif /* uECC_SUPPORT_COMPRESSED_POINT */
+
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+/* Computes result = product % curve_p
+   from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+#if uECC_WORD_SIZE == 1
+static void vli_mmod_fast_secp224r1(uint8_t *result, uint8_t *product) {
+    uint8_t tmp[num_words_secp224r1];
+    int8_t carry;
+
+    /* t */
+    uECC_vli_set(result, product, num_words_secp224r1);
+
+    /* s1 */
+    tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;
+    tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;
+    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;
+    tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31];
+    tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35];
+    tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39];
+    tmp[24] = product[40]; tmp[25] = product[41]; tmp[26] = product[42]; tmp[27] = product[43];
+    carry = uECC_vli_add(result, result, tmp, num_words_secp224r1);
+
+    /* s2 */
+    tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47];
+    tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51];
+    tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55];
+    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;
+    carry += uECC_vli_add(result, result, tmp, num_words_secp224r1);
+
+    /* d1 */
+    tmp[0]  = product[28]; tmp[1]  = product[29]; tmp[2]  = product[30]; tmp[3]  = product[31];
+    tmp[4]  = product[32]; tmp[5]  = product[33]; tmp[6]  = product[34]; tmp[7]  = product[35];
+    tmp[8]  = product[36]; tmp[9]  = product[37]; tmp[10] = product[38]; tmp[11] = product[39];
+    tmp[12] = product[40]; tmp[13] = product[41]; tmp[14] = product[42]; tmp[15] = product[43];
+    tmp[16] = product[44]; tmp[17] = product[45]; tmp[18] = product[46]; tmp[19] = product[47];
+    tmp[20] = product[48]; tmp[21] = product[49]; tmp[22] = product[50]; tmp[23] = product[51];
+    tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55];
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1);
+
+    /* d2 */
+    tmp[0]  = product[44]; tmp[1]  = product[45]; tmp[2]  = product[46]; tmp[3]  = product[47];
+    tmp[4]  = product[48]; tmp[5]  = product[49]; tmp[6]  = product[50]; tmp[7]  = product[51];
+    tmp[8]  = product[52]; tmp[9]  = product[53]; tmp[10] = product[54]; tmp[11] = product[55];
+    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;
+    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;
+    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;
+    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1);
+
+    if (carry < 0) {
+        do {
+            carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1);
+        } while (carry < 0);
+    } else {
+        while (carry || uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) {
+            carry -= uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1);
+        }
+    }
+}
+#elif uECC_WORD_SIZE == 4
+static void vli_mmod_fast_secp224r1(uint32_t *result, uint32_t *product)
+{
+    uint32_t tmp[num_words_secp224r1];
+    int carry;
+
+    /* t */
+    uECC_vli_set(result, product, num_words_secp224r1);
+
+    /* s1 */
+    tmp[0] = tmp[1] = tmp[2] = 0;
+    tmp[3] = product[7];
+    tmp[4] = product[8];
+    tmp[5] = product[9];
+    tmp[6] = product[10];
+    carry = uECC_vli_add(result, result, tmp, num_words_secp224r1);
+
+    /* s2 */
+    tmp[3] = product[11];
+    tmp[4] = product[12];
+    tmp[5] = product[13];
+    tmp[6] = 0;
+    carry += uECC_vli_add(result, result, tmp, num_words_secp224r1);
+
+    /* d1 */
+    tmp[0] = product[7];
+    tmp[1] = product[8];
+    tmp[2] = product[9];
+    tmp[3] = product[10];
+    tmp[4] = product[11];
+    tmp[5] = product[12];
+    tmp[6] = product[13];
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1);
+
+    /* d2 */
+    tmp[0] = product[11];
+    tmp[1] = product[12];
+    tmp[2] = product[13];
+    tmp[3] = tmp[4] = tmp[5] = tmp[6] = 0;
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1);
+
+    if (carry < 0) {
+        do {
+            carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1);
+        } while (carry < 0);
+    } else {
+        while (carry || uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) {
+            carry -= uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1);
+        }
+    }
+}
+#else
+static void vli_mmod_fast_secp224r1(uint64_t *result, uint64_t *product)
+{
+    uint64_t tmp[num_words_secp224r1];
+    int carry = 0;
+
+    /* t */
+    uECC_vli_set(result, product, num_words_secp224r1);
+    result[num_words_secp224r1 - 1] &= 0xffffffff;
+
+    /* s1 */
+    tmp[0] = 0;
+    tmp[1] = product[3] & 0xffffffff00000000ull;
+    tmp[2] = product[4];
+    tmp[3] = product[5] & 0xffffffff;
+    uECC_vli_add(result, result, tmp, num_words_secp224r1);
+
+    /* s2 */
+    tmp[1] = product[5] & 0xffffffff00000000ull;
+    tmp[2] = product[6];
+    tmp[3] = 0;
+    uECC_vli_add(result, result, tmp, num_words_secp224r1);
+
+    /* d1 */
+    tmp[0] = (product[3] >> 32) | (product[4] << 32);
+    tmp[1] = (product[4] >> 32) | (product[5] << 32);
+    tmp[2] = (product[5] >> 32) | (product[6] << 32);
+    tmp[3] = product[6] >> 32;
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1);
+
+    /* d2 */
+    tmp[0] = (product[5] >> 32) | (product[6] << 32);
+    tmp[1] = product[6] >> 32;
+    tmp[2] = tmp[3] = 0;
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1);
+
+    if (carry < 0) {
+        do {
+            carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1);
+        } while (carry < 0);
+    } else {
+        while (uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) {
+            uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1);
+        }
+    }
+}
+#endif /* uECC_WORD_SIZE */
+#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */
+
+#endif /* uECC_SUPPORTS_secp224r1 */
+
+#if uECC_SUPPORTS_secp256r1
+
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+static void vli_mmod_fast_secp256r1(uECC_word_t *result, uECC_word_t *product);
+#endif
+
+static const struct uECC_Curve_t curve_secp256r1 = {
+    num_words_secp256r1,
+    num_bytes_secp256r1,
+    256, /* num_n_bits */
+    { BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
+        BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00),
+        BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),
+        BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF) },
+    { BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3),
+        BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC),
+        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
+        BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF) },
+    { BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4),
+        BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77),
+        BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8),
+        BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B),
+
+        BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB),
+        BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B),
+        BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E),
+        BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F) },
+    { BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B),
+        BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65),
+        BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3),
+        BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A) },
+    &double_jacobian_default,
+#if uECC_SUPPORT_COMPRESSED_POINT
+    &mod_sqrt_default,
+#endif
+    &x_side_default,
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+    &vli_mmod_fast_secp256r1
+#endif
+};
+
+uECC_Curve uECC_secp256r1(void) { return &curve_secp256r1; }
+
+
+#if (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256r1)
+/* Computes result = product % curve_p
+   from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+#if uECC_WORD_SIZE == 1
+static void vli_mmod_fast_secp256r1(uint8_t *result, uint8_t *product) {
+    uint8_t tmp[num_words_secp256r1];
+    int8_t carry;
+    
+    /* t */
+    uECC_vli_set(result, product, num_words_secp256r1);
+    
+    /* s1 */
+    tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;
+    tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;
+    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;
+    tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47];
+    tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51];
+    tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55];
+    tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59];
+    tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63];
+    carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1);
+    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);
+    
+    /* s2 */
+    tmp[12] = product[48]; tmp[13] = product[49]; tmp[14] = product[50]; tmp[15] = product[51];
+    tmp[16] = product[52]; tmp[17] = product[53]; tmp[18] = product[54]; tmp[19] = product[55];
+    tmp[20] = product[56]; tmp[21] = product[57]; tmp[22] = product[58]; tmp[23] = product[59];
+    tmp[24] = product[60]; tmp[25] = product[61]; tmp[26] = product[62]; tmp[27] = product[63];
+    tmp[28] = tmp[29] = tmp[30] = tmp[31] = 0;
+    carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1);
+    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);
+    
+    /* s3 */
+    tmp[0] = product[32]; tmp[1] = product[33]; tmp[2] = product[34]; tmp[3] = product[35];
+    tmp[4] = product[36]; tmp[5] = product[37]; tmp[6] = product[38]; tmp[7] = product[39];
+    tmp[8] = product[40]; tmp[9] = product[41]; tmp[10] = product[42]; tmp[11] = product[43];
+    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;
+    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;
+    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;
+    tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59];
+    tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63];
+    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);
+    
+    /* s4 */
+    tmp[0] = product[36]; tmp[1] = product[37]; tmp[2] = product[38]; tmp[3] = product[39];
+    tmp[4] = product[40]; tmp[5] = product[41]; tmp[6] = product[42]; tmp[7] = product[43];
+    tmp[8] = product[44]; tmp[9] = product[45]; tmp[10] = product[46]; tmp[11] = product[47];
+    tmp[12] = product[52]; tmp[13] = product[53]; tmp[14] = product[54]; tmp[15] = product[55];
+    tmp[16] = product[56]; tmp[17] = product[57]; tmp[18] = product[58]; tmp[19] = product[59];
+    tmp[20] = product[60]; tmp[21] = product[61]; tmp[22] = product[62]; tmp[23] = product[63];
+    tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55];
+    tmp[28] = product[32]; tmp[29] = product[33]; tmp[30] = product[34]; tmp[31] = product[35];
+    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);
+    
+    /* d1 */
+    tmp[0] = product[44]; tmp[1] = product[45]; tmp[2] = product[46]; tmp[3] = product[47];
+    tmp[4] = product[48]; tmp[5] = product[49]; tmp[6] = product[50]; tmp[7] = product[51];
+    tmp[8] = product[52]; tmp[9] = product[53]; tmp[10] = product[54]; tmp[11] = product[55];
+    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;
+    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;
+    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;
+    tmp[24] = product[32]; tmp[25] = product[33]; tmp[26] = product[34]; tmp[27] = product[35];
+    tmp[28] = product[40]; tmp[29] = product[41]; tmp[30] = product[42]; tmp[31] = product[43];
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);
+    
+    /* d2 */
+    tmp[0] = product[48]; tmp[1] = product[49]; tmp[2] = product[50]; tmp[3] = product[51];
+    tmp[4] = product[52]; tmp[5] = product[53]; tmp[6] = product[54]; tmp[7] = product[55];
+    tmp[8] = product[56]; tmp[9] = product[57]; tmp[10] = product[58]; tmp[11] = product[59];
+    tmp[12] = product[60]; tmp[13] = product[61]; tmp[14] = product[62]; tmp[15] = product[63];
+    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;
+    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;
+    tmp[24] = product[36]; tmp[25] = product[37]; tmp[26] = product[38]; tmp[27] = product[39];
+    tmp[28] = product[44]; tmp[29] = product[45]; tmp[30] = product[46]; tmp[31] = product[47];
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);
+    
+    /* d3 */
+    tmp[0] = product[52]; tmp[1] = product[53]; tmp[2] = product[54]; tmp[3] = product[55];
+    tmp[4] = product[56]; tmp[5] = product[57]; tmp[6] = product[58]; tmp[7] = product[59];
+    tmp[8] = product[60]; tmp[9] = product[61]; tmp[10] = product[62]; tmp[11] = product[63];
+    tmp[12] = product[32]; tmp[13] = product[33]; tmp[14] = product[34]; tmp[15] = product[35];
+    tmp[16] = product[36]; tmp[17] = product[37]; tmp[18] = product[38]; tmp[19] = product[39];
+    tmp[20] = product[40]; tmp[21] = product[41]; tmp[22] = product[42]; tmp[23] = product[43];
+    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;
+    tmp[28] = product[48]; tmp[29] = product[49]; tmp[30] = product[50]; tmp[31] = product[51];
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);
+    
+    /* d4 */
+    tmp[0] = product[56]; tmp[1] = product[57]; tmp[2] = product[58]; tmp[3] = product[59];
+    tmp[4] = product[60]; tmp[5] = product[61]; tmp[6] = product[62]; tmp[7] = product[63];
+    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;
+    tmp[12] = product[36]; tmp[13] = product[37]; tmp[14] = product[38]; tmp[15] = product[39];
+    tmp[16] = product[40]; tmp[17] = product[41]; tmp[18] = product[42]; tmp[19] = product[43];
+    tmp[20] = product[44]; tmp[21] = product[45]; tmp[22] = product[46]; tmp[23] = product[47];
+    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;
+    tmp[28] = product[52]; tmp[29] = product[53]; tmp[30] = product[54]; tmp[31] = product[55];
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);
+    
+    if (carry < 0) {
+        do {
+            carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1);
+        } while (carry < 0);
+    } else {
+        while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) {
+            carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1);
+        }
+    }
+}
+#elif uECC_WORD_SIZE == 4
+static void vli_mmod_fast_secp256r1(uint32_t *result, uint32_t *product) {
+    uint32_t tmp[num_words_secp256r1];
+    int carry;
+    
+    /* t */
+    uECC_vli_set(result, product, num_words_secp256r1);
+    
+    /* s1 */
+    tmp[0] = tmp[1] = tmp[2] = 0;
+    tmp[3] = product[11];
+    tmp[4] = product[12];
+    tmp[5] = product[13];
+    tmp[6] = product[14];
+    tmp[7] = product[15];
+    carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1);
+    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);
+    
+    /* s2 */
+    tmp[3] = product[12];
+    tmp[4] = product[13];
+    tmp[5] = product[14];
+    tmp[6] = product[15];
+    tmp[7] = 0;
+    carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1);
+    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);
+    
+    /* s3 */
+    tmp[0] = product[8];
+    tmp[1] = product[9];
+    tmp[2] = product[10];
+    tmp[3] = tmp[4] = tmp[5] = 0;
+    tmp[6] = product[14];
+    tmp[7] = product[15];
+    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);
+    
+    /* s4 */
+    tmp[0] = product[9];
+    tmp[1] = product[10];
+    tmp[2] = product[11];
+    tmp[3] = product[13];
+    tmp[4] = product[14];
+    tmp[5] = product[15];
+    tmp[6] = product[13];
+    tmp[7] = product[8];
+    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);
+    
+    /* d1 */
+    tmp[0] = product[11];
+    tmp[1] = product[12];
+    tmp[2] = product[13];
+    tmp[3] = tmp[4] = tmp[5] = 0;
+    tmp[6] = product[8];
+    tmp[7] = product[10];
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);
+    
+    /* d2 */
+    tmp[0] = product[12];
+    tmp[1] = product[13];
+    tmp[2] = product[14];
+    tmp[3] = product[15];
+    tmp[4] = tmp[5] = 0;
+    tmp[6] = product[9];
+    tmp[7] = product[11];
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);
+    
+    /* d3 */
+    tmp[0] = product[13];
+    tmp[1] = product[14];
+    tmp[2] = product[15];
+    tmp[3] = product[8];
+    tmp[4] = product[9];
+    tmp[5] = product[10];
+    tmp[6] = 0;
+    tmp[7] = product[12];
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);
+    
+    /* d4 */
+    tmp[0] = product[14];
+    tmp[1] = product[15];
+    tmp[2] = 0;
+    tmp[3] = product[9];
+    tmp[4] = product[10];
+    tmp[5] = product[11];
+    tmp[6] = 0;
+    tmp[7] = product[13];
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);
+    
+    if (carry < 0) {
+        do {
+            carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1);
+        } while (carry < 0);
+    } else {
+        while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) {
+            carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1);
+        }
+    }
+}
+#else
+static void vli_mmod_fast_secp256r1(uint64_t *result, uint64_t *product) {
+    uint64_t tmp[num_words_secp256r1];
+    int carry;
+    
+    /* t */
+    uECC_vli_set(result, product, num_words_secp256r1);
+    
+    /* s1 */
+    tmp[0] = 0;
+    tmp[1] = product[5] & 0xffffffff00000000ull;
+    tmp[2] = product[6];
+    tmp[3] = product[7];
+    carry = (int)uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1);
+    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);
+    
+    /* s2 */
+    tmp[1] = product[6] << 32;
+    tmp[2] = (product[6] >> 32) | (product[7] << 32);
+    tmp[3] = product[7] >> 32;
+    carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1);
+    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);
+    
+    /* s3 */
+    tmp[0] = product[4];
+    tmp[1] = product[5] & 0xffffffff;
+    tmp[2] = 0;
+    tmp[3] = product[7];
+    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);
+    
+    /* s4 */
+    tmp[0] = (product[4] >> 32) | (product[5] << 32);
+    tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull);
+    tmp[2] = product[7];
+    tmp[3] = (product[6] >> 32) | (product[4] << 32);
+    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);
+    
+    /* d1 */
+    tmp[0] = (product[5] >> 32) | (product[6] << 32);
+    tmp[1] = (product[6] >> 32);
+    tmp[2] = 0;
+    tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32);
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);
+    
+    /* d2 */
+    tmp[0] = product[6];
+    tmp[1] = product[7];
+    tmp[2] = 0;
+    tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull);
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);
+    
+    /* d3 */
+    tmp[0] = (product[6] >> 32) | (product[7] << 32);
+    tmp[1] = (product[7] >> 32) | (product[4] << 32);
+    tmp[2] = (product[4] >> 32) | (product[5] << 32);
+    tmp[3] = (product[6] << 32);
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);
+    
+    /* d4 */
+    tmp[0] = product[7];
+    tmp[1] = product[4] & 0xffffffff00000000ull;
+    tmp[2] = product[5];
+    tmp[3] = product[6] & 0xffffffff00000000ull;
+    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);
+    
+    if (carry < 0) {
+        do {
+            carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1);
+        } while (carry < 0);
+    } else {
+        while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) {
+            carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1);
+        }
+    }
+}
+#endif /* uECC_WORD_SIZE */
+#endif /* (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256r1) */
+
+#endif /* uECC_SUPPORTS_secp256r1 */
+
+#if uECC_SUPPORTS_secp256k1
+
+static void double_jacobian_secp256k1(uECC_word_t * X1,
+                                      uECC_word_t * Y1,
+                                      uECC_word_t * Z1,
+                                      uECC_Curve curve);
+static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve);
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product);
+#endif
+
+static const struct uECC_Curve_t curve_secp256k1 = {
+    num_words_secp256k1,
+    num_bytes_secp256k1,
+    256, /* num_n_bits */
+    { BYTES_TO_WORDS_8(2F, FC, FF, FF, FE, FF, FF, FF),
+        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
+        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
+        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) },
+    { BYTES_TO_WORDS_8(41, 41, 36, D0, 8C, 5E, D2, BF),
+        BYTES_TO_WORDS_8(3B, A0, 48, AF, E6, DC, AE, BA),
+        BYTES_TO_WORDS_8(FE, FF, FF, FF, FF, FF, FF, FF),
+        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) },
+    { BYTES_TO_WORDS_8(98, 17, F8, 16, 5B, 81, F2, 59),
+        BYTES_TO_WORDS_8(D9, 28, CE, 2D, DB, FC, 9B, 02),
+        BYTES_TO_WORDS_8(07, 0B, 87, CE, 95, 62, A0, 55),
+        BYTES_TO_WORDS_8(AC, BB, DC, F9, 7E, 66, BE, 79),
+
+        BYTES_TO_WORDS_8(B8, D4, 10, FB, 8F, D0, 47, 9C),
+        BYTES_TO_WORDS_8(19, 54, 85, A6, 48, B4, 17, FD),
+        BYTES_TO_WORDS_8(A8, 08, 11, 0E, FC, FB, A4, 5D),
+        BYTES_TO_WORDS_8(65, C4, A3, 26, 77, DA, 3A, 48) },
+    { BYTES_TO_WORDS_8(07, 00, 00, 00, 00, 00, 00, 00),
+        BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),
+        BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),
+        BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00) },
+    &double_jacobian_secp256k1,
+#if uECC_SUPPORT_COMPRESSED_POINT
+    &mod_sqrt_default,
+#endif
+    &x_side_secp256k1,
+#if (uECC_OPTIMIZATION_LEVEL > 0)
+    &vli_mmod_fast_secp256k1
+#endif
+};
+
+uECC_Curve uECC_secp256k1(void) { return &curve_secp256k1; }
+
+
+/* Double in place */
+static void double_jacobian_secp256k1(uECC_word_t * X1,
+                                      uECC_word_t * Y1,
+                                      uECC_word_t * Z1,
+                                      uECC_Curve curve) {
+    /* t1 = X, t2 = Y, t3 = Z */
+    uECC_word_t t4[num_words_secp256k1];
+    uECC_word_t t5[num_words_secp256k1];
+    
+    if (uECC_vli_isZero(Z1, num_words_secp256k1)) {
+        return;
+    }
+    
+    uECC_vli_modSquare_fast(t5, Y1, curve);   /* t5 = y1^2 */
+    uECC_vli_modMult_fast(t4, X1, t5, curve); /* t4 = x1*y1^2 = A */
+    uECC_vli_modSquare_fast(X1, X1, curve);   /* t1 = x1^2 */
+    uECC_vli_modSquare_fast(t5, t5, curve);   /* t5 = y1^4 */
+    uECC_vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 = y1*z1 = z3 */
+    
+    uECC_vli_modAdd(Y1, X1, X1, curve->p, num_words_secp256k1); /* t2 = 2*x1^2 */
+    uECC_vli_modAdd(Y1, Y1, X1, curve->p, num_words_secp256k1); /* t2 = 3*x1^2 */
+    if (uECC_vli_testBit(Y1, 0)) {
+        uECC_word_t carry = uECC_vli_add(Y1, Y1, curve->p, num_words_secp256k1);
+        uECC_vli_rshift1(Y1, num_words_secp256k1);
+        Y1[num_words_secp256k1 - 1] |= carry << (uECC_WORD_BITS - 1);
+    } else {
+        uECC_vli_rshift1(Y1, num_words_secp256k1);
+    }
+    /* t2 = 3/2*(x1^2) = B */
+    
+    uECC_vli_modSquare_fast(X1, Y1, curve);                     /* t1 = B^2 */
+    uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - A */
+    uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - 2A = x3 */
+    
+    uECC_vli_modSub(t4, t4, X1, curve->p, num_words_secp256k1); /* t4 = A - x3 */
+    uECC_vli_modMult_fast(Y1, Y1, t4, curve);                   /* t2 = B * (A - x3) */
+    uECC_vli_modSub(Y1, Y1, t5, curve->p, num_words_secp256k1); /* t2 = B * (A - x3) - y1^4 = y3 */
+}
+
+/* Computes result = x^3 + b. result must not overlap x. */
+static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) {
+    uECC_vli_modSquare_fast(result, x, curve);                                /* r = x^2 */
+    uECC_vli_modMult_fast(result, result, x, curve);                          /* r = x^3 */
+    uECC_vli_modAdd(result, result, curve->b, curve->p, num_words_secp256k1); /* r = x^3 + b */
+}
+
+#if (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256k1)
+static void omega_mult_secp256k1(uECC_word_t *result, const uECC_word_t *right);
+static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product) {
+    uECC_word_t tmp[2 * num_words_secp256k1];
+    uECC_word_t carry;
+    
+    uECC_vli_clear(tmp, num_words_secp256k1);
+    uECC_vli_clear(tmp + num_words_secp256k1, num_words_secp256k1);
+    
+    omega_mult_secp256k1(tmp, product + num_words_secp256k1); /* (Rq, q) = q * c */
+    
+    carry = uECC_vli_add(result, product, tmp, num_words_secp256k1); /* (C, r) = r + q       */
+    uECC_vli_clear(product, num_words_secp256k1);
+    omega_mult_secp256k1(product, tmp + num_words_secp256k1); /* Rq*c */
+    carry += uECC_vli_add(result, result, product, num_words_secp256k1); /* (C1, r) = r + Rq*c */
+    
+    while (carry > 0) {
+        --carry;
+        uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1);
+    }
+    if (uECC_vli_cmp_unsafe(result, curve_secp256k1.p, num_words_secp256k1) > 0) {
+        uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1);
+    }
+}
+
+#if uECC_WORD_SIZE == 1
+static void omega_mult_secp256k1(uint8_t * result, const uint8_t * right) {
+    /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */
+    uECC_word_t r0 = 0;
+    uECC_word_t r1 = 0;
+    uECC_word_t r2 = 0;
+    wordcount_t k;
+    
+    /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */
+    muladd(0xD1, right[0], &r0, &r1, &r2);
+    result[0] = r0;
+    r0 = r1;
+    r1 = r2;
+    /* r2 is still 0 */
+    
+    for (k = 1; k < num_words_secp256k1; ++k) {
+        muladd(0x03, right[k - 1], &r0, &r1, &r2);
+        muladd(0xD1, right[k], &r0, &r1, &r2);
+        result[k] = r0;
+        r0 = r1;
+        r1 = r2;
+        r2 = 0;
+    }
+    muladd(0x03, right[num_words_secp256k1 - 1], &r0, &r1, &r2);
+    result[num_words_secp256k1] = r0;
+    result[num_words_secp256k1 + 1] = r1;
+    /* add the 2^32 multiple */
+    result[4 + num_words_secp256k1] =
+        uECC_vli_add(result + 4, result + 4, right, num_words_secp256k1); 
+}
+#elif uECC_WORD_SIZE == 4
+static void omega_mult_secp256k1(uint32_t * result, const uint32_t * right) {
+    /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */
+    uint32_t carry = 0;
+    wordcount_t k;
+    
+    for (k = 0; k < num_words_secp256k1; ++k) {
+        uint64_t p = (uint64_t)0x3D1 * right[k] + carry;
+        result[k] = p;
+        carry = p >> 32;
+    }
+    result[num_words_secp256k1] = carry;
+    /* add the 2^32 multiple */
+    result[1 + num_words_secp256k1] =
+        uECC_vli_add(result + 1, result + 1, right, num_words_secp256k1); 
+}
+#else
+static void omega_mult_secp256k1(uint64_t * result, const uint64_t * right) {
+    uECC_word_t r0 = 0;
+    uECC_word_t r1 = 0;
+    uECC_word_t r2 = 0;
+    wordcount_t k;
+    
+    /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */
+    for (k = 0; k < num_words_secp256k1; ++k) {
+        muladd(0x1000003D1ull, right[k], &r0, &r1, &r2);
+        result[k] = r0;
+        r0 = r1;
+        r1 = r2;
+        r2 = 0;
+    }
+    result[num_words_secp256k1] = r0;
+}
+#endif /* uECC_WORD_SIZE */
+#endif /* (uECC_OPTIMIZATION_LEVEL > 0 &&  && !asm_mmod_fast_secp256k1) */
+
+#endif /* uECC_SUPPORTS_secp256k1 */
+
+#endif /* _UECC_CURVE_SPECIFIC_H_ */

+ 67 - 0
joylink/auth/joylink3_auth_uECC_platform-specific.inc

@@ -0,0 +1,67 @@
+/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
+
+#ifndef _UECC_PLATFORM_SPECIFIC_H_
+#define _UECC_PLATFORM_SPECIFIC_H_
+
+#include "joylink3_auth_uECC_types.h"
+
+#if (defined(_WIN32) || defined(_WIN64))
+/* Windows */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <wincrypt.h>
+
+static int default_RNG(uint8_t *dest, unsigned size) {
+    HCRYPTPROV prov;
+    if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+        return 0;
+    }
+
+    CryptGenRandom(prov, size, (BYTE *)dest);
+    CryptReleaseContext(prov, 0);
+    return 1;
+}
+#define default_RNG_defined 1
+
+#elif defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \
+    (defined(__IOS__) && defined(__MACH__)) || defined(uECC_POSIX)
+
+/* Some POSIX-like system with /dev/urandom or /dev/random. */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifndef O_CLOEXEC
+    #define O_CLOEXEC 0
+#endif
+
+static int default_RNG(uint8_t *dest, unsigned size) {
+    int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
+    if (fd == -1) {
+        fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
+        if (fd == -1) {
+            return 0;
+        }
+    }
+    
+    char *ptr = (char *)dest;
+    size_t left = size;
+    while (left > 0) {
+        ssize_t bytes_read = read(fd, ptr, left);
+        if (bytes_read <= 0) { // read failed
+            close(fd);
+            return 0;
+        }
+        left -= bytes_read;
+        ptr += bytes_read;
+    }
+    
+    close(fd);
+    return 1;
+}
+#define default_RNG_defined 1
+
+#endif /* platform */
+
+#endif /* _UECC_PLATFORM_SPECIFIC_H_ */

+ 107 - 0
joylink/auth/joylink3_auth_uECC_types.h

@@ -0,0 +1,107 @@
+/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
+
+#ifndef _UECC_TYPES_H_
+#define _UECC_TYPES_H_
+
+#if defined(__QC_4010__)
+#include "joylink_utils.h"
+#endif
+
+#ifndef uECC_PLATFORM
+    #if __AVR__
+        #define uECC_PLATFORM jl3_uECC_avr
+    #elif defined(__thumb2__) || defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */
+        #define uECC_PLATFORM jl3_uECC_arm_thumb2
+    #elif defined(__thumb__)
+        #define uECC_PLATFORM uECC_arm_thumb
+    #elif defined(__arm__) || defined(_M_ARM)
+        #define uECC_PLATFORM uECC_arm
+    #elif defined(__aarch64__)
+        #define uECC_PLATFORM uECC_arm64
+    #elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__)
+        #define uECC_PLATFORM uECC_x86
+    #elif defined(__amd64__) || defined(_M_X64)
+        #define uECC_PLATFORM uECC_x86_64
+    #else
+        #define uECC_PLATFORM uECC_arch_other
+    #endif
+#endif
+
+#ifdef __RT_THREAD__
+#undef  uECC_PLATFORM
+#define uECC_PLATFORM uECC_arch_other
+#endif
+
+#ifndef uECC_WORD_SIZE
+    #if uECC_PLATFORM == jl3_uECC_avr
+        #define uECC_WORD_SIZE 1
+    #elif (uECC_PLATFORM == uECC_x86_64 || uECC_PLATFORM == uECC_arm64)
+        #define uECC_WORD_SIZE 8
+    #else
+        #define uECC_WORD_SIZE 4
+    #endif
+#endif
+
+#if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8)
+    #error "Unsupported value for uECC_WORD_SIZE"
+#endif
+
+#if ((uECC_PLATFORM == jl3_uECC_avr) && (uECC_WORD_SIZE != 1))
+    #pragma message ("uECC_WORD_SIZE must be 1 for AVR")
+    #undef uECC_WORD_SIZE
+    #define uECC_WORD_SIZE 1
+#endif
+
+#if ((uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \
+        uECC_PLATFORM ==  jl3_uECC_arm_thumb2) && \
+     (uECC_WORD_SIZE != 4))
+    #pragma message ("uECC_WORD_SIZE must be 4 for ARM")
+    #undef uECC_WORD_SIZE
+    #define uECC_WORD_SIZE 4
+#endif
+
+#if defined(__SIZEOF_INT128__) || ((__clang_major__ * 100 + __clang_minor__) >= 302)
+    #define SUPPORTS_INT128 1
+#else
+    #define SUPPORTS_INT128 0
+#endif
+
+typedef int8_t wordcount_t;
+typedef int16_t bitcount_t;
+typedef int8_t cmpresult_t;
+
+#if (uECC_WORD_SIZE == 1)
+
+typedef uint8_t uECC_word_t;
+typedef uint16_t uECC_dword_t;
+
+#define HIGH_BIT_SET 0x80
+#define uECC_WORD_BITS 8
+#define uECC_WORD_BITS_SHIFT 3
+#define uECC_WORD_BITS_MASK 0x07
+
+#elif (uECC_WORD_SIZE == 4)
+
+typedef uint32_t uECC_word_t;
+typedef uint64_t uECC_dword_t;
+
+#define HIGH_BIT_SET 0x80000000
+#define uECC_WORD_BITS 32
+#define uECC_WORD_BITS_SHIFT 5
+#define uECC_WORD_BITS_MASK 0x01F
+
+#elif (uECC_WORD_SIZE == 8)
+
+typedef uint64_t uECC_word_t;
+#if SUPPORTS_INT128
+typedef unsigned __int128 uECC_dword_t;
+#endif
+
+#define HIGH_BIT_SET 0x8000000000000000ull
+#define uECC_WORD_BITS 64
+#define uECC_WORD_BITS_SHIFT 6
+#define uECC_WORD_BITS_MASK 0x03F
+
+#endif /* uECC_WORD_SIZE */
+
+#endif /* _UECC_TYPES_H_ */

+ 172 - 0
joylink/auth/joylink3_auth_uECC_vli.h

@@ -0,0 +1,172 @@
+/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
+
+#ifndef _UECC_VLI_H_
+#define _UECC_VLI_H_
+
+#include "joylink3_auth_uECC.h"
+#include "joylink3_auth_uECC_types.h"
+
+/* Functions for raw large-integer manipulation. These are only available
+   if uECC.c is compiled with uECC_ENABLE_VLI_API defined to 1. */
+#ifndef uECC_ENABLE_VLI_API
+    #define uECC_ENABLE_VLI_API 0
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if uECC_ENABLE_VLI_API
+
+void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words);
+
+/* Constant-time comparison to zero - secure way to compare long integers */
+/* Returns 1 if vli == 0, 0 otherwise. */
+uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words);
+
+/* Returns nonzero if bit 'bit' of vli is set. */
+uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit);
+
+/* Counts the number of bits required to represent vli. */
+bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words);
+
+/* Sets dest = src. */
+void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words);
+
+/* Constant-time comparison function - secure way to compare long integers */
+/* Returns one if left == right, zero otherwise */
+uECC_word_t uECC_vli_equal(const uECC_word_t *left,
+                           const uECC_word_t *right,
+                           wordcount_t num_words);
+
+/* Constant-time comparison function - secure way to compare long integers */
+/* Returns sign of left - right, in constant time. */
+cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words);
+
+/* Computes vli = vli >> 1. */
+void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words);
+
+/* Computes result = left + right, returning carry. Can modify in place. */
+uECC_word_t uECC_vli_add(uECC_word_t *result,
+                         const uECC_word_t *left,
+                         const uECC_word_t *right,
+                         wordcount_t num_words);
+
+/* Computes result = left - right, returning borrow. Can modify in place. */
+uECC_word_t uECC_vli_sub(uECC_word_t *result,
+                         const uECC_word_t *left,
+                         const uECC_word_t *right,
+                         wordcount_t num_words);
+
+/* Computes result = left * right. Result must be 2 * num_words long. */
+void uECC_vli_mult(uECC_word_t *result,
+                   const uECC_word_t *left,
+                   const uECC_word_t *right,
+                   wordcount_t num_words);
+
+/* Computes result = left^2. Result must be 2 * num_words long. */
+void uECC_vli_square(uECC_word_t *result, const uECC_word_t *left, wordcount_t num_words);
+
+/* Computes result = (left + right) % mod.
+   Assumes that left < mod and right < mod, and that result does not overlap mod. */
+void uECC_vli_modAdd(uECC_word_t *result,
+                     const uECC_word_t *left,
+                     const uECC_word_t *right,
+                     const uECC_word_t *mod,
+                     wordcount_t num_words);
+
+/* Computes result = (left - right) % mod.
+   Assumes that left < mod and right < mod, and that result does not overlap mod. */
+void uECC_vli_modSub(uECC_word_t *result,
+                     const uECC_word_t *left,
+                     const uECC_word_t *right,
+                     const uECC_word_t *mod,
+                     wordcount_t num_words);
+
+/* Computes result = product % mod, where product is 2N words long.
+   Currently only designed to work for mod == curve->p or curve_n. */
+void uECC_vli_mmod(uECC_word_t *result,
+                   uECC_word_t *product,
+                   const uECC_word_t *mod,
+                   wordcount_t num_words);
+
+/* Calculates result = product (mod curve->p), where product is up to
+   2 * curve->num_words long. */
+void uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product, uECC_Curve curve);
+
+/* Computes result = (left * right) % mod.
+   Currently only designed to work for mod == curve->p or curve_n. */
+void uECC_vli_modMult(uECC_word_t *result,
+                      const uECC_word_t *left,
+                      const uECC_word_t *right,
+                      const uECC_word_t *mod,
+                      wordcount_t num_words);
+
+/* Computes result = (left * right) % curve->p. */
+void uECC_vli_modMult_fast(uECC_word_t *result,
+                           const uECC_word_t *left,
+                           const uECC_word_t *right,
+                           uECC_Curve curve);
+
+/* Computes result = left^2 % mod.
+   Currently only designed to work for mod == curve->p or curve_n. */
+void uECC_vli_modSquare(uECC_word_t *result,
+                        const uECC_word_t *left,
+                        const uECC_word_t *mod,
+                        wordcount_t num_words);
+
+/* Computes result = left^2 % curve->p. */
+void uECC_vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left, uECC_Curve curve);
+
+/* Computes result = (1 / input) % mod.*/
+void uECC_vli_modInv(uECC_word_t *result,
+                     const uECC_word_t *input,
+                     const uECC_word_t *mod,
+                     wordcount_t num_words);
+
+#if uECC_SUPPORT_COMPRESSED_POINT
+/* Calculates a = sqrt(a) (mod curve->p) */
+void uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve);
+#endif
+
+/* Converts an integer in uECC native format to big-endian bytes. */
+void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes, const uECC_word_t *native);
+/* Converts big-endian bytes to an integer in uECC native format. */
+void uECC_vli_bytesToNative(uECC_word_t *native, const uint8_t *bytes, int num_bytes);
+
+unsigned uECC_curve_num_words(uECC_Curve curve);
+unsigned uECC_curve_num_bytes(uECC_Curve curve);
+unsigned uECC_curve_num_bits(uECC_Curve curve);
+unsigned uECC_curve_num_n_words(uECC_Curve curve);
+unsigned uECC_curve_num_n_bytes(uECC_Curve curve);
+unsigned uECC_curve_num_n_bits(uECC_Curve curve);
+
+const uECC_word_t *uECC_curve_p(uECC_Curve curve);
+const uECC_word_t *uECC_curve_n(uECC_Curve curve);
+const uECC_word_t *uECC_curve_G(uECC_Curve curve);
+const uECC_word_t *uECC_curve_b(uECC_Curve curve);
+
+int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve);
+
+/* Multiplies a point by a scalar. Points are represented by the X coordinate followed by
+   the Y coordinate in the same array, both coordinates are curve->num_words long. Note
+   that scalar must be curve->num_n_words long (NOT curve->num_words). */
+void uECC_point_mult(uECC_word_t *result,
+                     const uECC_word_t *point,
+                     const uECC_word_t *scalar,
+                     uECC_Curve curve);
+
+/* Generates a random integer in the range 0 < random < top.
+   Both random and top have num_words words. */
+int uECC_generate_random_int(uECC_word_t *random,
+                             const uECC_word_t *top,
+                             wordcount_t num_words);
+
+#endif /* uECC_ENABLE_VLI_API */
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif /* _UECC_VLI_H_ */

+ 725 - 0
joylink/auth/joylink_aes.c

@@ -0,0 +1,725 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "joylink_aes.h"
+
+static int joylinkPadding(UINT8 *data, UINT32 len, UINT32 maxLen, int isPKCS5)
+{
+    if (isPKCS5)
+    {
+        int i;
+        UINT8 padding = 16;
+        
+        if ( len % 16 )
+            padding = 16 - ( len % 16 );
+        
+        if ( ( len + padding ) > maxLen )
+            return JOYLINK_ENCINFO_ERR;
+        
+        for ( i=0; i<padding; i++ )
+            data[len + i] = padding;
+        return len + padding;
+    }
+    else
+    {
+        len = (len + 15) & 0xfffffff0;
+        if (len > maxLen)
+            return JOYLINK_ENCINFO_ERR;
+        return len;
+    }
+}
+
+static int joylinkUnPadding(UINT8 *data, UINT32 len, int isPKCS5)
+{
+    if ( len % 16 )
+        return JOYLINK_ENCINFO_ERR;
+    
+    if (isPKCS5)
+    {
+        int i;
+        UINT8 padding;
+        
+        padding = data[len - 1];
+        for (i=0; i<padding; i++)
+        {
+            if (data[len - 1 - i] != padding)
+                return JOYLINK_RECV_DATA_ERR;
+        }
+        
+        return len - padding;
+    }
+    else
+    {
+        return len;
+    }
+}
+
+#if ( HARDWARE_AES == 0 )
+
+typedef struct
+{
+    int nr;                     /*!<  number of rounds  */
+    unsigned long *rk;          /*!<  AES round keys    */
+    unsigned long buf[68];      /*!<  unaligned data    */
+}joylinkEnc2Context;
+
+/*
+ * 32-bit integer manipulation macros (little endian)
+ */
+#ifndef JOYLINK_GET_ULONG_LE
+#define JOYLINK_GET_ULONG_LE(n,b,i)                             \
+{                                                       \
+(n) = ( (unsigned long) (b)[(i)    ]       )        \
+| ( (unsigned long) (b)[(i) + 1] <<  8 )        \
+| ( (unsigned long) (b)[(i) + 2] << 16 )        \
+| ( (unsigned long) (b)[(i) + 3] << 24 );       \
+}
+#endif
+
+#ifndef JOYLINK_PUT_ULONG_LE
+#define JOYLINK_PUT_ULONG_LE(n,b,i)                             \
+{                                                       \
+(b)[(i)    ] = (unsigned char) ( (n)       );       \
+(b)[(i) + 1] = (unsigned char) ( (n) >>  8 );       \
+(b)[(i) + 2] = (unsigned char) ( (n) >> 16 );       \
+(b)[(i) + 3] = (unsigned char) ( (n) >> 24 );       \
+}
+#endif
+
+/*
+ * Forward S-box & tables
+ */
+static unsigned char FSb[256];
+static unsigned long FT0[256];
+static unsigned long FT1[256];
+static unsigned long FT2[256];
+static unsigned long FT3[256];
+
+/*
+ * Reverse S-box & tables
+ */
+static unsigned char RSb[256];
+static unsigned long RT0[256];
+static unsigned long RT1[256];
+static unsigned long RT2[256];
+static unsigned long RT3[256];
+
+/*
+ * Round constants
+ */
+static unsigned long RCON[10];
+
+/*
+ * Tables generation code
+ */
+#define JOYLINKROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 )
+#define JOYLINKXTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) )
+#define JOYLINKMUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 )
+
+static int joylink_enc2_init_done = 0;
+
+static void joylink_enc2_gen_tables( void )
+{
+    int i, x, y, z;
+    int pow[256];
+    int log[256];
+    
+    /*
+     * compute pow and log tables over GF(2^8)
+     */
+    for( i = 0, x = 1; i < 256; i++ )
+    {
+        pow[i] = x;
+        log[x] = i;
+        x = ( x ^ JOYLINKXTIME( x ) ) & 0xFF;
+    }
+    
+    /*
+     * calculate the round constants
+     */
+    for( i = 0, x = 1; i < 10; i++ )
+    {
+        RCON[i] = (unsigned long) x;
+        x = JOYLINKXTIME( x ) & 0xFF;
+    }
+    
+    /*
+     * generate the forward and reverse S-boxes
+     */
+    FSb[0x00] = 0x63;
+    RSb[0x63] = 0x00;
+    
+    for( i = 1; i < 256; i++ )
+    {
+        x = pow[255 - log[i]];
+        
+        y  = x; y = ( (y << 1) | (y >> 7) ) & 0xFF;
+        x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF;
+        x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF;
+        x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF;
+        x ^= y ^ 0x63;
+        
+        FSb[i] = (unsigned char) x;
+        RSb[x] = (unsigned char) i;
+    }
+    
+    /*
+     * generate the forward and reverse tables
+     */
+    for( i = 0; i < 256; i++ )
+    {
+        x = FSb[i];
+        y = JOYLINKXTIME( x ) & 0xFF;
+        z =  ( y ^ x ) & 0xFF;
+        
+        FT0[i] = ( (unsigned long) y       ) ^
+        ( (unsigned long) x <<  8 ) ^
+        ( (unsigned long) x << 16 ) ^
+        ( (unsigned long) z << 24 );
+        
+        FT1[i] = JOYLINKROTL8( FT0[i] );
+        FT2[i] = JOYLINKROTL8( FT1[i] );
+        FT3[i] = JOYLINKROTL8( FT2[i] );
+        
+        x = RSb[i];
+        
+        RT0[i] = ( (unsigned long) JOYLINKMUL( 0x0E, x )       ) ^
+        ( (unsigned long) JOYLINKMUL( 0x09, x ) <<  8 ) ^
+        ( (unsigned long) JOYLINKMUL( 0x0D, x ) << 16 ) ^
+        ( (unsigned long) JOYLINKMUL( 0x0B, x ) << 24 );
+        
+        RT1[i] = JOYLINKROTL8( RT0[i] );
+        RT2[i] = JOYLINKROTL8( RT1[i] );
+        RT3[i] = JOYLINKROTL8( RT2[i] );
+    }
+}
+
+/*
+ * AES key schedule (encryption)
+ */
+static int joylink_enc2_setkey_enc(joylinkEnc2Context *ctx, const unsigned char *key, unsigned int keysize)
+{
+    unsigned int i;
+    unsigned long *RK;
+    
+    if( joylink_enc2_init_done == 0 )
+    {
+        joylink_enc2_gen_tables();
+        joylink_enc2_init_done = 1;
+    }
+    
+    switch( keysize )
+    {
+        case 128: ctx->nr = 10; break;
+        case 192: ctx->nr = 12; break;
+        case 256: ctx->nr = 14; break;
+        default : return( JOYLINK_ENCINFO_ERR );
+    }
+    
+    ctx->rk = RK = ctx->buf;
+    
+    for( i = 0; i < (keysize >> 5); i++ )
+    {
+        JOYLINK_GET_ULONG_LE( RK[i], key, i << 2 );
+    }
+    
+    switch( ctx->nr )
+    {
+        case 10:
+            
+            for( i = 0; i < 10; i++, RK += 4 )
+            {
+                RK[4]  = RK[0] ^ RCON[i] ^
+                ( (unsigned long) FSb[ ( RK[3] >>  8 ) & 0xFF ]       ) ^
+                ( (unsigned long) FSb[ ( RK[3] >> 16 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) FSb[ ( RK[3]       ) & 0xFF ] << 24 );
+                
+                RK[5]  = RK[1] ^ RK[4];
+                RK[6]  = RK[2] ^ RK[5];
+                RK[7]  = RK[3] ^ RK[6];
+            }
+            break;
+            
+        case 12:
+            
+            for( i = 0; i < 8; i++, RK += 6 )
+            {
+                RK[6]  = RK[0] ^ RCON[i] ^
+                ( (unsigned long) FSb[ ( RK[5] >>  8 ) & 0xFF ]       ) ^
+                ( (unsigned long) FSb[ ( RK[5] >> 16 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) FSb[ ( RK[5]       ) & 0xFF ] << 24 );
+                
+                RK[7]  = RK[1] ^ RK[6];
+                RK[8]  = RK[2] ^ RK[7];
+                RK[9]  = RK[3] ^ RK[8];
+                RK[10] = RK[4] ^ RK[9];
+                RK[11] = RK[5] ^ RK[10];
+            }
+            break;
+            
+        case 14:
+            
+            for( i = 0; i < 7; i++, RK += 8 )
+            {
+                RK[8]  = RK[0] ^ RCON[i] ^
+                ( (unsigned long) FSb[ ( RK[7] >>  8 ) & 0xFF ]       ) ^
+                ( (unsigned long) FSb[ ( RK[7] >> 16 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) FSb[ ( RK[7]       ) & 0xFF ] << 24 );
+                
+                RK[9]  = RK[1] ^ RK[8];
+                RK[10] = RK[2] ^ RK[9];
+                RK[11] = RK[3] ^ RK[10];
+                
+                RK[12] = RK[4] ^
+                ( (unsigned long) FSb[ ( RK[11]       ) & 0xFF ]       ) ^
+                ( (unsigned long) FSb[ ( RK[11] >>  8 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 );
+                
+                RK[13] = RK[5] ^ RK[12];
+                RK[14] = RK[6] ^ RK[13];
+                RK[15] = RK[7] ^ RK[14];
+            }
+            break;
+            
+        default:
+            
+            break;
+    }
+    
+    return( 0 );
+}
+
+/*
+ * AES key schedule (decryption)
+ */
+static int joylink_enc2_setkey_dec( joylinkEnc2Context *ctx, const unsigned char *key, unsigned int keysize )
+{
+    int i, j;
+    joylinkEnc2Context cty;
+    unsigned long *RK;
+    unsigned long *SK;
+    int ret;
+    
+    switch( keysize )
+    {
+        case 128: ctx->nr = 10; break;
+        case 192: ctx->nr = 12; break;
+        case 256: ctx->nr = 14; break;
+        default : return( JOYLINK_ENCINFO_ERR );
+    }
+    
+    ctx->rk = RK = ctx->buf;
+    
+    ret = joylink_enc2_setkey_enc( &cty, key, keysize );
+    if( ret != 0 )
+        return( ret );
+    
+    SK = cty.rk + cty.nr * 4;
+    
+    *RK++ = *SK++;
+    *RK++ = *SK++;
+    *RK++ = *SK++;
+    *RK++ = *SK++;
+    
+    for( i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8 )
+    {
+        for( j = 0; j < 4; j++, SK++ )
+        {
+            *RK++ = RT0[ FSb[ ( *SK       ) & 0xFF ] ] ^
+            RT1[ FSb[ ( *SK >>  8 ) & 0xFF ] ] ^
+            RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^
+            RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ];
+        }
+    }
+    
+    *RK++ = *SK++;
+    *RK++ = *SK++;
+    *RK++ = *SK++;
+    *RK++ = *SK++;
+    
+    memset( &cty, 0, sizeof( joylinkEnc2Context ) );
+    
+    return( 0 );
+}
+
+#define JOYLINK_AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3)     \
+{                                               \
+X0 = *RK++ ^ FT0[ ( Y0       ) & 0xFF ] ^   \
+FT1[ ( Y1 >>  8 ) & 0xFF ] ^   \
+FT2[ ( Y2 >> 16 ) & 0xFF ] ^   \
+FT3[ ( Y3 >> 24 ) & 0xFF ];    \
+\
+X1 = *RK++ ^ FT0[ ( Y1       ) & 0xFF ] ^   \
+FT1[ ( Y2 >>  8 ) & 0xFF ] ^   \
+FT2[ ( Y3 >> 16 ) & 0xFF ] ^   \
+FT3[ ( Y0 >> 24 ) & 0xFF ];    \
+\
+X2 = *RK++ ^ FT0[ ( Y2       ) & 0xFF ] ^   \
+FT1[ ( Y3 >>  8 ) & 0xFF ] ^   \
+FT2[ ( Y0 >> 16 ) & 0xFF ] ^   \
+FT3[ ( Y1 >> 24 ) & 0xFF ];    \
+\
+X3 = *RK++ ^ FT0[ ( Y3       ) & 0xFF ] ^   \
+FT1[ ( Y0 >>  8 ) & 0xFF ] ^   \
+FT2[ ( Y1 >> 16 ) & 0xFF ] ^   \
+FT3[ ( Y2 >> 24 ) & 0xFF ];    \
+}
+
+#define JOYLINK_AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3)     \
+{                                               \
+X0 = *RK++ ^ RT0[ ( Y0       ) & 0xFF ] ^   \
+RT1[ ( Y3 >>  8 ) & 0xFF ] ^   \
+RT2[ ( Y2 >> 16 ) & 0xFF ] ^   \
+RT3[ ( Y1 >> 24 ) & 0xFF ];    \
+\
+X1 = *RK++ ^ RT0[ ( Y1       ) & 0xFF ] ^   \
+RT1[ ( Y0 >>  8 ) & 0xFF ] ^   \
+RT2[ ( Y3 >> 16 ) & 0xFF ] ^   \
+RT3[ ( Y2 >> 24 ) & 0xFF ];    \
+\
+X2 = *RK++ ^ RT0[ ( Y2       ) & 0xFF ] ^   \
+RT1[ ( Y1 >>  8 ) & 0xFF ] ^   \
+RT2[ ( Y0 >> 16 ) & 0xFF ] ^   \
+RT3[ ( Y3 >> 24 ) & 0xFF ];    \
+\
+X3 = *RK++ ^ RT0[ ( Y3       ) & 0xFF ] ^   \
+RT1[ ( Y2 >>  8 ) & 0xFF ] ^   \
+RT2[ ( Y1 >> 16 ) & 0xFF ] ^   \
+RT3[ ( Y0 >> 24 ) & 0xFF ];    \
+}
+
+/*
+ * AES-ECB block encryption/decryption
+ */
+static int joylink_enc2_crypt_ecb( joylinkEnc2Context *ctx,
+                             int mode,
+                             const unsigned char input[16],
+                             unsigned char output[16] )
+{
+    int i;
+    unsigned long *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3;
+    
+    RK = ctx->rk;
+    
+    JOYLINK_GET_ULONG_LE( X0, input,  0 ); X0 ^= *RK++;
+    JOYLINK_GET_ULONG_LE( X1, input,  4 ); X1 ^= *RK++;
+    JOYLINK_GET_ULONG_LE( X2, input,  8 ); X2 ^= *RK++;
+    JOYLINK_GET_ULONG_LE( X3, input, 12 ); X3 ^= *RK++;
+    
+    if( mode == JOYLINK_ENC2_DECRYPT )
+    {
+        for( i = (ctx->nr >> 1) - 1; i > 0; i-- )
+        {
+            JOYLINK_AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
+            JOYLINK_AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
+        }
+        
+        JOYLINK_AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
+        
+        X0 = *RK++ ^ \
+        ( (unsigned long) RSb[ ( Y0       ) & 0xFF ]       ) ^
+        ( (unsigned long) RSb[ ( Y3 >>  8 ) & 0xFF ] <<  8 ) ^
+        ( (unsigned long) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
+        ( (unsigned long) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 );
+        
+        X1 = *RK++ ^ \
+        ( (unsigned long) RSb[ ( Y1       ) & 0xFF ]       ) ^
+        ( (unsigned long) RSb[ ( Y0 >>  8 ) & 0xFF ] <<  8 ) ^
+        ( (unsigned long) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
+        ( (unsigned long) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 );
+        
+        X2 = *RK++ ^ \
+        ( (unsigned long) RSb[ ( Y2       ) & 0xFF ]       ) ^
+        ( (unsigned long) RSb[ ( Y1 >>  8 ) & 0xFF ] <<  8 ) ^
+        ( (unsigned long) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
+        ( (unsigned long) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 );
+        
+        X3 = *RK++ ^ \
+        ( (unsigned long) RSb[ ( Y3       ) & 0xFF ]       ) ^
+        ( (unsigned long) RSb[ ( Y2 >>  8 ) & 0xFF ] <<  8 ) ^
+        ( (unsigned long) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
+        ( (unsigned long) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 );
+    }
+    else /* JOYLINK_AES_ENCRYPT */
+    {
+        for( i = (ctx->nr >> 1) - 1; i > 0; i-- )
+        {
+            JOYLINK_AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
+            JOYLINK_AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
+        }
+        
+        JOYLINK_AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
+        
+        X0 = *RK++ ^ \
+        ( (unsigned long) FSb[ ( Y0       ) & 0xFF ]       ) ^
+        ( (unsigned long) FSb[ ( Y1 >>  8 ) & 0xFF ] <<  8 ) ^
+        ( (unsigned long) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
+        ( (unsigned long) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 );
+        
+        X1 = *RK++ ^ \
+        ( (unsigned long) FSb[ ( Y1       ) & 0xFF ]       ) ^
+        ( (unsigned long) FSb[ ( Y2 >>  8 ) & 0xFF ] <<  8 ) ^
+        ( (unsigned long) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
+        ( (unsigned long) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 );
+        
+        X2 = *RK++ ^ \
+        ( (unsigned long) FSb[ ( Y2       ) & 0xFF ]       ) ^
+        ( (unsigned long) FSb[ ( Y3 >>  8 ) & 0xFF ] <<  8 ) ^
+        ( (unsigned long) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
+        ( (unsigned long) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 );
+        
+        X3 = *RK++ ^ \
+        ( (unsigned long) FSb[ ( Y3       ) & 0xFF ]       ) ^
+        ( (unsigned long) FSb[ ( Y0 >>  8 ) & 0xFF ] <<  8 ) ^
+        ( (unsigned long) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
+        ( (unsigned long) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 );
+    }
+    
+    JOYLINK_PUT_ULONG_LE( X0, output,  0 );
+    JOYLINK_PUT_ULONG_LE( X1, output,  4 );
+    JOYLINK_PUT_ULONG_LE( X2, output,  8 );
+    JOYLINK_PUT_ULONG_LE( X3, output, 12 );
+    
+    return( 0 );
+}
+
+/*
+ * AES-CBC buffer encryption/decryption
+ */
+static int joylink_enc2_crypt_cbc( joylinkEnc2Context *ctx,
+                             int mode,
+                             size_t length,
+                             unsigned char iv[16],
+                             const unsigned char *input,
+                             unsigned char *output )
+{
+    int i;
+    unsigned char temp[16];
+    
+    if( length % 16 )
+        return( JOYLINK_ENCINFO_ERR );
+    
+    if( mode == JOYLINK_ENC2_DECRYPT )
+    {
+        while( length > 0 )
+        {
+            memcpy( temp, input, 16 );
+            joylink_enc2_crypt_ecb( ctx, mode, input, output );
+            
+            for( i = 0; i < 16; i++ )
+                output[i] = (unsigned char)( output[i] ^ iv[i] );
+            
+            memcpy( iv, temp, 16 );
+            
+            input  += 16;
+            output += 16;
+            length -= 16;
+        }
+    }
+    else
+    {
+        while( length > 0 )
+        {
+            for( i = 0; i < 16; i++ )
+                output[i] = (unsigned char)( input[i] ^ iv[i] );
+            
+            joylink_enc2_crypt_ecb( ctx, mode, output, output );
+            memcpy( iv, output, 16 );
+            
+            input  += 16;
+            output += 16;
+            length -= 16;
+        }
+    }
+    
+    return( 0 );
+}
+
+//AES crypt
+int joylinkEnc2Crypt(UINT8 *key, UINT32 keyLen, UINT8 *iv, UINT8 *data, UINT32 *len, UINT32 maxLen, int isPKCS5, int type)
+{
+    int dl;
+    int ret;
+    joylinkEnc2Context ctx;
+    
+    memset(&ctx, 0, sizeof(joylinkEnc2Context));
+    if (type == JOYLINK_ENC2_DECRYPT)
+    {
+        joylink_enc2_setkey_dec(&ctx, key, keyLen);
+        ret = joylink_enc2_crypt_cbc(&ctx, type, (size_t)(*len), iv, data, data);
+        dl = joylinkUnPadding(data, (UINT32)(*len), isPKCS5);
+        if (dl < 0)
+            return dl;
+    }
+    else
+    {
+        dl = joylinkPadding(data, *len, maxLen, isPKCS5);
+        if (dl < 0)
+            return dl;
+        joylink_enc2_setkey_enc(&ctx, key, keyLen);
+        ret = joylink_enc2_crypt_cbc(&ctx, type, (size_t)dl, iv, data, data);
+    }
+	
+	*len = dl;
+	
+	return ret;
+}
+
+int device_aes_encrypt(const UINT8 * key, int keyLength,
+        const UINT8 * iv, const UINT8 *pPlainIn,
+        int plainLength, UINT8 *pEncOut, int maxOutLen)
+{
+    char TIV[128] = {0}; 
+    memcpy(TIV, (char*)iv, 16);
+    
+    char *tdata  = (char *)malloc(plainLength + 16);
+    int dlen = plainLength;
+    int ret;
+
+    if(NULL != tdata){
+        memcpy(tdata,  pPlainIn, plainLength);
+        ret = joylinkEnc2Crypt((UINT8 *)key, 128, 
+                (UINT8*)TIV, (UINT8*)tdata, (UINT32*)&dlen, plainLength + 16, 1, JOYLINK_ENC2_ENCRYPT);
+        if(ret == 0){
+            if(dlen <= maxOutLen){
+                memcpy(pEncOut, tdata, dlen);
+            }else{
+                dlen = 0;
+            }
+        }
+        free(tdata);
+    }else{
+        dlen = 0;
+    }
+
+	return dlen;
+}
+
+int device_aes_decrypt(const UINT8 * key, int keyLength, 
+        const UINT8 * iv, const UINT8 *pEncIn, 
+        int encLength, UINT8 *pPlainOut, int maxOutLen)
+{
+    char TIV[128] = {0}; 
+    memcpy(TIV, (char*)iv, 16);
+    
+    char *tdata  = malloc(encLength + 16);
+    int dlen = encLength;
+    int ret;
+
+    if(NULL != tdata){
+        memset(tdata, 0, encLength + 16);
+        memcpy(tdata,  pEncIn, dlen);
+        ret = joylinkEnc2Crypt((UINT8 *)key, 128, 
+                (UINT8*)TIV, (UINT8*)tdata, (UINT32*)&dlen, encLength + 16, 1, JOYLINK_ENC2_DECRYPT);
+        if(ret == 0){
+            if(dlen <= maxOutLen){
+                memcpy(pPlainOut, tdata, dlen);
+            }else{
+                dlen = 0;
+            }
+        }
+        free(tdata);
+    }else{
+        dlen = 0;
+    }
+	return dlen;
+}
+int device_aes_encrypt_entire_iv(const UINT8 * key, int keyLength,
+        const UINT8 * iv, const UINT8 *pPlainIn,
+        int plainLength, UINT8 *pEncOut, int maxOutLen)
+{
+    char TIV[128] = {0}; 
+    memcpy(TIV, (char*)iv, 16);
+    
+    char *tdata  = (char *)malloc(plainLength + 16);
+    int dlen = plainLength;
+    int ret;
+
+    if(NULL != tdata){
+        memcpy(tdata,  pPlainIn, plainLength);
+        ret = joylinkEnc2Crypt((UINT8 *)key, 128, 
+                (UINT8*)TIV, (UINT8*)tdata, (UINT32*)&dlen, plainLength + 16, 1, JOYLINK_ENC2_ENCRYPT);
+        if(ret == 0){
+            if(dlen <= maxOutLen){
+                memcpy(pEncOut, tdata, dlen);
+            }else{
+                dlen = 0;
+            }
+        }
+        free(tdata);
+    }else{
+        dlen = 0;
+    }
+
+	return dlen;
+}
+
+int device_aes_decrypt_entire_iv(const UINT8 * key, int keyLength, 
+        const UINT8 * iv, const UINT8 *pEncIn, 
+        int encLength, UINT8 *pPlainOut, int maxOutLen)
+{
+    char TIV[128] = {0}; 
+    memcpy(TIV, (char*)iv, 16);
+    
+    char *tdata  = malloc(encLength + 16);
+    int dlen = encLength;
+    int ret;
+
+    if(NULL != tdata){
+        memset(tdata, 0, encLength + 16);
+        memcpy(tdata,  pEncIn, dlen);
+        ret = joylinkEnc2Crypt((UINT8 *)key, 128, 
+                (UINT8*)TIV, (UINT8*)tdata, (UINT32*)&dlen, encLength + 16, 1, JOYLINK_ENC2_DECRYPT);
+        if(ret == 0){
+            if(dlen <= maxOutLen){
+                memcpy(pPlainOut, tdata, dlen);
+            }else{
+                dlen = 0;
+            }
+        }
+        free(tdata);
+    }else{
+        dlen = 0;
+    }
+	return dlen;
+}
+#else
+
+#if defined (__MRVL_MW300__) || defined(__BOARDLINK__)
+
+#include "joylinkHaes.h"
+
+//AES crypt
+int joylinkEnc2Crypt(UINT8 *key, UINT32 keyLen, UINT8 *iv, UINT8 *data, UINT32 *len, UINT32 maxLen, int isPKCS5, int type)
+{
+	int dl;
+    int ret = -1;
+    
+    if (type == JOYLINK_ENC2_DECRYPT)
+	{
+        ret = joylinkAesDecryt(data, *len, key, iv, data);
+		dl = joylinkUnPadding(data, (UINT32)(*len), isPKCS5);
+        if (dl < 0)
+            return dl;
+	}
+    else
+	{
+		dl = joylinkPadding(data, *len, maxLen, isPKCS5);
+        if (dl < 0)
+            return dl;
+        ret = joylinkAesEncryt(data, dl, key, iv, data);
+	}
+	
+	*len = dl;
+	
+    return ret;
+}
+
+#endif
+
+#endif

+ 87 - 0
joylink/auth/joylink_aes.h

@@ -0,0 +1,87 @@
+#ifndef JOYLINK2_AES_H
+#define JOYLINK2_AES_H 
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define UINT8 unsigned char
+#define UINT32 unsigned int
+
+enum
+{
+    JOYLINK_SUCCESS                 = 0,
+    JOYLINK_BUFFER_SPACE_ERR        = -100,             /*buffer不足*/
+    JOYLINK_RECV_LEN_ERR            = -101,             /*接收数据长度有误*/
+    JOYLINK_CHECKSUM_ERR            = -102,             /*数据校验失败*/
+    JOYLINK_GET_CMD_ERR             = -103,             /*接收命令类型有误*/
+    JOYLINK_GET_DEVID_ERR           = -104,             /*设备ID不一致*/
+    JOYLINK_DEVID_ERR               = -105,             /*设备ID有误*/
+    JOYLINK_TOKEN_ERR               = -106,             /*设备TOKEN有误*/
+    JOYLINK_ENCTYPE_ERR             = -107,             /*不支持的加密策略*/
+    JOYLINK_MAGIC_ERR               = -108,             /*无效数据包,magic有误*/
+    JOYLINK_ENCINFO_ERR             = -109,             /*加密信息有误*/
+    
+    
+    JOYLINK_PARAM_INVALID           = -1000,            /*参数数据有误*/
+    JOYLINK_SYSTEM_ERR              = -1001,            /*系统调用错误,例如创建socket失败*/
+    JOYLINK_NETWORK_TIMEOUT         = -1002,            /*网络超时*/
+    JOYLINK_RECV_DATA_ERR           = -1003,             /*接收到的数据有误*/
+    JOYLINK_CANCEL_ERR              = -1004,            /*用户取消操作*/
+};
+
+// ARC4 crypt, 若有用户自己实现, 则宏定义为1
+#define HARDWARE_ARC4   0
+extern int joylinkEnc1Crypt(UINT8 *key, UINT32 keyLen, UINT8 *data, UINT32 len);
+
+#define JOYLINK_ENC2_ENCRYPT     1
+#define JOYLINK_ENC2_DECRYPT     0
+
+//#define JOYLINK_ERR_ENC2_INVALID_KEY_LENGTH                -0x0020  /**< Invalid key length. */
+//#define JOYLINK_ERR_ENC2_INVALID_INPUT_LENGTH              -0x0022  /**< Invalid data input length. */
+
+//AES crypt, 若用户自己实现,则宏定义为1
+#define HARDWARE_AES    0
+extern int joylinkEnc2Crypt(UINT8 *key, UINT32 keyLen, UINT8 *iv, UINT8 *data, UINT32 *len, UINT32 maxLen, int isPKCS5, int type);
+
+//MD5 crypt, 若用户自己实现,则宏定义为1
+#define HARDWARE_MD5    1
+extern void joylinkENC3(UINT8 *input, UINT32 inputlen, UINT8 output[16]);
+
+
+#define JOYLINK_ENC4_KEY_BIT     1024
+#define JOYLINK_ENC4_ENCRYPT     1
+#define JOYLINK_ENC4_DECRYPT     0
+//RSA crypt, 需要由用户自己实现,
+#define HARDWARE_RSA    1
+extern int joylinkEnc4Crypt(UINT8 *input, UINT32 inputLen, UINT8 *output, UINT32 maxLen, UINT8 *key, int type);
+
+/**
+ * brief: 
+ *
+ * @Param: key
+ * @Param: keyLength
+ * @Param: iv
+ * @Param: pEncIn
+ * @Param: encLength
+ * @Param: pPlainOut
+ * @Param: maxOutLen
+ *
+ * @Returns: 
+ */
+extern int device_aes_decrypt(const UINT8 * key, int keyLength, const UINT8 * iv, const UINT8 *pEncIn, int encLength, UINT8 *pPlainOut, int maxOutLen);
+extern int device_aes_encrypt(const UINT8 * key, int keyLength, const UINT8 * iv, const UINT8 *pPlainIn, int plainLength, UINT8 *pEncOut, int maxOutLen);
+
+extern int device_aes_encrypt_entire_iv(const UINT8 * key, int keyLength,
+        const UINT8 * iv, const UINT8 *pPlainIn,
+        int plainLength, UINT8 *pEncOut, int maxOutLen);
+
+extern int device_aes_decrypt_entire_iv(const UINT8 * key, int keyLength, 
+        const UINT8 * iv, const UINT8 *pEncIn, 
+        int encLength, UINT8 *pPlainOut, int maxOutLen);
+#ifdef __cplusplus
+}
+#endif
+    
+#endif

+ 75 - 0
joylink/auth/joylink_auth_crc.c

@@ -0,0 +1,75 @@
+#include "joylink_auth_crc.h"
+
+unsigned short CRC16(const unsigned char* buffer, unsigned int size)
+{
+	uint16_t crc = 0xFFFF;  
+
+	if (buffer && size)    
+		while (size--)    
+		{
+			crc = (crc >> 8) | (crc << 8);
+			crc ^= *buffer++;
+			crc ^= ((unsigned char) crc) >> 4;
+			crc ^= crc << 12;
+			crc ^= (crc & 0xFF) << 5;
+		}  
+	return crc;
+}
+
+unsigned char crc8(unsigned char *A,unsigned char n)
+{
+	unsigned char i;
+	unsigned char checksum = 0;
+
+	while(n--)
+	{
+		for(i=1;i!=0;i*=2)
+		{
+			if( (checksum&1) != 0 )
+			{
+				checksum /= 2;
+				checksum ^= 0X8C;
+			}
+			else
+			{
+				checksum /= 2;
+			}
+
+			if( (*A & i) != 0 )
+			{
+				checksum ^= 0X8C;
+			}
+		}
+		A++;
+	}
+	return(checksum);
+}
+
+uint32_t crc32_table[256];
+void make_crc32_table()
+{
+    uint32_t c;
+    int i = 0;
+    int bit = 0;
+      
+    for(i = 0; i < 256; i++)
+    {
+        c  = (uint32_t)i;
+        for(bit = 0; bit < 8; bit++)
+        {
+            if(c&1)
+                c = (c >> 1)^(0xEDB88320);
+            else
+                c =  c >> 1;
+        }
+        crc32_table[i] = c;
+    }
+}
+
+uint32_t make_crc(uint32_t crc, unsigned char *string, uint32_t size)
+{
+    while(size--)
+        crc = (crc >> 8)^(crc32_table[(crc ^ *string++)&0xff]);
+
+    return crc;  
+}

+ 19 - 0
joylink/auth/joylink_auth_crc.h

@@ -0,0 +1,19 @@
+#ifndef _CRC_H
+#define _CRC_H
+
+#ifdef __LINUX_UB2__
+#include <stdint.h>
+#endif
+
+#if defined(__MTK_7687__)
+#include <stdint.h>
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+unsigned short CRC16(const unsigned char* buffer, unsigned int size);
+unsigned char crc8(unsigned char *A, unsigned char n);
+void make_crc32_table();
+uint32_t make_crc(uint32_t crc, unsigned char *string, uint32_t size);
+
+#endif

+ 197 - 0
joylink/auth/joylink_auth_md5.c

@@ -0,0 +1,197 @@
+#include <string.h>
+
+#include "joylink_auth_md5.h"
+
+static void JDMD5Transform(unsigned int state[4], unsigned char block[64]);
+static void JDMD5Encode(unsigned char *output, unsigned int *input, unsigned int len);
+static void JDMD5Decode(unsigned int *output, unsigned char *input, unsigned int len);
+
+#define F(x,y,z) ((x & y) | (~x & z))
+#define G(x,y,z) ((x & z) | (y & ~z))
+#define H(x,y,z) (x^y^z)
+#define I(x,y,z) (y ^ (x | ~z))
+#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))
+#define FF(a,b,c,d,x,s,ac) \
+		  { \
+		  a += F(b, c, d) + x + ac; \
+		  a = ROTATE_LEFT(a, s); \
+		  a += b; \
+		  }
+#define GG(a,b,c,d,x,s,ac) \
+		  { \
+		  a += G(b, c, d) + x + ac; \
+		  a = ROTATE_LEFT(a, s); \
+		  a += b; \
+		  }
+#define HH(a,b,c,d,x,s,ac) \
+		  { \
+		  a += H(b, c, d) + x + ac; \
+		  a = ROTATE_LEFT(a, s); \
+		  a += b; \
+		  }
+#define II(a,b,c,d,x,s,ac) \
+		  { \
+		  a += I(b, c, d) + x + ac; \
+		  a = ROTATE_LEFT(a, s); \
+		  a += b; \
+		  }
+
+
+static unsigned char PADDING[]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+                         
+void JDMD5Init(MD5_CTX *context)
+{
+     context->count[0] = 0;
+     context->count[1] = 0;
+     context->state[0] = 0x67452301;
+     context->state[1] = 0xEFCDAB89;
+     context->state[2] = 0x98BADCFE;
+     context->state[3] = 0x10325476;
+}
+void JDMD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)
+{
+    unsigned int i = 0,index = 0,partlen = 0;
+    index = (context->count[0] >> 3) & 0x3F;
+    partlen = 64 - index;
+    context->count[0] += inputlen << 3;
+    if(context->count[0] < (inputlen << 3))
+       context->count[1]++;
+    context->count[1] += inputlen >> 29;
+    
+    if(inputlen >= partlen)
+    {
+       memcpy(&context->buffer[index],input,partlen);
+       JDMD5Transform(context->state,context->buffer);
+       for(i = partlen;i+64 <= inputlen;i+=64)
+           JDMD5Transform(context->state,&input[i]);
+       index = 0;        
+    }  
+    else
+    {
+        i = 0;
+    }
+    memcpy(&context->buffer[index],&input[i],inputlen-i);
+}
+void JDMD5Final(MD5_CTX *context,unsigned char digest[16])
+{
+    unsigned int index = 0,padlen = 0;
+    unsigned char bits[8];
+    index = (context->count[0] >> 3) & 0x3F;
+    padlen = (index < 56)?(56-index):(120-index);
+    JDMD5Encode(bits,context->count,8);
+    JDMD5Update(context,PADDING,padlen);
+    JDMD5Update(context,bits,8);
+    JDMD5Encode(digest,context->state,16);
+}
+static void JDMD5Encode(unsigned char *output, unsigned int *input, unsigned int len)
+{
+    unsigned int i = 0,j = 0;
+    while(j < len)
+    {
+         output[j] = input[i] & 0xFF;  
+         output[j+1] = (input[i] >> 8) & 0xFF;
+         output[j+2] = (input[i] >> 16) & 0xFF;
+         output[j+3] = (input[i] >> 24) & 0xFF;
+         i++;
+         j+=4;
+    }
+}
+static void JDMD5Decode(unsigned int *output, unsigned char *input, unsigned int len)
+{
+     unsigned int i = 0,j = 0;
+     while(j < len)
+     {
+           output[i] = (input[j]) |
+                       (input[j+1] << 8) |
+                       (input[j+2] << 16) |
+                       (input[j+3] << 24);
+           i++;
+           j+=4; 
+     }
+}
+static void JDMD5Transform(unsigned int state[4], unsigned char block[64])
+{
+     unsigned int a = state[0];
+     unsigned int b = state[1];
+     unsigned int c = state[2];
+     unsigned int d = state[3];
+     unsigned int x[64];
+     JDMD5Decode(x,block,64);
+     FF(a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */
+ FF(d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */
+ FF(c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */
+ FF(b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */
+ FF(a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */
+ FF(d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */
+ FF(c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */
+ FF(b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */
+ FF(a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */
+ FF(d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */
+ FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
+ FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
+ FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
+ FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
+ FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
+ FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
+ 
+ /* Round 2 */
+ GG(a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */
+ GG(d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */
+ GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
+ GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */
+ GG(a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */
+ GG(d, a, b, c, x[10], 9,  0x2441453); /* 22 */
+ GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
+ GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */
+ GG(a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */
+ GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
+ GG(c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */
+ GG(b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */
+ GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
+ GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */
+ GG(c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */
+ GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
+ 
+ /* Round 3 */
+ HH(a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */
+ HH(d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */
+ HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
+ HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
+ HH(a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */
+ HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */
+ HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */
+ HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
+ HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
+ HH(d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */
+ HH(c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */
+ HH(b, c, d, a, x[ 6], 23,  0x4881d05); /* 44 */
+ HH(a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */
+ HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
+ HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
+ HH(b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */
+ 
+ /* Round 4 */
+ II(a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */
+ II(d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */
+ II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
+ II(b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */
+ II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
+ II(d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */
+ II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
+ II(b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */
+ II(a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */
+ II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
+ II(c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */
+ II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
+ II(a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */
+ II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
+ II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */
+ II(b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */
+     state[0] += a;
+     state[1] += b;
+     state[2] += c;
+     state[3] += d;
+}

+ 15 - 0
joylink/auth/joylink_auth_md5.h

@@ -0,0 +1,15 @@
+#ifndef MD5_H
+#define MD5_H
+ 
+typedef struct
+{
+    unsigned int count[2];
+    unsigned int state[4];
+    unsigned char buffer[64];   
+}MD5_CTX;
+ 
+void JDMD5Init(MD5_CTX *context);
+void JDMD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);
+void JDMD5Final(MD5_CTX *context,unsigned char digest[16]);
+ 
+#endif

+ 2809 - 0
joylink/auth/joylink_auth_uECC.c

@@ -0,0 +1,2809 @@
+/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
+#ifdef QCOM_4004B
+#include "scw_common.h"
+#define __AVR__ 0
+#define asm_clear 0
+#define asm_isZero 0
+#define asm_testBit 0
+#define asm_numBits 0
+#define asm_cmp 0
+#define asm_set 0
+#define asm_rshift1 0
+#define asm_add 0
+#define asm_sub 0
+#define asm_mult 0
+#define asm_square 0
+#define asm_modAdd 0
+#define asm_modSub 0
+#define asm_modSub_fast 0
+#define asm_mmod_fast 0
+#define asm_modInv 0
+#else
+#include "joylink_auth_uECC.h"
+#endif
+
+#ifndef uECC_PLATFORM
+    #if __AVR__
+        #define uECC_PLATFORM uECC_avr
+    #elif defined(__thumb2__) || defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */
+        #define uECC_PLATFORM uECC_arm_thumb2
+    #elif defined(__thumb__)
+        #define uECC_PLATFORM uECC_arm_thumb
+    #elif defined(__arm__) || defined(_M_ARM)
+        #define uECC_PLATFORM uECC_arm
+    #elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__)
+        #define uECC_PLATFORM uECC_x86
+    #elif defined(__amd64__) || defined(_M_X64)
+        #define uECC_PLATFORM uECC_x86_64
+    #else
+        #define uECC_PLATFORM uECC_arch_other
+    #endif
+#endif
+
+#ifdef __MTK_7687__
+#define uECC_PLATFORM uECC_arch_other
+#endif
+
+#ifdef __RT_THREAD__
+#define uECC_PLATFORM uECC_arch_other
+#endif
+
+#ifndef uECC_WORD_SIZE
+    #if uECC_PLATFORM == uECC_avr
+        #define uECC_WORD_SIZE 1
+    #elif (uECC_PLATFORM == uECC_x86_64)
+        #define uECC_WORD_SIZE 8
+    #else
+        #define uECC_WORD_SIZE 4
+    #endif
+#endif
+
+#if (uECC_CURVE == uECC_secp160r1 || uECC_CURVE == uECC_secp224r1) && (uECC_WORD_SIZE == 8)
+    #undef uECC_WORD_SIZE
+    #define uECC_WORD_SIZE 4
+    #if (uECC_PLATFORM == uECC_x86_64)
+        #undef uECC_PLATFORM
+        #define uECC_PLATFORM uECC_x86
+    #endif
+#endif
+
+#if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8)
+    #error "Unsupported value for uECC_WORD_SIZE"
+#endif
+
+#if (uECC_ASM && (uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1))
+    #pragma message ("uECC_WORD_SIZE must be 1 when using AVR asm")
+    #undef uECC_WORD_SIZE
+    #define uECC_WORD_SIZE 1
+#endif
+
+#if (uECC_ASM && \
+     (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb) && \
+     (uECC_WORD_SIZE != 4))
+    #pragma message ("uECC_WORD_SIZE must be 4 when using ARM asm")
+    #undef uECC_WORD_SIZE
+    #define uECC_WORD_SIZE 4
+#endif
+
+#ifdef QCOM_4004B
+#define RESTRICT
+#else
+#if __STDC_VERSION__ >= 199901L
+    #define RESTRICT restrict
+#else
+    #define RESTRICT
+#endif
+#endif
+
+#ifdef QCOM_4004B
+#define SUPPORTS_INT128 0
+#else
+#if defined(__SIZEOF_INT128__) || ((__clang_major__ * 100 + __clang_minor__) >= 302)
+    #define SUPPORTS_INT128 1
+#else
+    #define SUPPORTS_INT128 0
+#endif
+#endif
+
+#define MAX_TRIES 64
+
+#if (uECC_WORD_SIZE == 1)
+
+typedef uint8_t uECC_word_t;
+typedef uint16_t uECC_dword_t;
+typedef uint8_t wordcount_t;
+typedef int8_t swordcount_t;
+typedef int16_t bitcount_t;
+typedef int8_t cmpresult_t;
+
+#define HIGH_BIT_SET 0x80
+#define uECC_WORD_BITS 8
+#define uECC_WORD_BITS_SHIFT 3
+#define uECC_WORD_BITS_MASK 0x07
+
+#define uECC_WORDS_1 20
+#define uECC_WORDS_2 24
+#define uECC_WORDS_3 32
+#define uECC_WORDS_4 32
+#define uECC_WORDS_5 28
+
+#define uECC_N_WORDS_1 21
+#define uECC_N_WORDS_2 24
+#define uECC_N_WORDS_3 32
+#define uECC_N_WORDS_4 32
+#define uECC_N_WORDS_5 28
+
+#define Curve_P_1 {0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, \
+                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+                   0xFF, 0xFF, 0xFF, 0xFF}
+#define Curve_P_2 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+                   0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
+#define Curve_P_3 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+                   0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \
+                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+                   0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}
+#define Curve_P_4 {0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, \
+                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
+#define Curve_P_5 {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+                   0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, \
+                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+                   0xFF, 0xFF, 0xFF, 0xFF}
+
+#define Curve_B_1 {0x45, 0xFA, 0x65, 0xC5, 0xAD, 0xD4, 0xD4, 0x81, \
+                   0x9F, 0xF8, 0xAC, 0x65, 0x8B, 0x7A, 0xBD, 0x54, \
+                   0xFC, 0xBE, 0x97, 0x1C}
+#define Curve_B_2 {0xB1, 0xB9, 0x46, 0xC1, 0xEC, 0xDE, 0xB8, 0xFE, \
+                   0x49, 0x30, 0x24, 0x72, 0xAB, 0xE9, 0xA7, 0x0F, \
+                   0xE7, 0x80, 0x9C, 0xE5, 0x19, 0x05, 0x21, 0x64}
+#define Curve_B_3 {0x4B, 0x60, 0xD2, 0x27, 0x3E, 0x3C, 0xCE, 0x3B, \
+                   0xF6, 0xB0, 0x53, 0xCC, 0xB0, 0x06, 0x1D, 0x65, \
+                   0xBC, 0x86, 0x98, 0x76, 0x55, 0xBD, 0xEB, 0xB3, \
+                   0xE7, 0x93, 0x3A, 0xAA, 0xD8, 0x35, 0xC6, 0x5A}
+#define Curve_B_4 {0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+#define Curve_B_5 {0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27, \
+                   0xBA, 0xD8, 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50, \
+                   0x56, 0x32, 0x41, 0xF5, 0xAB, 0xB3, 0x04, 0x0C, \
+                   0x85, 0x0A, 0x05, 0xB4}
+
+#define Curve_G_1 { \
+    {0x82, 0xFC, 0xCB, 0x13, 0xB9, 0x8B, 0xC3, 0x68, \
+        0x89, 0x69, 0x64, 0x46, 0x28, 0x73, 0xF5, 0x8E, \
+        0x68, 0xB5, 0x96, 0x4A}, \
+    {0x32, 0xFB, 0xC5, 0x7A, 0x37, 0x51, 0x23, 0x04, \
+        0x12, 0xC9, 0xDC, 0x59, 0x7D, 0x94, 0x68, 0x31, \
+        0x55, 0x28, 0xA6, 0x23}}
+
+#define Curve_G_2 { \
+    {0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4, \
+        0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C, \
+        0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18}, \
+    {0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73, \
+        0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63, \
+        0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07}}
+
+#define Curve_G_3 { \
+    {0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4, \
+        0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77, \
+        0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8, \
+        0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B}, \
+    {0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB, \
+        0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B, \
+        0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E, \
+        0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F}}
+
+#define Curve_G_4 { \
+    {0x98, 0x17, 0xF8, 0x16, 0x5B, 0x81, 0xF2, 0x59, \
+        0xD9, 0x28, 0xCE, 0x2D, 0xDB, 0xFC, 0x9B, 0x02, \
+        0x07, 0x0B, 0x87, 0xCE, 0x95, 0x62, 0xA0, 0x55, \
+        0xAC, 0xBB, 0xDC, 0xF9, 0x7E, 0x66, 0xBE, 0x79}, \
+    {0xB8, 0xD4, 0x10, 0xFB, 0x8F, 0xD0, 0x47, 0x9C, \
+        0x19, 0x54, 0x85, 0xA6, 0x48, 0xB4, 0x17, 0xFD, \
+        0xA8, 0x08, 0x11, 0x0E, 0xFC, 0xFB, 0xA4, 0x5D, \
+        0x65, 0xC4, 0xA3, 0x26, 0x77, 0xDA, 0x3A, 0x48}}
+
+#define Curve_G_5 { \
+    {0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34, \
+        0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A, \
+        0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B, \
+        0xBD, 0x0C, 0x0E, 0xB7}, \
+    {0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44, \
+        0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD, \
+        0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5, \
+        0x88, 0x63, 0x37, 0xBD}}
+
+#define Curve_N_1 {0x57, 0x22, 0x75, 0xCA, 0xD3, 0xAE, 0x27, 0xF9, \
+                   0xC8, 0xF4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, \
+                   0x00, 0x00, 0x00, 0x00, 0x01}
+#define Curve_N_2 {0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14, \
+                   0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, \
+                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
+#define Curve_N_3 {0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3, \
+                   0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC, \
+                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+                   0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}
+#define Curve_N_4 {0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, \
+                   0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA, \
+                   0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
+#define Curve_N_5 {0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13, \
+                   0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF, \
+                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+                   0xFF, 0xFF, 0xFF, 0xFF}
+
+#elif (uECC_WORD_SIZE == 4)
+
+typedef uint32_t uECC_word_t;
+#ifdef QCOM_4004B
+typedef unsigned long long uECC_dword_t;
+#else
+typedef uint64_t uECC_dword_t;
+#endif
+
+typedef unsigned wordcount_t;
+typedef int swordcount_t;
+typedef int bitcount_t;
+typedef int cmpresult_t;
+
+#define HIGH_BIT_SET 0x80000000
+#define uECC_WORD_BITS 32
+#define uECC_WORD_BITS_SHIFT 5
+#define uECC_WORD_BITS_MASK 0x01F
+
+#define uECC_WORDS_1 5
+#define uECC_WORDS_2 6
+#define uECC_WORDS_3 8
+#define uECC_WORDS_4 8
+#define uECC_WORDS_5 7
+
+#define uECC_N_WORDS_1 6
+#define uECC_N_WORDS_2 6
+#define uECC_N_WORDS_3 8
+#define uECC_N_WORDS_4 8
+#define uECC_N_WORDS_5 7
+
+#define Curve_P_1 {0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
+#define Curve_P_2 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
+#define Curve_P_3 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, \
+                   0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF}
+#define Curve_P_4 {0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, \
+                   0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
+#define Curve_P_5 {0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, \
+                   0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
+
+#define Curve_B_1 {0xC565FA45, 0x81D4D4AD, 0x65ACF89F, 0x54BD7A8B, 0x1C97BEFC}
+#define Curve_B_2 {0xC146B9B1, 0xFEB8DEEC, 0x72243049, 0x0FA7E9AB, 0xE59C80E7, 0x64210519}
+#define Curve_B_3 {0x27D2604B, 0x3BCE3C3E, 0xCC53B0F6, 0x651D06B0, \
+                   0x769886BC, 0xB3EBBD55, 0xAA3A93E7, 0x5AC635D8}
+#define Curve_B_4 {0x00000007, 0x00000000, 0x00000000, 0x00000000, \
+                   0x00000000, 0x00000000, 0x00000000, 0x00000000}
+#define Curve_B_5 {0x2355FFB4, 0x270B3943, 0xD7BFD8BA, 0x5044B0B7, \
+                   0xF5413256, 0x0C04B3AB, 0xB4050A85}
+
+#define Curve_G_1 { \
+    {0x13CBFC82, 0x68C38BB9, 0x46646989, 0x8EF57328, 0x4A96B568}, \
+    {0x7AC5FB32, 0x04235137, 0x59DCC912, 0x3168947D, 0x23A62855}}
+
+#define Curve_G_2 { \
+    {0x82FF1012, 0xF4FF0AFD, 0x43A18800, 0x7CBF20EB, 0xB03090F6, 0x188DA80E}, \
+    {0x1E794811, 0x73F977A1, 0x6B24CDD5, 0x631011ED, 0xFFC8DA78, 0x07192B95}}
+    
+#define Curve_G_3 { \
+    {0xD898C296, 0xF4A13945, 0x2DEB33A0, 0x77037D81,  \
+     0x63A440F2, 0xF8BCE6E5, 0xE12C4247, 0x6B17D1F2}, \
+    {0x37BF51F5, 0xCBB64068, 0x6B315ECE, 0x2BCE3357,  \
+     0x7C0F9E16, 0x8EE7EB4A, 0xFE1A7F9B, 0x4FE342E2}}
+
+#define Curve_G_4 { \
+    {0x16F81798, 0x59F2815B, 0x2DCE28D9, 0x029BFCDB,  \
+     0xCE870B07, 0x55A06295, 0xF9DCBBAC, 0x79BE667E}, \
+    {0xFB10D4B8, 0x9C47D08F, 0xA6855419, 0xFD17B448,  \
+     0x0E1108A8, 0x5DA4FBFC, 0x26A3C465, 0x483ADA77}}
+
+#define Curve_G_5 { \
+    {0x115C1D21, 0x343280D6, 0x56C21122, 0x4A03C1D3, \
+     0x321390B9, 0x6BB4BF7F, 0xB70E0CBD}, \
+    {0x85007E34, 0x44D58199, 0x5A074764, 0xCD4375A0, \
+     0x4C22DFE6, 0xB5F723FB, 0xBD376388}}
+
+#define Curve_N_1 {0xCA752257, 0xF927AED3, 0x0001F4C8, 0x00000000, 0x00000000, 0x00000001}
+#define Curve_N_2 {0xB4D22831, 0x146BC9B1, 0x99DEF836, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
+#define Curve_N_3 {0xFC632551, 0xF3B9CAC2, 0xA7179E84, 0xBCE6FAAD, \
+                   0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF}
+#define Curve_N_4 {0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, \
+                   0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
+#define Curve_N_5 {0x5C5C2A3D, 0x13DD2945, 0xE0B8F03E, 0xFFFF16A2, \
+                   0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
+
+#elif (uECC_WORD_SIZE == 8)
+
+typedef uint64_t uECC_word_t;
+#if SUPPORTS_INT128
+typedef unsigned __int128 uECC_dword_t;
+#endif
+typedef unsigned wordcount_t;
+typedef int swordcount_t;
+typedef int bitcount_t;
+typedef int cmpresult_t;
+
+#define HIGH_BIT_SET 0x8000000000000000ull
+#define uECC_WORD_BITS 64
+#define uECC_WORD_BITS_SHIFT 6
+#define uECC_WORD_BITS_MASK 0x03F
+
+#define uECC_WORDS_1 3
+#define uECC_WORDS_2 3
+#define uECC_WORDS_3 4
+#define uECC_WORDS_4 4
+#define uECC_WORDS_5 4
+
+#define uECC_N_WORDS_1 3
+#define uECC_N_WORDS_2 3
+#define uECC_N_WORDS_3 4
+#define uECC_N_WORDS_4 4
+#define uECC_N_WORDS_5 4
+
+#define Curve_P_1 {0xFFFFFFFF7FFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull}
+#define Curve_P_2 {0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull}
+#define Curve_P_3 {0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull, \
+                   0x0000000000000000ull, 0xFFFFFFFF00000001ull}
+#define Curve_P_4 {0xFFFFFFFEFFFFFC2Full, 0xFFFFFFFFFFFFFFFFull, \
+                   0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull}
+#define Curve_P_5 {0x0000000000000001ull, 0xFFFFFFFF00000000ull, \
+                   0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull}
+
+#define Curve_B_1 {0x81D4D4ADC565FA45ull, 0x54BD7A8B65ACF89Full, 0x000000001C97BEFCull}
+#define Curve_B_2 {0xFEB8DEECC146B9B1ull, 0x0FA7E9AB72243049ull, 0x64210519E59C80E7ull}
+#define Curve_B_3 {0x3BCE3C3E27D2604Bull, 0x651D06B0CC53B0F6ull, \
+                   0xB3EBBD55769886BCull, 0x5AC635D8AA3A93E7ull}
+#define Curve_B_4 {0x0000000000000007ull, 0x0000000000000000ull, \
+                   0x0000000000000000ull, 0x0000000000000000ull}
+#define Curve_B_5 {0x270B39432355FFB4ull, 0x5044B0B7D7BFD8BAull, \
+                   0x0C04B3ABF5413256ull, 0x00000000B4050A85ull}
+
+#define Curve_G_1 { \
+    {0x68C38BB913CBFC82ull, 0x8EF5732846646989ull, 0x000000004A96B568ull}, \
+    {0x042351377AC5FB32ull, 0x3168947D59DCC912ull, 0x0000000023A62855ull}}
+
+#define Curve_G_2 { \
+    {0xF4FF0AFD82FF1012ull, 0x7CBF20EB43A18800ull, 0x188DA80EB03090F6ull}, \
+    {0x73F977A11E794811ull, 0x631011ED6B24CDD5ull, 0x07192B95FFC8DA78ull}}
+    
+#define Curve_G_3 { \
+    {0xF4A13945D898C296ull, 0x77037D812DEB33A0ull, 0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull}, \
+    {0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull, 0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull}}
+
+#define Curve_G_4 { \
+    {0x59F2815B16F81798ull, 0x029BFCDB2DCE28D9ull, 0x55A06295CE870B07ull, 0x79BE667EF9DCBBACull}, \
+    {0x9C47D08FFB10D4B8ull, 0xFD17B448A6855419ull, 0x5DA4FBFC0E1108A8ull, 0x483ADA7726A3C465ull}}
+
+#define Curve_G_5 { \
+    {0x343280D6115C1D21ull, 0x4A03C1D356C21122ull, 0x6BB4BF7F321390B9ull, 0x00000000B70E0CBDull}, \
+    {0x44D5819985007E34ull, 0xCD4375A05A074764ull, 0xB5F723FB4C22DFE6ull, 0x00000000BD376388ull}}
+
+#define Curve_N_1 {0xF927AED3CA752257ull, 0x000000000001F4C8ull, 0x0000000100000000ull}
+#define Curve_N_2 {0x146BC9B1B4D22831ull, 0xFFFFFFFF99DEF836ull, 0xFFFFFFFFFFFFFFFFull}
+#define Curve_N_3 {0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull, \
+                   0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull}
+#define Curve_N_4 {0xBFD25E8CD0364141ull, 0xBAAEDCE6AF48A03Bull, \
+                   0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull}
+#define Curve_N_5 {0x13DD29455C5C2A3Dull, 0xFFFF16A2E0B8F03Eull, \
+                   0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull}
+
+#endif /* (uECC_WORD_SIZE == 8) */
+
+#define uECC_WORDS uECC_CONCAT(uECC_WORDS_, uECC_CURVE)
+#define uECC_N_WORDS uECC_CONCAT(uECC_N_WORDS_, uECC_CURVE)
+
+typedef struct EccPoint {
+    uECC_word_t x[uECC_WORDS];
+    uECC_word_t y[uECC_WORDS];
+} EccPoint;
+
+static const uECC_word_t curve_p[uECC_WORDS] = uECC_CONCAT(Curve_P_, uECC_CURVE);
+static const uECC_word_t curve_b[uECC_WORDS] = uECC_CONCAT(Curve_B_, uECC_CURVE);
+static const EccPoint curve_G = uECC_CONCAT(Curve_G_, uECC_CURVE);
+static const uECC_word_t curve_n[uECC_N_WORDS] = uECC_CONCAT(Curve_N_, uECC_CURVE);
+
+static void vli_clear(uECC_word_t *vli);
+static uECC_word_t vli_isZero(const uECC_word_t *vli);
+static uECC_word_t vli_testBit(const uECC_word_t *vli, bitcount_t bit);
+static bitcount_t vli_numBits(const uECC_word_t *vli, wordcount_t max_words);
+static void vli_set(uECC_word_t *dest, const uECC_word_t *src);
+static cmpresult_t vli_cmp(const uECC_word_t *left, const uECC_word_t *right);
+static cmpresult_t vli_equal(const uECC_word_t *left, const uECC_word_t *right);
+static void vli_rshift1(uECC_word_t *vli);
+static uECC_word_t vli_add(uECC_word_t *result,
+                           const uECC_word_t *left,
+                           const uECC_word_t *right);
+static uECC_word_t vli_sub(uECC_word_t *result,
+                           const uECC_word_t *left,
+                           const uECC_word_t *right);
+static void vli_mult(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right);
+static void vli_modAdd(uECC_word_t *result,
+                       const uECC_word_t *left,
+                       const uECC_word_t *right,
+                       const uECC_word_t *mod);
+static void vli_modSub(uECC_word_t *result,
+                       const uECC_word_t *left,
+                       const uECC_word_t *right,
+                       const uECC_word_t *mod);
+static void vli_mmod_fast(uECC_word_t *RESTRICT result, uECC_word_t *RESTRICT product);
+static void vli_modMult_fast(uECC_word_t *result,
+                             const uECC_word_t *left,
+                             const uECC_word_t *right);
+static void vli_modInv(uECC_word_t *result, const uECC_word_t *input, const uECC_word_t *mod);
+#if uECC_SQUARE_FUNC
+static void vli_square(uECC_word_t *result, const uECC_word_t *left);
+static void vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left);
+#endif
+
+#if (defined(_WIN32) || defined(_WIN64))
+/* Windows */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <wincrypt.h>
+
+static int default_RNG(uint8_t *dest, unsigned size) {
+    HCRYPTPROV prov;
+    if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+        return 0;
+    }
+
+    CryptGenRandom(prov, size, (BYTE *)dest);
+    CryptReleaseContext(prov, 0);
+    return 1;
+}
+
+#elif defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \
+    (defined(__APPLE__) && defined(__MACH__)) || defined(uECC_POSIX)
+
+/* Some POSIX-like system with /dev/urandom or /dev/random. */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifndef O_CLOEXEC
+    #define O_CLOEXEC 0
+#endif
+
+static int default_RNG(uint8_t *dest, unsigned size) {
+    int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
+    if (fd == -1) {
+        fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
+        if (fd == -1) {
+            return 0;
+        }
+    }
+    
+    char *ptr = (char *)dest;
+    size_t left = size;
+    while (left > 0) {
+        ssize_t bytes_read = read(fd, ptr, left);
+        if (bytes_read <= 0) { // read failed
+            close(fd);
+            return 0;
+        }
+        left -= bytes_read;
+        ptr += bytes_read;
+    }
+    
+    close(fd);
+    return 1;
+}
+
+#else /* Some other platform */
+
+static int default_RNG(uint8_t *dest, unsigned size) {
+#ifdef QCOM_4004B
+    memset(dest, 2, size);    
+    return 1;
+#else
+    memset(dest, 2, size);    
+    return 1;
+#endif
+    printf("must set random\n");
+    return 0;
+}
+
+#endif
+
+static uECC_RNG_Function g_rng_function = &default_RNG;
+
+void uECC_set_rng(uECC_RNG_Function rng_function) {
+    g_rng_function = rng_function;
+}
+
+#ifdef __GNUC__ /* Only support GCC inline asm for now */
+    #if (uECC_ASM && (uECC_PLATFORM == uECC_avr))
+        #include "asm_avr.inc"
+    #endif
+
+    #if (uECC_ASM && (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \
+                      uECC_PLATFORM == uECC_arm_thumb2))
+        #include "asm_arm.inc"
+    #endif
+#endif
+
+#if !asm_clear
+static void vli_clear(uECC_word_t *vli) {
+    wordcount_t i;
+    for (i = 0; i < uECC_WORDS; ++i) {
+        vli[i] = 0;
+    }
+}
+#endif
+
+/* Returns 1 if vli == 0, 0 otherwise. */
+#if !asm_isZero
+static uECC_word_t vli_isZero(const uECC_word_t *vli) {
+    wordcount_t i;
+    for (i = 0; i < uECC_WORDS; ++i) {
+        if (vli[i]) {
+            return 0;
+        }
+    }
+    return 1;
+}
+#endif
+
+/* Returns nonzero if bit 'bit' of vli is set. */
+#if !asm_testBit
+static uECC_word_t vli_testBit(const uECC_word_t *vli, bitcount_t bit) {
+    return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));
+}
+#endif
+
+/* Counts the number of words in vli. */
+#if !asm_numBits
+static wordcount_t vli_numDigits(const uECC_word_t *vli, wordcount_t max_words) {
+    swordcount_t i;
+    /* Search from the end until we find a non-zero digit.
+       We do it in reverse because we expect that most digits will be nonzero. */
+    for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) {
+    }
+
+    return (i + 1);
+}
+
+/* Counts the number of bits required to represent vli. */
+static bitcount_t vli_numBits(const uECC_word_t *vli, wordcount_t max_words) {
+    uECC_word_t i;
+    uECC_word_t digit;
+    
+    wordcount_t num_digits = vli_numDigits(vli, max_words);
+    if (num_digits == 0) {
+        return 0;
+    }
+
+    digit = vli[num_digits - 1];
+    for (i = 0; digit; ++i) {
+        digit >>= 1;
+    }
+    
+    return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);
+}
+#endif /* !asm_numBits */
+
+/* Sets dest = src. */
+#if !asm_set
+static void vli_set(uECC_word_t *dest, const uECC_word_t *src) {
+    wordcount_t i;
+    for (i = 0; i < uECC_WORDS; ++i) {
+        dest[i] = src[i];
+    }
+}
+#endif
+
+/* Returns sign of left - right. */
+#if !asm_cmp
+static cmpresult_t vli_cmp(const uECC_word_t *left, const uECC_word_t *right) {
+    swordcount_t i;
+    for (i = uECC_WORDS - 1; i >= 0; --i) {
+        if (left[i] > right[i]) {
+            return 1;
+        } else if (left[i] < right[i]) {
+            return -1;
+        }
+    }
+    return 0;
+}
+#endif
+
+static cmpresult_t vli_equal(const uECC_word_t *left, const uECC_word_t *right) {
+    uECC_word_t result = 0;
+    swordcount_t i;
+    for (i = uECC_WORDS - 1; i >= 0; --i) {
+        result |= (left[i] ^ right[i]);
+    }
+    return (result == 0);
+}
+
+/* Computes vli = vli >> 1. */
+#if !asm_rshift1
+static void vli_rshift1(uECC_word_t *vli) {
+    uECC_word_t *end = vli;
+    uECC_word_t carry = 0;
+    
+    vli += uECC_WORDS;
+    while (vli-- > end) {
+        uECC_word_t temp = *vli;
+        *vli = (temp >> 1) | carry;
+        carry = temp << (uECC_WORD_BITS - 1);
+    }
+}
+#endif
+
+/* Computes result = left + right, returning carry. Can modify in place. */
+#if !asm_add
+static uECC_word_t vli_add(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {
+    uECC_word_t carry = 0;
+    wordcount_t i;
+    for (i = 0; i < uECC_WORDS; ++i) {
+        uECC_word_t sum = left[i] + right[i] + carry;
+        if (sum != left[i]) {
+            carry = (sum < left[i]);
+        }
+        result[i] = sum;
+    }
+    return carry;
+}
+#endif
+
+/* Computes result = left - right, returning borrow. Can modify in place. */
+#if !asm_sub
+static uECC_word_t vli_sub(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {
+    uECC_word_t borrow = 0;
+    wordcount_t i;
+    for (i = 0; i < uECC_WORDS; ++i) {
+        uECC_word_t diff = left[i] - right[i] - borrow;
+        if (diff != left[i]) {
+            borrow = (diff > left[i]);
+        }
+        result[i] = diff;
+    }
+    return borrow;
+}
+#endif
+
+#if (!asm_mult || (uECC_SQUARE_FUNC && !asm_square) || uECC_CURVE == uECC_secp256k1)
+static void muladd(uECC_word_t a,
+                   uECC_word_t b,
+                   uECC_word_t *r0,
+                   uECC_word_t *r1,
+                   uECC_word_t *r2) {
+#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128
+    uint64_t a0 = a & 0xffffffffull;
+    uint64_t a1 = a >> 32;
+    uint64_t b0 = b & 0xffffffffull;
+    uint64_t b1 = b >> 32;
+    
+    uint64_t i0 = a0 * b0;
+    uint64_t i1 = a0 * b1;
+    uint64_t i2 = a1 * b0;
+    uint64_t i3 = a1 * b1;
+    
+    uint64_t p0, p1;
+    
+    i2 += (i0 >> 32);
+    i2 += i1;
+    if (i2 < i1) { // overflow
+        i3 += 0x100000000ull;
+    }
+    
+    p0 = (i0 & 0xffffffffull) | (i2 << 32);
+    p1 = i3 + (i2 >> 32);
+    
+    *r0 += p0;
+    *r1 += (p1 + (*r0 < p0));
+    *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0));
+#else
+    uECC_dword_t p = (uECC_dword_t)a * b;
+    uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
+    r01 += p;
+    *r2 += (r01 < p);
+    *r1 = r01 >> uECC_WORD_BITS;
+    *r0 = (uECC_word_t)r01;
+#endif
+}
+#define muladd_exists 1
+#endif
+
+#if !asm_mult
+static void vli_mult(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {
+    uECC_word_t r0 = 0;
+    uECC_word_t r1 = 0;
+    uECC_word_t r2 = 0;
+    wordcount_t i, k;
+    
+    /* Compute each digit of result in sequence, maintaining the carries. */
+    for (k = 0; k < uECC_WORDS; ++k) {
+        for (i = 0; i <= k; ++i) {
+            muladd(left[i], right[k - i], &r0, &r1, &r2);
+        }
+        result[k] = r0;
+        r0 = r1;
+        r1 = r2;
+        r2 = 0;
+    }
+    for (k = uECC_WORDS; k < uECC_WORDS * 2 - 1; ++k) {
+        for (i = (k + 1) - uECC_WORDS; i < uECC_WORDS; ++i) {
+            muladd(left[i], right[k - i], &r0, &r1, &r2);
+        }
+        result[k] = r0;
+        r0 = r1;
+        r1 = r2;
+        r2 = 0;
+    }
+    result[uECC_WORDS * 2 - 1] = r0;
+}
+#endif
+
+#if uECC_SQUARE_FUNC
+
+#if !asm_square
+static void mul2add(uECC_word_t a,
+                    uECC_word_t b,
+                    uECC_word_t *r0,
+                    uECC_word_t *r1,
+                    uECC_word_t *r2) {
+#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128
+    uint64_t a0 = a & 0xffffffffull;
+    uint64_t a1 = a >> 32;
+    uint64_t b0 = b & 0xffffffffull;
+    uint64_t b1 = b >> 32;
+    
+    uint64_t i0 = a0 * b0;
+    uint64_t i1 = a0 * b1;
+    uint64_t i2 = a1 * b0;
+    uint64_t i3 = a1 * b1;
+    
+    uint64_t p0, p1;
+    
+    i2 += (i0 >> 32);
+    i2 += i1;
+    if (i2 < i1)
+    { // overflow
+        i3 += 0x100000000ull;
+    }
+    
+    p0 = (i0 & 0xffffffffull) | (i2 << 32);
+    p1 = i3 + (i2 >> 32);
+    
+    *r2 += (p1 >> 63);
+    p1 = (p1 << 1) | (p0 >> 63);
+    p0 <<= 1;
+    
+    *r0 += p0;
+    *r1 += (p1 + (*r0 < p0));
+    *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0));
+#else
+    uECC_dword_t p = (uECC_dword_t)a * b;
+    uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
+    *r2 += (p >> (uECC_WORD_BITS * 2 - 1));
+    p *= 2;
+    r01 += p;
+    *r2 += (r01 < p);
+    *r1 = r01 >> uECC_WORD_BITS;
+    *r0 = (uECC_word_t)r01;
+#endif
+}
+
+static void vli_square(uECC_word_t *result, const uECC_word_t *left) {
+    uECC_word_t r0 = 0;
+    uECC_word_t r1 = 0;
+    uECC_word_t r2 = 0;
+    
+    wordcount_t i, k;
+    
+    for (k = 0; k < uECC_WORDS * 2 - 1; ++k) {
+        uECC_word_t min = (k < uECC_WORDS ? 0 : (k + 1) - uECC_WORDS);
+        for (i = min; i <= k && i <= k - i; ++i) {
+            if (i < k-i) {
+                mul2add(left[i], left[k - i], &r0, &r1, &r2);
+            } else {
+                muladd(left[i], left[k - i], &r0, &r1, &r2);
+            }
+        }
+        result[k] = r0;
+        r0 = r1;
+        r1 = r2;
+        r2 = 0;
+    }
+    
+    result[uECC_WORDS * 2 - 1] = r0;
+}
+#endif
+
+#else /* uECC_SQUARE_FUNC */
+
+#define vli_square(result, left, size) vli_mult((result), (left), (left), (size))
+    
+#endif /* uECC_SQUARE_FUNC */
+
+
+/* Computes result = (left + right) % mod.
+   Assumes that left < mod and right < mod, and that result does not overlap mod. */
+#if !asm_modAdd
+static void vli_modAdd(uECC_word_t *result,
+                       const uECC_word_t *left,
+                       const uECC_word_t *right,
+                       const uECC_word_t *mod) {
+    uECC_word_t carry = vli_add(result, left, right);
+    if (carry || vli_cmp(result, mod) >= 0) {
+        /* result > mod (result = mod + remainder), so subtract mod to get remainder. */
+        vli_sub(result, result, mod);
+    }
+}
+#endif
+
+/* Computes result = (left - right) % mod.
+   Assumes that left < mod and right < mod, and that result does not overlap mod. */
+#if !asm_modSub
+static void vli_modSub(uECC_word_t *result,
+                       const uECC_word_t *left,
+                       const uECC_word_t *right,
+                       const uECC_word_t *mod) {
+    uECC_word_t l_borrow = vli_sub(result, left, right);
+    if (l_borrow) {
+        /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,
+           we can get the correct result from result + mod (with overflow). */
+        vli_add(result, result, mod);
+    }
+}
+#endif
+
+#if !asm_modSub_fast
+    #define vli_modSub_fast(result, left, right) vli_modSub((result), (left), (right), curve_p)
+#endif
+
+#if !asm_mmod_fast
+
+#if (uECC_CURVE == uECC_secp160r1 || uECC_CURVE == uECC_secp256k1)
+/* omega_mult() is defined farther below for the different curves / word sizes */
+static void omega_mult(uECC_word_t * RESTRICT result, const uECC_word_t * RESTRICT right);
+
+/* Computes result = product % curve_p
+    see http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf page 354
+    
+    Note that this only works if log2(omega) < log2(p) / 2 */
+static void vli_mmod_fast(uECC_word_t *RESTRICT result, uECC_word_t *RESTRICT product) {
+    uECC_word_t tmp[2 * uECC_WORDS];
+    uECC_word_t carry;
+    
+    vli_clear(tmp);
+    vli_clear(tmp + uECC_WORDS);
+    
+    omega_mult(tmp, product + uECC_WORDS); /* (Rq, q) = q * c */
+    
+    carry = vli_add(result, product, tmp); /* (C, r) = r + q       */
+    vli_clear(product);
+    omega_mult(product, tmp + uECC_WORDS); /* Rq*c */
+    carry += vli_add(result, result, product); /* (C1, r) = r + Rq*c */
+    
+    while (carry > 0) {
+        --carry;
+        vli_sub(result, result, curve_p);
+    }
+    if (vli_cmp(result, curve_p) > 0) {
+        vli_sub(result, result, curve_p);
+    }
+}
+
+#endif
+
+#if uECC_CURVE == uECC_secp160r1
+
+#if uECC_WORD_SIZE == 1
+static void omega_mult(uint8_t * RESTRICT result, const uint8_t * RESTRICT right) {
+    uint8_t carry;
+    uint8_t i;
+    
+    /* Multiply by (2^31 + 1). */
+    vli_set(result + 4, right); /* 2^32 */
+    vli_rshift1(result + 4); /* 2^31 */
+    result[3] = right[0] << 7; /* get last bit from shift */
+    
+    carry = vli_add(result, result, right); /* 2^31 + 1 */
+    for (i = uECC_WORDS; carry; ++i) {
+        uint16_t sum = (uint16_t)result[i] + carry;
+        result[i] = (uint8_t)sum;
+        carry = sum >> 8;
+    }
+}
+#elif uECC_WORD_SIZE == 4
+static void omega_mult(uint32_t * RESTRICT result, const uint32_t * RESTRICT right) {
+    uint32_t carry;
+    unsigned i;
+    
+    /* Multiply by (2^31 + 1). */
+    vli_set(result + 1, right); /* 2^32 */
+    vli_rshift1(result + 1); /* 2^31 */
+    result[0] = right[0] << 31; /* get last bit from shift */
+    
+    carry = vli_add(result, result, right); /* 2^31 + 1 */
+    for (i = uECC_WORDS; carry; ++i) {
+		uECC_dword_t sum = (uECC_dword_t)result[i] + carry;
+        result[i] = (uint32_t)sum;
+        carry = sum >> 32;
+    }
+}
+#endif /* uECC_WORD_SIZE */
+
+#elif uECC_CURVE == uECC_secp192r1
+
+/* Computes result = product % curve_p.
+   See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */
+#if uECC_WORD_SIZE == 1
+static void vli_mmod_fast(uint8_t *RESTRICT result, uint8_t *RESTRICT product) {
+    uint8_t tmp[uECC_WORDS];
+    uint8_t carry;
+    
+    vli_set(result, product);
+    
+    vli_set(tmp, &product[24]);
+    carry = vli_add(result, result, tmp);
+    
+    tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;
+    tmp[8] = product[24]; tmp[9] = product[25]; tmp[10] = product[26]; tmp[11] = product[27];
+    tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31];
+    tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35];
+    tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39];
+    carry += vli_add(result, result, tmp);
+    
+    tmp[0] = tmp[8] = product[40];
+    tmp[1] = tmp[9] = product[41];
+    tmp[2] = tmp[10] = product[42];
+    tmp[3] = tmp[11] = product[43];
+    tmp[4] = tmp[12] = product[44];
+    tmp[5] = tmp[13] = product[45];
+    tmp[6] = tmp[14] = product[46];
+    tmp[7] = tmp[15] = product[47];
+    tmp[16] = tmp[17] = tmp[18] = tmp[19] = tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;
+    carry += vli_add(result, result, tmp);
+    
+    while (carry || vli_cmp(curve_p, result) != 1) {
+        carry -= vli_sub(result, result, curve_p);
+    }
+}
+#elif uECC_WORD_SIZE == 4
+static void vli_mmod_fast(uint32_t *RESTRICT result, uint32_t *RESTRICT product) {
+    uint32_t tmp[uECC_WORDS];
+    int carry;
+    
+    vli_set(result, product);
+    
+    vli_set(tmp, &product[6]);
+    carry = vli_add(result, result, tmp);
+    
+    tmp[0] = tmp[1] = 0;
+    tmp[2] = product[6];
+    tmp[3] = product[7];
+    tmp[4] = product[8];
+    tmp[5] = product[9];
+    carry += vli_add(result, result, tmp);
+    
+    tmp[0] = tmp[2] = product[10];
+    tmp[1] = tmp[3] = product[11];
+    tmp[4] = tmp[5] = 0;
+    carry += vli_add(result, result, tmp);
+    
+    while (carry || vli_cmp(curve_p, result) != 1) {
+        carry -= vli_sub(result, result, curve_p);
+    }
+}
+#else
+static void vli_mmod_fast(uint64_t *RESTRICT result, uint64_t *RESTRICT product) {
+    uint64_t tmp[uECC_WORDS];
+    int carry;
+    
+    vli_set(result, product);
+    
+    vli_set(tmp, &product[3]);
+    carry = vli_add(result, result, tmp);
+    
+    tmp[0] = 0;
+    tmp[1] = product[3];
+    tmp[2] = product[4];
+    carry += vli_add(result, result, tmp);
+    
+    tmp[0] = tmp[1] = product[5];
+    tmp[2] = 0;
+    carry += vli_add(result, result, tmp);
+    
+    while (carry || vli_cmp(curve_p, result) != 1) {
+        carry -= vli_sub(result, result, curve_p);
+    }
+}
+#endif /* uECC_WORD_SIZE */
+
+#elif uECC_CURVE == uECC_secp256r1
+
+/* Computes result = product % curve_p
+   from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+#if uECC_WORD_SIZE == 1
+static void vli_mmod_fast(uint8_t *RESTRICT result, uint8_t *RESTRICT product) {
+    uint8_t tmp[uECC_BYTES];
+    int8_t carry;
+    
+    /* t */
+    vli_set(result, product);
+    
+    /* s1 */
+    tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;
+    tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;
+    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;
+    tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47];
+    tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51];
+    tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55];
+    tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59];
+    tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63];
+    carry = vli_add(tmp, tmp, tmp);
+    carry += vli_add(result, result, tmp);
+    
+    /* s2 */
+    tmp[12] = product[48]; tmp[13] = product[49]; tmp[14] = product[50]; tmp[15] = product[51];
+    tmp[16] = product[52]; tmp[17] = product[53]; tmp[18] = product[54]; tmp[19] = product[55];
+    tmp[20] = product[56]; tmp[21] = product[57]; tmp[22] = product[58]; tmp[23] = product[59];
+    tmp[24] = product[60]; tmp[25] = product[61]; tmp[26] = product[62]; tmp[27] = product[63];
+    tmp[28] = tmp[29] = tmp[30] = tmp[31] = 0;
+    carry += vli_add(tmp, tmp, tmp);
+    carry += vli_add(result, result, tmp);
+    
+    /* s3 */
+    tmp[0] = product[32]; tmp[1] = product[33]; tmp[2] = product[34]; tmp[3] = product[35];
+    tmp[4] = product[36]; tmp[5] = product[37]; tmp[6] = product[38]; tmp[7] = product[39];
+    tmp[8] = product[40]; tmp[9] = product[41]; tmp[10] = product[42]; tmp[11] = product[43];
+    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;
+    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;
+    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;
+    tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59];
+    tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63];
+    carry += vli_add(result, result, tmp);
+    
+    /* s4 */
+    tmp[0] = product[36]; tmp[1] = product[37]; tmp[2] = product[38]; tmp[3] = product[39];
+    tmp[4] = product[40]; tmp[5] = product[41]; tmp[6] = product[42]; tmp[7] = product[43];
+    tmp[8] = product[44]; tmp[9] = product[45]; tmp[10] = product[46]; tmp[11] = product[47];
+    tmp[12] = product[52]; tmp[13] = product[53]; tmp[14] = product[54]; tmp[15] = product[55];
+    tmp[16] = product[56]; tmp[17] = product[57]; tmp[18] = product[58]; tmp[19] = product[59];
+    tmp[20] = product[60]; tmp[21] = product[61]; tmp[22] = product[62]; tmp[23] = product[63];
+    tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55];
+    tmp[28] = product[32]; tmp[29] = product[33]; tmp[30] = product[34]; tmp[31] = product[35];
+    carry += vli_add(result, result, tmp);
+    
+    /* d1 */
+    tmp[0] = product[44]; tmp[1] = product[45]; tmp[2] = product[46]; tmp[3] = product[47];
+    tmp[4] = product[48]; tmp[5] = product[49]; tmp[6] = product[50]; tmp[7] = product[51];
+    tmp[8] = product[52]; tmp[9] = product[53]; tmp[10] = product[54]; tmp[11] = product[55];
+    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;
+    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;
+    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;
+    tmp[24] = product[32]; tmp[25] = product[33]; tmp[26] = product[34]; tmp[27] = product[35];
+    tmp[28] = product[40]; tmp[29] = product[41]; tmp[30] = product[42]; tmp[31] = product[43];
+    carry -= vli_sub(result, result, tmp);
+    
+    /* d2 */
+    tmp[0] = product[48]; tmp[1] = product[49]; tmp[2] = product[50]; tmp[3] = product[51];
+    tmp[4] = product[52]; tmp[5] = product[53]; tmp[6] = product[54]; tmp[7] = product[55];
+    tmp[8] = product[56]; tmp[9] = product[57]; tmp[10] = product[58]; tmp[11] = product[59];
+    tmp[12] = product[60]; tmp[13] = product[61]; tmp[14] = product[62]; tmp[15] = product[63];
+    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;
+    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;
+    tmp[24] = product[36]; tmp[25] = product[37]; tmp[26] = product[38]; tmp[27] = product[39];
+    tmp[28] = product[44]; tmp[29] = product[45]; tmp[30] = product[46]; tmp[31] = product[47];
+    carry -= vli_sub(result, result, tmp);
+    
+    /* d3 */
+    tmp[0] = product[52]; tmp[1] = product[53]; tmp[2] = product[54]; tmp[3] = product[55];
+    tmp[4] = product[56]; tmp[5] = product[57]; tmp[6] = product[58]; tmp[7] = product[59];
+    tmp[8] = product[60]; tmp[9] = product[61]; tmp[10] = product[62]; tmp[11] = product[63];
+    tmp[12] = product[32]; tmp[13] = product[33]; tmp[14] = product[34]; tmp[15] = product[35];
+    tmp[16] = product[36]; tmp[17] = product[37]; tmp[18] = product[38]; tmp[19] = product[39];
+    tmp[20] = product[40]; tmp[21] = product[41]; tmp[22] = product[42]; tmp[23] = product[43];
+    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;
+    tmp[28] = product[48]; tmp[29] = product[49]; tmp[30] = product[50]; tmp[31] = product[51];
+    carry -= vli_sub(result, result, tmp);
+    
+    /* d4 */
+    tmp[0] = product[56]; tmp[1] = product[57]; tmp[2] = product[58]; tmp[3] = product[59];
+    tmp[4] = product[60]; tmp[5] = product[61]; tmp[6] = product[62]; tmp[7] = product[63];
+    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;
+    tmp[12] = product[36]; tmp[13] = product[37]; tmp[14] = product[38]; tmp[15] = product[39];
+    tmp[16] = product[40]; tmp[17] = product[41]; tmp[18] = product[42]; tmp[19] = product[43];
+    tmp[20] = product[44]; tmp[21] = product[45]; tmp[22] = product[46]; tmp[23] = product[47];
+    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;
+    tmp[28] = product[52]; tmp[29] = product[53]; tmp[30] = product[54]; tmp[31] = product[55];
+    carry -= vli_sub(result, result, tmp);
+    
+    if (carry < 0) {
+        do {
+            carry += vli_add(result, result, curve_p);
+        } while (carry < 0);
+    } else {
+        while (carry || vli_cmp(curve_p, result) != 1) {
+            carry -= vli_sub(result, result, curve_p);
+        }
+    }
+}
+#elif uECC_WORD_SIZE == 4
+static void vli_mmod_fast(uint32_t *RESTRICT result, uint32_t *RESTRICT product) {
+    uint32_t tmp[uECC_WORDS];
+    int carry;
+    
+    /* t */
+    vli_set(result, product);
+    
+    /* s1 */
+    tmp[0] = tmp[1] = tmp[2] = 0;
+    tmp[3] = product[11];
+    tmp[4] = product[12];
+    tmp[5] = product[13];
+    tmp[6] = product[14];
+    tmp[7] = product[15];
+    carry = vli_add(tmp, tmp, tmp);
+    carry += vli_add(result, result, tmp);
+    
+    /* s2 */
+    tmp[3] = product[12];
+    tmp[4] = product[13];
+    tmp[5] = product[14];
+    tmp[6] = product[15];
+    tmp[7] = 0;
+    carry += vli_add(tmp, tmp, tmp);
+    carry += vli_add(result, result, tmp);
+    
+    /* s3 */
+    tmp[0] = product[8];
+    tmp[1] = product[9];
+    tmp[2] = product[10];
+    tmp[3] = tmp[4] = tmp[5] = 0;
+    tmp[6] = product[14];
+    tmp[7] = product[15];
+    carry += vli_add(result, result, tmp);
+    
+    /* s4 */
+    tmp[0] = product[9];
+    tmp[1] = product[10];
+    tmp[2] = product[11];
+    tmp[3] = product[13];
+    tmp[4] = product[14];
+    tmp[5] = product[15];
+    tmp[6] = product[13];
+    tmp[7] = product[8];
+    carry += vli_add(result, result, tmp);
+    
+    /* d1 */
+    tmp[0] = product[11];
+    tmp[1] = product[12];
+    tmp[2] = product[13];
+    tmp[3] = tmp[4] = tmp[5] = 0;
+    tmp[6] = product[8];
+    tmp[7] = product[10];
+    carry -= vli_sub(result, result, tmp);
+    
+    /* d2 */
+    tmp[0] = product[12];
+    tmp[1] = product[13];
+    tmp[2] = product[14];
+    tmp[3] = product[15];
+    tmp[4] = tmp[5] = 0;
+    tmp[6] = product[9];
+    tmp[7] = product[11];
+    carry -= vli_sub(result, result, tmp);
+    
+    /* d3 */
+    tmp[0] = product[13];
+    tmp[1] = product[14];
+    tmp[2] = product[15];
+    tmp[3] = product[8];
+    tmp[4] = product[9];
+    tmp[5] = product[10];
+    tmp[6] = 0;
+    tmp[7] = product[12];
+    carry -= vli_sub(result, result, tmp);
+    
+    /* d4 */
+    tmp[0] = product[14];
+    tmp[1] = product[15];
+    tmp[2] = 0;
+    tmp[3] = product[9];
+    tmp[4] = product[10];
+    tmp[5] = product[11];
+    tmp[6] = 0;
+    tmp[7] = product[13];
+    carry -= vli_sub(result, result, tmp);
+    
+    if (carry < 0) {
+        do {
+            carry += vli_add(result, result, curve_p);
+        } while (carry < 0);
+    } else {
+        while (carry || vli_cmp(curve_p, result) != 1) {
+            carry -= vli_sub(result, result, curve_p);
+        }
+    }
+}
+#else
+static void vli_mmod_fast(uint64_t *RESTRICT result, uint64_t *RESTRICT product) {
+    uint64_t tmp[uECC_WORDS];
+    int carry;
+    
+    /* t */
+    vli_set(result, product);
+    
+    /* s1 */
+    tmp[0] = 0;
+    tmp[1] = product[5] & 0xffffffff00000000ull;
+    tmp[2] = product[6];
+    tmp[3] = product[7];
+    carry = vli_add(tmp, tmp, tmp);
+    carry += vli_add(result, result, tmp);
+    
+    /* s2 */
+    tmp[1] = product[6] << 32;
+    tmp[2] = (product[6] >> 32) | (product[7] << 32);
+    tmp[3] = product[7] >> 32;
+    carry += vli_add(tmp, tmp, tmp);
+    carry += vli_add(result, result, tmp);
+    
+    /* s3 */
+    tmp[0] = product[4];
+    tmp[1] = product[5] & 0xffffffff;
+    tmp[2] = 0;
+    tmp[3] = product[7];
+    carry += vli_add(result, result, tmp);
+    
+    /* s4 */
+    tmp[0] = (product[4] >> 32) | (product[5] << 32);
+    tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull);
+    tmp[2] = product[7];
+    tmp[3] = (product[6] >> 32) | (product[4] << 32);
+    carry += vli_add(result, result, tmp);
+    
+    /* d1 */
+    tmp[0] = (product[5] >> 32) | (product[6] << 32);
+    tmp[1] = (product[6] >> 32);
+    tmp[2] = 0;
+    tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32);
+    carry -= vli_sub(result, result, tmp);
+    
+    /* d2 */
+    tmp[0] = product[6];
+    tmp[1] = product[7];
+    tmp[2] = 0;
+    tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull);
+    carry -= vli_sub(result, result, tmp);
+    
+    /* d3 */
+    tmp[0] = (product[6] >> 32) | (product[7] << 32);
+    tmp[1] = (product[7] >> 32) | (product[4] << 32);
+    tmp[2] = (product[4] >> 32) | (product[5] << 32);
+    tmp[3] = (product[6] << 32);
+    carry -= vli_sub(result, result, tmp);
+    
+    /* d4 */
+    tmp[0] = product[7];
+    tmp[1] = product[4] & 0xffffffff00000000ull;
+    tmp[2] = product[5];
+    tmp[3] = product[6] & 0xffffffff00000000ull;
+    carry -= vli_sub(result, result, tmp);
+    
+    if (carry < 0) {
+        do {
+            carry += vli_add(result, result, curve_p);
+        } while (carry < 0);
+    } else {
+        while (carry || vli_cmp(curve_p, result) != 1) {
+            carry -= vli_sub(result, result, curve_p);
+        }
+    }
+}
+#endif /* uECC_WORD_SIZE */
+
+#elif uECC_CURVE == uECC_secp256k1
+
+#if uECC_WORD_SIZE == 1
+static void omega_mult(uint8_t * RESTRICT result, const uint8_t * RESTRICT right) {
+    /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */
+    uECC_word_t r0 = 0;
+    uECC_word_t r1 = 0;
+    uECC_word_t r2 = 0;
+    wordcount_t k;
+    
+    /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */
+    muladd(0xD1, right[0], &r0, &r1, &r2);
+    result[0] = r0;
+    r0 = r1;
+    r1 = r2;
+    /* r2 is still 0 */
+    
+    for (k = 1; k < uECC_WORDS; ++k) {
+        muladd(0x03, right[k - 1], &r0, &r1, &r2);
+        muladd(0xD1, right[k], &r0, &r1, &r2);
+        result[k] = r0;
+        r0 = r1;
+        r1 = r2;
+        r2 = 0;
+    }
+    muladd(0x03, right[uECC_WORDS - 1], &r0, &r1, &r2);
+    result[uECC_WORDS] = r0;
+    result[uECC_WORDS + 1] = r1;
+
+    result[4 + uECC_WORDS] = vli_add(result + 4, result + 4, right); /* add the 2^32 multiple */
+}
+#elif uECC_WORD_SIZE == 4
+static void omega_mult(uint32_t * RESTRICT result, const uint32_t * RESTRICT right) {
+    /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */
+    uint32_t carry = 0;
+    wordcount_t k;
+    
+    for (k = 0; k < uECC_WORDS; ++k) {
+        uint64_t p = (uint64_t)0x3D1 * right[k] + carry;
+        result[k] = (p & 0xffffffff);
+        carry = p >> 32;
+    }
+    result[uECC_WORDS] = carry;
+    
+    result[1 + uECC_WORDS] = vli_add(result + 1, result + 1, right); /* add the 2^32 multiple */
+}
+#else
+static void omega_mult(uint64_t * RESTRICT result, const uint64_t * RESTRICT right) {
+    uECC_word_t r0 = 0;
+    uECC_word_t r1 = 0;
+    uECC_word_t r2 = 0;
+    wordcount_t k;
+    
+    /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */
+    for (k = 0; k < uECC_WORDS; ++k) {
+        muladd(0x1000003D1ull, right[k], &r0, &r1, &r2);
+        result[k] = r0;
+        r0 = r1;
+        r1 = r2;
+        r2 = 0;
+    }
+    result[uECC_WORDS] = r0;
+}
+#endif /* uECC_WORD_SIZE */
+
+#elif uECC_CURVE == uECC_secp224r1
+
+/* Computes result = product % curve_p
+   from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+#if uECC_WORD_SIZE == 1
+// TODO it may be faster to use the omega_mult method when fully asm optimized.
+void vli_mmod_fast(uint8_t *RESTRICT result, uint8_t *RESTRICT product) {
+    uint8_t tmp[uECC_WORDS];
+    int8_t carry;
+
+    /* t */
+    vli_set(result, product);
+
+    /* s1 */
+    tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;
+    tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;
+    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;
+    tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31];
+    tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35];
+    tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39];
+    tmp[24] = product[40]; tmp[25] = product[41]; tmp[26] = product[42]; tmp[27] = product[43];
+    carry = vli_add(result, result, tmp);
+
+    /* s2 */
+    tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47];
+    tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51];
+    tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55];
+    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;
+    carry += vli_add(result, result, tmp);
+
+    /* d1 */
+    tmp[0]  = product[28]; tmp[1]  = product[29]; tmp[2]  = product[30]; tmp[3]  = product[31];
+    tmp[4]  = product[32]; tmp[5]  = product[33]; tmp[6]  = product[34]; tmp[7]  = product[35];
+    tmp[8]  = product[36]; tmp[9]  = product[37]; tmp[10] = product[38]; tmp[11] = product[39];
+    tmp[12] = product[40]; tmp[13] = product[41]; tmp[14] = product[42]; tmp[15] = product[43];
+    tmp[16] = product[44]; tmp[17] = product[45]; tmp[18] = product[46]; tmp[19] = product[47];
+    tmp[20] = product[48]; tmp[21] = product[49]; tmp[22] = product[50]; tmp[23] = product[51];
+    tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55];
+    carry -= vli_sub(result, result, tmp);
+
+    /* d2 */
+    tmp[0]  = product[44]; tmp[1]  = product[45]; tmp[2]  = product[46]; tmp[3]  = product[47];
+    tmp[4]  = product[48]; tmp[5]  = product[49]; tmp[6]  = product[50]; tmp[7]  = product[51];
+    tmp[8]  = product[52]; tmp[9]  = product[53]; tmp[10] = product[54]; tmp[11] = product[55];
+    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;
+    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;
+    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;
+    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;
+    carry -= vli_sub(result, result, tmp);
+
+    if (carry < 0) {
+        do {
+            carry += vli_add(result, result, curve_p);
+        } while (carry < 0);
+    } else {
+        while (carry || vli_cmp(curve_p, result) != 1) {
+            carry -= vli_sub(result, result, curve_p);
+        }
+    }
+}
+#elif uECC_WORD_SIZE == 4
+void vli_mmod_fast(uint32_t *RESTRICT result, uint32_t *RESTRICT product)
+{
+    uint32_t tmp[uECC_WORDS];
+    int carry;
+
+    /* t */
+    vli_set(result, product);
+
+    /* s1 */
+    tmp[0] = tmp[1] = tmp[2] = 0;
+    tmp[3] = product[7];
+    tmp[4] = product[8];
+    tmp[5] = product[9];
+    tmp[6] = product[10];
+    carry = vli_add(result, result, tmp);
+
+    /* s2 */
+    tmp[3] = product[11];
+    tmp[4] = product[12];
+    tmp[5] = product[13];
+    tmp[6] = 0;
+    carry += vli_add(result, result, tmp);
+
+    /* d1 */
+    tmp[0] = product[7];
+    tmp[1] = product[8];
+    tmp[2] = product[9];
+    tmp[3] = product[10];
+    tmp[4] = product[11];
+    tmp[5] = product[12];
+    tmp[6] = product[13];
+    carry -= vli_sub(result, result, tmp);
+
+    /* d2 */
+    tmp[0] = product[11];
+    tmp[1] = product[12];
+    tmp[2] = product[13];
+    tmp[3] = tmp[4] = tmp[5] = tmp[6] = 0;
+    carry -= vli_sub(result, result, tmp);
+
+    if (carry < 0) {
+        do {
+            carry += vli_add(result, result, curve_p);
+        } while (carry < 0);
+    } else {
+        while (carry || vli_cmp(curve_p, result) != 1) {
+            carry -= vli_sub(result, result, curve_p);
+        }
+    }
+}
+#endif /* uECC_WORD_SIZE */
+
+#endif /* uECC_CURVE */
+#endif /* !asm_mmod_fast */
+
+/* Computes result = (left * right) % curve_p. */
+static void vli_modMult_fast(uECC_word_t *result,
+                             const uECC_word_t *left,
+                             const uECC_word_t *right) {
+    uECC_word_t product[2 * uECC_WORDS];
+    vli_mult(product, left, right);
+    vli_mmod_fast(result, product);
+}
+
+#if uECC_SQUARE_FUNC
+
+/* Computes result = left^2 % curve_p. */
+static void vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left) {
+    uECC_word_t product[2 * uECC_WORDS];
+    vli_square(product, left);
+    vli_mmod_fast(result, product);
+}
+
+#else /* uECC_SQUARE_FUNC */
+
+#define vli_modSquare_fast(result, left) vli_modMult_fast((result), (left), (left))
+    
+#endif /* uECC_SQUARE_FUNC */
+
+
+#define EVEN(vli) (!(vli[0] & 1))
+/* Computes result = (1 / input) % mod. All VLIs are the same size.
+   See "From Euclid's GCD to Montgomery Multiplication to the Great Divide"
+   https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf */
+#if !asm_modInv
+static void vli_modInv(uECC_word_t *result, const uECC_word_t *input, const uECC_word_t *mod) {
+    uECC_word_t a[uECC_WORDS], b[uECC_WORDS], u[uECC_WORDS], v[uECC_WORDS];
+    uECC_word_t carry;
+    cmpresult_t cmpResult;
+    
+    if (vli_isZero(input)) {
+        vli_clear(result);
+        return;
+    }
+
+    vli_set(a, input);
+    vli_set(b, mod);
+    vli_clear(u);
+    u[0] = 1;
+    vli_clear(v);
+    while ((cmpResult = vli_cmp(a, b)) != 0) {
+        carry = 0;
+        if (EVEN(a)) {
+            vli_rshift1(a);
+            if (!EVEN(u)) {
+                carry = vli_add(u, u, mod);
+            }
+            vli_rshift1(u);
+            if (carry) {
+                u[uECC_WORDS - 1] |= HIGH_BIT_SET;
+            }
+        } else if (EVEN(b)) {
+            vli_rshift1(b);
+            if (!EVEN(v)) {
+                carry = vli_add(v, v, mod);
+            }
+            vli_rshift1(v);
+            if (carry) {
+                v[uECC_WORDS - 1] |= HIGH_BIT_SET;
+            }
+        } else if (cmpResult > 0) {
+            vli_sub(a, a, b);
+            vli_rshift1(a);
+            if (vli_cmp(u, v) < 0) {
+                vli_add(u, u, mod);
+            }
+            vli_sub(u, u, v);
+            if (!EVEN(u)) {
+                carry = vli_add(u, u, mod);
+            }
+            vli_rshift1(u);
+            if (carry) {
+                u[uECC_WORDS - 1] |= HIGH_BIT_SET;
+            }
+        } else {
+            vli_sub(b, b, a);
+            vli_rshift1(b);
+            if (vli_cmp(v, u) < 0) {
+                vli_add(v, v, mod);
+            }
+            vli_sub(v, v, u);
+            if (!EVEN(v)) {
+                carry = vli_add(v, v, mod);
+            }
+            vli_rshift1(v);
+            if (carry) {
+                v[uECC_WORDS - 1] |= HIGH_BIT_SET;
+            }
+        }
+    }
+    vli_set(result, u);
+}
+#endif /* !asm_modInv */
+
+/* ------ Point operations ------ */
+
+/* Returns 1 if 'point' is the point at infinity, 0 otherwise. */
+static cmpresult_t EccPoint_isZero(const EccPoint *point) {
+    return (vli_isZero(point->x) && vli_isZero(point->y));
+}
+
+/* Point multiplication algorithm using Montgomery's ladder with co-Z coordinates.
+From http://eprint.iacr.org/2011/338.pdf
+*/
+
+/* Double in place */
+#if (uECC_CURVE == uECC_secp256k1)
+static void EccPoint_double_jacobian(uECC_word_t * RESTRICT X1,
+                                     uECC_word_t * RESTRICT Y1,
+                                     uECC_word_t * RESTRICT Z1) {
+    /* t1 = X, t2 = Y, t3 = Z */
+    uECC_word_t t4[uECC_WORDS];
+    uECC_word_t t5[uECC_WORDS];
+    
+    if (vli_isZero(Z1)) {
+        return;
+    }
+    
+    vli_modSquare_fast(t5, Y1);   /* t5 = y1^2 */
+    vli_modMult_fast(t4, X1, t5); /* t4 = x1*y1^2 = A */
+    vli_modSquare_fast(X1, X1);   /* t1 = x1^2 */
+    vli_modSquare_fast(t5, t5);   /* t5 = y1^4 */
+    vli_modMult_fast(Z1, Y1, Z1); /* t3 = y1*z1 = z3 */
+    
+    vli_modAdd(Y1, X1, X1, curve_p); /* t2 = 2*x1^2 */
+    vli_modAdd(Y1, Y1, X1, curve_p); /* t2 = 3*x1^2 */
+    if (vli_testBit(Y1, 0)) {
+        uECC_word_t carry = vli_add(Y1, Y1, curve_p);
+        vli_rshift1(Y1);
+        Y1[uECC_WORDS - 1] |= carry << (uECC_WORD_BITS - 1);
+    } else {
+        vli_rshift1(Y1);
+    }
+    /* t2 = 3/2*(x1^2) = B */
+    
+    vli_modSquare_fast(X1, Y1);      /* t1 = B^2 */
+    vli_modSub(X1, X1, t4, curve_p); /* t1 = B^2 - A */
+    vli_modSub(X1, X1, t4, curve_p); /* t1 = B^2 - 2A = x3 */
+    
+    vli_modSub(t4, t4, X1, curve_p); /* t4 = A - x3 */
+    vli_modMult_fast(Y1, Y1, t4);    /* t2 = B * (A - x3) */
+    vli_modSub(Y1, Y1, t5, curve_p); /* t2 = B * (A - x3) - y1^4 = y3 */
+}
+#else
+static void EccPoint_double_jacobian(uECC_word_t * RESTRICT X1,
+                                     uECC_word_t * RESTRICT Y1,
+                                     uECC_word_t * RESTRICT Z1) {
+    /* t1 = X, t2 = Y, t3 = Z */
+    uECC_word_t t4[uECC_WORDS];
+    uECC_word_t t5[uECC_WORDS];
+    
+    if (vli_isZero(Z1)) {
+        return;
+    }
+    
+    vli_modSquare_fast(t4, Y1);   /* t4 = y1^2 */
+    vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */
+    vli_modSquare_fast(t4, t4);   /* t4 = y1^4 */
+    vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */
+    vli_modSquare_fast(Z1, Z1);   /* t3 = z1^2 */
+    
+    vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */
+    vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */
+    vli_modSub_fast(Z1, X1, Z1);     /* t3 = x1 - z1^2 */
+    vli_modMult_fast(X1, X1, Z1);    /* t1 = x1^2 - z1^4 */
+    
+    vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */
+    vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */
+    if (vli_testBit(X1, 0)) {
+        uECC_word_t l_carry = vli_add(X1, X1, curve_p);
+        vli_rshift1(X1);
+        X1[uECC_WORDS - 1] |= l_carry << (uECC_WORD_BITS - 1);
+    } else {
+        vli_rshift1(X1);
+    }
+    /* t1 = 3/2*(x1^2 - z1^4) = B */
+    
+    vli_modSquare_fast(Z1, X1);   /* t3 = B^2 */
+    vli_modSub_fast(Z1, Z1, t5);  /* t3 = B^2 - A */
+    vli_modSub_fast(Z1, Z1, t5);  /* t3 = B^2 - 2A = x3 */
+    vli_modSub_fast(t5, t5, Z1);  /* t5 = A - x3 */
+    vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */
+    vli_modSub_fast(t4, X1, t4);  /* t4 = B * (A - x3) - y1^4 = y3 */
+    
+    vli_set(X1, Z1);
+    vli_set(Z1, Y1);
+    vli_set(Y1, t4);
+}
+#endif
+
+/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */
+static void apply_z(uECC_word_t * RESTRICT X1,
+                    uECC_word_t * RESTRICT Y1,
+                    const uECC_word_t * RESTRICT Z) {
+    uECC_word_t t1[uECC_WORDS];
+
+    vli_modSquare_fast(t1, Z);    /* z^2 */
+    vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */
+    vli_modMult_fast(t1, t1, Z);  /* z^3 */
+    vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */
+}
+
+/* P = (x1, y1) => 2P, (x2, y2) => P' */
+static void XYcZ_initial_double(uECC_word_t * RESTRICT X1,
+                                uECC_word_t * RESTRICT Y1,
+                                uECC_word_t * RESTRICT X2,
+                                uECC_word_t * RESTRICT Y2,
+                                const uECC_word_t * RESTRICT initial_Z) {
+    uECC_word_t z[uECC_WORDS];
+    if (initial_Z) {
+        vli_set(z, initial_Z);
+    } else {
+        vli_clear(z);
+        z[0] = 1;
+    }
+
+    vli_set(X2, X1);
+    vli_set(Y2, Y1);
+
+    apply_z(X1, Y1, z);
+    EccPoint_double_jacobian(X1, Y1, z);
+    apply_z(X2, Y2, z);
+}
+
+/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
+   Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3)
+   or P => P', Q => P + Q
+*/
+static void XYcZ_add(uECC_word_t * RESTRICT X1,
+                     uECC_word_t * RESTRICT Y1,
+                     uECC_word_t * RESTRICT X2,
+                     uECC_word_t * RESTRICT Y2) {
+    /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
+    uECC_word_t t5[uECC_WORDS];
+    
+    vli_modSub_fast(t5, X2, X1);  /* t5 = x2 - x1 */
+    vli_modSquare_fast(t5, t5);   /* t5 = (x2 - x1)^2 = A */
+    vli_modMult_fast(X1, X1, t5); /* t1 = x1*A = B */
+    vli_modMult_fast(X2, X2, t5); /* t3 = x2*A = C */
+    vli_modSub_fast(Y2, Y2, Y1);  /* t4 = y2 - y1 */
+    vli_modSquare_fast(t5, Y2);   /* t5 = (y2 - y1)^2 = D */
+    
+    vli_modSub_fast(t5, t5, X1);  /* t5 = D - B */
+    vli_modSub_fast(t5, t5, X2);  /* t5 = D - B - C = x3 */
+    vli_modSub_fast(X2, X2, X1);  /* t3 = C - B */
+    vli_modMult_fast(Y1, Y1, X2); /* t2 = y1*(C - B) */
+    vli_modSub_fast(X2, X1, t5);  /* t3 = B - x3 */
+    vli_modMult_fast(Y2, Y2, X2); /* t4 = (y2 - y1)*(B - x3) */
+    vli_modSub_fast(Y2, Y2, Y1);  /* t4 = y3 */
+    
+    vli_set(X2, t5);
+}
+
+/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
+   Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
+   or P => P - Q, Q => P + Q
+*/
+static void XYcZ_addC(uECC_word_t * RESTRICT X1,
+                      uECC_word_t * RESTRICT Y1,
+                      uECC_word_t * RESTRICT X2,
+                      uECC_word_t * RESTRICT Y2) {
+    /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
+    uECC_word_t t5[uECC_WORDS];
+    uECC_word_t t6[uECC_WORDS];
+    uECC_word_t t7[uECC_WORDS];
+    
+    vli_modSub_fast(t5, X2, X1);     /* t5 = x2 - x1 */
+    vli_modSquare_fast(t5, t5);      /* t5 = (x2 - x1)^2 = A */
+    vli_modMult_fast(X1, X1, t5);    /* t1 = x1*A = B */
+    vli_modMult_fast(X2, X2, t5);    /* t3 = x2*A = C */
+    vli_modAdd(t5, Y2, Y1, curve_p); /* t5 = y2 + y1 */
+    vli_modSub_fast(Y2, Y2, Y1);     /* t4 = y2 - y1 */
+
+    vli_modSub_fast(t6, X2, X1);     /* t6 = C - B */
+    vli_modMult_fast(Y1, Y1, t6);    /* t2 = y1 * (C - B) = E */
+    vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */
+    vli_modSquare_fast(X2, Y2);      /* t3 = (y2 - y1)^2 = D */
+    vli_modSub_fast(X2, X2, t6);     /* t3 = D - (B + C) = x3 */
+    
+    vli_modSub_fast(t7, X1, X2);  /* t7 = B - x3 */
+    vli_modMult_fast(Y2, Y2, t7); /* t4 = (y2 - y1)*(B - x3) */
+    vli_modSub_fast(Y2, Y2, Y1);  /* t4 = (y2 - y1)*(B - x3) - E = y3 */
+    
+    vli_modSquare_fast(t7, t5);   /* t7 = (y2 + y1)^2 = F */
+    vli_modSub_fast(t7, t7, t6);  /* t7 = F - (B + C) = x3' */
+    vli_modSub_fast(t6, t7, X1);  /* t6 = x3' - B */
+    vli_modMult_fast(t6, t6, t5); /* t6 = (y2 + y1)*(x3' - B) */
+    vli_modSub_fast(Y1, t6, Y1);  /* t2 = (y2 + y1)*(x3' - B) - E = y3' */
+    
+    vli_set(X1, t7);
+}
+
+static void EccPoint_mult(EccPoint * RESTRICT result,
+                          const EccPoint * RESTRICT point,
+                          const uECC_word_t * RESTRICT scalar,
+                          const uECC_word_t * RESTRICT initialZ,
+                          bitcount_t numBits) {
+    /* R0 and R1 */
+    uECC_word_t Rx[2][uECC_WORDS];
+    uECC_word_t Ry[2][uECC_WORDS];
+    uECC_word_t z[uECC_WORDS];
+    bitcount_t i;
+    uECC_word_t nb;
+    
+    vli_set(Rx[1], point->x);
+    vli_set(Ry[1], point->y);
+
+    XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initialZ);
+
+    for (i = numBits - 2; i > 0; --i) {
+        nb = !vli_testBit(scalar, i);
+        XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb]);
+        XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb]);
+    }
+
+    nb = !vli_testBit(scalar, 0);
+    XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb]);
+    
+    /* Find final 1/Z value. */
+    vli_modSub_fast(z, Rx[1], Rx[0]);   /* X1 - X0 */
+    vli_modMult_fast(z, z, Ry[1 - nb]); /* Yb * (X1 - X0) */
+    vli_modMult_fast(z, z, point->x); /* xP * Yb * (X1 - X0) */
+    vli_modInv(z, z, curve_p);          /* 1 / (xP * Yb * (X1 - X0)) */
+    vli_modMult_fast(z, z, point->y); /* yP / (xP * Yb * (X1 - X0)) */
+    vli_modMult_fast(z, z, Rx[1 - nb]); /* Xb * yP / (xP * Yb * (X1 - X0)) */
+    /* End 1/Z calculation */
+
+    XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb]);
+    apply_z(Rx[0], Ry[0], z);
+    
+    vli_set(result->x, Rx[0]);
+    vli_set(result->y, Ry[0]);
+}
+
+static int EccPoint_compute_public_key(EccPoint *result, uECC_word_t *private) {
+#ifdef QCOM_4004B
+
+#else 
+    /*uECC_word_t tmp1[uECC_WORDS];*/
+    /*uECC_word_t tmp2[uECC_WORDS];*/
+    /*uECC_word_t *p2[2] = {tmp1, tmp2};*/
+    /*uECC_word_t carry;*/
+#endif  
+
+    /* Make sure the private key is in the range [1, n-1]. */
+    if (vli_isZero(private)) {
+        return 0;
+    }
+
+#if (uECC_CURVE == uECC_secp160r1)
+    // Don't regularize the bitcount for secp160r1, since it would have a larger performance
+    // impact (about 2% slower on average) and requires the vli_xxx_n functions, leading to
+    // a significant increase in code size.
+
+    EccPoint_mult(result, &curve_G, private, 0, vli_numBits(private, uECC_WORDS));
+#else
+    if (vli_cmp(curve_n, private) != 1) {
+        return 0;
+    }
+
+    // Regularize the bitcount for the private key so that attackers cannot use a side channel
+    // attack to learn the number of leading zeros.
+    carry = vli_add(tmp1, private, curve_n);
+    vli_add(tmp2, tmp1, curve_n);
+    EccPoint_mult(result, &curve_G, p2[!carry], 0, (uECC_BYTES * 8) + 1);
+#endif
+
+    if (EccPoint_isZero(result)) {
+        return 0;
+    }
+    return 1;
+}
+
+#if uECC_CURVE == uECC_secp224r1
+
+/* Routine 3.2.4 RS;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+static void mod_sqrt_secp224r1_rs(uECC_word_t *d1,
+                                  uECC_word_t *e1,
+                                  uECC_word_t *f1,
+                                  const uECC_word_t *d0,
+                                  const uECC_word_t *e0,
+                                  const uECC_word_t *f0) {
+    uECC_word_t t[uECC_WORDS];
+
+    vli_modSquare_fast(t, d0);                 /* t <-- d0 ^ 2 */
+    vli_modMult_fast(e1, d0, e0);              /* e1 <-- d0 * e0 */
+    vli_modAdd(d1, t, f0, curve_p);            /* d1 <-- t  + f0 */
+    vli_modAdd(e1, e1, e1, curve_p);           /* e1 <-- e1 + e1 */
+    vli_modMult_fast(f1, t, f0);               /* f1 <-- t  * f0 */
+    vli_modAdd(f1, f1, f1, curve_p);           /* f1 <-- f1 + f1 */
+    vli_modAdd(f1, f1, f1, curve_p);           /* f1 <-- f1 + f1 */
+}
+
+/* Routine 3.2.5 RSS;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+static void mod_sqrt_secp224r1_rss(uECC_word_t *d1,
+                                   uECC_word_t *e1,
+                                   uECC_word_t *f1,
+                                   const uECC_word_t *d0,
+                                   const uECC_word_t *e0,
+                                   const uECC_word_t *f0,
+                                   const bitcount_t j) {
+    bitcount_t i;
+
+    vli_set(d1, d0);                           /* d1 <-- d0 */
+    vli_set(e1, e0);                           /* e1 <-- e0 */
+    vli_set(f1, f0);                           /* f1 <-- f0 */
+    for (i = 1; i <= j; i++) {
+        mod_sqrt_secp224r1_rs(d1, e1, f1, d1, e1, f1); /* RS (d1,e1,f1,d1,e1,f1) */
+    }
+}
+
+/* Routine 3.2.6 RM;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+static void mod_sqrt_secp224r1_rm(uECC_word_t *d2,
+                                  uECC_word_t *e2,
+                                  uECC_word_t *f2,
+                                  const uECC_word_t *c,
+                                  const uECC_word_t *d0,
+                                  const uECC_word_t *e0,
+                                  const uECC_word_t *d1,
+                                  const uECC_word_t *e1) {
+    uECC_word_t t1[uECC_WORDS];
+    uECC_word_t t2[uECC_WORDS];
+
+    vli_modMult_fast(t1, e0, e1);              /* t1 <-- e0 * e1 */
+    vli_modMult_fast(t1, t1, c);               /* t1 <-- t1 * c */
+    vli_modSub_fast(t1, curve_p, t1);          /* t1 <-- p  - t1 */
+    vli_modMult_fast(t2, d0, d1);              /* t2 <-- d0 * d1 */
+    vli_modAdd(t2, t2, t1, curve_p);           /* t2 <-- t2 + t1 */
+    vli_modMult_fast(t1, d0, e1);              /* t1 <-- d0 * e1 */
+    vli_modMult_fast(e2, d1, e0);              /* e2 <-- d1 * e0 */
+    vli_modAdd(e2, e2, t1, curve_p);           /* e2 <-- e2 + t1 */
+    vli_modSquare_fast(f2, e2);                /* f2 <-- e2^2 */
+    vli_modMult_fast(f2, f2, c);               /* f2 <-- f2 * c */
+    vli_modSub_fast(f2, curve_p, f2);          /* f2 <-- p  - f2 */
+    vli_set(d2, t2);                           /* d2 <-- t2 */
+}
+
+/* Routine 3.2.7 RP;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+static void mod_sqrt_secp224r1_rp(uECC_word_t *d1,
+                                  uECC_word_t *e1,
+                                  uECC_word_t *f1,
+                                  const uECC_word_t *c,
+                                  const uECC_word_t *r) {
+    wordcount_t i;
+    wordcount_t pow2i = 1;
+    uECC_word_t d0[uECC_WORDS];
+    uECC_word_t e0[uECC_WORDS] = {1};          /* e0 <-- 1 */
+    uECC_word_t f0[uECC_WORDS];
+
+    vli_set(d0, r);                            /* d0 <-- r */
+    vli_modSub_fast(f0, curve_p, c);           /* f0 <-- p  - c */
+    for (i = 0; i <= 6; i++) {
+        mod_sqrt_secp224r1_rss(d1, e1, f1, d0, e0, f0, pow2i); /* RSS (d1,e1,f1,d0,e0,f0,2^i) */
+        mod_sqrt_secp224r1_rm(d1, e1, f1, c, d1, e1, d0, e0);  /* RM (d1,e1,f1,c,d1,e1,d0,e0) */
+        vli_set(d0, d1);                       /* d0 <-- d1 */
+        vli_set(e0, e1);                       /* e0 <-- e1 */
+        vli_set(f0, f1);                       /* f0 <-- f1 */
+        pow2i *= 2;
+    }
+}
+
+/* Compute a = sqrt(a) (mod curve_p). */
+/* Routine 3.2.8 mp_mod_sqrt_224; from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+static void mod_sqrt(uECC_word_t *a) {
+    bitcount_t i;
+    uECC_word_t e1[uECC_WORDS];
+    uECC_word_t f1[uECC_WORDS];
+    uECC_word_t d0[uECC_WORDS];
+    uECC_word_t e0[uECC_WORDS];
+    uECC_word_t f0[uECC_WORDS];
+    uECC_word_t d1[uECC_WORDS];
+
+    // s = a; using constant instead of random value
+    mod_sqrt_secp224r1_rp(d0, e0, f0, a, a);           /* RP (d0, e0, f0, c, s) */
+    mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0);     /* RS (d1, e1, f1, d0, e0, f0) */
+    for (i = 1; i <= 95; i++) {
+        vli_set(d0, d1);                               /* d0 <-- d1 */
+        vli_set(e0, e1);                               /* e0 <-- e1 */
+        vli_set(f0, f1);                               /* f0 <-- f1 */
+        mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0); /* RS (d1, e1, f1, d0, e0, f0) */
+        if (vli_isZero(d1)) {                          /* if d1 == 0 */
+	        break;
+        }
+    }
+    vli_modInv(f1, e0, curve_p);                       /* f1 <-- 1 / e0 */
+    vli_modMult_fast(a, d0, f1);                       /* a  <-- d0 / e0 */
+}
+
+#else /* uECC_CURVE */
+
+/* Compute a = sqrt(a) (mod curve_p). */
+static void mod_sqrt(uECC_word_t *a) {
+    bitcount_t i;
+    uECC_word_t p1[uECC_WORDS] = {1};
+    uECC_word_t l_result[uECC_WORDS] = {1};
+    
+    /* Since curve_p == 3 (mod 4) for all supported curves, we can
+       compute sqrt(a) = a^((curve_p + 1) / 4) (mod curve_p). */
+    vli_add(p1, curve_p, p1); /* p1 = curve_p + 1 */
+    for (i = vli_numBits(p1, uECC_WORDS) - 1; i > 1; --i) {
+        vli_modSquare_fast(l_result, l_result);
+        if (vli_testBit(p1, i)) {
+            vli_modMult_fast(l_result, l_result, a);
+        }
+    }
+    vli_set(a, l_result);
+}
+#endif /* uECC_CURVE */
+
+#if uECC_WORD_SIZE == 1
+
+static void vli_nativeToBytes(uint8_t * RESTRICT dest, const uint8_t * RESTRICT src) {
+    uint8_t i;
+    for (i = 0; i < uECC_BYTES; ++i) {
+        dest[i] = src[(uECC_BYTES - 1) - i];
+    }
+}
+
+#define vli_bytesToNative(dest, src) vli_nativeToBytes((dest), (src))
+
+#elif uECC_WORD_SIZE == 4
+
+static void vli_nativeToBytes(uint8_t *bytes, const uint32_t *native) {
+    unsigned i;
+    for (i = 0; i < uECC_WORDS; ++i) {
+        uint8_t *digit = bytes + 4 * (uECC_WORDS - 1 - i);
+        digit[0] = native[i] >> 24;
+        digit[1] = native[i] >> 16;
+        digit[2] = native[i] >> 8;
+        digit[3] = native[i];
+    }
+}
+
+static void vli_bytesToNative(uint32_t *native, const uint8_t *bytes) {
+    unsigned i;
+    for (i = 0; i < uECC_WORDS; ++i) {
+        const uint8_t *digit = bytes + 4 * (uECC_WORDS - 1 - i);
+        native[i] = ((uint32_t)digit[0] << 24) | ((uint32_t)digit[1] << 16) |
+                    ((uint32_t)digit[2] << 8) | (uint32_t)digit[3];
+    }
+}
+
+#else
+
+static void vli_nativeToBytes(uint8_t *bytes, const uint64_t *native) {
+    unsigned i;
+    for (i = 0; i < uECC_WORDS; ++i) {
+        uint8_t *digit = bytes + 8 * (uECC_WORDS - 1 - i);
+        digit[0] = native[i] >> 56;
+        digit[1] = native[i] >> 48;
+        digit[2] = native[i] >> 40;
+        digit[3] = native[i] >> 32;
+        digit[4] = native[i] >> 24;
+        digit[5] = native[i] >> 16;
+        digit[6] = native[i] >> 8;
+        digit[7] = native[i];
+    }
+}
+
+static void vli_bytesToNative(uint64_t *native, const uint8_t *bytes) {
+    unsigned i;
+    for (i = 0; i < uECC_WORDS; ++i) {
+        const uint8_t *digit = bytes + 8 * (uECC_WORDS - 1 - i);
+        native[i] = ((uint64_t)digit[0] << 56) | ((uint64_t)digit[1] << 48) |
+                    ((uint64_t)digit[2] << 40) | ((uint64_t)digit[3] << 32) |
+                    ((uint64_t)digit[4] << 24) | ((uint64_t)digit[5] << 16) |
+                    ((uint64_t)digit[6] << 8) | (uint64_t)digit[7];
+    }
+}
+
+#endif /* uECC_WORD_SIZE */
+
+int uECC_make_key(uint8_t public_key[uECC_BYTES*2], uint8_t private_key[uECC_BYTES]) {
+    uECC_word_t private[uECC_WORDS];
+    EccPoint public;
+    uECC_word_t tries;
+    for (tries = 0; tries < MAX_TRIES; ++tries) {
+        if (g_rng_function((uint8_t *)private, sizeof(private)) &&
+                EccPoint_compute_public_key(&public, private)) {
+            vli_nativeToBytes(private_key, private);
+            vli_nativeToBytes(public_key, public.x);
+            vli_nativeToBytes(public_key + uECC_BYTES, public.y);
+            return 1;
+        }
+    }
+    return 0;
+}
+
+int uECC_shared_secret(const uint8_t public_key[uECC_BYTES*2],
+                       const uint8_t private_key[uECC_BYTES],
+                       uint8_t secret[uECC_BYTES]) {
+    EccPoint public;
+    EccPoint product;
+    uECC_word_t private[uECC_WORDS];
+    uECC_word_t random[uECC_WORDS];
+#ifdef QCOM_4004B
+#else 
+    /*uECC_word_t tmp[uECC_WORDS];*/
+    /*uECC_word_t *p2[2] = {private, tmp};*/
+    /*uECC_word_t carry;*/
+#endif  
+    
+    
+    uECC_word_t *initial_Z = 0;
+    uECC_word_t tries;
+
+    
+    // Try to get a random initial Z value to improve protection against side-channel
+    // attacks. If the RNG fails every time (eg it was not defined), we continue so that
+    // uECC_shared_secret() can still work without an RNG defined.
+    for (tries = 0; tries < MAX_TRIES; ++tries) {
+        if (g_rng_function((uint8_t *)random, sizeof(random)) && !vli_isZero(random)) {
+            initial_Z = random;
+            break;
+        }
+    }
+    
+    vli_bytesToNative(private, private_key);
+    vli_bytesToNative(public.x, public_key);
+    vli_bytesToNative(public.y, public_key + uECC_BYTES);
+    
+#if (uECC_CURVE == uECC_secp160r1)
+    // Don't regularize the bitcount for secp160r1.
+    EccPoint_mult(&product, &public, private, initial_Z, vli_numBits(private, uECC_WORDS));
+#else
+    // Regularize the bitcount for the private key so that attackers cannot use a side channel
+    // attack to learn the number of leading zeros.
+    carry = vli_add(private, private, curve_n);
+    vli_add(tmp, private, curve_n);
+    EccPoint_mult(&product, &public, p2[!carry], initial_Z, (uECC_BYTES * 8) + 1);
+#endif
+
+    vli_nativeToBytes(secret, product.x);
+    return !EccPoint_isZero(&product);
+}
+
+void uECC_compress(const uint8_t public_key[uECC_BYTES*2], uint8_t compressed[uECC_BYTES+1]) {
+    wordcount_t i;
+    for (i = 0; i < uECC_BYTES; ++i) {
+        compressed[i+1] = public_key[i];
+    }
+    compressed[0] = 2 + (public_key[uECC_BYTES * 2 - 1] & 0x01);
+}
+
+/* Computes result = x^3 + ax + b. result must not overlap x. */
+static void curve_x_side(uECC_word_t * RESTRICT result, const uECC_word_t * RESTRICT x) {
+#if (uECC_CURVE == uECC_secp256k1)
+    vli_modSquare_fast(result, x); /* r = x^2 */
+    vli_modMult_fast(result, result, x); /* r = x^3 */
+    vli_modAdd(result, result, curve_b, curve_p); /* r = x^3 + b */
+#else
+    uECC_word_t _3[uECC_WORDS] = {3}; /* -a = 3 */
+
+    vli_modSquare_fast(result, x); /* r = x^2 */
+    vli_modSub_fast(result, result, _3); /* r = x^2 - 3 */
+    vli_modMult_fast(result, result, x); /* r = x^3 - 3x */
+    vli_modAdd(result, result, curve_b, curve_p); /* r = x^3 - 3x + b */
+#endif
+}
+
+void uECC_decompress(const uint8_t compressed[uECC_BYTES+1], uint8_t public_key[uECC_BYTES*2]) {
+    EccPoint point;
+    vli_bytesToNative(point.x, compressed + 1);
+    curve_x_side(point.y, point.x);
+    mod_sqrt(point.y);
+    
+    if ((point.y[0] & 0x01) != (compressed[0] & 0x01)) {
+        vli_sub(point.y, curve_p, point.y);
+    }
+    
+    vli_nativeToBytes(public_key, point.x);
+    vli_nativeToBytes(public_key + uECC_BYTES, point.y);
+}
+
+int uECC_valid_public_key(const uint8_t public_key[uECC_BYTES*2]) {
+    uECC_word_t tmp1[uECC_WORDS];
+    uECC_word_t tmp2[uECC_WORDS];
+    EccPoint public;
+    
+    vli_bytesToNative(public.x, public_key);
+    vli_bytesToNative(public.y, public_key + uECC_BYTES);
+    
+    // The point at infinity is invalid.
+    if (EccPoint_isZero(&public)) {
+        return 0;
+    }
+    
+    // x and y must be smaller than p.
+    if (vli_cmp(curve_p, public.x) != 1 || vli_cmp(curve_p, public.y) != 1) {
+        return 0;
+    }
+    
+    vli_modSquare_fast(tmp1, public.y); /* tmp1 = y^2 */
+    curve_x_side(tmp2, public.x); /* tmp2 = x^3 + ax + b */
+    
+    /* Make sure that y^2 == x^3 + ax + b */
+    return (vli_cmp(tmp1, tmp2) == 0);
+}
+
+int uECC_compute_public_key(const uint8_t private_key[uECC_BYTES],
+                            uint8_t public_key[uECC_BYTES * 2]) {
+    uECC_word_t private[uECC_WORDS];
+    EccPoint public;
+
+    vli_bytesToNative(private, private_key);
+
+    if (!EccPoint_compute_public_key(&public, private)) {
+        return 0;
+    }
+
+    vli_nativeToBytes(public_key, public.x);
+    vli_nativeToBytes(public_key + uECC_BYTES, public.y);
+    return 1;
+}
+
+int uECC_bytes(void) {
+    return uECC_BYTES;
+}
+
+int uECC_curve(void) {
+    return uECC_CURVE;
+}
+
+/* -------- ECDSA code -------- */
+
+#if (uECC_CURVE == uECC_secp160r1)
+static void vli_clear_n(uECC_word_t *vli) {
+    vli_clear(vli);
+    vli[uECC_N_WORDS - 1] = 0;
+}
+
+static uECC_word_t vli_isZero_n(const uECC_word_t *vli) {
+    if (vli[uECC_N_WORDS - 1]) {
+        return 0;
+    }
+    return vli_isZero(vli);
+}
+
+static void vli_set_n(uECC_word_t *dest, const uECC_word_t *src) {
+    vli_set(dest, src);
+    dest[uECC_N_WORDS - 1] = src[uECC_N_WORDS - 1];
+}
+
+static cmpresult_t vli_cmp_n(const uECC_word_t *left, const uECC_word_t *right) {
+    if (left[uECC_N_WORDS - 1] > right[uECC_N_WORDS - 1]) {
+        return 1;
+    } else if (left[uECC_N_WORDS - 1] < right[uECC_N_WORDS - 1]) {
+        return -1;
+    }
+    return vli_cmp(left, right);
+}
+
+static void vli_rshift1_n(uECC_word_t *vli) {
+    vli_rshift1(vli);
+    vli[uECC_N_WORDS - 2] |= vli[uECC_N_WORDS - 1] << (uECC_WORD_BITS - 1);
+    vli[uECC_N_WORDS - 1] = vli[uECC_N_WORDS - 1] >> 1;
+}
+
+static uECC_word_t vli_add_n(uECC_word_t *result,
+                             const uECC_word_t *left,
+                             const uECC_word_t *right) {
+    uECC_word_t carry = vli_add(result, left, right);
+    uECC_word_t sum = left[uECC_N_WORDS - 1] + right[uECC_N_WORDS - 1] + carry;
+    if (sum != left[uECC_N_WORDS - 1]) {
+        carry = (sum < left[uECC_N_WORDS - 1]);
+    }
+    result[uECC_N_WORDS - 1] = sum;
+    return carry;
+}
+
+static uECC_word_t vli_sub_n(uECC_word_t *result,
+                             const uECC_word_t *left,
+                             const uECC_word_t *right) {
+    uECC_word_t borrow = vli_sub(result, left, right);
+    uECC_word_t diff = left[uECC_N_WORDS - 1] - right[uECC_N_WORDS - 1] - borrow;
+    if (diff != left[uECC_N_WORDS - 1]) {
+        borrow = (diff > left[uECC_N_WORDS - 1]);
+    }
+    result[uECC_N_WORDS - 1] = diff;
+    return borrow;
+}
+
+#if !muladd_exists
+static void muladd(uECC_word_t a,
+                   uECC_word_t b,
+                   uECC_word_t *r0,
+                   uECC_word_t *r1,
+                   uECC_word_t *r2) {
+    uECC_dword_t p = (uECC_dword_t)a * b;
+    uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
+    r01 += p;
+    *r2 += (r01 < p);
+    *r1 = r01 >> uECC_WORD_BITS;
+    *r0 = (uECC_word_t)r01;
+}
+#define muladd_exists 1
+#endif
+
+static void vli_mult_n(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {
+    uECC_word_t r0 = 0;
+    uECC_word_t r1 = 0;
+    uECC_word_t r2 = 0;
+    wordcount_t i, k;
+    
+    for (k = 0; k < uECC_N_WORDS * 2 - 1; ++k) {
+        wordcount_t min = (k < uECC_N_WORDS ? 0 : (k + 1) - uECC_N_WORDS);
+        wordcount_t max = (k < uECC_N_WORDS ? k : uECC_N_WORDS - 1);
+        for (i = min; i <= max; ++i) {
+            muladd(left[i], right[k - i], &r0, &r1, &r2);
+        }
+        result[k] = r0;
+        r0 = r1;
+        r1 = r2;
+        r2 = 0;
+    }
+    result[uECC_N_WORDS * 2 - 1] = r0;
+}
+
+static void vli_modAdd_n(uECC_word_t *result,
+                         const uECC_word_t *left,
+                         const uECC_word_t *right,
+                         const uECC_word_t *mod) {
+    uECC_word_t carry = vli_add_n(result, left, right);
+    if (carry || vli_cmp_n(result, mod) >= 0) {
+        vli_sub_n(result, result, mod);
+    }
+}
+
+static void vli_modInv_n(uECC_word_t *result, const uECC_word_t *input, const uECC_word_t *mod) {
+    uECC_word_t a[uECC_N_WORDS], b[uECC_N_WORDS], u[uECC_N_WORDS], v[uECC_N_WORDS];
+    uECC_word_t carry;
+    cmpresult_t cmpResult;
+    
+    if (vli_isZero_n(input)) {
+        vli_clear_n(result);
+        return;
+    }
+
+    vli_set_n(a, input);
+    vli_set_n(b, mod);
+    vli_clear_n(u);
+    u[0] = 1;
+    vli_clear_n(v);
+    while ((cmpResult = vli_cmp_n(a, b)) != 0) {
+        carry = 0;
+        if (EVEN(a)) {
+            vli_rshift1_n(a);
+            if (!EVEN(u)) {
+                carry = vli_add_n(u, u, mod);
+            }
+            vli_rshift1_n(u);
+            if (carry) {
+                u[uECC_N_WORDS - 1] |= HIGH_BIT_SET;
+            }
+        } else if (EVEN(b)) {
+            vli_rshift1_n(b);
+            if (!EVEN(v)) {
+                carry = vli_add_n(v, v, mod);
+            }
+            vli_rshift1_n(v);
+            if (carry) {
+                v[uECC_N_WORDS - 1] |= HIGH_BIT_SET;
+            }
+        } else if (cmpResult > 0) {
+            vli_sub_n(a, a, b);
+            vli_rshift1_n(a);
+            if (vli_cmp_n(u, v) < 0) {
+                vli_add_n(u, u, mod);
+            }
+            vli_sub_n(u, u, v);
+            if (!EVEN(u)) {
+                carry = vli_add_n(u, u, mod);
+            }
+            vli_rshift1_n(u);
+            if (carry) {
+                u[uECC_N_WORDS - 1] |= HIGH_BIT_SET;
+            }
+        } else {
+            vli_sub_n(b, b, a);
+            vli_rshift1_n(b);
+            if (vli_cmp_n(v, u) < 0) {
+                vli_add_n(v, v, mod);
+            }
+            vli_sub_n(v, v, u);
+            if (!EVEN(v)) {
+                carry = vli_add_n(v, v, mod);
+            }
+            vli_rshift1_n(v);
+            if (carry) {
+                v[uECC_N_WORDS - 1] |= HIGH_BIT_SET;
+            }
+        }
+    }
+    vli_set_n(result, u);
+}
+
+static void vli2_rshift1_n(uECC_word_t *vli) {
+    vli_rshift1_n(vli);
+    vli[uECC_N_WORDS - 1] |= vli[uECC_N_WORDS] << (uECC_WORD_BITS - 1);
+    vli_rshift1_n(vli + uECC_N_WORDS);
+}
+
+static uECC_word_t vli2_sub_n(uECC_word_t *result,
+                              const uECC_word_t *left,
+                              const uECC_word_t *right) {
+    uECC_word_t borrow = 0;
+    wordcount_t i;
+    for (i = 0; i < uECC_N_WORDS * 2; ++i) {
+        uECC_word_t diff = left[i] - right[i] - borrow;
+        if (diff != left[i]) {
+            borrow = (diff > left[i]);
+        }
+        result[i] = diff;
+    }
+    return borrow;
+}
+
+/* Computes result = (left * right) % curve_n. */
+static void vli_modMult_n(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {
+    bitcount_t i;
+    uECC_word_t product[2 * uECC_N_WORDS];
+    uECC_word_t modMultiple[2 * uECC_N_WORDS];
+    uECC_word_t tmp[2 * uECC_N_WORDS];
+    uECC_word_t *v[2] = {tmp, product};
+    uECC_word_t index = 1;
+    
+    vli_mult_n(product, left, right);
+    vli_clear_n(modMultiple);
+    vli_set(modMultiple + uECC_N_WORDS + 1, curve_n);
+    vli_rshift1(modMultiple + uECC_N_WORDS + 1);
+    modMultiple[2 * uECC_N_WORDS - 1] |= HIGH_BIT_SET;
+    modMultiple[uECC_N_WORDS] = HIGH_BIT_SET;
+    
+    for (i = 0;
+         i <= ((((bitcount_t)uECC_N_WORDS) << uECC_WORD_BITS_SHIFT) + (uECC_WORD_BITS - 1));
+         ++i) {
+        uECC_word_t borrow = vli2_sub_n(v[1 - index], v[index], modMultiple);
+        index = !(index ^ borrow); /* Swap the index if there was no borrow */
+        vli2_rshift1_n(modMultiple);
+    }
+    vli_set_n(result, v[index]);
+}
+
+#else
+
+#define vli_cmp_n vli_cmp
+#define vli_modInv_n vli_modInv
+#define vli_modAdd_n vli_modAdd
+
+static void vli2_rshift1(uECC_word_t *vli) {
+    vli_rshift1(vli);
+    vli[uECC_WORDS - 1] |= vli[uECC_WORDS] << (uECC_WORD_BITS - 1);
+    vli_rshift1(vli + uECC_WORDS);
+}
+
+static uECC_word_t vli2_sub(uECC_word_t *result,
+                            const uECC_word_t *left,
+                            const uECC_word_t *right) {
+    uECC_word_t borrow = 0;
+    wordcount_t i;
+    for (i = 0; i < uECC_WORDS * 2; ++i) {
+        uECC_word_t diff = left[i] - right[i] - borrow;
+        if (diff != left[i]) {
+            borrow = (diff > left[i]);
+        }
+        result[i] = diff;
+    }
+    return borrow;
+}
+
+/* Computes result = (left * right) % curve_n. */
+static void vli_modMult_n(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {
+    uECC_word_t product[2 * uECC_WORDS];
+    uECC_word_t modMultiple[2 * uECC_WORDS];
+    uECC_word_t tmp[2 * uECC_WORDS];
+    uECC_word_t *v[2] = {tmp, product};
+    bitcount_t i;
+    uECC_word_t index = 1;
+    
+    vli_mult(product, left, right);
+    vli_set(modMultiple + uECC_WORDS, curve_n); /* works if curve_n has its highest bit set */
+    vli_clear(modMultiple);
+    
+    for (i = 0; i <= uECC_BYTES * 8; ++i) {
+        uECC_word_t borrow = vli2_sub(v[1 - index], v[index], modMultiple);
+        index = !(index ^ borrow); /* Swap the index if there was no borrow */
+        vli2_rshift1(modMultiple);
+    }
+    vli_set(result, v[index]);
+}
+#endif /* (uECC_CURVE != uECC_secp160r1) */
+
+static int uECC_sign_with_k(const uint8_t private_key[uECC_BYTES],
+                            const uint8_t message_hash[uECC_BYTES],
+                            uECC_word_t k[uECC_N_WORDS],
+                            uint8_t signature[uECC_BYTES*2]) {
+    uECC_word_t tmp[uECC_N_WORDS];
+    uECC_word_t s[uECC_N_WORDS];
+    uECC_word_t *k2[2] = {tmp, s};
+    EccPoint p;
+    uECC_word_t carry;
+    uECC_word_t tries;
+    
+    /* Make sure 0 < k < curve_n */
+    if (vli_isZero(k) || vli_cmp_n(curve_n, k) != 1) {
+        return 0;
+    }
+
+#if (uECC_CURVE == uECC_secp160r1)
+    /* Make sure that we don't leak timing information about k.
+       See http://eprint.iacr.org/2011/232.pdf */
+    vli_add_n(tmp, k, curve_n);
+    carry = (tmp[uECC_WORDS] & 0x02);
+    vli_add_n(s, tmp, curve_n);
+
+    /* p = k * G */
+    EccPoint_mult(&p, &curve_G, k2[!carry], 0, (uECC_BYTES * 8) + 2);
+#else
+    /* Make sure that we don't leak timing information about k.
+       See http://eprint.iacr.org/2011/232.pdf */
+    carry = vli_add(tmp, k, curve_n);
+    vli_add(s, tmp, curve_n);
+
+    /* p = k * G */
+    EccPoint_mult(&p, &curve_G, k2[!carry], 0, (uECC_BYTES * 8) + 1);
+
+    /* r = x1 (mod n) */
+    if (vli_cmp(curve_n, p.x) != 1) {
+        vli_sub(p.x, p.x, curve_n);
+    }
+#endif
+    if (vli_isZero(p.x)) {
+        return 0;
+    }
+    
+    // Attempt to get a random number to prevent side channel analysis of k.
+    // If the RNG fails every time (eg it was not defined), we continue so that
+    // deterministic signing can still work (with reduced security) without
+    // an RNG defined.
+    carry = 0; // use to signal that the RNG succeeded at least once.
+    for (tries = 0; tries < MAX_TRIES; ++tries) {
+        if (!g_rng_function((uint8_t *)tmp, sizeof(tmp))) {
+            continue;
+        }
+        carry = 1;
+        if (!vli_isZero(tmp)) {
+            break;
+        }
+    }
+    if (!carry) {
+        vli_clear(tmp);
+        tmp[0] = 1;
+    }
+    
+    /* Prevent side channel analysis of vli_modInv() to determine
+       bits of k / the private key by premultiplying by a random number */
+    vli_modMult_n(k, k, tmp); /* k' = rand * k */
+    vli_modInv_n(k, k, curve_n); /* k = 1 / k' */
+    vli_modMult_n(k, k, tmp); /* k = 1 / k */
+    
+    vli_nativeToBytes(signature, p.x); /* store r */
+    
+    tmp[uECC_N_WORDS - 1] = 0;
+    vli_bytesToNative(tmp, private_key); /* tmp = d */
+    s[uECC_N_WORDS - 1] = 0;
+    vli_set(s, p.x);
+    vli_modMult_n(s, tmp, s); /* s = r*d */
+
+    vli_bytesToNative(tmp, message_hash);
+    vli_modAdd_n(s, tmp, s, curve_n); /* s = e + r*d */
+    vli_modMult_n(s, s, k); /* s = (e + r*d) / k */
+#if (uECC_CURVE == uECC_secp160r1)
+    if (s[uECC_N_WORDS - 1]) {
+        return 0;
+    }
+#endif
+    vli_nativeToBytes(signature + uECC_BYTES, s);
+    return 1;
+}
+
+int uECC_sign(const uint8_t private_key[uECC_BYTES],
+              const uint8_t message_hash[uECC_BYTES],
+              uint8_t signature[uECC_BYTES*2]) {
+    uECC_word_t k[uECC_N_WORDS];
+#ifdef QCOM_4004B
+#else
+    /*uECC_word_t tmp[uECC_N_WORDS];*/
+    /*uECC_word_t s[uECC_N_WORDS];*/
+    /*uECC_word_t *k2[2] = {tmp, s};*/
+    /*EccPoint p;*/
+#endif 
+    uECC_word_t tries;
+    
+    for (tries = 0; tries < MAX_TRIES; ++tries) {
+        if(g_rng_function((uint8_t *)k, sizeof(k))) {
+        #if (uECC_CURVE == uECC_secp160r1)
+            k[uECC_WORDS] &= 0x01;
+        #endif
+            if (uECC_sign_with_k(private_key, message_hash, k, signature)) {
+                return 1;
+            }
+        }
+    }
+    return 0;
+}
+
+/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always
+   the same size as the hash result size. */
+static void HMAC_init(uECC_HashContext *hash_context, const uint8_t *K) {
+    uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size;
+    unsigned i;
+    for (i = 0; i < hash_context->result_size; ++i)
+        pad[i] = K[i] ^ 0x36;
+    for (; i < hash_context->block_size; ++i)
+        pad[i] = 0x36;
+    
+    hash_context->init_hash(hash_context);
+    hash_context->update_hash(hash_context, pad, hash_context->block_size);
+}
+
+static void HMAC_update(uECC_HashContext *hash_context,
+                        const uint8_t *message,
+                        unsigned message_size) {
+    hash_context->update_hash(hash_context, message, message_size);
+}
+
+static void HMAC_finish(uECC_HashContext *hash_context, const uint8_t *K, uint8_t *result) {
+    uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size;
+    unsigned i;
+    for (i = 0; i < hash_context->result_size; ++i)
+        pad[i] = K[i] ^ 0x5c;
+    for (; i < hash_context->block_size; ++i)
+        pad[i] = 0x5c;
+
+    hash_context->finish_hash(hash_context, result);
+    
+    hash_context->init_hash(hash_context);
+    hash_context->update_hash(hash_context, pad, hash_context->block_size);
+    hash_context->update_hash(hash_context, result, hash_context->result_size);
+    hash_context->finish_hash(hash_context, result);
+}
+
+/* V = HMAC_K(V) */
+static void update_V(uECC_HashContext *hash_context, uint8_t *K, uint8_t *V) {
+    HMAC_init(hash_context, K);
+    HMAC_update(hash_context, V, hash_context->result_size);
+    HMAC_finish(hash_context, K, V);
+}
+
+/* Deterministic signing, similar to RFC 6979. Differences are:
+    * We just use (truncated) H(m) directly rather than bits2octets(H(m))
+      (it is not reduced modulo curve_n).
+    * We generate a value for k (aka T) directly rather than converting endianness.
+    
+   Layout of hash_context->tmp: <K> | <V> | (1 byte overlapped 0x00 or 0x01) / <HMAC pad> */
+int uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES],
+                            const uint8_t message_hash[uECC_BYTES],
+                            uECC_HashContext *hash_context,
+                            uint8_t signature[uECC_BYTES*2]) {
+    uint8_t *K = hash_context->tmp;
+    uint8_t *V = K + hash_context->result_size;
+    uECC_word_t tries;
+    unsigned i;
+    for (i = 0; i < hash_context->result_size; ++i) {
+        V[i] = 0x01;
+        K[i] = 0;
+    }
+    
+    // K = HMAC_K(V || 0x00 || int2octets(x) || h(m))
+    HMAC_init(hash_context, K);
+    V[hash_context->result_size] = 0x00;
+    HMAC_update(hash_context, V, hash_context->result_size + 1);
+    HMAC_update(hash_context, private_key, uECC_BYTES);
+    HMAC_update(hash_context, message_hash, uECC_BYTES);
+    HMAC_finish(hash_context, K, K);
+    
+    update_V(hash_context, K, V);
+    
+    // K = HMAC_K(V || 0x01 || int2octets(x) || h(m))
+    HMAC_init(hash_context, K);
+    V[hash_context->result_size] = 0x01;
+    HMAC_update(hash_context, V, hash_context->result_size + 1);
+    HMAC_update(hash_context, private_key, uECC_BYTES);
+    HMAC_update(hash_context, message_hash, uECC_BYTES);
+    HMAC_finish(hash_context, K, K);
+    
+    update_V(hash_context, K, V);
+
+    for (tries = 0; tries < MAX_TRIES; ++tries) {
+        uECC_word_t T[uECC_N_WORDS];
+        uint8_t *T_ptr = (uint8_t *)T;
+        unsigned T_bytes = 0;
+        while (T_bytes < sizeof(T)) {
+            update_V(hash_context, K, V);
+            for (i = 0; i < hash_context->result_size && T_bytes < sizeof(T); ++i, ++T_bytes) {
+                T_ptr[T_bytes] = V[i];
+            }
+        }
+    #if (uECC_CURVE == uECC_secp160r1)
+        T[uECC_WORDS] &= 0x01;
+    #endif
+    
+        if (uECC_sign_with_k(private_key, message_hash, T, signature)) {
+            return 1;
+        }
+
+        // K = HMAC_K(V || 0x00)
+        HMAC_init(hash_context, K);
+        V[hash_context->result_size] = 0x00;
+        HMAC_update(hash_context, V, hash_context->result_size + 1);
+        HMAC_finish(hash_context, K, K);
+        
+        update_V(hash_context, K, V);
+    }
+    return 0;
+}
+
+static bitcount_t smax(bitcount_t a, bitcount_t b) {
+    return (a > b ? a : b);
+}
+
+int uECC_verify(const uint8_t public_key[uECC_BYTES*2],
+                const uint8_t hash[uECC_BYTES],
+                const uint8_t signature[uECC_BYTES*2]) {
+    uECC_word_t u1[uECC_N_WORDS], u2[uECC_N_WORDS];
+    uECC_word_t z[uECC_N_WORDS];
+    EccPoint public, sum;
+    uECC_word_t rx[uECC_WORDS];
+    uECC_word_t ry[uECC_WORDS];
+    uECC_word_t tx[uECC_WORDS];
+    uECC_word_t ty[uECC_WORDS];
+    uECC_word_t tz[uECC_WORDS];
+    const EccPoint *points[4];
+    const EccPoint *point;
+    bitcount_t numBits;
+    bitcount_t i;
+    uECC_word_t r[uECC_N_WORDS], s[uECC_N_WORDS];
+    r[uECC_N_WORDS - 1] = 0;
+    s[uECC_N_WORDS - 1] = 0;
+
+    vli_bytesToNative(public.x, public_key);
+    vli_bytesToNative(public.y, public_key + uECC_BYTES);
+    vli_bytesToNative(r, signature);
+    vli_bytesToNative(s, signature + uECC_BYTES);
+    
+    if (vli_isZero(r) || vli_isZero(s)) { /* r, s must not be 0. */
+        return 0;
+    }
+    
+#if (uECC_CURVE != uECC_secp160r1)
+    if (vli_cmp(curve_n, r) != 1 || vli_cmp(curve_n, s) != 1) { /* r, s must be < n. */
+        return 0;
+    }
+#endif
+
+    /* Calculate u1 and u2. */
+    vli_modInv_n(z, s, curve_n); /* Z = s^-1 */
+    u1[uECC_N_WORDS - 1] = 0;
+    vli_bytesToNative(u1, hash);
+    vli_modMult_n(u1, u1, z); /* u1 = e/s */
+    vli_modMult_n(u2, r, z); /* u2 = r/s */
+    
+    /* Calculate sum = G + Q. */
+    vli_set(sum.x, public.x);
+    vli_set(sum.y, public.y);
+    vli_set(tx, curve_G.x);
+    vli_set(ty, curve_G.y);
+    vli_modSub_fast(z, sum.x, tx); /* Z = x2 - x1 */
+    XYcZ_add(tx, ty, sum.x, sum.y);
+    vli_modInv(z, z, curve_p); /* Z = 1/Z */
+    apply_z(sum.x, sum.y, z);
+    
+    /* Use Shamir's trick to calculate u1*G + u2*Q */
+    points[0] = 0;
+    points[1] = &curve_G;
+    points[2] = &public;
+    points[3] = &sum;
+    numBits = smax(vli_numBits(u1, uECC_N_WORDS), vli_numBits(u2, uECC_N_WORDS));
+    
+    point = points[(!!vli_testBit(u1, numBits - 1)) | ((!!vli_testBit(u2, numBits - 1)) << 1)];
+    vli_set(rx, point->x);
+    vli_set(ry, point->y);
+    vli_clear(z);
+    z[0] = 1;
+
+    for (i = numBits - 2; i >= 0; --i) {
+        uECC_word_t index;
+        EccPoint_double_jacobian(rx, ry, z);
+        
+        index = (!!vli_testBit(u1, i)) | ((!!vli_testBit(u2, i)) << 1);
+        point = points[index];
+        if (point) {
+            vli_set(tx, point->x);
+            vli_set(ty, point->y);
+            apply_z(tx, ty, z);
+            vli_modSub_fast(tz, rx, tx); /* Z = x2 - x1 */
+            XYcZ_add(tx, ty, rx, ry);
+            vli_modMult_fast(z, z, tz);
+        }
+    }
+
+    vli_modInv(z, z, curve_p); /* Z = 1/Z */
+    apply_z(rx, ry, z);
+    
+    /* v = x1 (mod n) */
+#if (uECC_CURVE != uECC_secp160r1)
+    if (vli_cmp(curve_n, rx) != 1) {
+        vli_sub(rx, rx, curve_n);
+    }
+#endif
+
+    /* Accept only if v == r. */
+    return vli_equal(rx, r);
+}

+ 319 - 0
joylink/auth/joylink_auth_uECC.h

@@ -0,0 +1,319 @@
+/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
+
+#ifndef _MICRO_ECC_H_
+#define _MICRO_ECC_H_
+
+#ifdef __LINUX_UB2__ 
+#include <stdint.h>
+#endif
+
+#if defined(__MTK_7687__)
+#include <stdint.h>
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+
+/* Platform selection options.
+If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros.
+Possible values for uECC_PLATFORM are defined below: */
+#define uECC_arch_other 0
+#define uECC_x86        1
+#define uECC_x86_64     2
+#define uECC_arm        3
+#define uECC_arm_thumb  4
+#define uECC_avr        5
+#define uECC_arm_thumb2 6
+
+//#define uECC_PLATFORM uECC_arm_thumb2
+
+/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes).
+If uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your
+platform. */
+
+/* Inline assembly options.
+uECC_asm_none  - Use standard C99 only.
+uECC_asm_small - Use GCC inline assembly for the target platform (if available), optimized for
+                 minimum size.
+uECC_asm_fast  - Use GCC inline assembly optimized for maximum speed. */
+#define uECC_asm_none  0
+#define uECC_asm_small 1
+#define uECC_asm_fast  2
+
+#if defined(__APPLE__)
+	#define uECC_ASM uECC_asm_none
+#elif defined(QCOM_4004B)
+	#define uECC_ASM uECC_asm_none
+#endif
+
+#ifndef uECC_ASM
+    #define uECC_ASM uECC_asm_fast
+#endif
+
+/* Curve selection options. */
+#define uECC_secp160r1 1
+#define uECC_secp192r1 2
+//#define uECC_secp256r1 3
+#define uECC_secp256k1 4
+#define uECC_secp224r1 5
+#ifndef uECC_CURVE
+    #define uECC_CURVE uECC_secp160r1
+#endif
+
+/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be
+used for (scalar) squaring instead of the generic multiplication function. This will make things
+faster by about 8% but increases the code size. */
+#ifndef uECC_SQUARE_FUNC
+    #define uECC_SQUARE_FUNC 1
+#endif
+
+#define uECC_CONCAT1(a, b) a##b
+#define uECC_CONCAT(a, b) uECC_CONCAT1(a, b)
+
+#define uECC_size_1 20 /* secp160r1 */
+#define uECC_size_2 24 /* secp192r1 */
+#define uECC_size_3 32 /* secp256r1 */
+#define uECC_size_4 32 /* secp256k1 */
+#define uECC_size_5 28 /* secp224r1 */
+
+#define uECC_BYTES uECC_CONCAT(uECC_size_, uECC_CURVE)
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* uECC_RNG_Function type
+The RNG function should fill 'size' random bytes into 'dest'. It should return 1 if
+'dest' was filled with random data, or 0 if the random data could not be generated.
+The filled-in values should be either truly random, or from a cryptographically-secure PRNG.
+
+A correctly functioning RNG function must be set (using uECC_set_rng()) before calling
+uECC_make_key() or uECC_sign().
+
+Setting a correctly functioning RNG function improves the resistance to side-channel attacks
+for uECC_shared_secret() and uECC_sign_deterministic().
+
+A correct RNG function is set by default when building for Windows, Linux, or OS X.
+If you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom,
+you can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined
+RNG function; you must provide your own.
+*/
+typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size);
+
+/* uECC_set_rng() function.
+Set the function that will be used to generate random bytes. The RNG function should
+return 1 if the random data was generated, or 0 if the random data could not be generated.
+
+On platforms where there is no predefined RNG function (eg embedded platforms), this must
+be called before uECC_make_key() or uECC_sign() are used.
+
+Inputs:
+    rng_function - The function that will be used to generate random bytes.
+*/
+void uECC_set_rng(uECC_RNG_Function rng_function);
+
+/* uECC_make_key() function.
+Create a public/private key pair.
+
+Outputs:
+    public_key  - Will be filled in with the public key.
+    private_key - Will be filled in with the private key.
+
+Returns 1 if the key pair was generated successfully, 0 if an error occurred.
+*/
+int uECC_make_key(uint8_t public_key[uECC_BYTES*2], uint8_t private_key[uECC_BYTES]);
+
+/* uECC_shared_secret() function.
+Compute a shared secret given your secret key and someone else's public key.
+Note: It is recommended that you hash the result of uECC_shared_secret() before using it for
+symmetric encryption or HMAC.
+
+Inputs:
+    public_key  - The public key of the remote party.
+    private_key - Your private key.
+
+Outputs:
+    secret - Will be filled in with the shared secret value.
+
+Returns 1 if the shared secret was generated successfully, 0 if an error occurred.
+*/
+int uECC_shared_secret(const uint8_t public_key[uECC_BYTES*2],
+                       const uint8_t private_key[uECC_BYTES],
+                       uint8_t secret[uECC_BYTES]);
+
+/* uECC_sign() function.
+Generate an ECDSA signature for a given hash value.
+
+Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to
+this function along with your private key.
+
+Inputs:
+    private_key  - Your private key.
+    message_hash - The hash of the message to sign.
+
+Outputs:
+    signature - Will be filled in with the signature value.
+
+Returns 1 if the signature generated successfully, 0 if an error occurred.
+*/
+int uECC_sign(const uint8_t private_key[uECC_BYTES],
+              const uint8_t message_hash[uECC_BYTES],
+              uint8_t signature[uECC_BYTES*2]);
+
+/* uECC_HashContext structure.
+This is used to pass in an arbitrary hash function to uECC_sign_deterministic().
+The structure will be used for multiple hash computations; each time a new hash
+is computed, init_hash() will be called, followed by one or more calls to
+update_hash(), and finally a call to finish_hash() to prudoce the resulting hash.
+
+The intention is that you will create a structure that includes uECC_HashContext
+followed by any hash-specific data. For example:
+
+typedef struct SHA256_HashContext {
+    uECC_HashContext uECC;
+    SHA256_CTX ctx;
+} SHA256_HashContext;
+
+void init_SHA256(uECC_HashContext *base) {
+    SHA256_HashContext *context = (SHA256_HashContext *)base;
+    SHA256_Init(&context->ctx);
+}
+
+void update_SHA256(uECC_HashContext *base,
+                   const uint8_t *message,
+                   unsigned message_size) {
+    SHA256_HashContext *context = (SHA256_HashContext *)base;
+    SHA256_Update(&context->ctx, message, message_size);
+}
+
+void finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) {
+    SHA256_HashContext *context = (SHA256_HashContext *)base;
+    SHA256_Final(hash_result, &context->ctx);
+}
+
+... when signing ...
+{
+    uint8_t tmp[32 + 32 + 64];
+    SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}};
+    uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature);
+}
+*/
+typedef struct uECC_HashContext {
+    void (*init_hash)(struct uECC_HashContext *context);
+    void (*update_hash)(struct uECC_HashContext *context,
+                        const uint8_t *message,
+                        unsigned message_size);
+    void (*finish_hash)(struct uECC_HashContext *context, uint8_t *hash_result);
+    unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */
+    unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */
+    uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */
+} uECC_HashContext;
+
+/* uECC_sign_deterministic() function.
+Generate an ECDSA signature for a given hash value, using a deterministic algorithm
+(see RFC 6979). You do not need to set the RNG using uECC_set_rng() before calling
+this function; however, if the RNG is defined it will improve resistance to side-channel
+attacks.
+
+Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to
+this function along with your private key and a hash context.
+
+Inputs:
+    private_key  - Your private key.
+    message_hash - The hash of the message to sign.
+    hash_context - A hash context to use.
+
+Outputs:
+    signature - Will be filled in with the signature value.
+
+Returns 1 if the signature generated successfully, 0 if an error occurred.
+*/
+int uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES],
+                            const uint8_t message_hash[uECC_BYTES],
+                            uECC_HashContext *hash_context,
+                            uint8_t signature[uECC_BYTES*2]);
+
+/* uECC_verify() function.
+Verify an ECDSA signature.
+
+Usage: Compute the hash of the signed data using the same hash as the signer and
+pass it to this function along with the signer's public key and the signature values (r and s).
+
+Inputs:
+    public_key - The signer's public key
+    hash       - The hash of the signed data.
+    signature  - The signature value.
+
+Returns 1 if the signature is valid, 0 if it is invalid.
+*/
+int uECC_verify(const uint8_t private_key[uECC_BYTES*2],
+                const uint8_t hash[uECC_BYTES],
+                const uint8_t signature[uECC_BYTES*2]);
+
+/* uECC_compress() function.
+Compress a public key.
+
+Inputs:
+    public_key - The public key to compress.
+
+Outputs:
+    compressed - Will be filled in with the compressed public key.
+*/
+void uECC_compress(const uint8_t public_key[uECC_BYTES*2], uint8_t compressed[uECC_BYTES+1]);
+
+/* uECC_decompress() function.
+Decompress a compressed public key.
+
+Inputs:
+    compressed - The compressed public key.
+
+Outputs:
+    public_key - Will be filled in with the decompressed public key.
+*/
+void uECC_decompress(const uint8_t compressed[uECC_BYTES+1], uint8_t public_key[uECC_BYTES*2]);
+
+/* uECC_valid_public_key() function.
+Check to see if a public key is valid.
+
+Note that you are not required to check for a valid public key before using any other uECC
+functions. However, you may wish to avoid spending CPU time computing a shared secret or
+verifying a signature using an invalid public key.
+
+Inputs:
+    public_key - The public key to check.
+
+Returns 1 if the public key is valid, 0 if it is invalid.
+*/
+int uECC_valid_public_key(const uint8_t public_key[uECC_BYTES*2]);
+
+/* uECC_compute_public_key() function.
+Compute the corresponding public key for a private key.
+
+Inputs:
+    private_key - The private key to compute the public key for
+
+Outputs:
+    public_key - Will be filled in with the corresponding public key
+
+Returns 1 if the key was computed successfully, 0 if an error occurred.
+*/
+int uECC_compute_public_key(const uint8_t private_key[uECC_BYTES],
+                            uint8_t public_key[uECC_BYTES * 2]);
+
+
+/* uECC_bytes() function.
+Returns the value of uECC_BYTES. Helpful for foreign-interfaces to higher-level languages.
+*/
+int uECC_bytes(void);
+
+/* uECC_curve() function.
+Returns the value of uECC_CURVE. Helpful for foreign-interfaces to higher-level languages.
+*/
+int uECC_curve(void);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif /* _MICRO_ECC_H_ */

+ 28 - 0
joylink/auth/joylink_crypt.c

@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "joylink_crypt.h"
+#include "joylink_utils.h"
+#include "auth/joylink_auth_uECC.h"
+#include "joylink.h"
+
+JLEccContex_t __g_ekey = {0};
+
+int 
+joylink_ecc_contex_init(void)
+{
+	if (!__g_ekey.isInited){
+		__g_ekey.isInited = 1;
+		if (!uECC_make_key(__g_ekey.devPubKey, __g_ekey.priKey)) {
+			printf("uECC_make_key() failed\n");
+			return 1;
+		}
+		uECC_compress(__g_ekey.devPubKey, __g_ekey.devPubKeyC);
+	}
+
+	memcpy(_g_pdev->jlp.pubkeyC, __g_ekey.devPubKeyC, uECC_BYTES + 1);
+	joylink_util_byte2hexstr(__g_ekey.devPubKeyC, uECC_BYTES + 1, 
+            (uint8_t*)_g_pdev->jlp.pubkeyS, uECC_BYTES * 2 + 3);
+	//printf("DevicePubKey:\t%s\n", _g_pdev->jlp.pubkeyS);
+
+    return 0;
+}

+ 20 - 0
joylink/auth/joylink_crypt.h

@@ -0,0 +1,20 @@
+#ifndef _NODECACHE_H
+#define _NODECACHE_H 
+#include "joylink.h"
+#include "joylink_aes.h"
+
+typedef struct {
+	int isInited;
+	uint8_t priKey[uECC_BYTES];
+	uint8_t devPubKey[uECC_BYTES * 2];
+	uint8_t devPubKeyC[uECC_BYTES + 1];
+}JLEccContex_t;
+
+typedef struct{
+	uint8_t pubkeyC[JL_MAX_KEY_BIN_LEN];		// ѹ????ʽ?Ĺ?Կ
+	uint8_t sharedkey[uECC_BYTES];		// ?豸?Ĺ?????Կ
+}JLKey_t;
+
+extern JLEccContex_t __g_ekey;
+
+#endif

+ 16 - 0
joylink/auth/test.c

@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define AES_128 128
+#define AES_LEN (AES_128/8)
+
+#define DATA_SIZE 32
+
+#ifdef LIB_TEST
+int main()
+{
+
+    return 0;
+}
+#endif

+ 47 - 0
joylink/config/Makefile

@@ -0,0 +1,47 @@
+include ../Makefile.rule
+
+HEADERS = $(wildcard *.h)
+ORG_SOURCES = $(wildcard *.c)
+OUT_SRC = test.c
+
+SOURCES=$(filter-out ${OUT_SRC}, ${ORG_SOURCES})
+OBJS = $(patsubst %.c, %.o, $(SOURCES))
+
+LIBNAME = $(strip ${shell pwd |xargs basename})
+
+INCLUDES += -I${PROJECT_ROOT_PATH}/joylink 
+INCLUDES += -I${PROJECT_ROOT_PATH}/example
+INCLUDES += -I${PROJECT_ROOT_PATH}/auth
+INCLUDES += -I${PROJECT_ROOT_PATH}/config
+
+STATIC_LIBS +=
+LIBS += -lm
+
+ifeq (${ARCH}, x86)  
+all:${OBJS} liba libso
+else
+all:${OBJS} liba 
+endif
+
+.SUFFIXES: .c .o
+.c.o:
+	${CC} ${CFLAGS} -c $(INCLUDES) ${STATIC_LIBS} $(LIBS) $*.c
+
+liba:${OBJS}
+	${AR} -crs lib${LIBNAME}.a ${OBJS}
+	${MV} lib${LIBNAME}.a ${TARGET_LIB}
+
+libso:${OBJS}
+	${CC}  ${OBJS} -shared -fPIC -o lib${LIBNAME}.so
+	${MV} lib${LIBNAME}.so ${TARGET_LIB} 
+
+test:
+	${CC} -DLIB_TEST test.c -o $@ ${CFLAGS} ${INCLUDES} ${STATIC_LIBS} ${LIBS} 
+
+clean:
+	${RM} *.o *.so *.a test
+
+distclean:clean
+	${RM} ./*.a ./*.so ${TARGET_LIB}/lib${LIBNAME}.*
+
+.PHONY:all clean test jt

+ 334 - 0
joylink/config/joylink_config_handle.c

@@ -0,0 +1,334 @@
+#include "joylink_log.h"
+#include "joylink_thunder.h"
+
+#include "joylink_extern.h"
+#include "joylink_utils.h"
+#include "joylink_auth_md5.h"
+
+
+#include "joylink_config_handle.h"
+
+#define CYCLE_HANDLE_TIME  50*1000  // 50ms
+
+#define JOY_CONFIG_STAY_COUNT 5
+
+uint8_t config_stop_flag = 0;
+
+typedef struct _Result
+{
+	uint8_t ssid_len;
+	uint8_t pass_len;
+	
+	char ssid[33];
+	char pass[33];
+} Result_t;
+
+Result_t config_result;
+
+int joylink_get_random(void)
+{
+	return 0;
+    //return rand();
+}
+
+void joylink_change_hannel(int ch)
+{
+    //mico_wlan_set_channel((int)ch);
+    return;
+}
+
+void joylink_80211_recv(uint8_t *buf, int buflen)
+{
+#ifdef JOYLINK_THUNDER_SLAVE
+	joyThunderSlaveProbeH(buf, buflen);
+#endif
+#ifdef JOYLINK_SMART_CONFIG
+	joylink_smnt_datahandler((PHEADER_802_11)buf, buflen);
+#endif
+}
+
+int joylink_80211_send(uint8_t *buf, int buflen)
+{
+	return 0;
+	//return mico_wlan_send_mgnt(buf, buflen);
+}
+
+int joylink_delete_mark(uint8_t *str)
+{
+	int for_i = 0;
+	int for_n = 0;
+
+	uint8_t temp[64] = {0};
+
+	if(str == NULL)	return -1;
+	
+	for(for_i = 0; for_i < strlen(str); for_i++)
+	{
+		if((str[for_i] >= '0' && str[for_i] <= '9') \
+		|| (str[for_i] >= 'a' && str[for_i] <= 'f') \
+		|| (str[for_i] >= 'A' && str[for_i] <= 'F')){
+			temp[for_n] = str[for_i];
+			for_n++;
+		}
+	}
+	memset(str, 0, 64);
+	memcpy(str, temp, strlen(temp));
+
+	return 0;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: thunder slave init and finish
+ *
+ * @Returns: 
+ */
+extern JLPInfo_t user_jlp;
+extern jl2_d_idt_t user_idt;
+
+int 
+joylink_thunder_slave_init(void)
+{
+	tc_slave_func_param_t thunder_param;
+
+	log_info("init thunder slave!\r\n");
+
+	memset(&thunder_param,0,sizeof(tc_slave_func_param_t));
+
+	memcpy(thunder_param.uuid, user_jlp.uuid, 6);
+
+	joylink_delete_mark(user_jlp.mac);
+	joylink_util_hexStr2bytes(user_jlp.mac, thunder_param.mac_dev, JOY_MAC_ADDRESS_LEN);
+
+	joylink_util_hexStr2bytes(user_jlp.prikey, thunder_param.prikey_d, JOY_ECC_PRIKEY_LEN);
+	joylink_util_hexStr2bytes(user_idt.cloud_pub_key, thunder_param.pubkey_c, JOY_ECC_PUBKEY_LEN);
+
+	thunder_param.deviceid.length = strlen(thunder_param.mac_dev);
+	thunder_param.deviceid.value = joylink_util_malloc(thunder_param.deviceid.length);
+	memcpy(thunder_param.deviceid.value, thunder_param.mac_dev, thunder_param.deviceid.length);
+
+	thunder_param.switch_channel = (switch_channel_cb_t)joylink_change_hannel;
+	thunder_param.get_random	 = 	(get_random_cb_t)joylink_get_random;
+	thunder_param.result_notify_cb = (thunder_finish_cb_t)joylink_thunder_slave_finish;
+	thunder_param.packet_80211_send_cb = (packet_80211_send_cb_t)joylink_80211_send;
+	joyThunderSlaveInit(&thunder_param);
+
+	joyThunderSlaveStart();
+
+	joylink_util_free(thunder_param.deviceid.value);
+	thunder_param.deviceid.value = NULL;
+	return 0;
+}
+
+extern E_JLRetCode_t joylink_dev_set_attr_jlp(JLPInfo_t *jlp);
+
+int 
+joylink_thunder_slave_finish(tc_slave_result_t *result)
+{
+    	JLPInfo_t jlp;
+
+	uint8_t temp[32] = {0};
+	uint8_t localkey[33] = {0};
+	MD5_CTX md5buf;
+	
+    	log_info("joylink thunder slave finish\r\n");
+
+    	memset(&jlp, 0, sizeof(JLPInfo_t));
+    	memcpy(jlp.feedid, result->cloud_feedid.value, result->cloud_feedid.length);
+    	memcpy(jlp.accesskey, result->cloud_ackey.value, result->cloud_ackey.length);
+
+	memset(&md5buf, 0, sizeof(MD5_CTX));
+	JDMD5Init(&md5buf);
+	JDMD5Update(&md5buf, result->cloud_ackey.value, strlen(result->cloud_ackey.value));
+	JDMD5Final(&md5buf, temp);
+	joylink_util_byte2hexstr(temp, 16, localkey, 32);
+	
+	memcpy(jlp.localkey, localkey, strlen(localkey));
+
+    	log_info("feedid:%s, accesskey:%s, localkey: %s, serverurl:%s\n", result->cloud_feedid.value, result->cloud_ackey.value, localkey, result->cloud_server.value);
+
+    	joylink_dev_set_attr_jlp(&jlp);
+
+	memset(&config_result, 0, sizeof(Result_t));
+	
+	memcpy(config_result.ssid, result->ap_ssid.value, result->ap_ssid.length);
+	config_result.ssid_len = result->ap_ssid.length;
+	
+	memcpy(config_result.pass, result->ap_password.value, result->ap_password.length);
+	config_result.pass_len = result->ap_password.length;
+	
+		
+    	log_info("ssid:%s, passwd:%s\n", config_result.ssid, config_result.pass);
+
+	joylink_config_stop();
+
+	return 0;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: smartConfig init and finish
+ *
+ * @Returns: 
+ */
+
+#define SMARTCONFIG_KEY "TJZ9M8SXE8IE9B5W"
+
+joylink_smnt_param_t smart_conf_param;
+
+int 
+joylink_smart_config_init(void)
+{
+	memset(&smart_conf_param, 0, sizeof(joylink_smnt_param_t));
+
+    memcpy(smart_conf_param.secretkey, SMARTCONFIG_KEY, strlen(SMARTCONFIG_KEY));
+
+	smart_conf_param.get_result_callback = &joylinke_smart_config_finish;
+
+	log_info("init smart config!\r\n");
+	joylink_smnt_init(smart_conf_param);
+}
+
+void
+joylinke_smart_config_finish(joylink_smnt_result_t* presult)
+{
+	int len = 0;
+	
+	uint8_t p_result[100] = {0};
+	uint8_t passOut[100] = {0};
+	
+	log_info("joylink smart config finish\r\n");
+	
+	memset(&config_result, 0, sizeof(Result_t));
+
+	memcpy(config_result.pass, presult->jd_password, presult->jd_password_len);
+	config_result.pass_len = presult->jd_password_len;
+
+	memcpy(config_result.ssid, presult->jd_ssid, presult->jd_ssid_len);
+	config_result.ssid_len = presult->jd_ssid_len;
+
+	log_info("ssid:%s, passwd:%s\n", config_result.ssid, config_result.pass);
+	joylink_config_stop();
+	return;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: change channel
+ *
+ * @Returns: 
+ */
+static uint8_t config_count = 0;
+static uint8_t config_channel = 0;
+
+extern joylinkSmnt_t* pSmnt;
+extern tc_slave_ctl_t tc_slave_ctl;
+
+void 
+joylink_config_change_channel(void)
+{
+#ifdef JOYLINK_THUNDER_SLAVE
+	if(tc_slave_ctl.thunder_state > sReqChannel)
+		return;
+#endif
+#ifdef JOYLINK_SMART_CONFIG
+	if(pSmnt->state > SMART_CH_LOCKING)
+		return;
+#endif	
+	config_count++;
+	if(config_count == JOY_CONFIG_STAY_COUNT){
+		config_count = 0;
+
+		joylink_change_hannel(config_channel+1);
+		log_info("-->switch channel to:%d", config_channel+1);
+		
+#ifdef JOYLINK_THUNDER_SLAVE	
+		tc_slave_ctl.current_channel = config_channel + 1;
+#endif
+#ifdef JOYLINK_SMART_CONFIG
+		pSmnt->chCurrentIndex = config_channel;
+
+		pSmnt->state = SMART_CH_LOCKING;
+		pSmnt->syncStepPoint = 0;
+		pSmnt->syncCount = 0;
+		pSmnt->chCurrentProbability = 0;
+#endif	
+		config_channel++;
+		if(config_channel == 13)
+			config_channel = 0;	
+	}			
+}
+/**
+ * brief: 
+ *
+ * @Param: config loop handle
+ *
+ * @Returns: 
+ */
+void *
+joylink_config_loop_handle(void *data)
+{
+	time_t *time_out = (time_t *)data;
+	time_t time_start = time(NULL);
+	double time_old = 0;
+	double time_now = 0;
+
+	while(1){
+		time_now = clock();
+		if(time_now - time_old >= CYCLE_HANDLE_TIME){
+			time_old = time_now;
+			#ifdef JOYLINK_THUNDER_SLAVE
+			joyThunderSlave50mCycle();
+			#endif
+			#ifdef JOYLINK_SMART_CONFIG
+			joylink_smnt_cyclecall();
+			#endif
+			joylink_config_change_channel();
+		}
+		#ifdef JOYLINK_THUNDER_SLAVE
+		if(config_stop_flag)
+			break;
+		#endif
+		if(time_now - time_start > *time_out){
+			joylink_config_stop();
+			break;
+		}
+	}
+}
+
+int joylink_config_start(uint32_t time_out)
+{
+	char check_flag = 0;
+#ifdef JOYLINK_THUNDER_SLAVE
+	config_stop_flag = 0;
+	check_flag = 1;
+	joylink_thunder_slave_init();
+#endif
+#ifdef JOYLINK_SMART_CONFIG
+	check_flag = 1;
+	joylink_smart_config_init();
+#endif	
+	if(check_flag == 0){
+		log_info("joylink config do not open!");
+		return -1;
+	}
+	pthread_t tidp;
+	int ret = pthread_create(&tidp, NULL, joylink_config_loop_handle, (void *)&time_out);
+	if(ret < 0){
+		log_info("joylink config pthread create failed!");
+	}
+	return 0;
+}
+int joylink_config_stop(void)
+{
+#ifdef JOYLINK_THUNDER_SLAVE
+	config_stop_flag = 1;
+	joyThunderSlaveStop();
+#endif
+	return 0;
+}
+
+

+ 24 - 0
joylink/config/joylink_config_handle.h

@@ -0,0 +1,24 @@
+/*
+ * joylink_thunder_test.h
+ *
+ *  Created on: 2018Äê9ÔÂ5ÈÕ
+ *      Author: lizhiwei5
+ */
+
+#ifndef _JOYLINK_SMARTCONFIG_JOYLINK_THUNDER_TEST_H_
+#define _JOYLINK_SMARTCONFIG_JOYLINK_THUNDER_TEST_H_
+
+#include "joylink_thunder_slave_sdk.h"
+#include "joylink_smart_config.h"
+
+int joylink_thunder_slave_init(void);
+int joylink_thunder_slave_finish(tc_slave_result_t *result);
+
+int joylink_smart_config_init(void);
+void joylinke_smart_config_finish(joylink_smnt_result_t* presult);
+
+int joylink_config_start(uint32_t time_out);
+int joylink_config_stop(void);
+
+
+#endif /* LIB_JOYLINK_SMARTCONFIG_JOYLINK_THUNDER_TEST_H_ */

+ 433 - 0
joylink/config/joylink_probe.c

@@ -0,0 +1,433 @@
+
+#include "joylink_log.h"
+#include "joylink_probe.h"
+#include "joylink_utils.h"
+
+/* Microsoft (also used in Wi-Fi specs) 00:50:F2 */
+#define OUI_MICROSOFT 0x0050f2
+#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
+
+#define WMM_OUI_TYPE 2
+#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
+#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1
+#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2
+#define WMM_VERSION 1
+
+#define OUI_WFA 0x506f9a
+#define P2P_OUI_TYPE 9
+#define WFD_OUI_TYPE 10
+#define HS20_INDICATION_OUI_TYPE 16
+#define HS20_OSEN_OUI_TYPE 18
+
+#define OUI_MEDIATEK 0x000ce7 /* MediaTek Information Element */
+
+uint8_t g_vendor_request[] = "Tell me AP info";
+uint8_t g_vendor_reply[] = "SSID:Test PSK:12345678";
+
+static inline uint32_t WPA_GET_BE24(const uint8_t *a)
+{
+	return (a[0] << 16) | (a[1] << 8) | a[2];
+}
+
+static inline void WPA_PUT_BE24(uint8_t *a, uint32_t val)
+{
+	a[0] = (val >> 16) & 0xff;
+	a[1] = (val >> 8) & 0xff;
+	a[2] = val & 0xff;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * @brief This function is to parse vendor specific element
+ *
+ * @param pos        Pointer to the start of vendor specific information element
+ * @param len        Length of vendor specific IE in octets
+ * @param elems      Data structure for parsed elements
+ *
+ * @retval 0      Success to parse elems
+ * @retval -1     Fail to parse elems
+ */
+/*----------------------------------------------------------------------------*/
+int ieee802_11_parse_vendor_specific(const uint8_t *pos, size_t elen,
+	struct ieee802_11_elems *elems)
+{
+	unsigned int oui;
+
+	/* first 3 bytes in vendor specific information element are the IEEE
+	* OUI of the vendor. The following byte is used a vendor specific
+	* sub-type.
+	*/
+	if (elen < 4) {
+		log_error("short vendor specific information element ignored (len=%lu)\n",
+			(unsigned long) elen);
+		return -1;
+	}
+
+	oui = WPA_GET_BE24(pos);
+	oui = OUI_MEDIATEK;				//changed by meng
+	switch (oui) {
+	//case OUI_MEDIATEK:
+	//	elems->vendor_custom = pos;
+	//	elems->vendor_custom_len = elen;
+	//	break;
+	case OUI_MICROSOFT:
+		/* Microsoft/Wi-Fi information elements are further typed and subtyped */
+		switch (pos[3]) {
+		case 1:
+			/* Microsoft OUI (00:50:F2) with OUI Type 1:
+			* real WPA information element
+			*/
+			elems->wpa_ie = pos;
+			elems->wpa_ie_len = elen;
+			break;
+		case WMM_OUI_TYPE:
+			/* WMM information element */
+			if (elen < 5) {
+				log_error("short WMM information element ignored (len=%lu)\n",
+					(unsigned long) elen);
+				return -1;
+			}
+			switch (pos[4]) {
+			case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
+			case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
+				/*
+				* Share same pointer since only one of these
+				* is used and they start with same data.
+				* Length field can be used to distinguish the
+				* IEs.
+				*/
+				elems->wmm = pos;
+				elems->wmm_len = elen;
+				break;
+			case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
+				elems->wmm_tspec = pos;
+				elems->wmm_tspec_len = elen;
+				break;
+			default:
+				log_error("unknown WMM information element ignored (subtype=%d len=%lu)\n",
+					pos[4], (unsigned long) elen);
+				return -1;
+			}
+			break;
+		case 4:
+			/* Wi-Fi Protected Setup (WPS) IE */
+			elems->wps_ie = pos;
+			elems->wps_ie_len = elen;
+			break;
+		default:
+			log_error("Unknown Microsoft information element ignored (type=%d len=%lu)\n",
+				pos[3], (unsigned long) elen);
+			return -1;
+		}
+		break;
+
+	case OUI_WFA:
+		switch (pos[3]) {
+		case P2P_OUI_TYPE:
+			/* Wi-Fi Alliance - P2P IE */
+			elems->p2p = pos;
+			elems->p2p_len = elen;
+			break;
+		case WFD_OUI_TYPE:
+			/* Wi-Fi Alliance - WFD IE */
+			elems->wfd = pos;
+			elems->wfd_len = elen;
+			break;
+		case HS20_INDICATION_OUI_TYPE:
+			/* Hotspot 2.0 */
+			elems->hs20 = pos;
+			elems->hs20_len = elen;
+			break;
+		case HS20_OSEN_OUI_TYPE:
+			/* Hotspot 2.0 OSEN */
+			elems->osen = pos;
+			elems->osen_len = elen;
+			break;
+		default:
+			log_error("Unknown WFA information element ignored (type=%d len=%lu)\n",
+				pos[3], (unsigned long) elen);
+			return -1;
+		}
+		break;
+
+	case OUI_BROADCOM:
+		switch (pos[3]) {
+		case VENDOR_HT_CAPAB_OUI_TYPE:
+			elems->vendor_ht_cap = pos;
+			elems->vendor_ht_cap_len = elen;
+			break;
+		default:
+			log_error("Unknown Broadcom information element ignored (type=%d len=%lu)\n",
+				pos[3], (unsigned long) elen);
+			return -1;
+		}
+		break;
+
+	default:
+		elems->vendor_custom = pos;
+		elems->vendor_custom_len = elen;
+		return 0;
+		log_error("unknown vendor specific information element ignored (vendor OUI "
+			"%02x:%02x:%02x len=%lu)\n",
+			pos[0], pos[1], pos[2], (unsigned long) elen);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * @brief This function is to parse information elements in management frames
+ *
+ * @param start      Pointer to the start of IEs
+ * @param len        Length of IE buffer in octets
+ * @param elems      Data structure for parsed elements
+ *
+ * @retval 0      Success to parse elems
+ * @retval -1     Fail to parse elems
+ */
+/*----------------------------------------------------------------------------*/
+int joylink_ieee802_11_parse_elems(const uint8_t *start, size_t len,
+	struct ieee802_11_elems *elems)
+{
+	size_t left = len;
+	const uint8_t *pos = start;
+	int unknown = 0;
+
+	memset(elems, 0, sizeof(*elems));
+
+	while (left >= 2) {
+		uint8_t id, elen;
+
+		id = *pos++;
+		elen = *pos++;
+		left -= 2;
+/*
+		if(elen == 0 || elen > left)
+		{
+		    return 0;
+		}
+		else if (elen > left) {
+			joylink_log_error("IEEE 802.11 element parse failed (id=%d elen=%d "
+				"left=%lu)", id, elen, (unsigned long) left);
+			return -1 ;
+		}
+*/
+		//printf("id: %02x\n", id);
+
+		switch (id) {
+		case WLAN_EID_SSID:
+			elems->ssid = pos;
+			elems->ssid_len = elen;
+			break;
+		case WLAN_EID_SUPP_RATES:
+			elems->supp_rates = pos;
+			elems->supp_rates_len = elen;
+			break;
+		case WLAN_EID_DS_PARAMS:
+			elems->ds_params = pos;
+			elems->ds_params_len = elen;
+			break;
+		case WLAN_EID_CF_PARAMS:
+		case WLAN_EID_TIM:
+			break;
+		case WLAN_EID_CHALLENGE:
+			elems->challenge = pos;
+			elems->challenge_len = elen;
+			break;
+		case WLAN_EID_ERP_INFO:
+			elems->erp_info = pos;
+			elems->erp_info_len = elen;
+			break;
+		case WLAN_EID_EXT_SUPP_RATES:
+			elems->ext_supp_rates = pos;
+			elems->ext_supp_rates_len = elen;
+			break;
+		case WLAN_EID_VENDOR_SPECIFIC:
+			elems->vendor_custom = pos;
+			elems->vendor_custom_len = elen;
+		    return 0;
+			//if (ieee802_11_parse_vendor_specific(pos, elen, elems))
+			//	unknown++;
+			//break;
+		default:
+			unknown++;
+			break;
+		}
+		left -= elen;
+		pos += elen;
+	}
+
+	if (left)
+	{
+		log_error("elem_len=, left=\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * @brief This function is to genarate vendor specific element
+ *
+ * @param vendor_ie      Pointer to the element buffer
+ *
+ * @retval element length
+ */
+/*----------------------------------------------------------------------------*/
+int joylink_gen_vendor_specific(uint8_t *vendor_ie, uint8_t *content, int content_len)
+{
+	uint8_t *pos, *len;
+
+	if(vendor_ie == NULL)
+		return 0;
+
+	pos = vendor_ie;
+	len = vendor_ie;
+	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+	len = pos++; /* to be filled */
+	WPA_PUT_BE24(pos, OUI_MEDIATEK);
+	pos += 3;
+
+	memcpy(pos, content, content_len);
+	pos += content_len;
+
+	*len = pos -len -1; /* fill vendor len */
+
+	return pos - vendor_ie;
+}
+
+uint8_t g_own_mac[ETH_ALEN] = {0};
+
+/*
+* Genarate probe request frame
+*/
+uint8_t * joylink_gen_probe_req(void *vendor_ie, int vendor_len, int *req_len)
+{
+    struct ieee80211_mgmt *resp = NULL;
+    uint8_t *pos = NULL;
+    int buflen = MAX_PROBERESP_LEN;
+    char *ssid = NULL;
+    int ssid_len = 0;
+
+    uint8_t supp_rate[4] = {0x02, 0x04, 0x0b, 0x16};
+    uint8_t da_mac[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+    if (vendor_ie == NULL || vendor_len == 0 || req_len == 0)
+    {
+        log_error("mtk_custom_gen_probe_req() param error\n");
+        return NULL;
+    }
+
+    /* alloc buffer for probe response */
+    resp = joylink_util_malloc(buflen);
+    if (resp == NULL)
+    {
+        log_error("malloc buffer fail\n");
+        return NULL;
+    }
+
+    memset(resp, 0, buflen);
+
+    resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+        WLAN_FC_STYPE_PROBE_REQ);
+
+    memcpy(resp->da, da_mac, ETH_ALEN);
+    memcpy(resp->sa, g_own_mac, ETH_ALEN);
+    memcpy(resp->bssid, da_mac, ETH_ALEN);
+    resp->seq_ctrl = 0;
+
+    pos = resp->u.probe_req.variable;
+
+    /* SSID */
+    *pos++ = WLAN_EID_SSID;
+    *pos++ = ssid_len;
+    memcpy(pos, ssid, ssid_len);
+    pos += ssid_len;
+
+    /* Supported rates */
+    *pos++ = WLAN_EID_SUPP_RATES;
+    *pos++ = 4;
+    memcpy(pos, supp_rate, 4);
+    pos += 4;
+
+    /* Vendor specific */
+    if (vendor_ie != NULL && vendor_len > 0) {
+        memcpy(pos, vendor_ie, vendor_len);
+        pos += vendor_len;
+    }
+
+    *req_len = pos - (uint8_t *)resp;
+
+    return (uint8_t *) resp;
+}
+
+/*
+* Genarate probe response frame
+*/
+uint8_t * joylink_gen_probe_resp(void *vendor_ie, int vendor_len,
+    const struct ieee80211_mgmt *probe_req, int *resp_len)
+{
+    struct ieee80211_mgmt *resp = NULL;
+    uint8_t *pos = NULL;
+    int buflen = MAX_PROBERESP_LEN;
+    char *ssid = GL_CUSTOM_PROBE_RESP_SSID;
+    int ssid_len = strlen(GL_CUSTOM_PROBE_RESP_SSID);
+    uint8_t supp_rate[4] = {0x02, 0x04, 0x0b, 0x16};
+
+    if (vendor_ie == NULL || vendor_len == 0 || probe_req == NULL || resp_len == 0)
+    {
+        log_error("mtk_custom_gen_probe_resp() param error\n");
+        return NULL;
+    }
+
+    /* alloc buffer for probe response */
+    resp = joylink_util_malloc(buflen);
+    if (resp == NULL)
+    {
+        log_error("malloc buffer fail\n");
+        return NULL;
+    }
+
+    memset(resp, 0, buflen);
+
+    resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+        WLAN_FC_STYPE_PROBE_RESP);
+
+    memcpy(resp->da, probe_req->sa, ETH_ALEN);
+    memcpy(resp->sa, g_own_mac, ETH_ALEN);
+    memcpy(resp->bssid, g_own_mac, ETH_ALEN);
+    resp->seq_ctrl = 0;
+    resp->u.probe_resp.timestamp[0] = 0;
+    resp->u.probe_resp.beacon_int = 100;
+    resp->u.probe_resp.capab_info = WLAN_CAPABILITY_ESS;
+
+    pos = resp->u.probe_resp.variable;
+
+    /* SSID */
+    *pos++ = WLAN_EID_SSID;
+    *pos++ = ssid_len;
+    memcpy(pos, ssid, ssid_len);
+    pos += ssid_len;
+
+    /* Supported rates */
+    *pos++ = WLAN_EID_SUPP_RATES;
+    *pos++ = 4;
+    memcpy(pos, supp_rate, 4);
+    pos += 4;
+
+    /* Vendor specific */
+    if (vendor_ie != NULL && vendor_len > 0) {
+        memcpy(pos, vendor_ie, vendor_len);
+        pos += vendor_len;
+    }
+
+    *resp_len = pos - (uint8_t *)resp;
+
+    return (uint8_t *) resp;
+}
+
+

+ 87 - 0
joylink/config/joylink_probe.h

@@ -0,0 +1,87 @@
+#ifndef _JOYLINK_PROBE_H_
+#define _JOYLINK_PROBE_H_
+
+#include "joylink_wlan_probe.h"
+//#include "joylink_syshdr.h"
+#include "stdint.h"
+
+struct ieee802_11_elems {
+	const uint8_t *ssid;
+	const uint8_t *supp_rates;
+	const uint8_t *ds_params;
+	const uint8_t *challenge;
+	const uint8_t *erp_info;
+	const uint8_t *ext_supp_rates;
+	const uint8_t *wpa_ie;
+	const uint8_t *rsn_ie;
+	const uint8_t *wmm; /* WMM Information or Parameter Element */
+	const uint8_t *wmm_tspec;
+	const uint8_t *wps_ie;
+	const uint8_t *supp_channels;
+	const uint8_t *mdie;
+	const uint8_t *ftie;
+	const uint8_t *timeout_int;
+	const uint8_t *ht_capabilities;
+	const uint8_t *ht_operation;
+	const uint8_t *vht_capabilities;
+	const uint8_t *vht_operation;
+	const uint8_t *vht_opmode_notif;
+	const uint8_t *vendor_ht_cap;
+	const uint8_t *p2p;
+	const uint8_t *wfd;
+	const uint8_t *link_id;
+	const uint8_t *interworking;
+	const uint8_t *qos_map_set;
+	const uint8_t *hs20;
+	const uint8_t *ext_capab;
+	const uint8_t *bss_max_idle_period;
+	const uint8_t *ssid_list;
+	const uint8_t *osen;
+
+	const uint8_t *vendor_custom;
+
+	uint8_t ssid_len;
+	uint8_t supp_rates_len;
+	uint8_t ds_params_len;
+	uint8_t challenge_len;
+	uint8_t erp_info_len;
+	uint8_t ext_supp_rates_len;
+	uint8_t wpa_ie_len;
+	uint8_t rsn_ie_len;
+	uint8_t wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
+	uint8_t wmm_tspec_len;
+	uint8_t wps_ie_len;
+	uint8_t supp_channels_len;
+	uint8_t mdie_len;
+	uint8_t ftie_len;
+	uint8_t timeout_int_len;
+	uint8_t ht_capabilities_len;
+	uint8_t ht_operation_len;
+	uint8_t vht_capabilities_len;
+	uint8_t vht_operation_len;
+	uint8_t vendor_ht_cap_len;
+	uint8_t p2p_len;
+	uint8_t wfd_len;
+	uint8_t interworking_len;
+	uint8_t qos_map_set_len;
+	uint8_t hs20_len;
+	uint8_t ext_capab_len;
+	uint8_t ssid_list_len;
+	uint8_t osen_len;
+
+	uint8_t vendor_custom_len;
+};
+
+
+int joylink_ieee802_11_parse_elems(const uint8_t *start, size_t len,struct ieee802_11_elems *elems);
+
+int joylink_gen_vendor_specific(uint8_t *vendor_ie, uint8_t *content, int content_len);
+/*
+* Genarate probe request frame
+*/
+uint8_t * joylink_gen_probe_req(void *vendor_ie, int vendor_len, int *req_len);
+
+uint8_t * joylink_gen_probe_resp(void *vendor_ie, int vendor_len, const struct ieee80211_mgmt *probe_req, int *resp_len);
+#endif
+
+

+ 565 - 0
joylink/config/joylink_smart_config.c

@@ -0,0 +1,565 @@
+/*************************************
+
+Copyright (c) 2015-2050, JD Smart All rights reserved. 
+
+*************************************/
+#include <stdio.h>
+#include <string.h>
+#include "joylink_smart_config.h"
+#include "joylink_aes.h"
+
+#define STEP_MULTICAST_HOLD_CHANNEL				5
+#define STEP_BROADCAST_HOLD_CHANNEL				4
+#define STEP_BROADCAST_ERROR_HOLE_CHANNEL		2
+#define PAYLOAD_MIN								(3)
+#define PAYLOAD_MAX								(48+1)				
+
+joylinkSmnt_t* pSmnt = NULL;
+joylink_smnt_param_t	joylink_smnt_gobal;
+static int  joylink_smnt_payLoadcheck(uint8 *payload);
+static void joylink_smnt_muticastadd(uint8* pAddr);
+static void joylink_smnt_broadcastadd(int ascii);
+static uint8 joylink_smnt_crc(uint8 *ptr, uint8 len);
+static void joylink_smnt_bufferprintf(uint8* p, int split, int len);
+
+void joylink_smnt_init(joylink_smnt_param_t param)
+{
+	printf("+++++++++++++SMNT INIT %s+++++++++++++++++\n",VERSION_SMNT);
+        
+    	pSmnt = (joylinkSmnt_t *)malloc(sizeof(joylinkSmnt_t));
+	
+    	memset(pSmnt, 0, sizeof(joylinkSmnt_t) );
+	memset(pSmnt->payload_multicast, 0xFF, sizeof(pSmnt->payload_multicast));	
+	memset(pSmnt->payload_broadcast, 0xFF, sizeof(pSmnt->payload_broadcast));
+	
+	memcpy(joylink_smnt_gobal.secretkey,param.secretkey,16);
+	
+	if(param.get_result_callback != NULL){
+		joylink_smnt_gobal.get_result_callback = param.get_result_callback;
+	}else{
+		printf("get_result_callback is NULL\n");
+	}
+/*
+	if(param.switch_channel_callback != NULL){
+		joylink_smnt_gobal.switch_channel_callback = param.switch_channel_callback;
+	}else{
+		printf("switch_channel_callback is NULL\n");
+	}
+*/
+	return;
+}
+
+void joylink_smnt_release(void)
+{
+	memset(joylink_smnt_gobal.secretkey,0,sizeof(joylink_smnt_gobal.secretkey));
+	joylink_smnt_gobal.get_result_callback 		= NULL;
+	//joylink_smnt_gobal.switch_channel_callback 	= NULL;
+
+	if(pSmnt != NULL){
+		free(pSmnt);
+		pSmnt = NULL;
+	}
+}
+
+void joylink_smnt_reset(void)
+{
+	if(pSmnt != NULL){
+		memset(pSmnt,0,sizeof(joylinkSmnt_t));
+	}
+}
+
+
+static void  joylink_smnt_finish(void)
+{
+	int ret = 128;
+	uint8 iv[16] = {0};
+	
+	joylink_smnt_result_t smnt_result;
+	memset(&smnt_result,0,sizeof(smnt_result));
+	if (pSmnt && (pSmnt->state== SMART_FINISH) ){
+
+		joylink_smnt_bufferprintf(pSmnt->result.encData, 1, pSmnt->result.encData[0]);
+		memset(&smnt_result,0,sizeof(smnt_result));
+
+		ret = device_aes_decrypt(joylink_smnt_gobal.secretkey,16,iv,pSmnt->result.encData+1,pSmnt->result.encData[0],pSmnt->result.encData+1,128);
+	
+		if((ret> 0) && (ret <= 96)){
+			smnt_result.jd_password_len = pSmnt->result.encData[1];
+			smnt_result.jd_ssid_len	 = ret - smnt_result.jd_password_len -1 -6;
+			memcpy(smnt_result.jd_password,pSmnt->result.encData+2,smnt_result.jd_password_len);
+			memcpy(smnt_result.jd_ssid,pSmnt->result.encData + 2 + smnt_result.jd_password_len +6,smnt_result.jd_ssid_len);	
+
+			smnt_result.smnt_result_status = smnt_result_ok;
+		}else{
+			smnt_result.smnt_result_status = smnt_result_decrypt_error;
+		}
+		
+		if(joylink_smnt_gobal.get_result_callback == NULL){
+			printf("ERROR:joylink_smnt_finish->get_result_callback NULL\n");
+			goto RET;
+		}
+		
+		joylink_smnt_gobal.get_result_callback(&smnt_result);
+	}
+RET:
+	return;
+}
+
+
+int joylink_smnt_cyclecall(void)
+{
+	if(pSmnt == NULL){
+    	return 50;
+  	}
+/*
+	if(joylink_smnt_gobal.switch_channel_callback == NULL){
+		printf("switch channel function NULL\n");
+		return 50;
+	}
+*/	
+    	if (pSmnt->directTimerSkip){
+		pSmnt->directTimerSkip--;
+		return 50;
+	}
+	
+	if (pSmnt->state == SMART_FINISH){
+		printf("-------------------->Finished\n");
+		pSmnt->directTimerSkip = 10000/50;
+		return 0;
+	}
+	
+	if (pSmnt->isProbeReceived >0 ){
+		printf("-------------------->Probe Stay(CH:%d) %d\n", (int)pSmnt->chCurrentIndex+1, (int)pSmnt->isProbeReceived);
+		pSmnt->isProbeReceived = 0;
+		pSmnt->directTimerSkip = 5000 / 50;
+		return 50;
+	}
+	
+	if (pSmnt->chCurrentProbability > 0){
+		pSmnt->chCurrentProbability--;
+		printf("------------------->SYNC (CH:%d) %d\n", (int)pSmnt->chCurrentIndex+1, (int)pSmnt->chCurrentProbability);
+		return 50;
+	}
+/*
+	pSmnt->chCurrentIndex = (pSmnt->chCurrentIndex + 1) % 13;
+	
+	if(joylink_smnt_gobal.switch_channel_callback != NULL){
+		joylink_smnt_gobal.switch_channel_callback(pSmnt->chCurrentIndex+1);
+	}
+	
+	pSmnt->state 			= SMART_CH_LOCKING;
+	pSmnt->syncStepPoint = 0;
+	pSmnt->syncCount = 0;
+	pSmnt->chCurrentProbability = 0;
+//	printf("CH=%d, T=%d\n", pSmnt->chCurrentIndex, 50);
+*/
+	return 50;
+}
+
+static void  joylink_smnt_broadcastadd(int ascii)
+{
+	uint8 isFlag = (uint8)((ascii >> 8) & 0x1);
+	uint8 is_finishpacket = 0;
+
+	uint8 *broadbuffer=pSmnt->broadBuffer,*broadindex = &(pSmnt->broadIndex);
+	if (isFlag){
+		*broadindex = 0;
+		*broadbuffer = (uint8)ascii;
+	}else{
+		*broadindex = *broadindex + 1;
+		broadbuffer[*broadindex] = (uint8)ascii;
+
+		if((((pSmnt->payload_broadcast[1] +2) / 4 + 1) == ( (*broadbuffer) >> 3))  && (pSmnt->payload_broadcast[1] != 0) && (pSmnt->payload_broadcast[1] != 0xFF))
+		{
+			if(*broadindex == 2){
+				is_finishpacket = 1;
+				*(broadbuffer + 3) = 0;
+				*(broadbuffer + 4) = 0;
+			}
+		}
+	
+		if (*broadindex >= 4 || is_finishpacket)
+		{
+			*broadindex = 0;
+			uint8 crc = (*broadbuffer) & 0x7;
+			uint8 index = (*broadbuffer) >> 3;
+			uint8 rCrc = joylink_smnt_crc(broadbuffer + 1, 4) & 0x7;
+			
+			/*not to check the last pacet crc,It is a patch for the last packet is a lot wrong which maybe leaded by the phone*/
+			if (((index>0) && (index<33) && (rCrc == crc)))
+			{
+				memcpy(pSmnt->payload_broadcast + (index - 1) * 4, broadbuffer + 1, 4);
+					
+				printf("B(%x=%x)--%02x,%02x,%02x,%02x\n", index, broadbuffer[0], broadbuffer[1], broadbuffer[2], broadbuffer[3], broadbuffer[4]);
+				index = joylink_smnt_payLoadcheck(pSmnt->payload_broadcast);
+
+				if (pSmnt->chCurrentProbability < 30){ 
+					pSmnt->chCurrentProbability += STEP_BROADCAST_HOLD_CHANNEL;
+				}
+				
+				if (index == 0){	
+					pSmnt->result.type = 2;
+				}
+				
+				//joylink_smnt_bufferprintf(pSmnt->payload, 1, 80);
+				
+			}else{
+				if (pSmnt->chCurrentProbability < 30){ 
+					pSmnt->chCurrentProbability += STEP_BROADCAST_ERROR_HOLE_CHANNEL;
+				}
+			}
+		}else if (*broadindex == 2){
+			uint8 index = broadbuffer[0] >> 3;
+			if (index == 0){
+				*broadindex = 0;
+				uint8 crc = broadbuffer[0] & 0x7;
+				uint8 rCrc = joylink_smnt_crc(broadbuffer + 1, 2) & 0x7;
+				if (rCrc == crc){
+					pSmnt->broadcastVersion = broadbuffer[1];
+					printf("Version RX:%x\n",pSmnt->broadcastVersion);
+				}
+			}
+		}
+	} 
+}
+
+/*
+Input: Muticast Addr
+Output: -1:Unkown Packet, 0:Parse OK, 1:Normal Process
+*/
+static void joylink_smnt_muticastadd(uint8* pAddr)
+{
+	int8 index = 0;
+	
+	if ((pAddr[3] >> 6) == ((pAddr[4] ^ pAddr[5]) & 0x1)){
+		index = pAddr[3] & 0x3F;
+	}else
+		return;
+	
+	if ((index >= 1) && (index < PAYLOAD_MAX))		//avoid overstep leaded by error
+	{
+		uint8 payloadIndex = index - 1;
+		if (payloadIndex > 64)
+			return;
+
+		if (pSmnt->chCurrentProbability < 20) 
+			pSmnt->chCurrentProbability += STEP_MULTICAST_HOLD_CHANNEL;			// Delay CH switch!
+		
+		printf("M%02d(CH=%d)--%02X:(%02X,%02X)\n", index, pSmnt->chCurrentIndex+1, pAddr[3], pAddr[4], pAddr[5]); 
+		pSmnt->payload_multicast[payloadIndex * 2]     = pAddr[4];
+		pSmnt->payload_multicast[payloadIndex * 2 + 1] = pAddr[5];
+
+		if (joylink_smnt_payLoadcheck(pSmnt->payload_multicast) == 0){
+			pSmnt->result.type = 3;
+			return;
+		}
+	}
+	return;
+}
+
+void joylink_smnt_datahandler(PHEADER_802_11 pHeader, int length)
+{
+	uint8 isUplink = 1;				
+	uint8 packetType = 0;					// 1-multicast packets 2-broadcast packets 0-thers
+	uint8 isDifferentAddr = 0;
+	uint8 *pDest, *pSrc, *pBssid;
+	uint16 lastLength = 0;
+	uint16 lastSeq_uplink = 0,lastSeq_downlink = 0;
+	static uint8 past_channel = 0xFF;
+	
+	if (pSmnt == NULL)
+		return;
+	if ((length > 100) && (pSmnt->state != SMART_CH_LOCKED))	
+		return;
+	
+	if (pHeader->FC.ToDs){
+		isUplink = 1;				
+		pBssid = pHeader->Addr1;
+		pSrc = pHeader->Addr2;
+		pDest = pHeader->Addr3;	
+
+		if (!((memcmp(pDest, "\xFF\xFF\xFF\xFF\xFF\xFF", 6) == 0) || (memcmp(pDest, "\x01\x00\x5E", 3) == 0))){
+			return;
+		}		
+		lastSeq_uplink = pSmnt->lastUploadSeq;
+		pSmnt->lastUploadSeq = pHeader->Sequence;
+	}else{
+		pDest = pHeader->Addr1;	
+		pBssid = pHeader->Addr2;
+		pSrc  = pHeader->Addr3;
+		
+		isUplink = 0;
+		//not broadcast nor multicast package ,return
+		if (!((memcmp(pDest, "\xFF\xFF\xFF\xFF\xFF\xFF", 6) == 0) || (memcmp(pDest, "\x01\x00\x5E", 3) == 0))){
+			return;
+		}
+		lastSeq_downlink = pSmnt->lastDownSeq;
+		pSmnt->lastDownSeq = pHeader->Sequence;
+	}
+	lastLength = pSmnt->lastLength;
+	pSmnt->lastLength = length;
+
+	if (memcmp(pDest, "\xFF\xFF\xFF\xFF\xFF\xFF", 6) == 0)
+	{
+		if (pSmnt->state == SMART_CH_LOCKING)
+		{
+			if(isUplink == 1)
+				printf("uplink:(%02x-%04d)->length:%2x, =length-synfirst:(0x%02x),synfirst:%2x\n", (int)(*((uint8*)pHeader) & 0xFF), pHeader->Sequence, length, (uint8)(length - pSmnt->syncFirst +1),pSmnt->syncFirst);
+			else
+				printf("downlink:(%02x-%04d)->length:%2x, =length-synfirst:(0x%02x),synfirst:%2x\n", (int)(*((uint8*)pHeader) & 0xFF), pHeader->Sequence, length, (uint8)(length - pSmnt->syncFirst_downlink +1),pSmnt->syncFirst_downlink);
+			
+		}
+		packetType = 2;
+	}
+	else if (memcmp(pDest, "\x01\x00\x5E", 3) == 0)
+	{
+		if (pSmnt->state == SMART_CH_LOCKING)
+			printf("(%02x-%04d):%02x:%02x:%02x->%d\n", (int)(*((uint8*)pHeader) & 0xFF), pHeader->Sequence, pDest[3], pDest[4], pDest[5], (int)length);
+		packetType = 1;
+	}
+
+	if (memcmp(pSrc, pSmnt->syncAppMac, 6) != 0)
+	{
+		isDifferentAddr = 1;
+	}
+
+	if(pSmnt->state == SMART_CH_LOCKING)
+	{
+		if (packetType == 0) return;
+		if ((isUplink==1) && (pHeader->Sequence == lastSeq_uplink)) return;
+		if ((isUplink==0) && (pHeader->Sequence == lastSeq_downlink)) return;
+		if(!isDifferentAddr)
+		{
+			if (packetType != 0)
+			{
+				if (packetType == 1)
+				{
+					if (((pDest[3] >> 6) == ((pDest[4] ^ pDest[5]) & 0x1)) && (pDest[3] != 0) && ((pDest[3]&0x3F) <=  PAYLOAD_MAX))
+					{
+						/*if receive multicast right message for two times,lock the channel*/
+						if(past_channel == pSmnt->chCurrentIndex + 1)
+						{
+							past_channel = 0xFF;
+							if (pSmnt->chCurrentProbability < 20) 
+								pSmnt->chCurrentProbability = 10;
+
+							memcpy(pSmnt->syncBssid, pBssid, 6);
+							pSmnt->state = SMART_CH_LOCKED;
+						}
+						else
+						{
+							past_channel = pSmnt->chCurrentIndex + 1;
+						}
+
+					}
+					joylink_smnt_muticastadd(pDest); // Internal state machine could delay the ch switching
+					return;
+				}
+
+				if(isUplink == 1)
+				{
+					if (lastLength == length)	return;
+
+					int expectLength = 1 + pSmnt->syncFirst + pSmnt->syncCount%4 - (pSmnt->syncStepPoint?4:0);
+					int isStep = (pSmnt->syncStepPoint == 0 && length == (expectLength - 4));	
+
+					if ( ( length == expectLength ) || isStep)
+					{
+						pSmnt->syncCount++;
+						pSmnt->chCurrentProbability++;
+
+						if (isStep)		pSmnt->syncStepPoint = pSmnt->syncCount;
+
+						if (pSmnt->syncCount >= 3)	// Achive SYNC count!
+						//if (pSmnt->syncCount >= 4)	// Achive SYNC count!
+						{
+							pSmnt->syncFirst = pSmnt->syncFirst + pSmnt->syncStepPoint - (pSmnt->syncStepPoint ? 4 : 0);	// Save sync world
+							memcpy(pSmnt->syncBssid, pBssid, 6);
+
+							pSmnt->state 		= SMART_CH_LOCKED;
+
+							printf("SYNC:(%02X%02X%02X%02X%02X%02X-%02X%02X%02X%02X%02X%02X)------->:CH=%d, WD=%d\n",
+								pSrc[0], pSrc[1], pSrc[2], pSrc[3], pSrc[4], pSrc[5],
+								pBssid[0], pBssid[1], pBssid[2], pBssid[3], pBssid[4], pBssid[5],
+								pSmnt->chCurrentIndex+1, (int)pSmnt->syncFirst);
+							
+							pSmnt->syncIsUplink = isUplink;
+							
+							if(pSmnt->chCurrentProbability < 20)
+								pSmnt->chCurrentProbability = 20;
+							printf("--->locked by uplink\n");
+						}
+						return;
+					}
+					if (pSmnt->syncCount)
+					{
+						pSmnt->syncStepPoint = 0;
+						pSmnt->syncCount = 0;
+						memcpy(pSmnt->syncAppMac, pSrc, 6);
+						pSmnt->syncFirst = length;
+						printf("SYNC LOST\n");
+					}
+				}
+				else
+				{
+					if (lastLength == length)	return;
+
+					int expectLength = 1 + pSmnt->syncFirst_downlink+ pSmnt->syncCount_downlink%4 - (pSmnt->syncStepPoint_downlink?4:0);
+					int isStep = (pSmnt->syncStepPoint_downlink == 0 && length == (expectLength - 4));	
+
+					if ( ( length == expectLength ) || isStep)
+					{
+						pSmnt->syncCount_downlink++;
+						pSmnt->chCurrentProbability++;
+						
+						if (isStep)			pSmnt->syncStepPoint_downlink = pSmnt->syncCount_downlink;
+
+						if (pSmnt->syncCount_downlink>= 3)	// Achive SYNC count!
+						//if (pSmnt->syncCount_downlink>= 4)	// Achive SYNC count!
+						{
+							pSmnt->syncFirst_downlink = pSmnt->syncFirst_downlink + pSmnt->syncStepPoint_downlink - (pSmnt->syncStepPoint_downlink? 4 : 0);	// Save sync world
+							memcpy(pSmnt->syncBssid, pBssid, 6);
+							pSmnt->state = SMART_CH_LOCKED;
+							printf("SYNC:(%02X%02X%02X%02X%02X%02X-%02X%02X%02X%02X%02X%02X)------->:CH=%d, WD=%d\n",
+								pSrc[0], pSrc[1], pSrc[2], pSrc[3], pSrc[4], pSrc[5],
+								pBssid[0], pBssid[1], pBssid[2], pBssid[3], pBssid[4], pBssid[5],
+								pSmnt->chCurrentIndex+1, (int)pSmnt->syncFirst_downlink);
+
+							pSmnt->syncIsUplink = isUplink;
+							if(pSmnt->chCurrentProbability < 20)
+								pSmnt->chCurrentProbability = 20;
+							printf("--->locked by downlink\n");
+						}
+						return;
+					}
+					pSmnt->syncStepPoint_downlink = 0;
+					pSmnt->syncCount_downlink = 0;
+					memcpy(pSmnt->syncAppMac, pSrc, 6);
+					pSmnt->syncFirst_downlink = length;
+					printf("SYNC LOST\n");
+				}
+			} 
+			return;	
+		}
+		memcpy(pSmnt->syncAppMac, pSrc, 6);
+		pSmnt->syncFirst = length;
+		pSmnt->syncFirst_downlink = length;
+		printf("Try to SYNC!\n");
+		return;
+	}
+	else if (pSmnt->state == SMART_CH_LOCKED)
+	{
+		if (isDifferentAddr) return;
+
+		if (packetType == 1){
+			joylink_smnt_muticastadd(pDest);
+			return;
+		}
+		
+		if ( (packetType != 1)&&(memcmp(pDest, pSmnt->syncBssid, 6) != 0) ){
+			packetType = 2;
+		}
+		
+		if(isUplink == 1)
+		{
+			if (length < (pSmnt->syncFirst - 1)) return;
+			if ( pHeader->Sequence == lastSeq_uplink) return;
+		}
+		else
+		{
+			if (length < (pSmnt->syncFirst_downlink - 1)) return;
+			if ( pHeader->Sequence == lastSeq_downlink) return;
+		}
+		if (packetType == 2)
+		{
+			int ascii;
+			if(isUplink == 1)
+				ascii = length - pSmnt->syncFirst + 1;
+			else
+				ascii = length - pSmnt->syncFirst_downlink + 1;
+
+			if((((ascii >> 8) & 0x01) == 1) && (((ascii >> 3)&0x1F) == 0))
+			{
+				;
+			}
+			else
+			{
+				joylink_smnt_broadcastadd(ascii);
+			}
+			if (((length + 4 - lastLength) % 4 == 1)&& (length - pSmnt->syncFirst)<4)  // There are SYNC packets even ch locked.
+			{
+				if (pSmnt->chCurrentProbability < 20) pSmnt->chCurrentProbability++;
+			}
+		}
+	}
+	else if (pSmnt->state == SMART_FINISH)
+	{
+		printf("SMART_FINISH-1\n");
+	}
+	else
+	{
+		pSmnt->state = SMART_CH_LOCKING;
+		memcpy(pSmnt->syncAppMac, pSrc, 6);
+		pSmnt->syncFirst = length;
+		pSmnt->syncStepPoint = 0;
+		pSmnt->syncCount = 0;
+		printf("Reset All State\n");
+	}
+	return;
+}
+
+static int joylink_smnt_payLoadcheck(uint8 *payload)
+{
+	uint8 crc = joylink_smnt_crc(payload + 1, payload[1]+1);
+	if ((payload[1] > (PAYLOAD_MIN*2)) &&
+		(payload[1] < (PAYLOAD_MAX*2)) &&
+        (payload[0] == crc)){
+
+		smnt_encrypt_data_t* pRet = &pSmnt->result;
+		memcpy(pRet->encData, payload+1, payload[1]+1);
+		pRet->type = pSmnt->result.type;
+          	pSmnt->state = SMART_FINISH;
+          	joylink_smnt_finish();
+        return 0;
+	}
+	return 1;
+}
+
+
+static uint8 joylink_smnt_crc(uint8 *ptr, uint8 len)
+{
+	unsigned char crc;
+	unsigned char i;
+	crc = 0;
+	while (len--)
+	{
+		crc ^= *ptr++;
+		for (i = 0; i < 8; i++)
+		{
+			if (crc & 0x01)
+			{
+				crc = (crc >> 1) ^ 0x8C;
+			}
+			else
+				crc >>= 1;
+		}
+	}
+	return crc;
+}
+static void joylink_smnt_bufferprintf(uint8* p, int split, int len)
+{
+	int i;
+	char buf[512];
+	int index = 0;
+	for (i = 0; i < len; i++)
+	{
+		if (split != 0 && ((i + 1) % split) == 0)
+		{
+			index += sprintf(buf + index, "%02x,", p[i]);
+		}
+		else
+			index += sprintf(buf + index, "%02x ", p[i]);
+	}
+	printf("Len=%d:%s\n",len, buf);
+}
+

+ 119 - 0
joylink/config/joylink_smart_config.h

@@ -0,0 +1,119 @@
+/*************************************
+
+Copyright (c) 2015-2050, JD Smart All rights reserved. 
+
+*************************************/
+#ifndef _JOYLINK_SMNT_H_
+#define _JOYLINK_SMNT_H_
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define MAC_ADDR_LEN            6
+#define SUBTYPE_PROBE_REQ       4
+#define VERSION_SMNT                                    "3.0.11"
+typedef  unsigned char        	uint8;
+typedef  char                  	int8;
+typedef  unsigned short      	uint16;
+
+
+typedef struct{
+	unsigned char type;	                        // 0:NotReady, 1:ControlPacketOK, 2:BroadcastOK, 3:MulticastOK
+	unsigned char encData[1+32+32+32];            // length + EncodeData
+}smnt_encrypt_data_t;
+
+typedef enum{
+	SMART_CH_INIT 		=	0x1,
+	SMART_CH_LOCKING 	=	0x2,
+	SMART_CH_LOCKED 	=	0x4,
+	SMART_FINISH 		= 	0x8
+}smnt_status_t;
+
+typedef struct{
+    uint16        Ver:2;                // Protocol version
+    uint16        Type:2;                // MSDU type
+    uint16        SubType:4;            // MSDU subtype
+    uint16        ToDs:1;                // To DS indication
+    uint16        FrDs:1;                // From DS indication
+    uint16        MoreFrag:1;            // More fragment bit
+    uint16        Retry:1;            // Retry status bit
+    uint16        PwrMgmt:1;            // Power management bit
+    uint16        MoreData:1;            // More data bit
+    uint16        Wep:1;                // Wep data
+    uint16        Order:1;            // Strict order expected
+} FRAME_CONTROL;
+
+typedef struct{
+    FRAME_CONTROL   FC;
+    uint16          Duration;
+    uint8           Addr1[MAC_ADDR_LEN];
+    uint8           Addr2[MAC_ADDR_LEN];
+    uint8            Addr3[MAC_ADDR_LEN];
+    uint16            Frag:4;
+    uint16            Sequence:12;
+    uint8            Octet[0];
+} *PHEADER_802_11;
+
+
+typedef enum{
+	smnt_result_ok,
+	smnt_result_decrypt_error,
+	smnt_result_ssidlen_error,
+	smnt_result_pwdlen_error
+}joylink_smnt_result_flag_t;
+
+typedef struct{
+	joylink_smnt_result_flag_t smnt_result_status;
+	uint8 jd_ssid_len;
+	uint8 jd_password_len;
+	uint8 jd_ssid[33];
+	uint8 jd_password[65];
+}joylink_smnt_result_t;
+
+
+//typedef void (*joylink_smnt_channel_cb)(unsigned char ch);
+typedef void (*joylink_smnt_result_cb)(joylink_smnt_result_t result_info);
+
+typedef struct{
+	unsigned char secretkey[16+1];
+	//void (*switch_channel_callback)(unsigned char);
+	void (*get_result_callback)(joylink_smnt_result_t *);
+} joylink_smnt_param_t;
+
+
+typedef struct{
+	smnt_status_t state;	
+	uint16 syncFirst;				
+	uint8 syncCount;				
+	uint8 syncStepPoint;			
+	uint8 syncFirst_downlink;		
+	uint8 syncCount_downlink;		
+	uint8 syncStepPoint_downlink;	
+	uint8 directTimerSkip;			
+	uint8 broadcastVersion;			
+	uint8 muticastVersion;			
+	uint8  broadIndex;				
+	uint8  broadBuffer[5];			
+	uint16 lastLength;			
+	uint16 lastUploadSeq;		
+	uint16 lastDownSeq;		
+	uint8  syncAppMac[6];		
+	uint8  syncBssid[6];		
+	uint16 syncIsUplink;		
+	uint8 chCurrentIndex;		
+	uint8 chCurrentProbability;	
+	uint8 isProbeReceived;	
+	uint8 payload_multicast[128];	
+	uint8 payload_broadcast[128];
+	smnt_encrypt_data_t result;	
+}joylinkSmnt_t;
+
+void joylink_smnt_init(joylink_smnt_param_t param);                                  
+int  joylink_smnt_cyclecall(void);                                               
+void joylink_smnt_datahandler(PHEADER_802_11 pHeader, int length);               
+void joylink_smnt_release(void);
+void joylink_smnt_reset(void);
+
+
+#endif

+ 90 - 0
joylink/config/joylink_smart_config.htxt

@@ -0,0 +1,90 @@
+/*************************************
+
+Copyright (c) 2015-2050, JD Smart All rights reserved. 
+
+*************************************/
+#ifndef _JOYLINK_SMART_CONFIG_H_
+#define _JOYLINK_SMART_CONFIG_H_
+
+#include "joylink_smnt_adp.h"
+
+//#define IS_FULL_LOG							//is to open the full log function
+
+/*
+typedef struct _joylinkResult
+{
+	unsigned char type;	                        // 0:NotReady, 1:ControlPacketOK, 2:BroadcastOK, 3:MulticastOK
+	unsigned char ssid[33];
+	unsigned char pass[33];
+	unsigned char bssid[6];
+}joylinkResult_t;
+*/
+typedef enum 
+{
+	TYPE_JOY_OTHER = 0,
+	TYPE_JOY_SMNT  = 1
+}joylink_smnt_type_t;
+
+typedef enum _joylink_smnt_status
+{
+	SMART_CH_INIT 		=		0x1,
+	SMART_CH_LOCKING 	=	0x2,
+	SMART_CH_LOCKED 	=	0x4,
+	SMART_FINISH 		= 0x8
+}joylink_smnt_status_t;
+
+typedef struct _joylink_smnt_info
+{
+	joylink_smnt_type_t			joy_smnt_type;				//smnt type TYPE_JOY_OTHER-other type, TYPE_JOY_SMNT - joylink's smnt
+	joylink_smnt_status_t 		joy_smnt_state;				//smnt state,
+	uint8 						joy_smnt_bssid[6];			//bssid
+	uint8 						joy_smnt_channel_fix;		//the current channel
+}joylink_smnt_info_t;
+
+typedef struct _joylinkResult
+{
+	unsigned char type;	                        // 0:NotReady, 1:ControlPacketOK, 2:BroadcastOK, 3:MulticastOK
+  unsigned char encData[1+32+32+32];            // length + EncodeData
+}joylinkResult_t;
+
+typedef struct _joylinkSmnt
+{
+    joylink_smnt_type_t jd_smnt_type;
+    joylink_smnt_status_t state;
+    uint16 syncFirst;
+    uint8 syncCount;
+    uint8 syncStepPoint;
+    uint8 syncFirst_downlink;
+    uint8 syncCount_downlink;
+    uint8 syncStepPoint_downlink;
+    uint8 directTimerSkip;
+    uint8 broadcastVersion;
+    uint8 muticastVersion;
+    uint8 broadIndex;
+    uint8 broadBuffer[5];
+    uint16 lastLength;
+    uint16 lastUploadSeq;
+    uint16 lastDownSeq;
+    uint8 syncAppMac[6];
+    uint8 syncBssid[6];
+    uint16 syncIsUplink;
+    uint8 chCurrentIndex;
+    uint8 chCurrentProbability;
+    uint8 isProbeReceived;
+    uint8 payload[128];
+    uint8 payload_multicast[128];
+    joylinkResult_t result;
+} joylinkSmnt_t;
+
+extern void joylink_change_hannel(int ch);
+
+
+void joylink_cfg_init(unsigned char* pBuffer);        // 传入一个1024字节的存储空间
+int  joylink_cfg_50msTimer(void);		// 50ms定时器回调,如果返回非零,那么这个值作为下一次调用的时间间隔,可能的取值为(50,100,5000,10000)
+
+int joylink_get_smnt_info(joylink_smnt_info_t *smnt_info);								//查看当前的joylink 一键配置状态
+void joylink_cfg_CtrlAction(PHEADER_802_11 pHeader, int length);                // 局域网收到控制包
+void joylink_cfg_DataAction(PHEADER_802_11 pHeader, int length);                // 局域网收到数据包
+int  joylink_cfg_Result(joylinkResult_t* pRet);					// Get Result
+
+#endif

+ 565 - 0
joylink/config/joylink_smart_config.txt

@@ -0,0 +1,565 @@
+/*************************************
+
+ Copyright (c) 2015-2050, JD Smart All rights reserved.
+
+ *************************************/
+#include <stdio.h>
+#include <string.h>
+#include "joylink_smart_config.h"
+#define STEP_MULTICAST_HOLD_CHANNEL				5
+#define STEP_BROADCAST_HOLE_CHANNEL				4
+#define STEP_BROADCAST_ERROR_HOLE_CHANNEL		2
+
+#define PAYLOAD_MIN		(3)
+#define PAYLOAD_MAX		(48+1)
+
+void printf_nul( )
+{
+    return;
+}
+
+//#define printf_high printf_nul//printf
+#define printf_high printf
+
+static uint8 getCrc( uint8 *ptr, uint8 len );
+//static void dump8(uint8* p, int split, int len);
+static int payLoadCheck( uint8 *payload  );
+static void muticastAdd( uint8* pAddr );
+static void broadcastAdd( int ascii );
+
+joylinkSmnt_t* pSmnt = NULL;
+
+static int payLoadCheck(uint8 *payload)
+{
+    uint8 crc = getCrc( payload + 1, payload[1] + 1 );
+    if ( (payload[1] > (PAYLOAD_MIN * 2)) &&
+         (payload[1] < (PAYLOAD_MAX * 2))
+         &&
+         (payload[0] == crc) )
+    {
+
+        joylinkResult_t* pRet = &pSmnt->result;
+        memcpy( pRet->encData, payload + 1, payload[1] + 1 );
+        pRet->type = pSmnt->result.type;
+        pSmnt->state = SMART_FINISH;
+        return 0;
+    }
+    return 1;
+}
+
+void joylink_cfg_init( unsigned char* pBuffer )
+{
+    pSmnt = (void*) pBuffer;
+    memset( pSmnt, 0, sizeof(joylinkSmnt_t) );
+    memset( pSmnt->payload, 0xFF, 128 );
+    memset(pSmnt->payload_multicast,0xFF,128);
+}
+
+int joylink_cfg_Result( joylinkResult_t* pRet )
+{
+    pRet->type = 0;
+
+    if ( pSmnt && (pSmnt->state == SMART_FINISH) )
+    {
+        memcpy( pRet, &pSmnt->result, sizeof(joylinkResult_t) );
+        return 0;
+    }
+
+    return 1;
+}
+
+int joylink_cfg_50msTimer( void )
+{
+    if ( pSmnt->directTimerSkip )
+    {
+        pSmnt->directTimerSkip--;
+        return 50;
+    }
+
+    if ( pSmnt->state == SMART_FINISH )
+    {
+        printf_high( "-------------------->Finished\r\n" );
+        pSmnt->directTimerSkip = 10000 / 50;
+        return 50;
+    }
+
+    if ( pSmnt->isProbeReceived > 0 )
+    {
+        //	printf_high("-------------------->Probe Stay(CH:%d) %d\r\n", pSmnt->chCurrentIndex + 1, pSmnt->isProbeReceived);
+        pSmnt->isProbeReceived = 0;
+        pSmnt->directTimerSkip = 5000 / 50;
+        return 50;
+    }
+
+    if ( pSmnt->chCurrentProbability > 0 )
+    {
+        pSmnt->chCurrentProbability--;
+        //	printf_high("------------------->SYNC (CH:%d) %d\r\n", pSmnt->chCurrentIndex + 1, pSmnt->chCurrentProbability);
+        return 50;
+    }
+/*
+    pSmnt->chCurrentIndex = (pSmnt->chCurrentIndex + 1) % 13;
+    joylink_change_hannel( pSmnt->chCurrentIndex + 1 );
+
+    pSmnt->state = SMART_CH_LOCKING;
+    pSmnt->jd_smnt_type = TYPE_JOY_OTHER;
+    pSmnt->syncStepPoint = 0;
+    pSmnt->syncCount = 0;
+    pSmnt->chCurrentProbability = 0;
+    printf_high("CH=%d, T=%d\r\n", pSmnt->chCurrentIndex + 1, 50 );
+*/
+    return 50;
+}
+
+static void broadcastAdd( int ascii )
+{
+    uint8 isFlag = (uint8) ((ascii >> 8) & 0x1);
+    uint8 is_finishpacket = 0;
+
+    uint8 *broadbuffer = pSmnt->broadBuffer, *broadindex = &(pSmnt->broadIndex);
+    if ( isFlag )
+    {
+        *broadindex = 0;
+        *broadbuffer = (uint8) ascii;
+    }
+    else
+    {
+        *broadindex = *broadindex + 1;
+        broadbuffer[*broadindex] = (uint8) ascii;
+
+        if ( (((pSmnt->payload[1] + 2) / 4 + 1) == ((*broadbuffer) >> 3))
+            && (pSmnt->payload[1] != 0) && (pSmnt->payload[1] != 0xFF) )
+        {
+            if ( *broadindex == 2 )
+            {
+                is_finishpacket = 1;
+                *(broadbuffer + 3) = 0;
+                *(broadbuffer + 4) = 0;
+            }
+        }
+
+        if ( *broadindex >= 4 || is_finishpacket )
+        {
+            *broadindex = 0;
+            uint8 crc = (*broadbuffer) & 0x7;
+            uint8 index = (*broadbuffer) >> 3;
+            uint8 rCrc = getCrc( broadbuffer + 1, 4 ) & 0x7;
+
+            /*not to check the last pacet crc,It is a patch for the last packet is a lot wrong which maybe leaded by the phone*/
+            if ( ((index > 0) && (index < 33) && (rCrc == crc)) )
+            {
+                memcpy( pSmnt->payload + (index - 1) * 4, broadbuffer + 1, 4 );
+
+                printf_high( "B(%x=%x)--%02x,%02x,%02x,%02x\r\n", index, broadbuffer[0],
+                             broadbuffer[1], broadbuffer[2], broadbuffer[3], broadbuffer[4] );
+                index = payLoadCheck(pSmnt->payload );
+
+                if ( pSmnt->chCurrentProbability < 30 )
+                {
+                    pSmnt->chCurrentProbability += STEP_BROADCAST_HOLE_CHANNEL;
+                }
+
+                if ( index == 0 )
+                {
+                    pSmnt->result.type = 2;
+                }
+
+                //dump8(pSmnt->payload, 1, 80);
+
+            }
+            else
+            {
+                if ( pSmnt->chCurrentProbability < 30 )
+                {
+                    pSmnt->chCurrentProbability += STEP_BROADCAST_ERROR_HOLE_CHANNEL;
+                }
+            }
+        }
+        else if ( *broadindex == 2 )
+        {
+            uint8 index = broadbuffer[0] >> 3;
+            if ( index == 0 )
+            {
+                *broadindex = 0;
+                uint8 crc = broadbuffer[0] & 0x7;
+                uint8 rCrc = getCrc( broadbuffer + 1, 2 ) & 0x7;
+                if ( rCrc == crc )
+                {
+                    pSmnt->broadcastVersion = broadbuffer[1];
+                    printf_high( "Version RX:%x\r\n", pSmnt->broadcastVersion );
+                }
+            }
+        }
+    }
+}
+
+/*
+ Input: Muticast Addr
+ Output: -1:Unkown Packet, 0:Parse OK, 1:Normal Process
+ */
+static void muticastAdd( uint8* pAddr )
+{
+    int8 index = 0;
+
+    /*version data*/
+    if ( (pAddr[3] == 0) && (pAddr[4] == 1) && (pAddr[5] <= 3) && (pAddr[5] > 0) )
+        pSmnt->jd_smnt_type = TYPE_JOY_SMNT;
+    if ( pAddr[3] == 0 )
+        index = 0 - pAddr[3];
+    else if ( (pAddr[3] >> 6) == ((pAddr[4] ^ pAddr[5]) & 0x1) )
+        index = pAddr[3] & 0x3F;
+    else
+        return;
+
+    if ( index < PAYLOAD_MAX )		//avoid overstep leaded by error
+    {
+        uint8 payloadIndex = index - 1;
+        if ( payloadIndex > 64 )
+            return;
+
+        if ( pSmnt->chCurrentProbability < 20 )
+            pSmnt->chCurrentProbability += STEP_MULTICAST_HOLD_CHANNEL;			// Delay CH switch!
+
+        printf_high( "M%02d(CH=%d)--%02X:(%02X,%02X)\r\n", index, pSmnt->chCurrentIndex + 1,
+                     pAddr[3], pAddr[4], pAddr[5] );
+        pSmnt->payload_multicast[payloadIndex * 2] = pAddr[4];
+        pSmnt->payload_multicast[payloadIndex * 2 + 1] = pAddr[5];
+#ifdef IS_FULL_LOG
+        dump8(pSmnt->payload, 1, 80);
+#endif
+        if ( payLoadCheck(pSmnt->payload_multicast) == 0 )
+        {
+            pSmnt->result.type = 3;
+            return;
+        }
+    }
+    return;
+}
+
+int joylink_get_smnt_info(joylink_smnt_info_t *smnt_info)
+{
+    memset(smnt_info, 0, sizeof(joylink_smnt_info_t) );
+
+    smnt_info->joy_smnt_type = pSmnt->jd_smnt_type;
+    smnt_info->joy_smnt_state = pSmnt->state;
+    memcpy( smnt_info->joy_smnt_bssid, pSmnt->syncBssid, 6 );
+    smnt_info->joy_smnt_channel_fix = pSmnt->chCurrentIndex + 1;
+    return 0;
+}
+
+void joylink_cfg_DataAction( PHEADER_802_11 pHeader, int length )
+{
+    uint8 isUplink = 1;
+    uint8 packetType = 0;					// 1-multicast packets 2-broadcast packets 0-thers
+    uint8 isDifferentAddr = 0;
+    uint8 *pDest, *pSrc, *pBssid;
+    uint16 lastLength = 0;
+    uint16 lastSeq_uplink = 0, lastSeq_downlink = 0;
+    static uint8 past_channel = 0xFF;
+
+    if ( pSmnt == NULL )
+        return;
+    if ( (length > 100) && (pSmnt->state != SMART_CH_LOCKED) )
+        return;
+
+    if ( pHeader->FC.ToDs )
+    {
+        isUplink = 1;
+        pBssid = pHeader->Addr1;
+        pSrc = pHeader->Addr2;
+        pDest = pHeader->Addr3;
+
+        if ( !((memcmp( pDest, "\xFF\xFF\xFF\xFF\xFF\xFF", 6 ) == 0)
+            || (memcmp( pDest, "\x01\x00\x5E", 3 ) == 0)) )
+        {
+            return;
+        }
+        lastSeq_uplink = pSmnt->lastUploadSeq;
+        pSmnt->lastUploadSeq = pHeader->Sequence;
+    } else
+    {
+        pDest = pHeader->Addr1;
+        pBssid = pHeader->Addr2;
+        pSrc = pHeader->Addr3;
+
+        isUplink = 0;
+        //not broadcast nor multicast package ,return
+        if ( !((memcmp( pDest, "\xFF\xFF\xFF\xFF\xFF\xFF", 6 ) == 0)
+            || (memcmp( pDest, "\x01\x00\x5E", 3 ) == 0)) )
+        {
+            return;
+        }
+        lastSeq_downlink = pSmnt->lastDownSeq;
+        pSmnt->lastDownSeq = pHeader->Sequence;
+    }
+    lastLength = pSmnt->lastLength;
+    pSmnt->lastLength = length;
+
+    if ( memcmp( pDest, "\xFF\xFF\xFF\xFF\xFF\xFF", 6 ) == 0 )
+    {
+        if ( pSmnt->state == SMART_CH_LOCKING )
+        {
+            if ( isUplink == 1 )
+                printf_high(
+                    "uplink:(%02x-%04d)->length:%2x, =length-synfirst:(0x%02x),synfirst:%2x\r\n",
+                    *((uint8*) pHeader) & 0xFF, pHeader->Sequence, length,
+                    (uint8) (length - pSmnt->syncFirst + 1), pSmnt->syncFirst );
+            else
+                printf_high(
+                    "downlink:(%02x-%04d)->length:%2x, =length-synfirst:(0x%02x),synfirst:%2x\r\n",
+                    *((uint8*) pHeader) & 0xFF, pHeader->Sequence, length,
+                    (uint8) (length - pSmnt->syncFirst_downlink + 1), pSmnt->syncFirst_downlink );
+
+        }
+        packetType = 2;
+    }
+    else if ( memcmp( pDest, "\x01\x00\x5E", 3 ) == 0 )
+    {
+        if ( pSmnt->state == SMART_CH_LOCKING )
+            printf_high( "(%02x-%04d):%02x:%02x:%02x->%d\r\n", *((uint8*) pHeader) & 0xFF,
+                         pHeader->Sequence, pDest[3], pDest[4], pDest[5], (uint8) length );
+        packetType = 1;
+    }
+
+    if ( memcmp( pSrc, pSmnt->syncAppMac, 6 ) != 0 )
+    {
+        isDifferentAddr = 1;
+    }
+
+    if ( pSmnt->state == SMART_CH_LOCKING )
+    {
+        if ( packetType == 0 ) return;
+        if ( (isUplink == 1) && (pHeader->Sequence == lastSeq_uplink) ) return;
+        if ( (isUplink == 0) && (pHeader->Sequence == lastSeq_downlink) ) return;
+        if ( !isDifferentAddr )
+        {
+            if ( packetType != 0 )
+            {
+                if ( packetType == 1 )
+                {
+                    if ( ((pDest[3] >> 6) == ((pDest[4] ^ pDest[5]) & 0x1)) && (pDest[3] != 0)
+                         && ((pDest[3] & 0x3F) <= PAYLOAD_MAX) )
+                    {
+                        /*if receive multicast right message for two times,lock the channel*/
+                        if ( past_channel == pSmnt->chCurrentIndex + 1 )
+                        {
+                            past_channel = 0xFF;
+                            if ( pSmnt->chCurrentProbability < 20 )
+                                pSmnt->chCurrentProbability = 10;
+
+                            memcpy( pSmnt->syncBssid, pBssid, 6 );
+                            pSmnt->state = SMART_CH_LOCKED;
+                        }
+                        else
+                        {
+                            past_channel = pSmnt->chCurrentIndex + 1;
+                        }
+
+                    }
+                    muticastAdd( pDest ); // Internal state machine could delay the ch switching
+
+                    return;
+                }
+
+                if ( isUplink == 1 )
+                {
+                    if ( lastLength == length ) return;
+
+                    int expectLength = 1 + pSmnt->syncFirst + pSmnt->syncCount % 4
+                        - (pSmnt->syncStepPoint ? 4 : 0);
+                    int isStep = (pSmnt->syncStepPoint == 0 && length == (expectLength - 4));
+
+                    if ( (length == expectLength) || isStep )
+                    {
+                        pSmnt->syncCount++;
+                        pSmnt->chCurrentProbability++;
+
+                        if ( isStep ) pSmnt->syncStepPoint = pSmnt->syncCount;
+
+                        if ( pSmnt->syncCount >= 3 )	// Achive SYNC count!
+                        //if (pSmnt->syncCount >= 4)	// Achive SYNC count!
+                        {
+                            pSmnt->syncFirst = pSmnt->syncFirst + pSmnt->syncStepPoint
+                                - (pSmnt->syncStepPoint ? 4 : 0);	// Save sync world
+                            memcpy( pSmnt->syncBssid, pBssid, 6 );
+
+                            pSmnt->state = SMART_CH_LOCKED;
+                            pSmnt->jd_smnt_type = TYPE_JOY_SMNT;
+
+                            //			printf_high("SYNC:(%02X%02X%02X%02X%02X%02X-%02X%02X%02X%02X%02X%02X)------->:CH=%d, WD=%d\r\n",
+//								pSrc[0], pSrc[1], pSrc[2], pSrc[3], pSrc[4], pSrc[5],
+//								pBssid[0], pBssid[1], pBssid[2], pBssid[3], pBssid[4], pBssid[5],
+//								pSmnt->chCurrentIndex+1, pSmnt->syncFirst);
+//
+                            pSmnt->syncIsUplink = isUplink;
+
+                            if ( pSmnt->chCurrentProbability < 20 )
+                                pSmnt->chCurrentProbability = 20;
+                            printf_high( "--->locked by uplink\r\n" );
+                        }
+                        return;
+                    }
+                    if ( pSmnt->syncCount )
+                    {
+                        pSmnt->syncStepPoint = 0;
+                        pSmnt->syncCount = 0;
+                        memcpy( pSmnt->syncAppMac, pSrc, 6 );
+                        pSmnt->syncFirst = length;
+                        printf_high( "SYNC LOST\r\n" );
+                    }
+                }
+                else
+                {
+                    if ( lastLength == length ) return;
+
+                    int expectLength = 1 + pSmnt->syncFirst_downlink + pSmnt->syncCount_downlink % 4
+                        - (pSmnt->syncStepPoint_downlink ? 4 : 0);
+                    int isStep = (pSmnt->syncStepPoint_downlink == 0 && length == (expectLength - 4));
+
+                    if ( (length == expectLength) || isStep )
+                    {
+                        pSmnt->syncCount_downlink++;
+                        pSmnt->chCurrentProbability++;
+
+                        if ( isStep ) pSmnt->syncStepPoint_downlink = pSmnt->syncCount_downlink;
+
+                        if ( pSmnt->syncCount_downlink >= 3 )	// Achive SYNC count!
+                        //if (pSmnt->syncCount_downlink>= 4)	// Achive SYNC count!
+                        {
+                            pSmnt->syncFirst_downlink = pSmnt->syncFirst_downlink
+                                + pSmnt->syncStepPoint_downlink
+                                                        - (pSmnt->syncStepPoint_downlink ? 4 : 0);// Save sync world
+                            memcpy( pSmnt->syncBssid, pBssid, 6 );
+                            pSmnt->state = SMART_CH_LOCKED;
+                            //			printf_high("SYNC:(%02X%02X%02X%02X%02X%02X-%02X%02X%02X%02X%02X%02X)------->:CH=%d, WD=%d\n",
+//								pSrc[0], pSrc[1], pSrc[2], pSrc[3], pSrc[4], pSrc[5],
+//								pBssid[0], pBssid[1], pBssid[2], pBssid[3], pBssid[4], pBssid[5],
+//								pSmnt->chCurrentIndex+1, pSmnt->syncFirst_downlink);
+
+                            pSmnt->syncIsUplink = isUplink;
+                            if ( pSmnt->chCurrentProbability < 20 )
+                                pSmnt->chCurrentProbability = 20;
+                            printf_high( "--->locked by downlink\r\n" );
+                        }
+                        return;
+                    }
+                    //if (pSmnt->syncCount_downlink)	// 意义在于:不用在每次收到不同Addr时都初始化以下内容
+                    {
+                        pSmnt->syncStepPoint_downlink = 0;
+                        pSmnt->syncCount_downlink = 0;
+                        memcpy( pSmnt->syncAppMac, pSrc, 6 );
+                        pSmnt->syncFirst_downlink = length;
+                        printf_high( "SYNC LOST\r\n" );
+                    }
+                }
+            }
+            return;
+        }
+        memcpy( pSmnt->syncAppMac, pSrc, 6 );
+        pSmnt->syncFirst = length;
+        pSmnt->syncFirst_downlink = length;
+        printf_high( "Try to SYNC!\r\n" );
+        return;
+    }
+    else if ( pSmnt->state == SMART_CH_LOCKED )
+    {
+        if ( isDifferentAddr ) return;
+
+        if ( packetType == 1 )
+        {
+            muticastAdd( pDest );
+            return;
+        }
+
+        if ( (packetType != 1) && (memcmp( pDest, pSmnt->syncBssid, 6 ) != 0) )
+        {
+            packetType = 2;
+        }
+
+        if ( isUplink == 1 )
+        {
+            if ( length < (pSmnt->syncFirst - 1) ) return;
+            if ( pHeader->Sequence == lastSeq_uplink ) return;
+        }
+        else
+        {
+            if ( length < (pSmnt->syncFirst_downlink - 1) ) return;
+            if ( pHeader->Sequence == lastSeq_downlink ) return;
+        }
+
+        //printf_high("length: %d\r\n", length);
+        if ( packetType == 2 )
+        {
+            int ascii;
+            if ( isUplink == 1 )
+                ascii = length - pSmnt->syncFirst + 1;
+            else
+                ascii = length - pSmnt->syncFirst_downlink + 1;
+
+            if ( (((ascii >> 8) & 0x01) == 1) && (((ascii >> 3) & 0x1F) == 0) )
+            {
+                ;
+            }
+            else
+            {
+                broadcastAdd( ascii );
+            }
+            if ( ((length + 4 - lastLength) % 4 == 1) && (length - pSmnt->syncFirst) < 4 ) // There are SYNC packets even ch locked.
+            {
+                if ( pSmnt->chCurrentProbability < 20 ) pSmnt->chCurrentProbability++;
+            }
+        }
+    }
+    else if ( pSmnt->state == SMART_FINISH )
+    {
+        //printf_high( "SMART_FINISH-1\r\n" );
+    }
+    else
+    {
+        pSmnt->state = SMART_CH_LOCKING;
+        memcpy( pSmnt->syncAppMac, pSrc, 6 );
+        pSmnt->syncFirst = length;
+        pSmnt->syncStepPoint = 0;
+        pSmnt->syncCount = 0;
+        printf_high( "Reset All State\r\n" );
+    }
+    return;
+}
+
+static uint8 getCrc( uint8 *ptr, uint8 len )
+{
+    unsigned char crc;
+    unsigned char i;
+    crc = 0;
+    while ( len-- )
+    {
+        crc ^= *ptr++;
+        for ( i = 0; i < 8; i++ )
+        {
+            if ( crc & 0x01 )
+            {
+                crc = (crc >> 1) ^ 0x8C;
+            }
+            else
+                crc >>= 1;
+        }
+    }
+    return crc;
+}
+//static void dump8(uint8* p, int split, int len)
+//{
+//	int i;
+//	char buf[512];
+//	int index = 0;
+//	for (i = 0; i < len; i++)
+//	{
+//		if (split != 0 && ((i + 1) % split) == 0)
+//		{
+//			index += sprintf(buf + index, "%02x,", p[i]);
+//		}
+//		else
+//			index += sprintf(buf + index, "%02x ", p[i]);
+//	}
+////	printf_high("Len=%d:%s\r\n",len, buf);
+//}
+

+ 44 - 0
joylink/config/joylink_smnt_adp.h

@@ -0,0 +1,44 @@
+/*************************************
+
+Copyright (c) 2015-2050, JD Smart All rights reserved. 
+
+*************************************/
+#ifndef _JOYLINK_SMNT_ADP_H_
+#define _JOYLINK_SMNT_ADP_H_
+/*
+ÊÊÅä²ãÎļþ
+*/
+typedef  unsigned char        uint8;
+typedef  char                  int8;
+typedef  unsigned short      uint16;
+#define MAC_ADDR_LEN            6
+#define SUBTYPE_PROBE_REQ       4
+
+
+// 2-byte Frame control field
+typedef    struct    GNU_PACKED {
+    uint16        Ver:2;                // Protocol version
+    uint16        Type:2;                // MSDU type
+    uint16        SubType:4;            // MSDU subtype
+    uint16        ToDs:1;                // To DS indication
+    uint16        FrDs:1;                // From DS indication
+    uint16        MoreFrag:1;            // More fragment bit
+    uint16        Retry:1;            // Retry status bit
+    uint16        PwrMgmt:1;            // Power management bit
+    uint16        MoreData:1;            // More data bit
+    uint16        Wep:1;                // Wep data
+    uint16        Order:1;            // Strict order expected
+} FRAME_CONTROL;
+
+typedef    struct    _HEADER_802_11    {
+    FRAME_CONTROL   FC;
+    uint16          Duration;
+    uint8           Addr1[MAC_ADDR_LEN];
+    uint8           Addr2[MAC_ADDR_LEN];
+    uint8            Addr3[MAC_ADDR_LEN];
+    uint16            Frag:4;
+    uint16            Sequence:12;
+    uint8            Octet[0];
+} *PHEADER_802_11;
+
+#endif

+ 120 - 0
joylink/config/joylink_syshdr.h

@@ -0,0 +1,120 @@
+//
+//  joylink_syshdr.h
+//
+// @brief system header , specailly for Device ,which has no operation system and necessary lib
+//
+//
+
+#ifndef _JOYLINK_SYSHDR_H_
+#define _JOYLINK_SYSHDR_H_
+
+#define JL_INT_32 
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* stdint.h subset */
+#ifndef JL_MISS_STDINT_H
+    #include <stdint.h>
+#else
+    /* You will need to modify these to match the word size of your platform. */
+    typedef signed char int8_t;
+    typedef unsigned char uint8_t;
+    typedef signed short int16_t;
+    typedef unsigned short uint16_t;    
+#ifdef JL_INT_32 
+    typedef signed int int32_t;
+    typedef unsigned int uint32_t;
+#else
+    typedef signed long int32_t;
+    typedef unsigned long uint32_t;
+#endif
+  
+#endif
+
+    /* stddef.h subset */
+#ifndef JL_MISS_STDDEF_H
+#include <stddef.h>
+#else
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif
+
+    /* stdbool.h subset */
+#ifndef JL_MISS_STDBOOL_H
+#include <stdbool.h>
+#else
+
+#ifndef __cplusplus
+typedef int bool;
+#define false 0
+#define true 1
+#endif
+
+#endif
+
+    /* stdlib.h subset */
+#ifndef JL_MISS_STDLIB_H
+#include <stdlib.h>
+#else
+#endif
+
+#ifndef JL_MISS_STRING_H
+#include <string.h>
+//for Broadcom build
+#ifdef JL_ONLY_BCM
+#include "spar_utils.h"
+#endif
+#else
+static size_t strlen( const char * s )
+{
+	size_t rc = 0;
+	while ( s[rc] )
+	{
+	    ++rc;
+	}
+	return rc;
+}
+
+static void * memcpy( void *s1, const void *s2, size_t n )
+{
+	char * dest = (char *) s1;
+	const char * src = (const char *) s2;
+	while ( n-- )
+	{
+	    *dest++ = *src++;
+	}
+	return s1;
+}
+
+static void * memset( void * s, int c, size_t n )
+{
+	unsigned char * p = (unsigned char *) s;
+	while ( n-- )
+	{
+	    *p++ = (unsigned char) c;
+	}
+	return s;
+}
+
+static  int memcmp (const void *s1, const void *s2, size_t n){
+	if (!n)
+	    return(0);
+	while ( --n && *(char *)s1 == *(char *)s2)
+	{
+	    s1 = (char *)s1 + 1;
+	    s2 = (char *)s2 + 1;
+	}
+	return( *((unsigned char *)s1) - *((unsigned char *)s2) );
+}
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 131 - 0
joylink/config/joylink_thunder.h

@@ -0,0 +1,131 @@
+#ifndef _JOYLINK_THUNEDER_H_
+#define _JOYLINK_THUNEDER_H_
+
+#define THUNDER_SLAVE_SUPPORT 	1
+#define THUNDER_MASTER_SUPPORT	1
+
+#include "joylink_syshdr.h"
+
+#define JOY_THUNDER_VERSION		"JOYL_V1.0"
+
+#define JOY_MEGIC_HEADER		"JOY"
+#define JOY_OUI_TYPE			0
+#define JOY_PACKET_HEADER_LEN	8
+#define JOY_MAC_ADDRESS_LEN		6
+
+#define JOY_CLA_ENCRYPT			1<<7			//
+#define JOY_CLA_DECRYPT			0
+#define JOY_CLA_UPLINK			0
+#define JOY_CLA_DOWNLINK		1<<6
+#define JOY_CLA_FIRSTPACKET		0
+#define JOY_CLA_RESENDPACKET	1<<5
+
+typedef enum
+{
+    TLV_TAG_MSG = 0x00,
+	TLV_TAG_THUNDERCONFIG_VERSION,
+	TLV_TAG_CID,
+	TLV_TAG_VENDOR,
+	TLV_TAG_UUID,
+	TLV_TAG_MAC,
+	TLV_TAG_SN,
+	TLV_TAG_WIFI_CHANNEL,
+	TLV_TAG_RANDOM,
+	TLV_TAG_SIGNATURE,
+	TLV_TAG_PUBKEY,
+	TLV_TAG_PRIKEY,
+	TLV_TAG_SSID,
+	TLV_TAG_PASSWD,
+	TLV_TAG_FEEDID,
+	TLV_TAG_ACKEY,
+	TLV_TAG_DEVICE_TOKEN,
+	
+	TLV_TAG_DEVICE_ID,
+	TLV_TAG_DEVICE_INFO,
+	TLV_TAG_CLOUD_SERVER
+} tc_tlv_tag_t;
+
+typedef enum
+{
+    INS_V1_BASE = 0x40,
+    INS_CONFIG_REQ,//1.d2g.0
+    INS_LOCK_CHANNEL,//1.g2d.1
+    INS_LOCK_CHANNEL_ACK,//1.d2g.2
+    INS_AUTH_ALLOWED,//1.g2d.7
+    INS_CHALLENGE_CLOUD,//2.d2g.0
+	INS_CHALLENGE_CLOUD_ACK,//2.g2d.5
+	INS_CHALLENGE_DEVICE_ACK,//3.d2g.0
+	INS_AUTH_INFO_A,//4.g2d.a.5
+	INS_AUTH_INFO_B,//4.g2d.b.5
+	INS_CONNECT_AP_ACK,//x.d2g.0
+	INS_DEVICE_BIND_REQ,//5.d2g.0
+	INS_DEVICE_BIND_ACK,//5.g2d.3
+} tc_ins_t;
+
+
+typedef enum
+{
+	MSG_OK = 0x00,
+	MSG_ERROR_REQ_DENIED,     //헝헹앳없
+	MSG_ERROR_TIMEOUT,        //낚珂
+	MSG_ERROR_VERIFY_FAILED, //훰聯呵겨
+	MSG_ERROR_UNKNOWN = 0Xff//灌列댄轎
+} tc_msg_value_t;
+
+typedef enum{
+	joy_cla_firstpacket,
+	joy_cla_resendpacket
+}tc_cla_type_t;
+
+
+typedef enum{
+	packet_init = 0,
+	packet_resend
+}tc_packet_type_t;
+
+typedef struct tc_package {
+	uint8_t oui_type;
+	uint8_t magic[3];
+	uint8_t cla;
+	uint8_t ins;
+	uint8_t p1;
+	uint8_t p2;
+	uint8_t lc;
+	uint8_t *data;
+	uint16_t crc;
+}tc_package_t;
+
+typedef struct{
+	uint8_t *value;
+	uint8_t length;
+}deviceid_t;
+
+typedef struct{
+	uint8_t *value;
+	uint8_t length;
+}deviceinfo_t;
+
+typedef struct{
+	uint8_t *value;
+	uint8_t length;
+}tc_vl_t;
+
+
+typedef struct{
+	uint8_t *value;
+	uint8_t length;
+}tc_random_t;
+
+typedef struct{
+	uint8_t *value;
+	uint8_t length;
+}tc_sig_t;
+
+typedef struct{
+	uint8_t *value;
+	uint8_t length;
+}tc_pubkey_t;
+
+#endif
+
+

+ 1587 - 0
joylink/config/joylink_thunder_slave_sdk.c

@@ -0,0 +1,1587 @@
+#include "joylink_thunder_slave_sdk.h"
+
+#include "joylink_utils.h"
+#include "joylink_auth_crc.h"
+#include "joylink3_auth_uECC.h"
+
+#include "joylink_probe.h"
+#include "joylink_aes.h"
+#include "joylink_log.h"
+#include "joylink_ret_code.h"
+
+static int joySlaveTxbufSetClaType(uint8_t *buf,tc_cla_type_t clatype);
+static int joySlaveAESDecrypt(uint8_t *pEncIn, int encLength, uint8_t *pPlainOut, int maxOutLen); 
+static int joySlaveAESEncrypt(uint8_t *pPlanin,int plainlength,uint8_t *pencout,int maxoutlen);
+static int joySlaveDevSigGen(char *sig_buf,tc_vl_t *cloud_random);
+static int joyCloudSigVerify(tc_vl_t *sig);
+static int joyThunderProbeReqSend(uint8_t *cmddata,uint8_t len,void *prob_req);
+static int joyDevRandomReSend(void);
+static int joy80211PacketResend(void);
+
+
+
+const char version_thunder[] = "JOYL_V1.0";
+
+tc_slave_ctl_t 				tc_slave_ctl;
+tc_slave_result_t			tc_slave_result;
+
+switch_channel_cb_t 		switch_channel = NULL;
+get_random_cb_t				get_random		= NULL;
+thunder_finish_cb_t			result_notify_cb = NULL;
+packet_80211_send_cb_t		packet_80211_send_cb = NULL;
+
+static int joySlaveRamReset(void)
+{
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	tc_slave_result_t *tthunder_result = &tc_slave_result;
+/*
+	if(tthunder_ctl->deviceid.value != NULL && tthunder_ctl->deviceid.length != 0){
+		joylink_util_free(tthunder_ctl->deviceid.value);
+	}
+
+	if(tthunder_ctl->deviceinfo.value != NULL && tthunder_ctl->deviceinfo.length != 0){
+		joylink_util_free(tthunder_ctl->deviceinfo.value);
+	}
+*/
+	memset(&tthunder_ctl->thunder_state, 0, sizeof(tc_slave_state_t));
+	tthunder_ctl->tcount = 0;
+	tthunder_ctl->randSendTimes = 0;
+	memset(tthunder_ctl->vendor_tx, 0, MAX_CUSTOM_VENDOR_LEN);
+	tthunder_ctl->vendor_tx_len = 0;
+	tthunder_ctl->current_channel = 1;
+
+    memset(tthunder_ctl->mac_master, 0, JOY_MAC_ADDRESS_LEN);
+    memset(tthunder_ctl->dev_random, 0, JOY_RANDOM_LEN);
+
+	//memset(tthunder_ctl,0,sizeof(tc_slave_ctl_t));
+
+	if(tthunder_result->ap_password.value != NULL && tthunder_result->ap_password.length != 0){
+		joylink_util_free(tthunder_result->ap_password.value);
+	}
+	if(tthunder_result->ap_ssid.value != NULL && tthunder_result->ap_ssid.length != 0){
+		joylink_util_free(tthunder_result->ap_ssid.value );
+	}
+	if(tthunder_result->cloud_feedid.value != NULL && tthunder_result->cloud_feedid.length != 0){
+		joylink_util_free(tthunder_result->cloud_feedid.value );
+	}
+	if(tthunder_result->cloud_ackey.value != NULL && tthunder_result->cloud_ackey.length != 0){
+		joylink_util_free(tthunder_result->cloud_ackey.value );
+	}
+	memset(tthunder_result,0,sizeof(tc_slave_result_t));
+	
+	return E_RET_OK;
+}
+
+static void joySlaveTimeReset(void)
+{
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	tthunder_ctl->tcount = 0;
+}
+
+
+/**
+ * brief: joylink thunderconfig state get.
+ * 
+ * @Param: N
+ *
+ * @Returns:N 
+ */
+tc_slave_state_t joySlaveStateGet(void)
+{
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	return tthunder_ctl->thunder_state;
+}
+
+/**
+ * brief: joylink thunderconfig state set.
+ * 
+ * @Param: tstate,the state to set.
+ *
+ * @Returns:N 
+ */
+static void joySlaveStateSet(tc_slave_state_t tstate)
+{
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	tthunder_ctl->thunder_state = tstate;
+	joySlaveTimeReset();
+}
+
+static int joySlaveCommCheck(tc_ins_t cmd,void *probe_req)
+{
+	int ret = E_RET_ERROR;
+
+	tc_slave_state_t tstate;
+	tstate = joySlaveStateGet();
+	if(cmd == INS_LOCK_CHANNEL){
+		if(tstate > sReqChannel){
+			log_error("cmd INS_LOCK_CHANNEL not right,now state is %d",tstate);
+			goto RET;
+		}
+	}else if(cmd == INS_AUTH_ALLOWED){
+		if(tstate != sDevInfoUp){
+			log_error("cmd INS_AUTH_ALLOWED not sDevInfoUp,now state is %d",tstate);
+			goto RET;
+		}
+	}else if(cmd == INS_CHALLENGE_CLOUD_ACK){
+		if(tstate != sDevChallengeUp){
+			log_error("cmd INS_CHALLENGE_CLOUD_ACK not sDevChallengeUp,now state is %d",tstate);
+			goto RET;
+		}
+	}else if(cmd == INS_AUTH_INFO_B){
+		if(tstate != sDevSigUp){
+			log_error("cmd INS_AUTH_INFO_B not sDevSigUp,now state is %d",tstate);
+			goto RET;
+		}
+	}else{
+		log_error("cmd not support");
+		goto RET;
+	}
+
+	ret = E_RET_OK;
+RET:	
+	return ret;
+}
+
+
+static uint8_t joyGenChannelReqData(uint8_t *txbuf)
+{
+	uint8_t *tbuf,lc,tlen;
+	tc_package_t *tc_packet;
+	uint16_t tcrc16;
+	
+	if(txbuf == NULL){
+		log_error("buff NULL");
+		return 0;
+	}
+
+	
+	tbuf = txbuf;
+	tc_packet = (tc_package_t *)tbuf;
+	tc_packet->oui_type = JOY_OUI_TYPE;
+	memcpy(tc_packet->magic,JOY_MEGIC_HEADER,strlen(JOY_MEGIC_HEADER));
+	tc_packet->cla 		= JOY_CLA_DECRYPT | JOY_CLA_UPLINK | JOY_CLA_FIRSTPACKET;
+	tc_packet->ins		= INS_CONFIG_REQ;
+	tc_packet->p1		= 0;
+	tc_packet->p2		= 0;
+	lc = joyTLVDataAdd(&(tc_packet->lc) + 1,TLV_TAG_THUNDERCONFIG_VERSION,strlen(version_thunder)+1,(uint8_t *)version_thunder);
+	tc_packet->lc		= lc;
+	
+	tcrc16 = CRC16(txbuf+1,tc_packet->lc + JOY_PACKET_HEADER_LEN);
+	tlen = JOY_PACKET_HEADER_LEN+tc_packet->lc + 1;
+	
+	memcpy(txbuf+tlen,&tcrc16,2);
+	tlen += 2;				//crc size
+
+	return tlen;
+}
+
+static uint8_t joyGenLockChlAckData(uint8_t *txbuf,tc_msg_value_t msg)
+{
+	uint8_t *tbuf,lc,tlen,offset_value = 0,*value;
+	tc_package_t *tc_packet;
+	uint16_t tcrc16;
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	
+	if(txbuf == NULL){
+		log_error("buff NULL");
+		return 0;
+	}
+	
+	tbuf = txbuf;
+	tc_packet = (tc_package_t *)tbuf;
+	tc_packet->oui_type = JOY_OUI_TYPE;
+	memcpy(tc_packet->magic,JOY_MEGIC_HEADER,strlen(JOY_MEGIC_HEADER));
+	tc_packet->cla 		= JOY_CLA_DECRYPT | JOY_CLA_UPLINK | JOY_CLA_FIRSTPACKET;
+	tc_packet->ins		= INS_LOCK_CHANNEL_ACK;
+	tc_packet->p1		= 0;
+	tc_packet->p2		= 0;
+
+	offset_value = 0;
+	value = &(tc_packet->lc) + 1;
+	
+	
+	if(msg != MSG_OK){
+		lc = joyTLVDataAdd(value+offset_value,TLV_TAG_MSG,sizeof(msg),(uint8_t *)&msg);
+		tc_packet->lc		= lc;
+	}else{
+		//uuid
+		lc = joyTLVDataAdd(value+offset_value,TLV_TAG_UUID,JOY_UUID_LEN,tthunder_ctl->uuid);
+		offset_value += lc;
+		tc_packet->lc += lc;
+		//device id
+		if((tthunder_ctl->deviceid.length > 0) && (tthunder_ctl->deviceid.value != NULL)){
+			lc = joyTLVDataAdd(value+offset_value,TLV_TAG_DEVICE_ID,\
+								tthunder_ctl->deviceid.length,tthunder_ctl->deviceid.value);
+			offset_value += lc;
+			tc_packet->lc += lc;
+		}
+		//device info
+		if((tthunder_ctl->deviceinfo.length > 0) && (tthunder_ctl->deviceinfo.value != NULL)){
+			lc = joyTLVDataAdd(value+offset_value,TLV_TAG_DEVICE_INFO,\
+								tthunder_ctl->deviceinfo.length,tthunder_ctl->deviceinfo.value );
+			offset_value += lc;
+			tc_packet->lc += lc;
+		}
+		//cid
+		//brand
+
+	}
+
+	tcrc16 = CRC16(txbuf+1,tc_packet->lc + JOY_PACKET_HEADER_LEN);
+	tlen = JOY_PACKET_HEADER_LEN+tc_packet->lc + 1;
+	
+	memcpy(txbuf+tlen,&tcrc16,2);
+	tlen += 2;				//crc size
+
+	return tlen;
+}
+
+
+static uint8_t joyGenDevRandomData(uint8_t *txbuf,tc_msg_value_t msg)
+{
+	uint8_t *tbuf,lc,tlen,offset_value = 0,*value;
+	tc_package_t *tc_packet;
+	uint16_t tcrc16;
+	int i = 0;
+	
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	
+	if(txbuf == NULL){
+		log_error("buff NULL");
+		return 0;
+	}
+	
+	tbuf = txbuf;
+	tc_packet = (tc_package_t *)tbuf;
+	tc_packet->oui_type = JOY_OUI_TYPE;
+	memcpy(tc_packet->magic,JOY_MEGIC_HEADER,strlen(JOY_MEGIC_HEADER));
+	tc_packet->cla 		= JOY_CLA_DECRYPT | JOY_CLA_UPLINK | JOY_CLA_FIRSTPACKET;
+	tc_packet->ins		= INS_CHALLENGE_CLOUD;
+	tc_packet->p1		= 0;
+	tc_packet->p2		= 0;
+
+	offset_value = 0;
+	value = &(tc_packet->lc) + 1;
+	
+	
+	if(msg != MSG_OK){
+		lc = joyTLVDataAdd(value+offset_value,TLV_TAG_MSG,sizeof(msg),(uint8_t *)&msg);
+		tc_packet->lc		= lc;
+	}else{
+		//uuid must param
+		lc = joyTLVDataAdd(value+offset_value,TLV_TAG_UUID,JOY_UUID_LEN,tthunder_ctl->uuid);
+		offset_value += lc;
+		tc_packet->lc += lc;
+
+		//mac must param
+		lc = joyTLVDataAdd(value+offset_value,TLV_TAG_MAC,JOY_MAC_ADDRESS_LEN,tthunder_ctl->mac_dev);
+		offset_value += lc;
+		tc_packet->lc += lc;
+
+		//device id optional param
+		if((tthunder_ctl->deviceid.length > 0) && (tthunder_ctl->deviceid.value != NULL)){
+			lc = joyTLVDataAdd(value+offset_value,TLV_TAG_DEVICE_ID,\
+								tthunder_ctl->deviceid.length,tthunder_ctl->deviceid.value);
+			offset_value += lc;
+			tc_packet->lc += lc;
+		}
+		//device info optional pram
+		if((tthunder_ctl->deviceinfo.length > 0) && (tthunder_ctl->deviceinfo.value != NULL)){
+			lc = joyTLVDataAdd(value+offset_value,TLV_TAG_DEVICE_INFO,\
+								tthunder_ctl->deviceinfo.length,tthunder_ctl->deviceinfo.value );
+			offset_value += lc;
+			tc_packet->lc += lc;
+		}
+
+		//random must param
+		if(get_random == NULL){
+			log_error("get random function NULL");
+			return 0;
+		}
+		for(i=0;i<JOY_RANDOM_LEN;i++){
+			tthunder_ctl->dev_random[i] = (uint8_t)(get_random());
+		}
+		lc = joyTLVDataAdd(value+offset_value,TLV_TAG_RANDOM,JOY_RANDOM_LEN,tthunder_ctl->dev_random);
+		offset_value += lc;
+		tc_packet->lc += lc;
+
+		//cid
+		//brand
+
+	}
+
+	tcrc16 = CRC16(txbuf+1,tc_packet->lc + JOY_PACKET_HEADER_LEN);
+	tlen = JOY_PACKET_HEADER_LEN+tc_packet->lc + 1;
+	
+	memcpy(txbuf+tlen,&tcrc16,2);
+	tlen += 2;				//crc size
+
+	return tlen;
+}
+
+
+static uint8_t joyGenDevSigData(uint8_t *txbuf,tc_msg_value_t msg,tc_vl_t *cloud_random)
+{
+	uint8_t *tbuf,lc,tlen,offset_value = 0,*value;
+	tc_package_t *tc_packet;
+	uint16_t tcrc16;
+	char sig_cloud_random[JOY_ECC_SIG_LEN];
+	
+	if(txbuf == NULL){
+		log_error("buff NULL");
+		return 0;
+	}
+	
+	tbuf = txbuf;
+	tc_packet = (tc_package_t *)tbuf;
+	tc_packet->oui_type = JOY_OUI_TYPE;
+	memcpy(tc_packet->magic,JOY_MEGIC_HEADER,strlen(JOY_MEGIC_HEADER));
+	tc_packet->cla 		= JOY_CLA_DECRYPT | JOY_CLA_UPLINK | JOY_CLA_FIRSTPACKET;
+	tc_packet->ins		= INS_CHALLENGE_DEVICE_ACK;
+	tc_packet->p1		= 0;
+	tc_packet->p2		= 0;
+
+	offset_value = 0;
+	value = &(tc_packet->lc) + 1;
+	
+
+	if((msg == MSG_OK) && (joySlaveDevSigGen(sig_cloud_random,cloud_random) == E_RET_ERROR)){
+		msg = MSG_ERROR_UNKNOWN;
+	}
+	
+	if(msg != MSG_OK){
+		lc = joyTLVDataAdd(value+offset_value,TLV_TAG_MSG,sizeof(msg),(uint8_t *)&msg);
+		tc_packet->lc		= lc;
+	}else{
+		//uuid must param
+		lc = joyTLVDataAdd(value+offset_value,TLV_TAG_SIGNATURE,JOY_ECC_SIG_LEN,(uint8_t *)sig_cloud_random);
+		offset_value += lc;
+		tc_packet->lc += lc;
+
+	}
+
+	tcrc16 = CRC16(txbuf+1,tc_packet->lc + JOY_PACKET_HEADER_LEN);
+	tlen = JOY_PACKET_HEADER_LEN+tc_packet->lc + 1;
+	
+	memcpy(txbuf+tlen,&tcrc16,2);
+	tlen += 2;				//crc size
+
+	return tlen;
+}
+
+
+static uint8_t joyGenAuthAckData(uint8_t *txbuf,tc_msg_value_t msg)
+{
+	uint8_t *tbuf,lc,tlen,offset_value = 0,*value;
+	tc_package_t *tc_packet;
+	uint16_t tcrc16;
+	
+	uint8_t encrypt_buf[256] = {0};
+	uint8_t lc_en;
+	
+	if(txbuf == NULL){
+		log_error("buff NULL");
+		return 0;
+	}
+	
+	tbuf = txbuf;
+	tc_packet = (tc_package_t *)tbuf;
+	tc_packet->oui_type = JOY_OUI_TYPE;
+	memcpy(tc_packet->magic,JOY_MEGIC_HEADER,strlen(JOY_MEGIC_HEADER));
+	tc_packet->cla 		= JOY_CLA_DECRYPT | JOY_CLA_UPLINK | JOY_CLA_FIRSTPACKET;
+	tc_packet->ins		= INS_CONNECT_AP_ACK;
+	tc_packet->p1		= 0;
+	tc_packet->p2		= 0;
+
+	offset_value = 0;
+	value = &(tc_packet->lc) + 1;
+
+	lc = joyTLVDataAdd(value+offset_value,TLV_TAG_MSG,sizeof(msg),(uint8_t *)&msg);
+	tc_packet->lc		= lc;
+
+	//decyptdata,
+	log_info("decrypt data:lc = 0x%02X",tc_packet->lc);
+	joylink_util_fmt_p("decrypt data:",value,tc_packet->lc);
+	
+	lc_en = joySlaveAESEncrypt(value,tc_packet->lc,encrypt_buf,sizeof(encrypt_buf));
+	if(lc_en == 0){
+		log_error("encrypt data error");
+	}
+	memcpy(value,encrypt_buf,lc_en);
+	tc_packet->lc = lc_en;
+		
+	log_info("encrypt data:lc = 0x%02X",tc_packet->lc);
+	joylink_util_fmt_p("decrypt data:",value,tc_packet->lc);
+		
+	tcrc16 = CRC16(txbuf+1,tc_packet->lc + JOY_PACKET_HEADER_LEN);
+	tlen = JOY_PACKET_HEADER_LEN+tc_packet->lc + 1;
+	
+	memcpy(txbuf+tlen,&tcrc16,2);
+	tlen += 2;				//crc size
+
+	return tlen;
+}
+
+
+
+static int joyLockChlCommH(uint8_t *tlvsdata,uint8_t lc,tc_packet_type_t ttype,void *probe_req)
+{
+	int ret = E_RET_OK;
+	uint8_t txlen,fixchl;
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	tc_msg_value_t msg_r = MSG_OK;
+	
+	struct ieee80211_mgmt *header_802 = NULL;
+	uint8_t tag,offset= 0;
+
+//	uint8_t len;
+
+	if(tlvsdata == NULL || probe_req == NULL){
+		log_error("BUFF NULL");
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+	
+	header_802 = (struct ieee80211_mgmt *)probe_req;
+	log_info("joyLockChlCommH In ,addr: %02x:%02x:%02x:%02x:%02x:%02x",MAC2STR(header_802->sa));
+
+	tag = *tlvsdata;
+	offset++;//len
+//	len = *(tlvsdata + offset);
+	offset++;//value
+	
+	if(tag == TLV_TAG_WIFI_CHANNEL){
+		fixchl = *(tlvsdata + offset);
+		if(fixchl > 14){
+			log_error("rev channel error");
+		}
+		
+		log_info("fix channel:%d,currunt channel:%d",fixchl,tthunder_ctl->current_channel);
+		if((fixchl != tthunder_ctl->current_channel) && (switch_channel != NULL)){
+			switch_channel(fixchl);
+			tthunder_ctl->current_channel = fixchl;
+			log_info("verify channel to %d",fixchl);
+		}
+	}
+
+    joySlaveStateSet(sDevInfoUp);
+
+#if 0
+	//must check param set
+	if((tthunder_ctl->deviceid.length == 0) || (tthunder_ctl->deviceid.value == NULL)){
+		log_error("deviceid NULL");
+		msg_r = MSG_ERROR_UNKNOWN;
+	}else{
+		msg_r = MSG_OK;
+	}
+#endif	
+	memset(tthunder_ctl->vendor_tx,0,sizeof(tthunder_ctl->vendor_tx));
+
+	txlen = joyGenLockChlAckData(tthunder_ctl->vendor_tx,msg_r);
+	if(txlen == 0){
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+
+	tthunder_ctl->vendor_tx_len = txlen;
+	log_info("joyGenLockChlAckData tx");
+	joylink_util_fmt_p("vendor data:",tthunder_ctl->vendor_tx,tthunder_ctl->vendor_tx_len);
+	
+	ret = joyThunderProbeReqSend(tthunder_ctl->vendor_tx,tthunder_ctl->vendor_tx_len,probe_req);
+	if(ret != E_RET_OK){
+		log_error("pobe request send error");
+		goto RET;
+	}
+
+	joySlaveStateSet(sDevInfoUp);
+	//joySlaveTxbufSetClaType(tthunder_ctl->vendor_tx,joy_cla_resendpacket);
+
+	//set mac address
+	memcpy(tthunder_ctl->mac_master,header_802->sa,JOY_MAC_ADDRESS_LEN);
+	//memcpy(tthunder_ctl->dev_info.mac,tthunder_ctl->dev_mac,JOY_MAC_ADDRESS_LEN);
+	
+	log_info("joyLockChlCommH Finsh,addr: %02x:%02x:%02x:%02x:%02x:%02x",MAC2STR(header_802->sa));
+RET:
+	
+	return ret;
+}
+
+static int joy80211PacketResend(void)
+{
+	int ret = E_RET_OK;
+	uint8_t txlens;
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	ret = joyThunderProbeReqSend(tthunder_ctl->vendor_tx,tthunder_ctl->vendor_tx_len,NULL);
+	if(ret != E_RET_OK){
+		log_error("pobe request send error");
+	}
+
+	return ret;
+}
+
+
+static int joyAuthAllowCommH(uint8_t *tlvsdata,uint8_t lc,tc_packet_type_t ttype,void *probe_req)
+{
+	int ret = E_RET_OK;
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	uint8_t toffset = 0,tag,length;
+	struct ieee80211_mgmt *header_802 = NULL;
+	uint8_t txlen;
+	
+	tc_msg_value_t rmsg = MSG_OK;
+	tc_slave_state_t state;
+	state = joySlaveStateGet();
+	if(state != sDevInfoUp){
+		log_error("now state is not right:%d",state);
+	}
+	
+	if(tlvsdata == NULL || probe_req == NULL){
+		log_error("NULL");
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+	
+	header_802 = (struct ieee80211_mgmt *)probe_req;
+	log_info("joyAuthAllowCommH In,addr: %02x:%02x:%02x:%02x:%02x:%02x",MAC2STR(header_802->sa));
+
+	while(toffset < lc){
+		tag = *(tlvsdata + toffset);
+		toffset++;
+		length	= *(tlvsdata + toffset);
+		toffset++;
+		switch(tag){
+			case TLV_TAG_MSG:
+				if(length != 1){
+					log_error("length of msg not right");
+					break;
+				}
+				rmsg = *(tlvsdata + toffset);
+				break;
+				
+			default:
+				log_error("not support tag get:0x%02X",tag);
+				break;
+		}
+		toffset += length;
+	}
+	if(rmsg != MSG_OK){
+		joySlaveStateSet(sReject);
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+	memset(tthunder_ctl->vendor_tx,0,sizeof(tthunder_ctl->vendor_tx));
+	txlen = joyGenDevRandomData(tthunder_ctl->vendor_tx,rmsg);
+	if(txlen == 0){
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+	
+	tthunder_ctl->vendor_tx_len = txlen;
+	log_info("joyGenDevRandomData tx");
+	joylink_util_fmt_p("vendor data:",tthunder_ctl->vendor_tx,tthunder_ctl->vendor_tx_len);
+		
+	ret = joyThunderProbeReqSend(tthunder_ctl->vendor_tx,tthunder_ctl->vendor_tx_len,probe_req);
+	if(ret != E_RET_OK){
+		log_error("pobe request send error");
+		goto RET;
+	}
+
+	joySlaveStateSet(sDevChallengeUp);
+	//joySlaveTxbufSetClaType(tthunder_ctl->vendor_tx,joy_cla_resendpacket);
+	log_info("joyAuthAllowCommH Finish");
+RET:
+	return ret;
+}
+
+
+static int joyDevRandomReSend(void)
+{
+	int ret = E_RET_OK;
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	uint8_t txlen;
+
+	memset(tthunder_ctl->vendor_tx,0,sizeof(tthunder_ctl->vendor_tx));
+	txlen = joyGenDevRandomData(tthunder_ctl->vendor_tx,MSG_OK);
+	if(txlen == 0){
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+	
+	tthunder_ctl->vendor_tx_len = txlen;
+	log_info("joyDevRandomReSend tx");
+	joylink_util_fmt_p("vendor data:",tthunder_ctl->vendor_tx,tthunder_ctl->vendor_tx_len);
+		
+	ret = joyThunderProbeReqSend(tthunder_ctl->vendor_tx,tthunder_ctl->vendor_tx_len,NULL);
+	if(ret != E_RET_OK){
+		log_error("pobe request send error");
+		goto RET;
+	}
+
+	joySlaveStateSet(sDevChallengeUp);
+	//joySlaveTxbufSetClaType(tthunder_ctl->vendor_tx,joy_cla_resendpacket);
+	log_info("joyAuthAllowCommH Finish");
+RET:
+	return ret;
+}
+
+
+
+
+static int joyCloudChanngeCommH(uint8_t *tlvsdata,uint8_t lc,tc_packet_type_t ttype,void *probe_req)
+{
+	int ret = E_RET_OK;
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	uint8_t toffset = 0,tag,length;
+	struct ieee80211_mgmt *header_802 = NULL;
+	uint8_t txlen;
+	tc_vl_t cloud_sig,cloud_random;
+	
+	tc_msg_value_t rmsg = MSG_OK;
+
+	tc_slave_state_t state;
+	state = joySlaveStateGet();
+	if(state != sDevChallengeUp){
+		log_error("now state is not right:%d",state);
+	}
+	
+	if(tlvsdata == NULL || probe_req == NULL){
+		log_error("NULL");
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+	
+	header_802 = (struct ieee80211_mgmt *)probe_req;
+	log_info("joyAuthAllowCommH In,addr: %02x:%02x:%02x:%02x:%02x:%02x",MAC2STR(header_802->sa));
+
+	memset(&cloud_sig,0,sizeof(cloud_sig));
+	memset(&cloud_random,0,sizeof(cloud_random));
+	
+	while(toffset < lc){
+		tag = *(tlvsdata + toffset);
+		toffset++;
+		length	= *(tlvsdata + toffset);
+		toffset++;
+		switch(tag){
+			case TLV_TAG_MSG:
+				if(length != 1){
+					log_error("length of msg not right");
+					break;
+				}
+				rmsg = *(tlvsdata + toffset);
+				if(rmsg != MSG_OK){
+					joySlaveStateSet(sReject);
+					ret = E_RET_ERROR;
+					goto RET;
+				}
+				break;
+			case TLV_TAG_SIGNATURE:
+				cloud_sig.length = length;
+				cloud_sig.value = joylink_util_malloc(length);
+
+				if(cloud_sig.value == NULL){
+					rmsg = MSG_ERROR_UNKNOWN;
+					log_error("malloc error");
+					goto RET;
+				}
+
+				memcpy(cloud_sig.value,tlvsdata + toffset,length);
+				
+				break;
+			case TLV_TAG_RANDOM:
+				cloud_random.length = length;
+				cloud_random.value = joylink_util_malloc(length);
+
+				if(cloud_random.value == NULL){
+					rmsg = MSG_ERROR_UNKNOWN;
+					log_error("malloc error");
+					goto RET;
+				}
+				memcpy(cloud_random.value,tlvsdata+toffset,length);
+				break;
+			default:
+				log_error("not support tag get:0x%02X",tag);
+				break;
+		}
+		toffset += length;
+	}
+
+	if(cloud_sig.length == 0 || cloud_random.length == 0){
+		rmsg = MSG_ERROR_UNKNOWN;
+	}
+	
+	//cloud signature verify
+	if(E_RET_ERROR== joyCloudSigVerify(&cloud_sig)){
+		rmsg = MSG_ERROR_VERIFY_FAILED;
+	}
+	memset(tthunder_ctl->vendor_tx,0,sizeof(tthunder_ctl->vendor_tx));
+	txlen = joyGenDevSigData(tthunder_ctl->vendor_tx,rmsg,&cloud_random);
+	if(txlen == 0){
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+	
+	tthunder_ctl->vendor_tx_len = txlen;
+	log_info("joyGenDevSigData tx");
+	joylink_util_fmt_p("vendor data:",tthunder_ctl->vendor_tx,tthunder_ctl->vendor_tx_len);
+		
+	ret = joyThunderProbeReqSend(tthunder_ctl->vendor_tx,tthunder_ctl->vendor_tx_len,probe_req);
+	if(ret != E_RET_OK){
+		log_error("pobe request send error");
+		goto RET;
+	}
+
+	joySlaveStateSet(sDevSigUp);
+	tthunder_ctl->randSendTimes = 0;
+	//joySlaveTxbufSetClaType(tthunder_ctl->vendor_tx,joy_cla_resendpacket);
+	log_info("joyAuthAllowCommH Finish");
+RET:
+	if(cloud_sig.value != NULL){
+		joylink_util_free(cloud_sig.value);
+	}
+	if(cloud_random.value != NULL){
+		joylink_util_free(cloud_random.value);
+	}
+	
+	return ret;
+}
+
+static int joyCloudAuthInfoCommH(uint8_t *tlvsdata,uint8_t lc,tc_packet_type_t ttype,void *probe_req)
+{
+	int ret = E_RET_OK;
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	tc_slave_result_t *thunderresult = &tc_slave_result;
+	uint8_t toffset = 0,tag,length;
+	struct ieee80211_mgmt *header_802 = NULL;
+	uint8_t txlen;
+	
+	tc_msg_value_t rmsg = MSG_OK;
+
+	tc_slave_state_t state;
+	state = joySlaveStateGet();
+	if(state != sDevSigUp){
+		log_error("now state is not right:%d",state);
+	}
+	
+	if(tlvsdata == NULL || probe_req == NULL){
+		log_error("NULL");
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+	
+	header_802 = (struct ieee80211_mgmt *)probe_req;
+	log_info("joyCloudAuthInfoCommH In,addr: %02x:%02x:%02x:%02x:%02x:%02x",MAC2STR(header_802->sa));
+	
+	while(toffset < lc){
+		tag = *(tlvsdata + toffset);
+		toffset++;
+		length	= *(tlvsdata + toffset);
+		toffset++;
+		switch(tag){			
+			case TLV_TAG_MSG:
+				if(length != 1){
+					log_error("length of msg not right");
+					break;
+				}
+				rmsg = *(tlvsdata + toffset);
+				if(rmsg != MSG_OK){
+					joySlaveStateSet(sReject);
+					ret = E_RET_ERROR;
+					goto RET;
+				}
+				break;
+			case TLV_TAG_SSID:
+				if(length > 32){
+					log_error("ssid length error");
+					rmsg = MSG_ERROR_UNKNOWN;
+					break;
+				}
+				thunderresult->ap_ssid.length = length;
+				thunderresult->ap_ssid.value = joylink_util_malloc(length+1);
+				if(thunderresult->ap_ssid.value == NULL){
+					log_error("malloc error");
+					rmsg = MSG_ERROR_UNKNOWN;
+					break;
+				}
+				memset(thunderresult->ap_ssid.value,0,length+1);
+				memcpy(thunderresult->ap_ssid.value,tlvsdata + toffset, length);
+				break;
+
+			case TLV_TAG_PASSWD:
+				if(length > 64){
+					log_error("pass word length error");
+					rmsg = MSG_ERROR_UNKNOWN;
+					break;
+				}
+				if(length == 0)	break;
+				thunderresult->ap_password.length = length;
+				thunderresult->ap_password.value = joylink_util_malloc(length + 1);
+				if(thunderresult->ap_password.value == NULL){
+					log_error("malloc error");
+					rmsg = MSG_ERROR_UNKNOWN;
+					break;
+				}
+				memset(thunderresult->ap_password.value,0,length);
+				memcpy(thunderresult->ap_password.value,tlvsdata + toffset,length);
+				break;
+			case TLV_TAG_FEEDID:
+				if(length == 0)	break;
+				thunderresult->cloud_feedid.length = length;
+				thunderresult->cloud_feedid.value = joylink_util_malloc(length + 1);
+				if(thunderresult->cloud_feedid.value == NULL){
+					log_error("malloc error");
+					rmsg = MSG_ERROR_UNKNOWN;
+					break;
+				}
+				memset(thunderresult->cloud_feedid.value,0,length);
+				memcpy(thunderresult->cloud_feedid.value,tlvsdata + toffset,length);
+				break;
+			case TLV_TAG_ACKEY:
+				if(length == 0)	break;
+				thunderresult->cloud_ackey.length = length;
+				thunderresult->cloud_ackey.value = joylink_util_malloc(length + 1);
+				if(thunderresult->cloud_ackey.value == NULL){
+					log_error("malloc error");
+					rmsg = MSG_ERROR_UNKNOWN;
+					break;
+				}
+				memset(thunderresult->cloud_ackey.value,0,length);
+				memcpy(thunderresult->cloud_ackey.value,tlvsdata + toffset,length);
+				break;
+			case TLV_TAG_CLOUD_SERVER:
+				if(length == 0)	break;
+				thunderresult->cloud_server.length = length;
+				thunderresult->cloud_server.value = joylink_util_malloc(length + 1);
+				if(thunderresult->cloud_server.value == NULL){
+					log_error("malloc error");
+					rmsg = MSG_ERROR_UNKNOWN;
+					break;
+				}
+
+				memset(thunderresult->cloud_server.value,0,length);
+				memcpy(thunderresult->cloud_server.value,tlvsdata + toffset,length);
+				//log_info("server: %s\r\n", thunderresult->cloud_server.value);
+				break;
+				
+			default:
+				log_error("not support tag get:0x%02X",tag);
+				break;
+		}
+		if(rmsg != MSG_OK)	break;
+		toffset += length;
+		
+	}
+	memset(tthunder_ctl->vendor_tx,0,sizeof(tthunder_ctl->vendor_tx));
+	txlen = joyGenAuthAckData(tthunder_ctl->vendor_tx,rmsg);
+	if(txlen == 0){
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+	
+	tthunder_ctl->vendor_tx_len = txlen;
+	log_info("joyGenAuthAckData tx");
+	joylink_util_fmt_p("vendor data:",tthunder_ctl->vendor_tx,tthunder_ctl->vendor_tx_len);
+		
+	ret = joyThunderProbeReqSend(tthunder_ctl->vendor_tx,tthunder_ctl->vendor_tx_len,probe_req);
+	if(ret != E_RET_OK){
+		log_error("pobe request send error");
+		goto RET;
+	}
+
+	joySlaveStateSet(sFinish);
+	//joySlaveTxbufSetClaType(tthunder_ctl->vendor_tx,joy_cla_resendpacket);
+	log_info("joyCloudAuthInfoCommH Finish");
+RET:
+
+	return ret;
+}
+
+
+static int joySlaveCommHandle(uint8_t *venderspecific,uint8_t len,void *probe_req)
+{
+	int ret = E_RET_OK;
+	uint8_t *vdata = venderspecific;
+	uint16_t crc16_src,crc16_ds;
+	tc_package_t *tcmmand;
+	tc_packet_type_t tpacket_type;
+
+	
+	uint8_t dec_buf[256] = {0},dec_len;
+//	struct ieee80211_mgmt *mgmt;
+//	mgmt = (struct ieee80211_mgmt *)probe_req;
+	
+	tcmmand = (tc_package_t *)vdata;
+	
+	if(memcmp(tcmmand->magic,JOY_MEGIC_HEADER,strlen(JOY_MEGIC_HEADER)) != 0){
+		ret = E_RET_ERROR;
+		log_error("magic error");
+		goto RET;
+	}
+	
+//	log_info("joy packet from address %02x:%02x:%02x:%02x:%02x:%02x len=%d\n",MAC2STR(mgmt->sa), len);
+		
+	crc16_src = *(uint16_t *)(vdata+len-2);
+tcmmand->cla &= 0xDF;//clear resend tag
+	crc16_ds  = CRC16((uint8_t *)&(tcmmand->magic),(unsigned int)(tcmmand->lc + JOY_PACKET_HEADER_LEN));//+1
+	if(crc16_src != crc16_ds){
+		log_error("crc error:calc=0x%04X,src=0x%04X\n",crc16_ds,crc16_src);
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+	
+	if((tcmmand->p1 != 0) || (tcmmand->p2 != 0)){
+		log_error("not support group packet now");
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+
+	ret = joySlaveCommCheck(tcmmand->ins,probe_req);
+	if(ret != E_RET_OK){
+		log_error("command is not right operated level");
+		goto RET;
+	}
+	
+	if(tcmmand->cla & 0x80){
+		//decrypt data
+		dec_len = joySlaveAESDecrypt(&(tcmmand->lc) + 1,tcmmand->lc,dec_buf,sizeof(dec_buf));
+		if((dec_len == 0) || (dec_len > tcmmand->lc)){
+			log_error("decrypt error:enlen=0x%02X,dec_len=0x%02X",tcmmand->lc,dec_len);
+			ret = E_RET_ERROR;
+			goto RET;
+		}
+		memcpy(&(tcmmand->lc) + 1,dec_buf,dec_len);
+
+		log_info("dec buffer->,len=%d",dec_len);
+		joylink_util_fmt_p("dec buffer->",&(tcmmand->lc) + 1,dec_len);
+
+		
+		tcmmand->lc = dec_len;
+	}
+
+	tpacket_type = ((tcmmand->cla & 0x20) == 0)?packet_init:packet_resend;
+
+	switch(tcmmand->ins){							//command handler
+		case INS_V1_BASE:
+			break;
+			
+		case INS_LOCK_CHANNEL:
+			joyLockChlCommH(&(tcmmand->lc) + 1,tcmmand->lc,tpacket_type,probe_req);
+			break;
+			
+		case INS_AUTH_ALLOWED:
+			joyAuthAllowCommH(&(tcmmand->lc) + 1,tcmmand->lc,tpacket_type,probe_req);
+			break;
+			
+		case INS_CHALLENGE_CLOUD_ACK:
+			joyCloudChanngeCommH(&(tcmmand->lc) + 1,tcmmand->lc,tpacket_type,probe_req);
+			break;
+			
+		case INS_AUTH_INFO_B:
+			joyCloudAuthInfoCommH(&(tcmmand->lc) + 1,tcmmand->lc,tpacket_type,probe_req);
+			break;
+			
+		default:
+			log_error("command not support now");
+			break;
+	};
+
+RET:
+	return ret;
+}
+
+int joylink_send_probe_request(void *vendor_ie, int vendor_len)
+{
+    uint8_t *req_frame = NULL;
+    int req_len = 0;
+
+    if(vendor_len > MAX_CUSTOM_VENDOR_LEN || vendor_ie == NULL)
+    {
+        log_error("Input vendor ie invalid!\n");
+        return -1;
+    }
+
+    req_frame = joylink_gen_probe_req(vendor_ie, vendor_len, &req_len);
+    if(req_frame == NULL)
+    {
+        log_error("Genarate probe response frame error\n");
+        return -1;
+    }
+
+    packet_80211_send_cb(req_frame, req_len);
+    //mtk_custom_send_cmd(g_nl_sock, g_nl_family_id, getpid(), GL_CUSTOM_COMMAND_SEND,
+    //    GL_CUSTOM_ATTR_MSG, req_frame, req_len);
+
+    joylink_util_free(req_frame);
+    return 0;
+}
+
+//probe response data cmddata:OUT-Type+payload
+static int joyThunderProbeReqSend(uint8_t *cmddata,uint8_t len,void *prob_req)
+{
+	int ret = E_RET_OK;
+	int vendor_len = 0;
+	uint8_t vendor_ie[MAX_CUSTOM_VENDOR_LEN];
+	vendor_len = joylink_gen_vendor_specific(vendor_ie,cmddata,len);
+
+	ret = joylink_send_probe_request(vendor_ie, vendor_len);
+
+	if(ret < 0){
+		log_error("send probe response error");
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+
+	//usleep(50*1000);
+	//mico_rtos_thread_msleep(50);
+	//system("wpa_cli -iwlan0 -p/tmp/wpa_supplicant scan");
+
+	ret = E_RET_OK;
+RET:
+	return ret;
+}
+
+static int joySlaveChanelReq(void)
+{
+	int ret = E_RET_OK;
+	tc_slave_state_t tstate;
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	uint8_t txlen;
+//	struct ieee80211_mgmt header_802;
+	
+	//log_info("joySlaveChanelReq In");
+	//check state
+	tstate = joySlaveStateGet();
+	if(tstate != sReqChannel){
+		log_error("current state = 0x%02x is not thunder sReqChannel state",tstate);
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+
+	//send probe response to fix channel
+	memset(tthunder_ctl->vendor_tx,0,sizeof(tthunder_ctl->vendor_tx));
+
+	txlen = joyGenChannelReqData(tthunder_ctl->vendor_tx);
+	if(txlen == 0){
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+
+	tthunder_ctl->vendor_tx_len = txlen;
+
+//	memcpy(header_802.sa,tthunder_ctl->dev_mac,JOY_MAC_ADDRESS_LEN);
+	
+	ret = joyThunderProbeReqSend(tthunder_ctl->vendor_tx,tthunder_ctl->vendor_tx_len,NULL);
+	if(ret != E_RET_OK){
+		log_error("pobe request send error");
+		goto RET;
+	}
+	
+//	joyTxbufSetClaType(tthunder_ctl->vendor_tx,joy_cla_resendpacket);
+	//log_info("joySlaveChanelReq Finish");
+
+RET:
+	return ret;
+}
+
+/**
+ * brief:  aes decrypt 
+ * @Param: pPlanin,
+ * @Param: plainlength,length	
+ * @Param: pencout,
+ * @Param: maxoutlen,
+ * @Returns:0-failed,<0-length
+*/ 
+static int joySlaveAESDecrypt(uint8_t *pEncIn, int encLength, uint8_t *pPlainOut, int maxOutLen)
+{
+
+	uint8_t sharekey[32],iv[16];
+	
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	uint8_t dc_pubkey[64] = {0};
+	jl3_uECC_decompress(tthunder_ctl->pubkey_c, dc_pubkey, uECC_secp256r1());
+		
+	if(0 == jl3_uECC_shared_secret(dc_pubkey,tthunder_ctl->prikey_d,sharekey,uECC_secp256r1())){
+		log_error("gen share key error");
+		return 0;
+	}
+
+	memcpy(iv,sharekey+16,sizeof(iv));
+
+	return device_aes_decrypt(sharekey,16,iv,pEncIn,encLength,pPlainOut,maxOutLen);
+	//return JLdevice_aes_decrypt(sharekey,16,iv,pEncIn,encLength,pPlainOut,maxOutLen);
+	
+}
+
+
+/**
+ * brief:  aes encrypt 
+ * @Param: pPlanin,
+ * @Param: plainlength,length	
+ * @Param: pencout,
+ * @Param: maxoutlen,
+ * @Returns:0-failed,<0-length
+*/ 
+static int joySlaveAESEncrypt(uint8_t *pPlanin,int plainlength,uint8_t *pencout,int maxoutlen)
+{
+	uint8_t sharekey[32],iv[16];
+		
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	
+    uint8_t dc_pubkey[64] = {0};
+    jl3_uECC_decompress(tthunder_ctl->pubkey_c, dc_pubkey, uECC_secp256r1());
+	
+	if(0 == jl3_uECC_shared_secret(jl3_uECC_decompress,tthunder_ctl->prikey_d,sharekey,uECC_secp256r1())){
+		log_error("gen share key error");
+		return 0;
+	}
+
+	joylink_util_fmt_p("sharekey->",sharekey,sizeof(sharekey));
+	
+	return device_aes_decrypt(sharekey,16,iv,pPlanin,plainlength,pencout,maxoutlen);
+	//return JLdevice_aes_encrypt(sharekey,16,iv,pPlanin,plainlength,pencout,maxoutlen);
+}
+
+
+/**
+ * brief:  generate signature used prikey_d to cloud random
+ * @Param: sig_buf,buffer used to store device signature
+ * @Param: cloud_random,cloud random in	
+ * @Returns:E_RET_OK,E_RET_ERROR;
+*/ 
+static int joySlaveDevSigGen(char *sig_buf,tc_vl_t *cloud_random)
+{
+	int ret = E_RET_OK;
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	int sign_res;
+
+	if(sig_buf == NULL || cloud_random == NULL){
+		log_error("param NULL");
+		return E_RET_ERROR;
+	}
+
+	if(cloud_random->value == NULL || cloud_random->length == 0){
+		log_error("random NULL");
+		return E_RET_ERROR;
+	}
+char rand_buf[65] = {0};
+	int i = 0;
+
+    joylink_util_byte2hexstr(cloud_random->value, cloud_random->length, rand_buf, 64);
+    for(i = 0; i < 64; i++)
+    {
+        if(rand_buf[i] == 'a') rand_buf[i] = 'A';
+        if(rand_buf[i] == 'b') rand_buf[i] = 'B';
+        if(rand_buf[i] == 'c') rand_buf[i] = 'C';
+        if(rand_buf[i] == 'd') rand_buf[i] = 'D';
+        if(rand_buf[i] == 'e') rand_buf[i] = 'E';
+        if(rand_buf[i] == 'f') rand_buf[i] = 'F';
+    }
+    printf("cloud random: %s\r\n", rand_buf);
+
+	sign_res = jl3_uECC_sign((const uint8_t *)(tthunder_ctl->prikey_d),(const uint8_t *)rand_buf,\
+	                            strlen(rand_buf),(uint8_t *)sig_buf,uECC_secp256r1());
+	if(sign_res == 1){
+		log_info("gen devsigature to cloud random success");
+		joylink_util_fmt_p("cloud random:",cloud_random->value,cloud_random->length);
+		joylink_util_fmt_p("prikey_d:",tthunder_ctl->prikey_d,JOY_ECC_PRIKEY_LEN);
+		joylink_util_fmt_p("signature:",(uint8_t *)sig_buf,JOY_ECC_SIG_LEN);
+		ret = E_RET_OK;
+	}else{
+		log_error("gen devsigature to cloud random error");
+		ret = E_RET_ERROR;
+	}
+	return ret;
+	
+}
+
+/**
+ * brief:  generate signature used prikey_d to cloud random
+ * @Param: sig_buf,buffer used to store device signature
+ * @Param: cloud_random,cloud random in	
+ * @Returns:E_RET_OK,E_RET_ERROR;
+*/ 
+static int joyCloudSigVerify(tc_vl_t *sig)
+{
+	int ret = E_RET_OK;
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	int verify_res;
+	char rand_buf[65] = {0};
+	int i;
+
+	if(sig->value == NULL || sig == NULL){
+		log_error("pram NULL");
+		return E_RET_ERROR;
+	}
+	if(sig->length!= JOY_ECC_SIG_LEN){
+		log_error("signature lengthe error:0x%02x",sig->length);
+		return E_RET_ERROR;
+	}
+
+	log_info("verify cloud signature:");
+	joylink_util_fmt_p("dev random:",tthunder_ctl->dev_random,JOY_RANDOM_LEN);
+	joylink_util_fmt_p("cloud sig:",sig->value,sig->length);
+
+joylink_util_byte2hexstr(tthunder_ctl->dev_random, JOY_RANDOM_LEN, rand_buf, 64);
+
+    for(i = 0; i < 64; i++)
+    {
+        if(rand_buf[i] == 'a') rand_buf[i] = 'A';
+        if(rand_buf[i] == 'b') rand_buf[i] = 'B';
+        if(rand_buf[i] == 'c') rand_buf[i] = 'C';
+        if(rand_buf[i] == 'd') rand_buf[i] = 'D';
+        if(rand_buf[i] == 'e') rand_buf[i] = 'E';
+        if(rand_buf[i] == 'f') rand_buf[i] = 'F';
+    }
+    log_info("dev_random: %s, len: %d\r\n", rand_buf, (int)strlen(rand_buf));
+
+    uint8_t dc_pubkey[64] = {0};
+    jl3_uECC_decompress(tthunder_ctl->pubkey_c, dc_pubkey, uECC_secp256r1());
+
+    joylink_util_fmt_p("pubkey:", tthunder_ctl->pubkey_c, 64);
+    joylink_util_fmt_p("pubkey_d:",dc_pubkey, 64);
+
+	verify_res = jl3_uECC_verify(dc_pubkey, rand_buf,\
+	                                strlen(rand_buf),sig->value,uECC_secp256r1());
+	if(verify_res == 1){
+		log_info("cloud sig verify success");
+		ret = E_RET_OK;
+	}else{
+		log_info("cloud sig verify failed");
+		ret =  E_RET_ERROR;
+	}
+	ret = E_RET_OK; /*!!!*/
+	return ret;
+}
+
+
+static int joySlaveTxbufSetClaType(uint8_t *buf,tc_cla_type_t clatype)
+{
+	int ret = E_RET_OK;
+	if(buf == NULL){
+		log_error("buf NULL");
+		ret = E_RET_ERROR;
+		goto RET;
+	}
+	
+	tc_package_t *tc_packet;
+	tc_packet = (tc_package_t *)buf;
+
+	if(clatype == joy_cla_firstpacket){
+		tc_packet->cla = tc_packet->cla & 0xDF;
+	}else{
+		tc_packet->cla |= JOY_CLA_RESENDPACKET;
+	}
+
+	
+RET:
+	return ret;
+}
+
+
+static int joyThunderSlaveFinish(tc_msg_value_t errorcode)
+{
+	tc_slave_result_t	*tthunderresult = &tc_slave_result;
+	if(errorcode == MSG_ERROR_TIMEOUT){
+		log_info("TIMEOUT ,restart now");
+		joyThunderSlaveStart();
+		return E_RET_ERROR;
+	}
+	
+	if(result_notify_cb == NULL){
+		log_error("result_notify_cb NULL");
+	}
+	tthunderresult->errorcode = errorcode;
+	result_notify_cb(tthunderresult);
+	
+	joySlaveRamReset();
+	joySlaveStateSet(sInit);
+	return E_RET_OK;
+}
+
+
+/**
+ * brief:  thunder config slave init function,
+ * @Param: tc_slave_func_param_t
+ 			typedef struct{
+					uint8_t 		uuid[JOY_UUID_LEN];				//UUID,MUST Param
+					uint8_t			prikey_d[JOY_ECC_PRIKEY_LEN];	//prikey_d,MUST Param
+					uint8_t			pubkey_c[JOY_ECC_PUBKEY_LEN];	//pubkey_c,MUST Param
+	
+					uint8_t			mac_dev[JOY_MAC_ADDRESS_LEN];	//device mac address,MUSG param
+					deviceid_t 		deviceid;						//device id,MUST Param,value--value address,length--value length
+					deviceinfo_t	deviceinfo;						//device id,opentional param,if no set len = 0 or value = NULL
+					void 			*switch_channel(unsigned char);	//swithc channel call back function
+					int  			*get_random(void);					//get random call back function
+					int				*result_notify_cb(tc_slave_result_t *);	//result notify call back function
+					int 			*packet_80211_send_cb(unsigned char *buf,int buflen);//802.11 layer packet send call back function
+			}tc_slave_func_param_t;
+			
+ * @Returns:E_RET_OK,E_RET_ERROR;
+*/ 
+extern uint8_t g_own_mac[ETH_ALEN];
+
+int joyThunderSlaveInit(tc_slave_func_param_t *para)
+{
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+	
+	log_info("thunder slave init,VERSION:%s",version_thunder);
+
+	joySlaveRamReset();
+
+	if(para->switch_channel == NULL){
+		log_error("switch_channel NULL");
+	}
+
+	switch_channel = para->switch_channel;
+
+	if(para->get_random == NULL){
+		log_error("get_random NULL");
+	}
+	get_random = para->get_random;
+	
+	//jl3_uECC_set_rng((uECC_RNG_Function)para->get_random);
+
+	if(para->result_notify_cb == NULL){
+		log_error("result_notify_cb NULL");
+	}
+	result_notify_cb = para->result_notify_cb;
+
+	if(para->packet_80211_send_cb == NULL){
+		log_error("packet_80211_send_cb NULL");
+	}
+	packet_80211_send_cb = para->packet_80211_send_cb;
+	
+	//uuid
+	memcpy(tthunder_ctl->uuid,para->uuid,JOY_UUID_LEN);
+	joylink_util_fmt_p("set UUID:",tthunder_ctl->uuid,JOY_UUID_LEN);
+
+	//pubkey_c
+	memcpy(tthunder_ctl->pubkey_c,para->pubkey_c,JOY_ECC_PUBKEY_LEN);
+	joylink_util_fmt_p("set pubkey_c:",tthunder_ctl->pubkey_c,JOY_ECC_PUBKEY_LEN);
+
+	//prikey_d
+	memcpy(tthunder_ctl->prikey_d,para->prikey_d,JOY_ECC_PRIKEY_LEN);
+	joylink_util_fmt_p("set prikey_d:",tthunder_ctl->prikey_d,JOY_ECC_PRIKEY_LEN);
+
+	//mac adress
+	memcpy(tthunder_ctl->mac_dev,para->mac_dev,JOY_MAC_ADDRESS_LEN);
+	memcpy(g_own_mac,para->mac_dev,JOY_MAC_ADDRESS_LEN);
+	joylink_util_fmt_p("set MAC:",tthunder_ctl->mac_dev,JOY_MAC_ADDRESS_LEN);
+	
+	if((para->deviceid.value != NULL) && (para->deviceid.length > 0)){
+	    if(tthunder_ctl->deviceid.value != NULL){
+	        joylink_util_free(tthunder_ctl->deviceid.value);
+	    }
+	    tthunder_ctl->deviceid.value = joylink_util_malloc(para->deviceid.length);
+		tthunder_ctl->deviceid.length = para->deviceid.length;
+		memcpy(tthunder_ctl->deviceid.value ,para->deviceid.value,tthunder_ctl->deviceid.length);
+		//log_info("set device id:len=%d",tthunder_ctl->deviceid.length);
+		//joylink_util_fmt_p("device id:",tthunder_ctl->deviceid.value,tthunder_ctl->deviceid.length);
+	}else{
+		//device id is the must set param
+		log_error("device id NULL");
+	}
+
+	if((para->deviceinfo.value != NULL) && (para->deviceinfo.length > 0)){
+		tthunder_ctl->deviceinfo.length = para->deviceinfo.length;
+		memcpy(tthunder_ctl->deviceinfo.value,para->deviceinfo.value,tthunder_ctl->deviceinfo.length);
+		log_info("set device info:len=%d",tthunder_ctl->deviceinfo.length);
+		joylink_util_fmt_p("device info:",tthunder_ctl->deviceinfo.value,tthunder_ctl->deviceinfo.length);
+	}
+	return E_RET_OK;
+}
+
+/**
+ * brief:  thunderconfig slave start function
+ * @Param: NULL
+ * @Returns:E_RET_OK,E_RET_ERROR;
+*/ 
+int joyThunderSlaveStart(void)
+{
+	joySlaveRamReset();
+	joySlaveStateSet(sReqChannel);
+	joySlaveChanelReq();
+	return E_RET_OK;
+}
+
+/**
+ * brief:  thunderconfig slave stop function
+ * @Param: NULL
+ * @Returns:E_RET_OK,E_RET_ERROR;
+*/ 
+int joyThunderSlaveStop(void)
+{
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+
+	joySlaveRamReset();
+
+	if(tthunder_ctl->deviceid.value != NULL && tthunder_ctl->deviceid.length != 0){
+		joylink_util_free(tthunder_ctl->deviceid.value);
+	}
+
+	if(tthunder_ctl->deviceinfo.value != NULL && tthunder_ctl->deviceinfo.length != 0){
+		joylink_util_free(tthunder_ctl->deviceinfo.value);
+	}
+
+	memset(tthunder_ctl,0,sizeof(tc_slave_ctl_t));
+	
+	return E_RET_OK;
+}
+/**
+ * brief:  802.11 packet handler function,the device capture the 802.11 layer packet,
+ 		transfer it to this function to handle it.
+ * @Param: probe_req,packet buffer address
+ * @Param: req_len,packet len
+ * @Returns:NULL
+*/ 
+void joyThunderSlaveProbeH(void *probe_req, int req_len)
+{
+	struct ieee80211_mgmt *mgmt;
+	const uint8_t *ie;
+	size_t ie_len;
+	struct ieee802_11_elems elems;
+	uint8_t content[MAX_CUSTOM_VENDOR_LEN] = {0};
+	static uint16_t seq = 0xFFFF;
+	mgmt = (struct ieee80211_mgmt *)probe_req;
+		
+	if((mgmt->frame_control & IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_PROBE_RESP))  != IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_PROBE_RESP) )
+	{
+		return;
+	}
+	ie = mgmt->u.probe_resp.variable;
+
+	if (req_len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+		return;
+
+	ie_len = req_len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+
+//	if(memcmp(mgmt->sa,addr,6) == 0){
+//		log_info("get request packet:seq num = 0x%04X",mgmt->seq_ctrl);
+//	}
+//	log_info("[Demo]Got ProbeReq from addr %02x:%02x:%02x:%02x:%02x:%02x len=%d\n",MAC2STR(mgmt->sa), req_len);
+
+	/* 1 parse probe request ie fields */
+	if (joylink_ieee802_11_parse_elems(ie, ie_len, &elems) != 0) {
+		log_error("Could not parse ProbeReq from \n");
+		return;
+	}
+
+	/* 2 Decide if it is wanted probe request frame from elems.vendor_custom */
+	/* elems.vendor_custom is alibaba vendor now */
+	memset(content, 0, MAX_CUSTOM_VENDOR_LEN);
+	if(seq == mgmt->seq_ctrl){
+		// log_error("seq number same");
+		return ;
+	}
+
+	seq = mgmt->seq_ctrl;
+	
+	if(elems.vendor_custom != NULL && elems.vendor_custom_len > 3)
+	{
+		memcpy(content, elems.vendor_custom + 3, elems.vendor_custom_len - 3);
+		joySlaveCommHandle(content,elems.vendor_custom_len - 3,probe_req);
+	}else{
+		if(elems.vendor_custom == NULL){
+			log_error("vendor_custom NULL");
+		}
+		log_error("vendor_custom_len=%d",elems.vendor_custom_len);
+	}
+}
+
+/**
+ * brief:  cycle call function ,the function is expected call every 50ms
+ * @Param: NULL
+ * @Param: NULL
+ * @Returns:NULL
+*/ 
+int joyThunderSlave50mCycle(void)
+{
+	tc_slave_state_t tstate;
+	tc_slave_ctl_t *tthunder_ctl = &tc_slave_ctl;
+
+	tstate = joySlaveStateGet();
+	//log_info("state: %d\n", tstate);
+	switch(tstate){
+		case sInit:					//init
+			break;	
+		case sReqChannel:				//requeset channel of thunderconfig master
+			tthunder_ctl->tcount++;
+			if(tthunder_ctl->tcount == JOY_REQCHANNEL_STAY_COUNT){
+				if(tthunder_ctl->current_channel >= 13) 
+					tthunder_ctl->current_channel = 1;
+				else 
+					tthunder_ctl->current_channel++;
+				
+				//tthunder_ctl->current_channel = 13;
+				if(switch_channel != NULL){
+					log_info("-->switch channel to:%d",tthunder_ctl->current_channel);
+					switch_channel(tthunder_ctl->current_channel);
+					joySlaveTimeReset();
+				}
+			}
+			
+			//send channel requeset packet every 3*50ms
+			if(tthunder_ctl->tcount % 3 == 0){
+				joySlaveChanelReq();
+			}
+			
+			break;
+		case sDevInfoUp: 			//devinfo transfer		//user confirm
+			tthunder_ctl->tcount++;
+			if(((tthunder_ctl->tcount) % 4) == 0){
+				joy80211PacketResend();
+			}
+			
+			if(tthunder_ctl->tcount > JOY_DEVINFO_UP_TIMEOUT){
+				joyThunderSlaveFinish(MSG_ERROR_TIMEOUT);
+			}
+
+			break;
+		case sDevChallengeUp:		//device challenge up
+		
+			tthunder_ctl->tcount++;
+			if(tthunder_ctl->tcount > JOY_DEVRAND_UP_TIMEOUT){
+				
+				if(tthunder_ctl->randSendTimes > JOY_THUNDER_RANDOM_SEND_TIME){
+					joyThunderSlaveFinish(MSG_ERROR_TIMEOUT);
+					tthunder_ctl->randSendTimes++;
+				}else{
+					tthunder_ctl->randSendTimes++;
+					joyDevRandomReSend();
+				}
+			}
+			break;
+		case sDevSigUp:				//device signature up
+			tthunder_ctl->tcount++;
+			if(tthunder_ctl->tcount > JOY_DEVSIG_UP_TIMEOUT){
+				
+				if(tthunder_ctl->randSendTimes > JOY_THUNDER_RANDOM_SEND_TIME){
+					joyThunderSlaveFinish(MSG_ERROR_TIMEOUT);
+					tthunder_ctl->randSendTimes++;
+				}else{
+					tthunder_ctl->randSendTimes++;
+					joyDevRandomReSend();
+				}
+			}
+			break;
+		case sFinish:
+			tthunder_ctl->tcount++;
+			if(tthunder_ctl->tcount > JOY_THUNDER_TIMEOUT_FINISH){
+				joyThunderSlaveFinish(MSG_OK);
+				return 0;
+			}
+			break;
+		case sReject:
+			tthunder_ctl->tcount++;
+			if(tthunder_ctl->tcount > JOY_THUNDER_TIMEOUT_REJECT){
+				joyThunderSlaveFinish(MSG_ERROR_REQ_DENIED);
+				return 0;
+			}
+			break;
+		default:
+			break;
+	}
+
+	return 1;
+}
+
+

+ 140 - 0
joylink/config/joylink_thunder_slave_sdk.h

@@ -0,0 +1,140 @@
+#ifndef _JOYLINK_THUNDER_SLAVE_SDK_H_
+#define _JOYLINK_THUNDER_SLAVE_SDK_H_
+//#include "joylink_syshdr.h"
+#include "joylink_thunder.h"
+
+#define JOY_REQCHANNEL_STAY_COUNT       5
+#define JOY_DEVINFO_UP_TIMEOUT          (20*20)      //2s
+#define JOY_DEVSIG_UP_TIMEOUT           (2*20)      //2s
+#define JOY_DEVRAND_UP_TIMEOUT          JOY_DEVSIG_UP_TIMEOUT
+#define JOY_THUNDER_TIMEOUT_FINISH      10*10
+#define JOY_THUNDER_TIMEOUT_REJECT      10*10
+
+
+#define JOY_UUID_LEN					6
+#define JOY_RANDOM_LEN					0x20
+
+#define JOY_THUNDER_RANDOM_SEND_TIME	2
+
+#define JOY_ECC_PRIKEY_LEN				0x20
+#define JOY_ECC_PUBKEY_LEN				0x40
+#define JOY_ECC_SIG_LEN					0x40
+
+typedef enum{
+	sInit,					//init
+	sReqChannel,			//requeset channel of thunderconfig master
+	sDevInfoUp,				//devinfo transfer
+	sDevChallengeUp,		//device challenge up
+	sDevSigUp,				//device signature up
+	sFinish,
+	sReject
+}tc_slave_state_t;
+
+typedef struct{
+	tc_msg_value_t errorcode;
+	tc_vl_t		ap_ssid;
+	tc_vl_t		ap_password;
+	tc_vl_t		cloud_feedid;
+	tc_vl_t		cloud_ackey;
+	tc_vl_t		cloud_server;
+}tc_slave_result_t;
+
+#define MAX_PROBERESP_LEN 1024
+#define MAX_CUSTOM_VENDOR_LEN 256
+
+typedef void (*switch_channel_cb_t)(unsigned char ch);
+typedef int (*get_random_cb_t)(void);
+typedef int (*thunder_finish_cb_t)(tc_slave_result_t *result);
+typedef int (*packet_80211_send_cb_t)(unsigned char *buf,int buflen);
+
+typedef struct 
+{
+	tc_slave_state_t thunder_state;
+	uint8_t 		tcount;
+	uint8_t			randSendTimes;
+	uint8_t 		vendor_tx[MAX_CUSTOM_VENDOR_LEN];
+	uint8_t 		vendor_tx_len;
+	uint8_t 		current_channel;
+
+	uint8_t			uuid[JOY_UUID_LEN];
+	uint8_t			prikey_d[JOY_ECC_PRIKEY_LEN];			
+	uint8_t			pubkey_c[JOY_ECC_PUBKEY_LEN];
+	
+	uint8_t			mac_master[JOY_MAC_ADDRESS_LEN];
+	uint8_t			mac_dev[JOY_MAC_ADDRESS_LEN];
+	uint8_t			dev_random[JOY_RANDOM_LEN];
+
+	deviceid_t 		deviceid;
+	deviceinfo_t 	deviceinfo;
+} tc_slave_ctl_t;
+
+typedef struct{
+	uint8_t 		uuid[JOY_UUID_LEN];				//UUID,MUST Param
+	uint8_t			prikey_d[JOY_ECC_PRIKEY_LEN];	//prikey_d,MUST Param
+	uint8_t			pubkey_c[JOY_ECC_PUBKEY_LEN];	//pubkey_c,MUST Param
+	
+	uint8_t			mac_dev[JOY_MAC_ADDRESS_LEN];	//device mac address,MUSG param
+	deviceid_t 		deviceid;						//device id,MUST Param,value--value address,length--value length
+	deviceinfo_t	deviceinfo;						//device id,opentional param,if no set len = 0 or value = NULL
+
+	switch_channel_cb_t	switch_channel;				//swithc channel call back function				
+	get_random_cb_t	get_random;						//get random call back function
+	thunder_finish_cb_t	result_notify_cb;			//result notify call back function
+	packet_80211_send_cb_t	packet_80211_send_cb;	//802.11 layer packet send call back function
+}tc_slave_func_param_t;
+
+/**
+ * brief:  thunder config slave init function,
+ * @Param: tc_slave_func_param_t
+ 			typedef struct{
+					uint8_t 		uuid[JOY_UUID_LEN];				//UUID,MUST Param
+					uint8_t			prikey_d[JOY_ECC_PRIKEY_LEN];	//prikey_d,MUST Param
+					uint8_t			pubkey_c[JOY_ECC_PUBKEY_LEN];	//pubkey_c,MUST Param
+	
+					uint8_t			mac_dev[JOY_MAC_ADDRESS_LEN];	//device mac address,MUSG param
+					deviceid_t 		deviceid;						//device id,MUST Param,value--value address,length--value length
+					deviceinfo_t	deviceinfo;						//device id,opentional param,if no set len = 0 or value = NULL
+					void 			*switch_channel(unsigned char);	//swithc channel call back function
+					int  			*get_random(void);					//get random call back function
+					int				*result_notify_cb(tc_slave_result_t *);	//result notify call back function
+					int 			*packet_80211_send_cb(unsigned char *buf,int buflen);//802.11 layer packet send call back function
+			}tc_slave_func_param_t;
+ * @Returns:RET_OK,RET_ERROR;
+*/ 
+int joyThunderSlaveInit(tc_slave_func_param_t *para);
+
+/**
+ * brief:  thunderconfig slave start function
+ * @Param: NULL
+ * @Returns:RET_OK,RET_ERROR;
+*/ 
+int joyThunderSlaveStart(void);
+
+/**
+ * brief:  thunderconfig slave stop function
+ * @Param: NULL
+ * @Returns:RET_OK,RET_ERROR;
+*/ 
+int joyThunderSlaveStop(void);
+
+/**
+ * brief:  802.11 packet handler function,the device capture the 802.11 layer packet,
+ 		transfer it to this function to handle it.
+ * @Param: probe_req,packet buffer address
+ * @Param: req_len,packet len
+ * @Returns:NULL
+*/ 
+void joyThunderSlaveProbeH(void *probe_req, int req_len);
+
+/**
+ * brief:  cycle call function ,the function is expected call every 50ms
+ * @Param: NULL
+ * @Param: NULL
+ * @Returns: 1: finish
+*/ 
+int joyThunderSlave50mCycle(void);
+
+#endif
+
+
+

+ 158 - 0
joylink/config/joylink_wlan_probe.h

@@ -0,0 +1,158 @@
+
+
+#ifndef _MTK_CUSTOM_WLAN_PROBE_H_
+#define _MTK_CUSTOM_WLAN_PROBE_H_
+
+/*******************************************************************************
+*                         C O M P I L E R   F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+*                    E X T E R N A L   R E F E R E N C E S
+********************************************************************************
+*/
+#include <stdio.h>
+#include <errno.h>
+#include "stdint.h"
+
+/******************************************************************************
+*                              C O N S T A N T S
+*******************************************************************************
+*/
+#define MTK_CUSTOM_SAVE_PCAP_FILE               0
+#define MTK_CUSTOM_PRINT_FRAME                  0
+
+/* Address 4 excluded */
+#define WLAN_MAC_MGMT_HEADER_LEN                24
+/* 7.3.1.10 Timestamp field */
+#define TIMESTAMP_FIELD_LEN                         8
+/* 7.3.1.3 Beacon Interval field */
+#define BEACON_INTERVAL_FIELD_LEN                   2
+/* 7.3.1.4 Capability Information field */
+#define CAP_INFO_FIELD_LEN                          2
+/* 7.3.2 Element IDs of information elements */
+#define ELEM_HDR_LEN                                2
+
+/* Information Element IDs */
+#define WLAN_EID_SSID 0
+#define WLAN_EID_SUPP_RATES 1
+#define WLAN_EID_FH_PARAMS 2
+#define WLAN_EID_DS_PARAMS 3
+#define WLAN_EID_CF_PARAMS 4
+#define WLAN_EID_TIM 5
+#define WLAN_EID_IBSS_PARAMS 6
+#define WLAN_EID_COUNTRY 7
+#define WLAN_EID_BSS_LOAD 11
+#define WLAN_EID_CHALLENGE 16
+#define WLAN_EID_ERP_INFO 42
+#define WLAN_EID_EXT_SUPP_RATES 50
+#define WLAN_EID_VENDOR_SPECIFIC 221
+
+#define GL_CUSTOM_PROBE_RESP_SSID ("MTK_Probe_SSID")
+
+#define WLAN_CAPABILITY_ESS ((unsigned int) 1U << 0)
+
+#define WLAN_FC_TYPE_MGMT		0
+#define WLAN_FC_TYPE_CTRL		1
+#define WLAN_FC_TYPE_DATA		2
+
+/* management */
+#define WLAN_FC_STYPE_ASSOC_REQ		0
+#define WLAN_FC_STYPE_ASSOC_RESP	1
+#define WLAN_FC_STYPE_REASSOC_REQ	2
+#define WLAN_FC_STYPE_REASSOC_RESP	3
+#define WLAN_FC_STYPE_PROBE_REQ		4
+#define WLAN_FC_STYPE_PROBE_RESP	5
+#define WLAN_FC_STYPE_BEACON		8
+#define WLAN_FC_STYPE_ATIM			9
+#define WLAN_FC_STYPE_DISASSOC		10
+#define WLAN_FC_STYPE_AUTH			11
+#define WLAN_FC_STYPE_DEAUTH		12
+#define WLAN_FC_STYPE_ACTION		13
+
+#define IEEE80211_FC(type, stype) ((type << 2) | (stype << 4))
+
+#define MAX_PROBERESP_LEN 1024
+
+#define MAX_CUSTOM_VENDOR_LEN 256
+
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+
+#ifndef MAC2STR
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+#endif
+
+#ifdef __GNUC__
+#define STRUCT_PACKED __attribute__ ((packed))
+#else
+#define STRUCT_PACKED
+#endif
+
+struct ieee80211_hdr {
+	uint16_t frame_control;
+	uint16_t duration_id;
+	uint8_t addr1[6];
+	uint8_t addr2[6];
+	uint8_t addr3[6];
+	uint16_t seq_ctrl;
+	/* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame
+	 */
+} STRUCT_PACKED;
+
+#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
+
+struct ieee80211_mgmt {
+	uint16_t frame_control;
+	uint16_t duration;
+	uint8_t da[6];
+	uint8_t sa[6];
+	uint8_t bssid[6];
+	uint16_t seq_ctrl;
+	union {
+		struct {
+			/* only variable items: SSID, Supported rates */
+			uint8_t variable[0];
+		} STRUCT_PACKED probe_req;
+		struct {
+			uint8_t timestamp[8];
+			uint16_t beacon_int;
+			uint16_t capab_info;
+			/* followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params */
+			uint8_t variable[0];
+		} STRUCT_PACKED probe_resp;
+		struct {
+			uint8_t timestamp[8];
+			uint16_t beacon_int;
+			uint16_t capab_info;
+			/* followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params, TIM */
+			uint8_t variable[0];
+		} STRUCT_PACKED beacon;
+	} u;
+} STRUCT_PACKED;
+
+struct pcap_pkthdr
+{
+	int tv_sec;
+	int tv_usec;
+	int caplen;
+	int len;
+};
+
+struct pcap_file_header
+{
+	int   magic;
+	short version_major;
+	short version_minor;
+	int   thiszone;   /* gmt to local correction */
+	int   sigfigs;    /* accuracy of timestamps */
+	int   snaplen;    /* max length saved portion of each pkt */
+	int   linktype;   /* data link type (LINKTYPE_*) */
+};
+
+#endif

+ 47 - 0
joylink/example/Makefile

@@ -0,0 +1,47 @@
+include ../Makefile.rule
+
+HEADERS = $(wildcard *.h)
+ORG_SOURCES = $(wildcard *.c)
+OUT_SRC = test.c joylink_porting_layer.c
+
+SOURCES=$(filter-out ${OUT_SRC}, ${ORG_SOURCES})
+OBJS = $(patsubst %.c, %.o, $(SOURCES))
+
+LIBNAME = $(strip ${shell pwd |xargs basename})
+
+INCLUDES += -I${PROJECT_ROOT_PATH}/json 
+INCLUDES += -I${PROJECT_ROOT_PATH}/extern
+INCLUDES += -I${PROJECT_ROOT_PATH}/joylink
+INCLUDES += -I${PROJECT_ROOT_PATH}/auth
+
+STATIC_LIBS += ${TARGET_LIB}/libjson.a
+LIBS += -lm  
+
+ifeq (${ARCH}, x86)  
+all:${OBJS} liba libso
+else
+all:${OBJS} liba 
+endif
+
+.SUFFIXES: .c .o
+.c.o:
+	${CC} ${CFLAGS} -c $(INCLUDES) ${STATIC_LIBS} $(LIBS) $*.c
+
+liba:${OBJS}
+	${AR} -crs lib${LIBNAME}.a ${OBJS}
+	${MV} lib${LIBNAME}.a ${TARGET_LIB}
+
+libso:${OBJS}
+	${CC}  ${OBJS} -shared -fPIC -o lib${LIBNAME}.so
+	${MV} lib${LIBNAME}.so ${TARGET_LIB} 
+
+test:
+	${CC} -DLIB_TEST test.c -o $@ ${CFLAGS} ${INCLUDES} ${STATIC_LIBS} ${LIBS} 
+
+clean:
+	${RM} *.o *.so *.a test
+
+distclean:clean
+	${RM} ./*.a ./*.so ${TARGET_LIB}/lib${LIBNAME}.*
+
+.PHONY:all clean test jt

+ 180 - 0
joylink/example/joylink_dev.h

@@ -0,0 +1,180 @@
+#ifndef _JOYLINK_DEV_H_
+#define _JOYLINK_DEV_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif /* __cplusplus */
+
+#include "joylink.h"
+
+#define LIGHT_CMD_NONE			(-1)
+#define LIGHT_CMD_POWER			(1)
+
+#define LIGHT_CTRL_NONE         (-1)
+#define LIGHT_CTRL_ON           (1)
+#define LIGHT_CTRL_OFF          (0)
+
+typedef struct __light_ctrl{
+    char cmd;
+    int para_power;
+    int para_state;
+    int para_look;
+    int para_move;
+}LightCtrl_t;
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_is_net_ok();
+
+/**
+ * brief: 
+ *
+ * @Param: st
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_set_connect_st(int st);
+
+/**
+ * brief: 
+ *
+ * @Param: jlp
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_set_attr_jlp(JLPInfo_t *jlp);
+
+/**
+ * brief: 
+ *
+ * @Param: jlp
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_get_jlp_info(JLPInfo_t *jlp);
+
+/**
+ * brief: 
+ *
+ * @Param: out_modelcode
+ * @Param: out_max
+ *
+ * @Returns: 
+ */
+int
+joylink_dev_get_modelcode(char *out_modelcode, int32_t out_max);
+
+/**
+ * brief: 
+ *
+ * @Param: out_snap
+ * @Param: out_max
+ *
+ * @Returns: 
+ */
+int
+joylink_dev_get_snap_shot(char *out_snap, int32_t out_max);
+
+/**
+ * brief: 
+ *
+ * @Param: out_snap
+ * @Param: out_max
+ * @Param: code
+ * @Param: feedid
+ *
+ * @Returns: 
+ */
+int
+joylink_dev_get_json_snap_shot(char *out_snap, int32_t out_max, int code, char *feedid);
+
+/**
+ * brief: 
+ *
+ * @Param: json_cmd
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t 
+joylink_dev_lan_json_ctrl(const char *json_cmd);
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ * @Param: ctr
+ * @Param: from_server
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t 
+joylink_dev_script_ctrl(const char *src, int src_len, JLContrl_t *ctr, int from_server);
+
+/**
+ * brief: 
+ *
+ * @Param: otaOrder
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_ota(JLOtaOrder_t *otaOrder);
+
+/**
+ * brief: 
+ */
+void
+joylink_dev_ota_status_upload();
+
+/**
+ * brief: 
+ */
+int 
+joylink_test_ota_crc();
+
+
+/**
+ * brief: 
+ *
+ * @Param: pidt
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_get_idt(jl2_d_idt_t *pidt);
+
+/**
+ * brief: 
+ *
+ * @Param: 
+ *
+ * @Returns: 
+ */
+int
+joylink_dev_get_random();
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int joylink_dev_https_post( char* host, char* query ,char *revbuf,int buflen);
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int joylink_dev_run_status(JLRunStatus_t status);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif

+ 524 - 0
joylink/example/joylink_extern.c

@@ -0,0 +1,524 @@
+/* --------------------------------------------------
+ * @brief: 
+ *
+ * @version: 1.0
+ *
+ * @date: 08/01/2018
+ *
+ * --------------------------------------------------
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "joylink.h"
+#include "joylink_packets.h"
+#include "joylink_json.h"
+#include "joylink_extern_json.h"
+#include "joylink_auth_crc.h"
+
+#include <fcntl.h> 
+
+#include "joylink_extern.h"
+#include "joylink_extern_ota.h"
+
+JLPInfo_t user_jlp = 
+{
+	.version = JLP_VERSION,
+	.uuid = JLP_UUID,
+
+	.devtype = JLP_DEV_TYPE,
+	.lancon = JLP_LAN_CTRL,
+	.cmd_tran_type = JLP_CMD_TYPE,
+
+	.joySdkVersion = _VERSION_,
+	.noSnapshot = JLP_SNAPSHOT,
+};
+jl2_d_idt_t user_idt = 
+{
+	.type = 0,
+	.cloud_pub_key = IDT_CLOUD_PUB_KEY,
+
+	.sig = "01234567890123456789012345678901",
+	.pub_key = "01234567890123456789012345678901",
+
+	.f_sig = "01234567890123456789012345678901",
+	.f_pub_key = "01234567890123456789012345678901",
+};
+
+user_dev_status_t user_dev;
+
+/*E_JLDEV_TYPE_GW*/
+#ifdef _SAVE_FILE_
+char  *file = "joylink_info.txt";
+#endif
+
+extern int joylink_parse_jlp(JLPInfo_t *jlp, char * pMsg);
+extern int joylink_util_cut_ip_port(const char *ipport, char *out_ip, int *out_port);
+
+/**
+ * brief: 
+ *
+ * @Param:
+ *
+ * @Returns: 
+ */
+int
+joylink_dev_get_random()
+{
+    /**
+     *FIXME:must to do
+     */
+    return random();
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_is_net_ok()
+{
+    /**
+     *FIXME:must to do
+     */
+    return E_RET_TRUE;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: st
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_set_connect_st(int st)
+{
+	/**
+	*FIXME:must to do
+	*/
+	char buff[64] = {0};
+	int ret = 0;
+
+	sprintf(buff, "{\"conn_status\":\"%d\"}", st);
+	log_info("--set_connect_st:%s\n", buff);
+
+	return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: jlp
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_set_attr_jlp(JLPInfo_t *jlp)
+{
+	if(NULL == jlp){
+		return E_RET_ERROR;
+	}
+	/**
+	*FIXME:must to do
+	*Must save jlp info to flash 
+	*/
+	int ret = E_RET_ERROR;
+
+	memcpy(&user_jlp, jlp, sizeof(JLPInfo_t));
+#ifdef _SAVE_FILE_
+	FILE *outfile;
+	outfile = fopen(file, "wb+" );
+	fwrite(&user_jlp, sizeof(JLPInfo_t), 1, outfile );
+	fclose(outfile);
+#endif
+	ret = E_RET_OK;
+
+	return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: jlp
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_get_idt(jl2_d_idt_t *pidt)
+{
+	if(NULL == pidt){
+		return E_RET_ERROR; 
+	}
+	pidt->type = 0;
+	/**
+	*FIXME:must to do
+	*/
+	strcpy(pidt->sig, user_idt.sig);
+	strcpy(pidt->pub_key, user_idt.pub_key);
+	//strcpy(pidt->rand, user_idt.rand);
+	strcpy(pidt->f_sig, user_idt.f_sig);
+	strcpy(pidt->f_pub_key, user_idt.f_pub_key);
+	strcpy(pidt->cloud_pub_key, user_idt.cloud_pub_key);
+
+	return E_RET_OK;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int
+joylink_dev_get_user_mac(char *out)
+{
+	/**
+	*FIXME:must to do
+	*/
+	return -1;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int
+joylink_dev_get_private_key(char *out)
+{
+	/**
+	*FIXME:must to do
+	*/
+	return -1;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: jlp
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_get_jlp_info(JLPInfo_t *jlp)
+{
+	if(NULL == jlp){
+		return -1;
+	}
+	/**
+	*FIXME:must to do
+ 	*Must get jlp info from flash 
+	*/
+	int ret = E_RET_OK;
+
+	JLPInfo_t fjlp;
+	memset(&fjlp, 0, sizeof(JLPInfo_t));
+
+#ifdef _SAVE_FILE_
+	FILE *infile;
+	infile = fopen(file, "rb+");
+	if(infile > 0)
+	{
+		fread(&fjlp, sizeof(fjlp), 1, infile);
+		fclose(infile);
+
+		strcpy(user_jlp.feedid, fjlp.feedid);
+		strcpy(user_jlp.accesskey, fjlp.accesskey);
+		strcpy(user_jlp.localkey, fjlp.localkey);
+		strcpy(user_jlp.joylink_server, fjlp.joylink_server);
+		user_jlp.server_port = fjlp.server_port;
+	}
+#endif
+	strcpy(jlp->feedid, user_jlp.feedid);
+	strcpy(jlp->accesskey, user_jlp.accesskey);
+	strcpy(jlp->localkey, user_jlp.localkey);
+	strcpy(jlp->joylink_server, user_jlp.joylink_server);
+	jlp->server_port = user_jlp.server_port;
+	if(strlen(jlp->feedid) > 0){
+		_g_pdev->jlp.is_actived = 1;
+	}
+	/**
+	*MUST TODO
+	*This jlp->mac must return the device real mac.
+	*/
+	if(joylink_dev_get_user_mac(jlp->mac) < 0){
+		strcpy(jlp->mac, user_jlp.mac);
+	}
+
+	if(joylink_dev_get_private_key(jlp->prikey) < 0){
+		strcpy(jlp->prikey, user_jlp.prikey);
+	}
+
+	jlp->version = user_jlp.version;
+	strcpy(jlp->uuid, user_jlp.uuid);
+
+	jlp->devtype = user_jlp.devtype;
+	jlp->lancon = user_jlp.lancon;
+	jlp->cmd_tran_type = user_jlp.cmd_tran_type;
+	
+	strcpy(jlp->joySdkVersion, user_jlp.joySdkVersion);
+	jlp->noSnapshot = user_jlp.noSnapshot;
+
+	return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: out_modelcode
+ * @Param: out_max
+ *
+ * @Returns: 
+ */
+int
+joylink_dev_get_modelcode(char *out_modelcode, int32_t out_max)
+{
+	if(NULL == out_modelcode || out_max < 0){
+		return 0;
+	}
+	/**
+	*FIXME:must to do
+	*/
+	int len = 0;
+
+	char *packet_data =  joylink_dev_modelcode_info(0, &_g_pdev->jlp);
+	if(NULL !=  packet_data){
+		len = strlen(packet_data);
+		log_info("------>%s:len:%d\n", packet_data, len);
+		if(len < out_max){
+			memcpy(out_modelcode, packet_data, len); 
+		}else{
+			len = 0;
+		}
+	}
+
+	if(NULL !=  packet_data){
+		free(packet_data);
+	}
+
+	return len;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int
+joylink_dev_user_data_get(user_dev_status_t *user_data)
+{
+	/**
+	*FIXME:must to do
+	*/
+	return 0;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: out_snap
+ * @Param: out_max
+ *
+ * @Returns: 
+ */
+int
+joylink_dev_get_snap_shot_with_retcode(int32_t ret_code, char *out_snap, int32_t out_max)
+{
+	if(NULL == out_snap || out_max < 0){
+		return 0;
+	}
+	/**
+	*FIXME:must to do
+	*/
+	int len = 0;
+
+	joylink_dev_user_data_get(&user_dev);
+
+	char *packet_data =  joylink_dev_package_info(ret_code, &user_dev);
+	if(NULL !=  packet_data){
+		len = strlen(packet_data);
+		log_info("------>%s:len:%d\n", packet_data, len);
+		if(len < out_max){
+			memcpy(out_snap, packet_data, len); 
+		}else{
+			len = 0;
+		}
+	}
+
+	if(NULL !=  packet_data){
+		free(packet_data);
+	}
+	return len;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: out_snap
+ * @Param: out_max
+ *
+ * @Returns: 
+ */
+int
+joylink_dev_get_snap_shot(char *out_snap, int32_t out_max)
+{
+	return joylink_dev_get_snap_shot_with_retcode(0, out_snap, out_max); 
+}
+
+/**
+ * brief: 
+ *
+ * @Param: out_snap
+ * @Param: out_max
+ * @Param: code
+ * @Param: feedid
+ *
+ * @Returns: 
+ */
+int
+joylink_dev_get_json_snap_shot(char *out_snap, int32_t out_max, int code, char *feedid)
+{
+    /**
+     *FIXME:must to do
+     */
+    sprintf(out_snap, "{\"code\":%d, \"feedid\":\"%s\"}", code, feedid);
+
+    return strlen(out_snap);
+}
+
+/**
+ * brief: 
+ *
+ * @Param: json_cmd
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t 
+joylink_dev_lan_json_ctrl(const char *json_cmd)
+{
+    /**
+     *FIXME:must to do
+     */
+    log_debug("json ctrl:%s", json_cmd);
+
+    return E_RET_OK;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int
+joylink_dev_user_data_set(char *cmd, user_dev_status_t *user_data)
+{
+	/**
+	*FIXME:must to do
+	*/
+	return 0;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ * @Param: ctr
+ * @Param: from_server
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t 
+joylink_dev_script_ctrl(const char *src, int src_len, JLContrl_t *ctr, int from_server)
+{
+	if(NULL == src || NULL == ctr){
+		return -1;
+	}
+	/**
+	*FIXME:must to do
+	*/
+	int ret = -1;
+	ctr->biz_code = (int)(*((int *)(src + 4)));
+	ctr->serial = (int)(*((int *)(src +8)));
+
+	time_t tt = time(NULL);
+	log_info("bcode:%d:server:%d:time:%ld", ctr->biz_code, from_server,(long)tt);
+
+	if(ctr->biz_code == JL_BZCODE_GET_SNAPSHOT){
+		/*
+		*Nothing to do!
+		*/
+		ret = 0;
+	}else if(ctr->biz_code == JL_BZCODE_CTRL){
+		joylink_dev_parse_ctrl(src + 12, &user_dev);
+#ifdef __MTK_7687__
+		gpio_ligt_ctrl(user_dev.power);
+#endif
+		return 0;
+	}else{
+		log_error("unKown biz_code:%d", ctr->biz_code);
+	}
+	return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: otaOrder
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_ota(JLOtaOrder_t *otaOrder)
+{
+	if(NULL == otaOrder){
+		return -1;
+	}
+#ifdef __MTK_7687__
+	log_debug("serial:%d | feedid:%s | productuuid:%s | version:%d | versionname:%s | crc32:%d | url:%s\n",
+		otaOrder->serial, otaOrder->feedid, otaOrder->productuuid, otaOrder->version, 
+		otaOrder->versionname, otaOrder->crc32, otaOrder->url);
+
+	strcpy(_g_fota_ctx.download_url, (const char*)otaOrder->url);
+	//strcpy(_g_fota_ctx.download_url, (const char*)"http://192.168.1.96/mt7687_iot_sdk.bin");
+	_g_fota_ctx.crc32 = otaOrder->crc32;
+	joylink_fota_download_package();
+#else
+	pthread_t tidp;
+	int ret = pthread_create(&tidp, NULL, (void *)joylink_ota_task, (void *)otaOrder);
+	if(ret < 0){
+		log_info("ota progress pthread create failed!");
+	}
+#endif
+	return E_RET_OK;
+}
+
+
+/**
+ * brief: 
+ */
+void
+joylink_dev_ota_status_upload()
+{
+	return;	
+}
+
+int joylink_dev_https_post( char* host, char* query ,char *revbuf,int buflen)
+{
+	int ret = -1;
+	/**
+		 *FIXME:must to do
+	*/
+	return ret;
+}
+
+int joylink_dev_run_status(JLRunStatus_t status)
+{
+	int ret = -1;
+	/**
+		 *FIXME:must to do
+	*/
+	return ret;
+}
+

+ 62 - 0
joylink/example/joylink_extern.h

@@ -0,0 +1,62 @@
+#ifndef _JOYLINK_EXTERN_H_
+#define _JOYLINK_EXTERN_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif /* __cplusplus */
+
+#include "joylink.h"
+
+#define JOYLINK_CLOUD_AUTH
+#define JOYLINK_DEVICE_AUTH
+
+#define JOYLINK_THUNDER_SLAVE
+#define JOYLINK_SMART_CONFIG
+
+/*
+ * user set
+ */
+#define JLP_VERSION  1
+/*
+ * Create dev and get the index from developer center
+ */
+
+#define JLP_DEV_TYPE    E_JLDEV_TYPE_NORMAL
+#define JLP_LAN_CTRL	E_LAN_CTRL_ENABLE
+#define JLP_CMD_TYPE	E_CMD_TYPE_LUA_SCRIPT
+#define JLP_SNAPSHOT    E_SNAPSHOT_NO
+
+#define JLP_UUID "" 
+#define IDT_CLOUD_PUB_KEY ""
+
+typedef struct _user_dev_status_t {
+
+} user_dev_status_t;
+
+/**
+ * brief:
+ *
+ * @Returns:
+ */
+int joylink_dev_get_user_mac(char *out);
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int joylink_dev_get_private_key(char *out);
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int joylink_dev_user_data_set(char *cmd, user_dev_status_t *user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+

+ 208 - 0
joylink/example/joylink_extern_json.c

@@ -0,0 +1,208 @@
+/* --------------------------------------------------
+ * @brief: 
+ *
+ * @version: 1.0
+ *
+ * @date: 08/01/2018
+ *
+ * @author: 
+ * --------------------------------------------------
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cJSON.h"
+
+#include "joylink_json.h"
+#include "joylink_dev.h"
+#include "joylink_log.h"
+#include "joylink_extern.h"
+
+/**
+ * brief: 
+ *
+ * @Param: pMsg
+ * @Param: user_dev
+ *
+ * @Returns: 
+ */
+int 
+joylink_dev_parse_ctrl(const char *pMsg, user_dev_status_t *userDev)
+{
+	int ret = -1;
+	if(NULL == pMsg || NULL == userDev){
+		goto RET;
+	}
+	log_debug("json_org:%s", pMsg);
+	cJSON * pSub;
+	cJSON * pJson = cJSON_Parse(pMsg);
+
+	if(NULL == pJson){
+		log_error("--->:ERROR: pMsg is NULL\n");
+		goto RET;
+	}
+
+	char tmp_str[64];
+	cJSON *pStreams = cJSON_GetObjectItem(pJson, "streams");
+	if(NULL != pStreams){
+		int iSize = cJSON_GetArraySize(pStreams);
+  		int iCnt;
+		for( iCnt = 0; iCnt < iSize; iCnt++){
+			pSub = cJSON_GetArrayItem(pStreams, iCnt);
+			if(NULL == pSub){
+				continue;
+			}
+
+			cJSON *pSId = cJSON_GetObjectItem(pSub, "stream_id");
+			if(NULL == pSId){
+				break;
+			}
+			cJSON *pV = cJSON_GetObjectItem(pSub, "current_value");
+			if(NULL == pV){
+				continue;
+			}
+
+			char *dout = cJSON_Print(pSub);
+			if(NULL != dout){
+				log_debug("org streams:%s", dout);
+				free(dout);
+			}
+		}
+	}                                                                                                         
+	cJSON_Delete(pJson);
+RET:
+	return ret;
+}
+
+/**
+ * brief: 
+ * NOTE: If return is not NULL, 
+ * must free it, after use.
+ *
+ * @Param: retMsg
+ * @Param: retCode
+ * @Param: wci
+ * @Param: devlist
+ *
+ * @Returns: char * 
+ */
+char * 
+joylink_dev_package_info(const int retCode, user_dev_status_t *userDev)
+{
+	if(NULL == userDev){
+		return NULL;
+	}
+	cJSON *root, *arrary;
+	char *out  = NULL; 
+
+	root = cJSON_CreateObject();
+	if(NULL == root){
+		goto RET;
+	}
+	arrary = cJSON_CreateArray();
+	if(NULL == arrary){
+		cJSON_Delete(root);
+		goto RET;
+	}
+	cJSON_AddNumberToObject(root, "code", retCode);
+	cJSON_AddItemToObject(root, "streams", arrary);
+
+	out=cJSON_Print(root);
+	cJSON_Delete(root);
+RET:
+	return out;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: retCode
+ * @Param: userDev
+ *
+ * @Returns: 
+ */
+char * 
+joylink_dev_modelcode_info(const int retCode, JLPInfo_t *userDev)
+{
+	if(NULL == userDev){
+		return NULL;
+	}
+	cJSON *root, *arrary;
+	char *out  = NULL; 
+
+	root = cJSON_CreateObject();
+	if(NULL == root){
+		goto RET;
+	}
+	arrary = cJSON_CreateArray();
+	if(NULL == arrary){
+		cJSON_Delete(root);
+		goto RET;
+	}
+	cJSON_AddItemToObject(root, "model_codes", arrary);
+    
+	char i2str[32];
+	bzero(i2str, sizeof(i2str));
+	cJSON *element = cJSON_CreateObject();
+	cJSON_AddItemToArray(arrary, element);
+	cJSON_AddStringToObject(element, "feedid", userDev->feedid);
+	cJSON_AddStringToObject(element, "model_code", "12345678123456781234567812345678");
+
+	out=cJSON_Print(root);  
+	cJSON_Delete(root); 
+RET:
+	return out;
+}
+/**
+ * brief: 
+ *
+ * @Param: jlp
+ * @Param: pMsg
+ *
+ * @Returns: 
+ */
+int 
+joylink_parse_jlp(JLPInfo_t *jlp, char * pMsg)
+{
+	int ret = -1;
+	if(NULL == pMsg || NULL == jlp){
+		return ret;
+	}
+	cJSON *pVal;
+	cJSON * pJson = cJSON_Parse(pMsg);
+
+	if(NULL == pJson){
+		log_error("--->:ERROR: pMsg is NULL\n");
+		goto RET;
+	}
+
+	pVal = cJSON_GetObjectItem(pJson, "uuid");
+	if(NULL != pVal){
+		strcpy(jlp->uuid, pVal->valuestring);
+	}
+
+	pVal = cJSON_GetObjectItem(pJson, "feedid");
+	if(NULL != pVal){
+		strcpy(jlp->feedid, pVal->valuestring);
+	}
+
+	pVal = cJSON_GetObjectItem(pJson, "accesskey");
+	if(NULL != pVal){
+		strcpy(jlp->accesskey, pVal->valuestring);
+	}
+
+	pVal = cJSON_GetObjectItem(pJson, "localkey");
+	if(NULL != pVal){
+		strcpy(jlp->localkey, pVal->valuestring);
+	}
+
+	pVal = cJSON_GetObjectItem(pJson, "version");
+	if(NULL != pVal){
+		jlp->version = pVal->valueint;
+	}
+
+	cJSON_Delete(pJson);
+	ret = 0;
+RET:
+	return ret;
+}

+ 59 - 0
joylink/example/joylink_extern_json.h

@@ -0,0 +1,59 @@
+/* --------------------------------------------------
+ * @file: joylink_extern_json.h
+ *
+ * @brief: 
+ *
+ * @version: 1.0
+ *
+ * @date: 10/26/2015 02:21:59 PM
+ *
+ * --------------------------------------------------
+ */
+
+#ifndef __JOYLINK_EXTERN_JSON__
+#define __JOYLINK_EXTERN_JSON__
+
+#include "joylink_dev.h"
+#include "joylink_extern.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif /* __cplusplus */
+
+/**
+ * brief: 
+ *
+ * @Param: pCtrl
+ * @Param: pMsg
+ *
+ * @Returns: 
+ */
+int 
+joylink_dev_parse_ctrl(const char * pMsg, user_dev_status_t *userDev);
+
+/**
+ * brief: 
+ *
+ * @Param: retCode
+ * @Param: pCtrl
+ *
+ * @Returns: 
+ */
+char * 
+joylink_dev_package_info(const int retCode, user_dev_status_t *userDev);
+
+/**
+ * brief: 
+ *
+ * @Param: retCode
+ * @Param: pCtrl
+ *
+ * @Returns: 
+ */
+char * 
+joylink_dev_modelcode_info(const int retCode, JLPInfo_t *userDev);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif

+ 533 - 0
joylink/example/joylink_extern_ota.c

@@ -0,0 +1,533 @@
+/************************************************************
+ *File : joylink_ota.c
+ *Auth : jd
+ *Date : 2018/07/25
+ *Mail : 
+ ***********************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+
+#include "joylink.h"
+#include "joylink_packets.h"
+#include "joylink_auth_crc.h"
+
+#include <fcntl.h> 
+
+#include "joylink_extern_user.h"
+#include "joylink_extern_ota.h"
+#include "joylink_extern_sub_dev.h"
+
+//-----------------------------------------------------------------------
+int 
+joylink_socket_create(const char *host, int port)
+{
+	struct hostent *he;
+	struct sockaddr_in server_addr; 
+	int socket_fd;
+	int flags;
+ 
+	if((he = gethostbyname(host)) == NULL){
+		return -1;
+	}
+ 
+	server_addr.sin_family = AF_INET;
+	server_addr.sin_port = htons(port);
+	server_addr.sin_addr = *((struct in_addr *)he->h_addr);
+ 
+	if((socket_fd = socket(AF_INET,SOCK_STREAM,0)) == -1){
+        	return -1;
+	}
+ 
+	if(connect(socket_fd, (struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1){
+		return -1;
+	}
+
+	flags = fcntl(socket_fd, F_GETFL, 0); 
+	fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
+
+	return socket_fd;
+}
+
+//-----------------------------------------------------------------------
+int 
+joylink_socket_recv(int socket_fd, char *recv_buf, int recv_len)
+{
+	int ret = 0;
+	fd_set  readfds;
+	struct timeval selectTimeOut;
+
+	FD_ZERO(&readfds);
+	FD_SET(socket_fd, &readfds);
+
+        selectTimeOut.tv_usec = 0L;
+        selectTimeOut.tv_sec = (long)2;
+
+	ret = select(socket_fd + 1, &readfds, NULL, NULL, &selectTimeOut);
+	if (ret <= 0){
+		return -1;
+	}
+	if(FD_ISSET(socket_fd, &readfds)){
+		return recv(socket_fd, recv_buf, recv_len, 0);
+	}
+	else{
+		return -1;
+	}
+}
+
+//-----------------------------------------------------------------------
+int 
+joylink_socket_send(int socket_fd, char *send_buf, int send_len)
+{
+	int send_ok = 0;
+	int ret_len = 0;
+
+	while(send_ok < send_len){
+		ret_len = send(socket_fd, send_buf + send_ok, send_len - send_ok, 0);
+		if(ret_len == -1){
+			return -1;
+		}
+		send_ok += ret_len;
+	}
+	return send_ok;
+}
+
+//-----------------------------------------------------------------------
+void 
+joylink_socket_close(int socket_fd)
+{
+	close(socket_fd);
+}
+
+//-----------------------------------------------------------------------
+int 
+joylink_parse_url(const char *url, http_ota_st *ota_info)
+{
+	char *strp1 = NULL;
+	char *strp2 = NULL;
+
+	int len = 0;
+	int file_len = 0;
+
+	if(!url || !ota_info){
+		return -1;
+	}
+
+	strp1 = (char *)url;
+ 
+	if(!strncmp(strp1, "http://", strlen("http://"))){
+		strp1 += strlen("http://");
+	}else{
+		return -1;
+	}
+
+	strp2 = strchr(strp1,'/');
+	if(strp2){
+		len = strlen(strp1) - strlen(strp2);
+		memcpy(ota_info->host_name, strp1, len);
+
+		if(*(strp2 + 1)){
+			memcpy(ota_info->file_path, strp2 + 1, strlen(strp2) - 1);
+		}
+	}
+	else{
+		memcpy(ota_info->host_name, strp1, strlen(strp1));
+	}
+
+	strp1 = strchr(ota_info->host_name, ':');
+	if(strp1){
+		*strp1++ = 0;
+		ota_info->host_port = atoi(strp1);
+	}
+	else{
+		ota_info->host_port = HTTP_DEFAULT_PORT;
+	}
+
+	file_len = strlen(strp2);
+	while(file_len--){
+		if(*(strp2 + file_len) == '/'){
+			strcpy(ota_info->file_name, strp2 + file_len + 1);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+//-----------------------------------------------------------------------
+int
+joylink_get_file_size(int socket_fd, http_ota_st *ota_info)
+{
+	char *str_p = NULL;
+
+	long int file_size = 0;
+	
+	char send_buf[512] = {0};
+	char recv_buf[512] = {0};
+
+	int ret_len = 0;
+	int recv_len = 0;
+
+	sprintf(send_buf, HTTP_HEAD, ota_info->file_path, ota_info->host_name, ota_info->host_port);
+	log_info("send:\n%s\n",send_buf);
+
+	if(joylink_socket_send(socket_fd, send_buf, strlen(send_buf)) < 0){
+		log_error("get_file_size send failed!\n");
+		return -1;
+	}
+
+	while(1)
+	{
+		ret_len = joylink_socket_recv(socket_fd, recv_buf + recv_len, 512 - recv_len);
+		if(ret_len < 0){
+			log_error("get_file_size recv failed!\n");
+			return -1;
+		}
+
+		recv_len += ret_len;
+
+		if(recv_len > 50){
+			break;
+#if 0
+			if(strstr(recv_buf,"\r\n\r\n") == NULL){
+				log_error("Parse head tail failed!\n");
+				return -1;
+			}
+			else{
+				break;
+			}
+#endif
+		}
+	}
+	log_info("recv:\n%s\n", recv_buf);
+
+	str_p = strstr(recv_buf,"Content-Length");
+	if(str_p == NULL){
+		log_error("http parse file size error!\n");
+		return -1;
+	}
+	else{
+		str_p = str_p + strlen("Content-Length") + 2; 
+		file_size = atoi(str_p);
+	}
+
+        return file_size;
+}
+
+//-----------------------------------------------------------------------
+
+int
+joylink_ota_get_info(char *url, http_ota_st *ota_info)
+{
+	int socket_fd = 0;
+	
+	int file_fd = 0;
+	char save_file[128] = {0};
+
+	if(!url){
+		log_error("url is NULL!\n");
+		return -1;
+	}
+
+	if(joylink_parse_url(url, ota_info)){
+		log_error("http_parse_url failed!\n");
+		return -1;
+	}
+	log_info("host name: %s port: %d\n", ota_info->host_name, ota_info->host_port);
+	log_info("file path: %s name: %s\n\n", ota_info->file_path, ota_info->file_name);
+
+	socket_fd = joylink_socket_create(ota_info->host_name, ota_info->host_port);
+	if(socket_fd < 0){
+		log_error("http_tcpclient_create failed\n");
+		return -1;
+	}
+
+	ota_info->file_size = joylink_get_file_size(socket_fd, ota_info);
+	if(ota_info->file_size <= 0){
+		log_error("get file size failed\n");
+		return -1;
+	}
+	log_info("file size %ld\n\n", ota_info->file_size);
+
+	joylink_memory_init((void *)ota_info->file_name, MEMORY_WRITE);
+	
+	joylink_socket_close(socket_fd);
+}
+
+int
+joylink_ota_set_download_len(int socket_fd, http_ota_st *ota_info)
+{
+	long int max_len = ota_info->file_size;
+	long int read_len = max_len;
+
+	char *recv_p1 = NULL;
+	char *recv_p2 = NULL;
+
+	char send_buf[256] = {0};
+	char recv_buf[1024] = {0};
+
+	int recv_len = 0;
+	int ret_len = 0;
+
+	long int data_len = 0;
+
+	if(ota_info->file_size - ota_info->file_offset < max_len){
+		read_len = ota_info->file_size - ota_info->file_offset;
+	}
+
+	sprintf(send_buf, HTTP_GET, ota_info->file_path, ota_info->host_name, ota_info->host_port, ota_info->file_offset, max_len);//, (ota_info->file_offset + read_len - 1));
+	//log_info("send:\n%s\n",send_buf);
+
+	if(joylink_socket_send(socket_fd, send_buf, strlen(send_buf)) < 0){
+		log_error("get_file_data send failed!\n");
+		return -1;
+	}
+
+	memset(recv_buf, 0, 1024);
+	while(1){
+		ret_len = joylink_socket_recv(socket_fd, recv_buf + recv_len, 1);
+		if(ret_len < 0){
+			log_error("get_file_data recv failed!\n");
+			return -1;
+		}
+		
+		recv_len += ret_len;
+
+		if(recv_len < 200) continue;
+
+		recv_p1 = strstr(recv_buf, "\r\n\r\n");
+		if(recv_p1 == NULL) continue;
+
+		recv_p2 = strstr(recv_buf, "Content-Length");
+		if(recv_p2 == NULL){
+			log_error("Parse data length error!\n");
+			return -1;
+		}
+		recv_p2 = recv_p2 + strlen("Content-Length") + 2; 
+		data_len = atoi(recv_p2);
+		break;
+	}
+
+	log_info("recv:\n%s\n", recv_buf);
+	log_info("read_len: %ld data_len: %ld\n", read_len, data_len);
+
+	if(read_len != data_len){
+		return -1;
+	}
+
+	return read_len;
+}
+
+//---------------------------------------------------------------------------
+int joylink_ota_report_status(int status, int progress, char *desc);
+
+extern void joylink_util_timer_reset(uint32_t *timestamp);
+extern int joylink_util_is_time_out(uint32_t timestamp, uint32_t timeout);
+
+int
+joylink_ota_get_data(http_ota_st *ota_info)
+{
+	int file_fd = 0;
+	int socket_fd = 0;
+	int download_len = 0;
+	int save_len = 0;
+
+	char recv_buf[EVERY_PACKET_LEN] = {0};
+	int read_len = 0;
+	int ret_len = 0;
+
+	char save_file[128] = {0};
+
+	unsigned int timer_out = 0;
+	unsigned int interval_out = OTA_TIME_OUT;
+
+	socket_fd = joylink_socket_create(ota_info->host_name, ota_info->host_port);
+	if(socket_fd < 0){
+		log_error("joylink_socket_create failed\n");
+		return -1;
+	}
+
+	joylink_util_timer_reset(&timer_out);
+	joylink_ota_report_status(OTA_STATUS_DOWNLOAD, 0, "ota download start");
+
+	while(ota_info->file_size > ota_info->file_offset){
+		download_len = joylink_ota_set_download_len(socket_fd, ota_info);
+		if(download_len < 0){
+			log_error("set download_len error!\n");
+			break;
+		}
+
+		read_len = EVERY_PACKET_LEN;
+		save_len = download_len;
+
+		while(download_len != 0){
+			memset(recv_buf, 0, EVERY_PACKET_LEN);
+			ret_len = joylink_socket_recv(socket_fd, recv_buf, read_len);
+
+			if(ret_len > 0){
+
+				joylink_memory_write(0, recv_buf, ret_len);
+			}
+			else{
+				log_error("recv file data error!\n");
+				break;
+			}
+
+			download_len -= ret_len;
+			if(download_len / EVERY_PACKET_LEN == 0){
+				read_len == download_len % EVERY_PACKET_LEN;
+			}
+			else{
+				read_len = EVERY_PACKET_LEN;
+			}
+		}
+
+		if(download_len == 0){
+			ota_info->file_offset += save_len;
+		}
+		else{
+			break;
+		}
+
+		ota_info->finish_percent = ota_info->file_offset * 100 / ota_info->file_size;
+		log_info("\njoylink OTA download: %d%%\n\n", ota_info->finish_percent);
+
+		if(joylink_util_is_time_out(timer_out, interval_out))
+		{
+			joylink_ota_report_status(OTA_STATUS_DOWNLOAD, ota_info->finish_percent, "ota timeout error");
+			break;
+		}
+		joylink_ota_report_status(OTA_STATUS_DOWNLOAD, ota_info->finish_percent, "ota download");
+	}
+	joylink_memory_finish();
+	joylink_socket_close(socket_fd);
+
+	if(ota_info->file_size == ota_info->file_offset){
+		return 0;
+	}
+	else{
+		return -1;	
+	}
+}
+
+int joylink_ota_check_crc(unsigned int cloud_crc32, char *path)
+{
+	int ret = 0;
+
+	int read_len = 0;
+	int file_size = 0;
+
+	char buffer[EVERY_PACKET_LEN];
+
+	unsigned int file_crc32 = 0;
+
+	log_info("ota check crc!\npath: %s\n", path);
+
+	make_crc32_table();
+
+	ret = joylink_memory_init(path, MEMORY_READ);
+	if(ret < 0){
+		log_error("open file error");
+		return -1;
+	}
+   
+	while(1){
+		memset(buffer, 0, sizeof(buffer));
+		read_len = joylink_memory_read(0, buffer, sizeof(buffer));
+		if(read_len <= 0){
+			break;
+		}
+		file_crc32 = make_crc(file_crc32, buffer, read_len);
+		file_size += read_len;		
+	}
+	joylink_memory_finish();
+
+	log_info("cloud crc32: %d, file crc32:%d, file size:%d\n", cloud_crc32, file_crc32, file_size);
+
+	if(cloud_crc32 == file_crc32)
+		return 0;
+	else
+		return -1;
+}
+
+//-----------------------------------------------------------------------
+
+static int dev_version = 0;
+static JLOtaOrder_t otaOrder;
+
+int
+joylink_ota_report_status(int status, int progress, char *desc)
+{
+	JLOtaUpload_t otaUpload;
+
+	strcpy(otaUpload.feedid, otaOrder.feedid);
+	strcpy(otaUpload.productuuid, otaOrder.productuuid);
+
+	otaUpload.status = status;
+
+	log_info("status: %d, version: %d\n", status, dev_version);
+
+	otaUpload.progress = progress;
+	strcpy(otaUpload.status_desc, desc);
+
+	joylink_server_ota_status_upload_req(&otaUpload);
+}
+
+//-----------------------------------------------------------------------
+void *
+joylink_ota_task(void *data)
+{
+	int ret = 0;
+	http_ota_st ota_info;
+	//JLOtaOrder_t *otaOrder = (JLOtaOrder_t *)index;
+
+	memset(&otaOrder, 0, sizeof(JLOtaOrder_t));
+	memcpy(&otaOrder, data, sizeof(JLOtaOrder_t));
+	
+	log_info("\n\nJoylink ota statrt!\n");
+
+	log_info("\nserial:%d | feedid:%s | productuuid:%s | version:%d | versionname:%s | crc32:%d | url:%s\n\n",\
+		otaOrder.serial, otaOrder.feedid, otaOrder.productuuid, otaOrder.version,\
+		otaOrder.versionname, otaOrder.crc32, otaOrder.url);
+
+	memset(&ota_info, 0, sizeof(http_ota_st));
+
+	dev_version = otaOrder.version;
+
+	ret = joylink_ota_get_info(otaOrder.url, &ota_info);
+	if(ret < 0){
+		joylink_ota_report_status(OTA_STATUS_FAILURE, 0, "get info error");
+		log_error("Joylink ota get info error!\n");
+		return NULL;
+	}
+
+	ret = joylink_ota_get_data(&ota_info);
+	if(ret < 0){
+		joylink_ota_report_status(OTA_STATUS_FAILURE, 0, "get data error");
+		log_error("Joylink ota get data error!\n");
+		return NULL;
+	}
+
+	ret = joylink_ota_check_crc(otaOrder.crc32, ota_info.file_name);
+	if(ret < 0){
+		joylink_ota_report_status(OTA_STATUS_FAILURE, 0, "check crc32 error");
+		log_error("Joylink ota check crc32 error!\n");
+		return NULL;
+	}
+
+	if(!strcmp(_g_pdev->jlp.feedid, otaOrder.feedid)){
+                _g_pdev->jlp.version = dev_version;
+        }
+        else{
+                joylink_dev_sub_version_update(otaOrder.feedid, dev_version);
+        }
+
+	joylink_ota_report_status(OTA_STATUS_SUCCESS, ota_info.finish_percent, "ota is ok");
+
+	memset(&ota_info, 0, sizeof(http_ota_st));
+
+	log_info("Joylink ota is ok!\n");
+}
+

+ 61 - 0
joylink/example/joylink_extern_ota.h

@@ -0,0 +1,61 @@
+/* --------------------------------------------------
+ * @file: joylink_extern_ota.h
+ *
+ * @brief: 
+ *
+ * @version: 2.0
+ *
+ * @date: 2018/07/26 PM
+ *
+ * --------------------------------------------------
+ */
+
+#ifndef _JOYLINK_EXTERN_OTA_H_
+#define _JOYLINK_EXTERN_OTA_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+//#define HTTP_URL "http://storage.360buyimg.com/devh5/micapp_ota_9_1532350290755.bin"
+
+#define OTA_STATUS_DOWNLOAD 0
+#define OTA_STATUS_INSTALL  1
+#define OTA_STATUS_SUCCESS  2
+#define OTA_STATUS_FAILURE  3
+
+//#define OTA_PACKET_NUMB  1
+
+#define HTTP_DEFAULT_PORT 80
+
+#define EVERY_PACKET_LEN  1024
+
+#define OTA_TIME_OUT (5 * 60 * 1000)
+
+#define HTTP_HEAD "HEAD /%s HTTP/1.1\r\nHOST: %s:%d\r\nConnection: Keep-Alive\r\n\r\n"
+#define HTTP_GET "GET /%s HTTP/1.1\r\nHOST: %s:%d\r\nRange: bytes=%ld-%ld\r\nKeep-Alive: 200\r\nConnection: Keep-Alive\r\n\r\n"
+
+typedef struct _http_ota_st
+{
+	char url[256];
+
+	char host_name[64];
+	int host_port;
+
+	char file_path[64];
+	char file_name[64];
+
+	long int file_size;
+	long int file_offset;
+
+	int finish_percent;
+} http_ota_st;
+
+
+void *joylink_ota_task(void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 440 - 0
joylink/example/joylink_extern_sub_dev.c

@@ -0,0 +1,440 @@
+/* --------------------------------------------------
+ * @brief: 
+ *
+ * @version: 1.0
+ * --------------------------------------------------
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "joylink.h"
+#include "joylink_packets.h"
+#include "joylink_json.h"
+#include "joylink_extern_json.h"
+#include "joylink_extern_sub_dev.h"
+#include "joylink_utils.h"
+
+#define JL_MAX_SUB 30
+
+int sub_dev_numb = 4;
+
+JLSubDevData_t _g_sub_dev[JL_MAX_SUB] = {
+#if 1
+    	{.mac = "AA0011223344", .type = E_JLDEV_TYPE_SUB, .uuid = "3C939C", .lancon = 1, .cmd_tran_type = 1, .state = 1, .protocol = 1, .subNoSnapshot = E_SNAPSHOT_NO, .devAuthValue = "96f730bd1a6f9fcc2d40cfad0c0d8b9c"},
+	{.mac = "AA0011223355", .type = E_JLDEV_TYPE_SUB, .uuid = "3C939C", .lancon = 1, .cmd_tran_type = 1, .state = 1, .protocol = 1, .subNoSnapshot = E_SNAPSHOT_NO, .devAuthValue = "9401a7005788efd93c25b46fdaf169ad"},
+	{.mac = "AA0011223399", .type = E_JLDEV_TYPE_SUB, .uuid = "3C939C", .lancon = 1, .cmd_tran_type = 1, .state = 1, .protocol = 1, .subNoSnapshot = E_SNAPSHOT_NO, .devAuthValue = "880c86bcd07b1648367c332cb2a1463a"},
+	{.mac = "AA00112233AA", .type = E_JLDEV_TYPE_SUB, .uuid = "3C939C", .lancon = 1, .cmd_tran_type = 1, .state = 1, .protocol = 1, .subNoSnapshot = E_SNAPSHOT_NO, .devAuthValue = "4445c58c13659307f298ec51444a7201"}
+#endif
+#if 0
+    	{.mac = "AA0011223344", .type = E_JLDEV_TYPE_SUB, .uuid = "4E4638", .lancon = 1, .cmd_tran_type = 1, .state = 1, .protocol = 1, .subNoSnapshot = E_SNAPSHOT_NO, .devAuthValue = "96f730bd1a6f9fcc2d40cfad0c0d8b9c"},
+	{.mac = "AA0011223355", .type = E_JLDEV_TYPE_SUB, .uuid = "4E4638", .lancon = 1, .cmd_tran_type = 1, .state = 1, .protocol = 1, .subNoSnapshot = E_SNAPSHOT_NO, .devAuthValue = "9401a7005788efd93c25b46fdaf169ad"},
+	{.mac = "AA0011223366", .type = E_JLDEV_TYPE_SUB, .uuid = "4E4638", .lancon = 1, .cmd_tran_type = 1, .state = 1, .protocol = 1, .subNoSnapshot = E_SNAPSHOT_NO, .devAuthValue = "844cd9ab1f28140d8d60bd389b660154"},
+	{.mac = "AA0011223377", .type = E_JLDEV_TYPE_SUB, .uuid = "4E4638", .lancon = 1, .cmd_tran_type = 1, .state = 1, .protocol = 1, .subNoSnapshot = E_SNAPSHOT_NO, .devAuthValue = "006b728b172e3e204e16380398ffe9da"},
+	{.mac = "AA0011223399", .type = E_JLDEV_TYPE_SUB, .uuid = "514C0E", .lancon = 1, .cmd_tran_type = 1, .state = 1, .protocol = 1, .subNoSnapshot = E_SNAPSHOT_NO, .devAuthValue = "880c86bcd07b1648367c332cb2a1463a"},
+	{.mac = "AA00112233AA", .type = E_JLDEV_TYPE_SUB, .uuid = "514C0E", .lancon = 1, .cmd_tran_type = 1, .state = 1, .protocol = 1, .subNoSnapshot = E_SNAPSHOT_NO, .devAuthValue = "4445c58c13659307f298ec51444a7201"},
+	{.mac = "AA00112233BB", .type = E_JLDEV_TYPE_SUB, .uuid = "514C0E", .lancon = 1, .cmd_tran_type = 1, .state = 1, .protocol = 1, .subNoSnapshot = E_SNAPSHOT_NO, .devAuthValue = "a2e3c63557d94575015ac713dff54b3d"},
+	{.mac = "AA00112233DD", .type = E_JLDEV_TYPE_SUB, .uuid = "514C0E", .lancon = 1, .cmd_tran_type = 1, .state = 1, .protocol = 1, .subNoSnapshot = E_SNAPSHOT_NO, .devAuthValue = "dbc499de2517fe99e7246a5f9b32ef54"}
+#endif
+};
+
+#ifdef _SAVE_FILE_
+char *sub_file = "joylink_subdev_info.txt";
+
+void joylink_dev_sub_data_save(void)
+{
+	FILE *outfile;
+	int i;
+	
+	if(sub_dev_numb <= 0){
+		system("rm joylink_subdev_info.txt");
+		sub_dev_numb = 0;
+		return;
+	}
+		
+	outfile = fopen(sub_file, "wb+" );
+	for(i = 0; i < JL_MAX_SUB; i++){
+		if(strlen(_g_sub_dev[i].uuid) > 0)
+			fwrite(&_g_sub_dev[i], sizeof(JLSubDevData_t), 1, outfile);
+	}
+	fclose(outfile);
+}
+
+void joylink_dev_sub_data_read(void)
+{
+	int ret;
+	FILE *infile;
+
+	infile = fopen(sub_file, "rb+");
+	if(infile > 0){
+		sub_dev_numb = 0;
+		memset(_g_sub_dev, 0, sizeof(JLSubDevData_t) * JL_MAX_SUB);
+
+		while(1){
+			ret = fread(&_g_sub_dev[sub_dev_numb], sizeof(JLSubDevData_t), 1, infile);
+			if(ret <= 0){
+				fclose(infile);
+				break;
+			}
+			sub_dev_numb++;
+		}
+	}
+}
+#endif
+
+/**
+ * brief: 
+ *
+ * @Param: dev
+ * @Param: num
+ *
+ * @Returns: 
+ */
+
+int error_auth_flag = 0;
+
+E_JLRetCode_t
+joylink_dev_sub_save_auth_value(char *uuid, char *mac, char *auth_value)
+{
+    int ret = E_RET_ERROR;
+    int i; 
+
+    for(i = 0; i < JL_MAX_SUB; i++){
+        if(!strcmp(uuid, _g_sub_dev[i].uuid) && !strcmp(mac, _g_sub_dev[i].mac)){            
+	    memset(_g_sub_dev[i].devAuthValue, 0, 33);
+
+	    joylink_util_byte2hexstr(auth_value, 16, _g_sub_dev[i].devAuthValue, 33);
+	    printf("SubDev value: %s %s\n", mac, _g_sub_dev[i].devAuthValue);
+            ret = E_RET_OK;
+	    break;
+        }
+    }
+#ifdef _SAVE_FILE_
+	joylink_dev_sub_data_save();
+#endif
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: dev
+ * @Param: num
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_sub_add(JLSubDevData_t *dev, int num)
+{
+    /**
+     *FIXME: todo
+     */
+    int i = 0;
+    int ret = E_RET_OK;
+
+	for(i = 0; i < JL_MAX_SUB; i++){
+		if(!strcmp(dev->uuid, _g_sub_dev[i].uuid) && !strcmp(dev->mac, _g_sub_dev[i].mac))
+			return ret;
+	}
+	for(i = 0; i < JL_MAX_SUB; i++){
+	    if(strlen(_g_sub_dev[i].uuid) == 0){
+	        memcpy(&_g_sub_dev[i], dev, sizeof(JLSubDevData_t));
+		sub_dev_numb++;
+		break;
+	    }
+	}
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: dev
+ * @Param: num
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_sub_dev_del(char *feedid)
+{
+    /**
+     *FIXME: todo
+     */
+    int ret = E_RET_OK;
+	int i = 0;
+	
+	for(i = 0; i < JL_MAX_SUB; i++){
+	    if(!strcmp(feedid, _g_sub_dev[i].feedid)){
+	        memset(&_g_sub_dev[i], 0, sizeof(JLSubDevData_t));
+		sub_dev_numb--;
+		break;
+	    }
+	}
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: feedid
+ * @Param: dev
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_sub_get_by_feedid(char *feedid, JLSubDevData_t *dev)
+{
+    /**
+     *FIXME: todo
+     */
+    int ret = E_RET_ERROR;
+    int i; 
+
+    for(i = 0; i < JL_MAX_SUB; i++){
+        if(!strcmp(feedid, _g_sub_dev[i].feedid)){
+            memcpy(dev, &_g_sub_dev[i], sizeof(JLSubDevData_t));
+            ret = E_RET_OK;
+	    break;
+        }
+    }
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: uuid
+ * @Param: mac
+ * @Param: dev
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_sub_dev_get_by_uuid_mac(char *uuid, char *mac, JLSubDevData_t *dev)
+{
+    /**
+     *FIXME: todo
+     */
+    int ret = E_RET_OK;
+    int i; 
+
+    for(i = 0; i < JL_MAX_SUB; i++){
+        if(!strcmp(uuid, _g_sub_dev[i].uuid) && !strcmp(mac, _g_sub_dev[i].mac)){
+            memcpy(dev, &_g_sub_dev[i], sizeof(JLSubDevData_t));
+            ret = E_RET_OK;
+	    break;
+        }
+    }
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: uuid
+ * @Param: mac
+ * @Param: dev
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_sub_update_keys_by_uuid_mac(char *uuid, char *mac, JLSubDevData_t *dev)
+{
+    /**
+     *FIXME: todo
+     */
+    int ret = E_RET_ERROR;
+    int i; 
+
+    for(i = 0; i < JL_MAX_SUB; i++){
+        if(!strcmp(uuid, _g_sub_dev[i].uuid) && !strcmp(mac, _g_sub_dev[i].mac)){
+            memcpy(_g_sub_dev[i].accesskey, dev->accesskey, sizeof(dev->accesskey));
+            memcpy(_g_sub_dev[i].localkey, dev->localkey, sizeof(dev->localkey));
+            memcpy(_g_sub_dev[i].feedid, dev->feedid, sizeof(dev->feedid));
+
+	    _g_sub_dev[i].lancon = dev->lancon;
+            _g_sub_dev[i].cmd_tran_type = dev->cmd_tran_type;
+    
+            _g_sub_dev[i].state = E_JLDEV_ONLINE;
+            ret = E_RET_OK;
+	    break;
+        }
+    }
+#ifdef _SAVE_FILE_
+	joylink_dev_sub_data_save();
+#endif
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: feedid
+ * @Param: version
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_sub_version_update(char *feedid, int version)
+{
+    /**
+     *FIXME: todo
+     */
+    int ret = E_RET_ERROR;
+    int i; 
+
+    for(i = 0; i < JL_MAX_SUB; i++){
+        if(!strcmp(feedid, _g_sub_dev[i].feedid)){
+            _g_sub_dev[i].version = version;
+            ret = E_RET_OK;
+	    break;
+        }
+    }
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: count
+ * @Param: scan_type
+ *
+ * @Returns: 
+ */
+
+static char read_flag = 0;
+
+JLSubDevData_t *
+joylink_dev_sub_devs_get(int *count)
+{
+    /**
+     *FIXME: todo must lock
+     */
+    int i = 0, j = 0, sum = 0; 
+    JLSubDevData_t *devs = NULL;
+
+    #ifdef _SAVE_FILE_
+    if(read_flag == 0){
+	read_flag = 1;
+	joylink_dev_sub_data_read();
+    }
+    #endif
+    
+    sum = sub_dev_numb;
+    devs = (JLSubDevData_t *)malloc(sizeof(JLSubDevData_t) * sum);
+    bzero(devs, sizeof(JLSubDevData_t) * sum);
+    if(devs != NULL){
+        for(i = 0; i < JL_MAX_SUB; i++){
+		if(strlen(_g_sub_dev[i].uuid) != 0){			
+            		memcpy(&devs[j], &_g_sub_dev[i], sizeof(JLSubDevData_t));
+			j++;
+		}
+        }
+    }
+   
+    *count = sum;
+    return devs;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: cmd
+ * @Param: cmd_len
+ * @Param: feedid
+ *
+ * @Returns: 
+ */
+
+static int sub_power = 0;
+
+E_JLRetCode_t
+joylink_dev_sub_ctrl(const char* cmd, int cmd_len, char* feedid)
+{
+    /**
+     *FIXME: todo must lock
+     */
+    log_debug("cmd:%s:feedid:%s\n", cmd, feedid);
+    int ret = E_RET_OK;
+
+    if(sub_power == 0)
+	sub_power = 1;
+    else if(sub_power == 1)
+	sub_power = 0;
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: feedid
+ * @Param: out_len
+ *
+ * @Returns: 
+ */
+
+
+char *
+joylink_dev_sub_get_snap_shot(char *feedid, int *out_len)
+{
+    /**
+     *FIXME: todo must lock
+     */
+    char on[] = "{\"code\": 0,  \"streams\": [{ \"current_value\": \"1\", \"stream_id\": \"power\" }]}";
+    char off[] = "{\"code\": 0,  \"streams\": [{ \"current_value\": \"0\", \"stream_id\": \"power\" }]}";
+
+    char *tp = 	NULL;
+
+    char *ss = (char*)malloc(100);
+
+    if(sub_power == 0)
+	tp = off;
+    else if(sub_power == 1)
+	tp = on;
+
+    if(ss != NULL){
+        memset(ss, 0, 100);
+        memcpy(ss, tp, strlen(tp)); 
+        *out_len = strlen(tp);
+    }
+
+    return ss;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: feedid
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_sub_unbind(const char *feedid)
+{
+    /**
+     *FIXME: todo must lock
+     */
+    int ret = E_RET_OK;
+	int i = 0;
+	
+    log_debug("feedid:%s\n", feedid);
+	
+	for(i = 0; i < JL_MAX_SUB; i++){
+		if(!strcmp(feedid, _g_sub_dev[i].feedid)){
+			//_g_sub_dev[i].state = 2;//E_JLDEV_UNBIND;
+			memset(&_g_sub_dev[i], 0, sizeof(JLSubDevData_t));
+			sub_dev_numb--;
+			break;
+		}
+	}
+#ifdef _SAVE_FILE_
+	joylink_dev_sub_data_save();
+#endif
+
+    return ret;
+}

+ 142 - 0
joylink/example/joylink_extern_sub_dev.h

@@ -0,0 +1,142 @@
+#ifndef _JOYLINK_EXTERN_SUB_DEV_H_
+#define _JOYLINK_EXTERN_SUB_DEV_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif /* __cplusplus */
+
+#include "joylink.h"
+#include "../joylink/joylink_sub_dev.h"
+
+/*
+ * user set
+ */
+
+#define DEV_AUTH_VALUE    0          // 0: disable; 1: enable.
+#define DEV_BATCH_BIND    0          // 0: disable; 1; enable.
+
+#define SUBDEV_UUID       "4E4638"
+#define SUBDEV_MAC        "AA0011223366"
+#define SUBDEV_LICENSE    "d91fa7fc6ba19811747d9d6ddc0971f2"
+
+/*---------------- sub dev api ---------------*/
+
+/**
+ * brief: 
+ *
+ * @Param: dev
+ * @Param: num
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_sub_add(JLSubDevData_t *dev, int num);
+
+/**
+ * brief: 
+ *
+ * @Param: dev
+ * @Param: num
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_sub_dev_del(char *feedid);
+
+/**
+ * brief: 
+ *
+ * @Param: feedid
+ * @Param: dev
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_sub_get_by_feedid(char *feedid, JLSubDevData_t *dev);
+/**
+ * brief: 
+ *
+ * @Param: feedid
+ * @Param: dev
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_sub_version_update(char *feedid, int version);
+/**
+ * brief: 
+ *
+ * @Param: uuid
+ * @Param: mac
+ * @Param: dev
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_sub_dev_get_by_uuid_mac(char *uuid, char *mac, JLSubDevData_t *dev);
+
+/**
+ * brief: 
+ *
+ * @Param: uuid
+ * @Param: mac
+ * @Param: dev
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_sub_update_keys_by_uuid_mac(char *uuid, char *mac, JLSubDevData_t *dev);
+
+/**
+ * brief: 
+ *
+ * @Param: count
+ * @Param: scan_type
+ *
+ * @Returns: 
+ */
+JLSubDevData_t *
+joylink_dev_sub_devs_get(int *count);
+
+/**
+ * brief: 
+ *
+ * @Param: cmd
+ * @Param: cmd_len
+ * @Param: feedid
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_sub_ctrl(const char* cmd, int cmd_len, char* feedid);
+
+/**
+ * brief: 
+ *
+ * @Param: feedid
+ * @Param: out_len
+ *
+ * @Returns: 
+ */
+char *
+joylink_dev_sub_get_snap_shot(char *feedid, int *out_len);
+
+/**
+ * brief: 
+ *
+ * @Param: feedid
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t
+joylink_dev_sub_unbind(const char *feedid);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+

+ 81 - 0
joylink/example/joylink_extern_user.c

@@ -0,0 +1,81 @@
+/* --------------------------------------------------
+ * @file: joylink_extern_tool.C
+ *
+ * @brief: 
+ *
+ * @version: 2.0
+ *
+ * @date: 2018/07/26 PM
+ *
+ * --------------------------------------------------
+ */
+
+#include <stdio.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "joylink_extern_user.h"
+
+int file_fd = -1;
+
+int
+joylink_memory_init(void *index, int flag)
+{
+	char *save_path = (char *)index;
+
+	if(file_fd > 0)	
+		return -1;
+
+	//printf("save_path: %s\n", save_path);
+	
+	if(flag == MEMORY_WRITE){
+		file_fd = open(save_path, O_WRONLY | O_CREAT | O_TRUNC, 0777);
+		if(file_fd < 0){
+			printf("Open file error!\n");
+			return -1;
+		}
+	}
+	else if(flag == MEMORY_READ){
+		file_fd = open(save_path, O_RDONLY | O_CREAT, 0777);
+		if(file_fd < 0){
+			printf("Open file error!\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+int
+joylink_memory_write(int offset, char *data, int len)
+{
+	if(file_fd < 0 || data == NULL)	
+		return -1;
+
+	return write(file_fd, data, len);
+}
+
+int
+joylink_memory_read(int offset, char *data, int len)
+{
+	if(file_fd < 0 || data == NULL)	
+		return -1;
+
+	return read(file_fd, data, len);
+}
+
+int
+joylink_memory_finish(void)
+{
+	if(file_fd < 0)
+		return -1;
+
+	close(file_fd);
+	file_fd = -1;
+	return 0;
+}
+
+
+

+ 34 - 0
joylink/example/joylink_extern_user.h

@@ -0,0 +1,34 @@
+/* --------------------------------------------------
+ * @file: joylink_extern_tool.h
+ *
+ * @brief: 
+ *
+ * @version: 2.0
+ *
+ * @date: 2018/07/26 PM
+ *
+ * --------------------------------------------------
+ */
+
+#ifndef _JOYLINK_EXTERN_TOOL_H_
+#define _JOYLINK_EXTERN_TOOL_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#define MEMORY_WRITE  0
+#define MEMORY_READ   1
+
+int joylink_memory_init(void *index, int flag);
+
+int joylink_memory_write(int offset, char *data, int len);
+int joylink_memory_read(int offset, char *data, int len);
+
+int joylink_memory_finish(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 69 - 0
joylink/joylink/Makefile

@@ -0,0 +1,69 @@
+include ../Makefile.rule
+
+HEADERS = $(wildcard *.h)
+ORG_SOURCES = $(wildcard *.c)
+
+ifeq (${DEV_REQ_ACTIVE_EN}, yes)
+OUT_SRC =  test.c
+else
+OUT_SRC = test.c joylink_dev_active.c joylink_cloud_log.c
+endif
+
+SOURCES=$(filter-out ${OUT_SRC}, ${ORG_SOURCES})
+OBJS = $(patsubst %.c, %.o, $(SOURCES))
+
+LIBNAME = $(strip ${shell pwd |xargs basename})
+
+INCLUDES += -I${PROJECT_ROOT_PATH}/json
+INCLUDES += -I${PROJECT_ROOT_PATH}/joylink
+INCLUDES += -I${PROJECT_ROOT_PATH}/example
+INCLUDES += -I${PROJECT_ROOT_PATH}/auth
+INCLUDES += -I${PROJECT_ROOT_PATH}/list
+INCLUDES += -I${PROJECT_ROOT_PATH}/softap
+
+ifeq ($(TARGET_SRC), extern)
+STATIC_LIBS += ${TARGET_LIB}/libextern.a
+else
+#STATIC_LIBS += ${TARGET_LIB}/libexample.a
+endif
+
+#STATIC_LIBS += ${TARGET_LIB}/libauth.a
+#STATIC_LIBS += ${TARGET_LIB}/libjson.a
+#STATIC_LIBS += ${TARGET_LIB}/liblist.a
+STATIC_LIBS += ${TARGET_LIB}/libjoylinksdk.a
+LIBS += 
+
+ifeq (${ARCH}, x86)  
+#all:${OBJS} liba libso jt test
+all:${OBJS} liba libso 
+else
+#all:${OBJS} liba jt
+all:${OBJS} liba 
+endif
+
+.SUFFIXES: .c .o
+.c.o:
+	${CC} ${CFLAGS} -c $(INCLUDES)  $*.c
+
+liba:${OBJS}
+	${AR} -crs lib${LIBNAME}.a ${OBJS}
+	${MV} lib${LIBNAME}.a ${TARGET_LIB}
+
+libso:${OBJS}
+	${CC}  ${OBJS} -shared -fPIC -o lib${LIBNAME}.so
+	${MV} lib${LIBNAME}.so ${TARGET_LIB} 
+
+jt:
+	${CC} -D_TEST_ test.c ${OBJS} -o $@ ${CFLAGS} ${INCLUDES} ${STATIC_LIBS} ${LIBS} 
+	${MV} $@ ${TARGET_BIN} 
+
+test:
+	${CC} -D_TEST_ test.c joylink_utils.c -o $@ ${CFLAGS} ${INCLUDES} ${STATIC_LIBS} ${LIBS} 
+
+clean:
+	${RM} *.o *.so *.a test ${TARGET_BIN}/jt
+
+distclean:clean
+	${RM} ./*.a ./*.so ${TARGET_LIB}/lib${LIBNAME}.*
+
+.PHONY:all clean test jt

+ 427 - 0
joylink/joylink/joylink.h

@@ -0,0 +1,427 @@
+#ifndef _JOYLINK_H_
+#define _JOYLINK_H_
+    
+#ifdef __cplusplus
+extern "C"{
+#endif /* __cplusplus */
+
+#include "joylink_log.h"
+#include "auth/joylink_auth_uECC.h"
+#include "joylink_ret_code.h"
+#include "joylink_extern.h"
+
+#define _VERSION_  "2.0.19"
+#define _RELEASE_TIME_  "2019_10_12"
+
+#define JL_MAX_PACKET_LEN	    (1400)
+#define JL_MAX_IP_LEN               (20)
+#define JL_MAX_MAC_LEN              (128)
+#define JL_MAX_UUID_LEN             (10)
+#define JL_MAX_FEEDID_LEN           (33)
+#define JL_MAX_KEY_BIN_LEN          (21)
+#define JL_MAX_KEY_STR_LEN          (21*2+1)
+#define JL_MAX_DBG_LEN              (128)
+#define JL_MAX_OPT_LEN              (128)
+#define JL_MAX_SERVER_HB_LOST       (3)
+#define JL_MAX_SERVER_NUM           (5)
+#define JL_MAX_SERVER_NAME_LEN      (128)
+#define JL_MAX_SUB_DEV              (4)
+#define JL_MAX_VERSION_NAME_LEN     (100)
+#define JL_MAX_URL_LEN              (100)
+#define JL_MAX_MSG_LEN 		    (1024)
+#define JL_MAX_STATUS_DESC_LEN      (100)
+#define JL_MAX_CUT_PACKET_LEN       (1000)
+#define JL_MAX_ACKEY_LEN            (33)
+#define JL_MAX_SESSION_KEY_LEN      (33)
+#define JL_APP_RANDOM_LEN           (65)
+
+#define JL_SERVER_ST_INIT           (0)
+#define JL_SERVER_ST_AUTH           (1)
+#define JL_SERVER_ST_WORK           (2)
+
+#define JL_BZCODE_GET_SNAPSHOT      (1004)
+#define JL_BZCODE_CTRL              (1002)
+#define JL_BZCODE_UNBIND            (1060)
+
+#pragma pack(1)
+typedef struct {
+	unsigned int magic;
+	unsigned int len;
+	unsigned int enctype;
+	unsigned char checksum;
+}JLCommonHeader_t;
+
+typedef struct {
+	unsigned int type;
+	unsigned char cmd[2];
+}JLCmdHeader_t;
+
+typedef struct {
+	unsigned int	magic;
+	unsigned short	optlen;
+	unsigned short	payloadlen;
+
+	unsigned char	version;
+	unsigned char	type;
+	unsigned char	total;
+	unsigned char	index;
+
+	unsigned char	enctype;
+	unsigned char	reserved;
+	unsigned short	crc;
+}JLPacketHead_t;
+#pragma pack()
+
+#define JL_MAX_PHEAD_LEN		    (sizeof(JLPacketHead_t))
+#define JL_MAX_PAYLOAD_LEN		    (JL_MAX_PACKET_LEN - JL_MAX_PHEAD_LEN - 20) 
+#define JL_MAX_AES_EXTERN           (20) 
+
+typedef enum {
+	PT_UNKNOWN =        0,
+	PT_SCAN =           1,
+	PT_WRITE_ACCESSKEY = 2,
+	PT_JSONCONTROL =    3,
+	PT_SCRIPTCONTROL =  4,
+
+	PT_OTA_ORDER =      7,
+	PT_OTA_UPLOAD =     8,
+	PT_AUTH =           9,
+	PT_BEAT =           10,
+	PT_SERVERCONTROL =  11,
+	PT_UPLOAD =         12,
+	PT_TIME_TASK =      13,
+	PT_MODEL_CODE =     17,
+
+	PT_SUB_AUTH =       102,
+	PT_SUB_LAN_JSON =   103,
+	PT_SUB_LAN_SCRIPT = 104,
+	PT_SUB_ADD =        105,
+	PT_SUB_HB  =        110,
+	PT_SUB_CLOUD_CTRL = 111,
+	PT_SUB_UPLOAD =     112,
+	PT_SUB_UNBIND =     113,
+
+    PT_AGENT_ADD_SUBDEV = 200,
+    PT_AGENT_DEL_SUBDEV = 201,
+    PT_AGENT_GET_DEV_LIST = 202,
+
+    PT_AGENT_AUTH =     211,
+    PT_AGENT_HB   =     212,
+    PT_AGENT_UPLOAD     =     213,
+    PT_AGENT_DEV_CTRL   =     220
+}E_PacketType;
+
+typedef enum {
+    BIZ_CODE_TIME_TASK_CHECK_REQ                =1090,
+    BIZ_CODE_TIME_TASK_CHECK_RSP                =190,
+    BIZ_CODE_TIME_TASK_ADD_REQ                  =1091,
+    BIZ_CODE_TIME_TASK_ADD_RSP                  =191,
+    BIZ_CODE_TIME_TASK_UPD_REQ                  =1092,
+    BIZ_CODE_TIME_TASK_UPD_RSP                  =192,
+    BIZ_CODE_TIME_TASK_DEL_REQ                  =1093,
+    BIZ_CODE_TIME_TASK_DEL_RSP                  =193,
+    BIZ_CODE_TIME_TASK_GET_REQ                  =1094,
+    BIZ_CODE_TIME_TASK_GET_RSP                  =194,
+    BIZ_CODE_TIME_TASK_STOP_REQ                 =1095,
+    BIZ_CODE_TIME_TASK_STOP_RSP                 =195,
+    BIZ_CODE_TIME_TASK_RESTART_REQ              =1096,
+    BIZ_CODE_TIME_TASK_RESTART_RSP              =196,
+    BIZ_CODE_TIME_TASK_REPORT_RESULT_REQ        =1097,
+    BIZ_CODE_TIME_TASK_REPORT_RESULT_RSP        =197,
+    BIZ_CODE_TIME_TASK_REPORT_NEW_TASK_REQ      =1098,
+    BIZ_CODE_TIME_TASK_REPORT_NEW_TASK_RSP      =198,
+    BIZ_CODE_TIME_TASK_REPORT_DEL_TASK_REQ      =1099,
+    BIZ_CODE_TIME_TASK_REPORT_DEL_TASK_RSP      =199,
+    BIZ_CODE_TIME_TASK_REPORT_UPDATE_TASK_REQ   =1100,
+    BIZ_CODE_TIME_TASK_REPORT_UPDATE_TASK_RSP   =200,
+    BIZ_CODE_TIME_TASK_REPORT_SNAPSHOT_TASK_REQ =1101,
+    BIZ_CODE_TIME_TASK_REPORT_SNAPSHOT_TASK_RSP =201 
+}E_TIMETASK_BIZCODE;
+
+typedef enum {
+	ET_NOTHING = 0,
+	ET_PSKAES = 1,
+	ET_ECDH = 2,
+	ET_ACCESSKEYAES = 3,
+	ET_SESSIONKEYAES = 4
+}E_EncType;
+
+typedef struct {
+	int version;	
+	E_PacketType type;
+}JLPacketParam_t;
+
+typedef enum _tran_type{
+    E_SUBDEV_TRANS_TYPE_WIFI = 0,
+    E_SUBDEV_TRANS_TYPE_ZIGBEE = 1,
+    E_SUBDEV_TRANS_TYPE_BLE = 2,
+    E_SUBDEV_TRANS_TYPE_433 = 3
+}E_JLSubDevTransType_t;
+
+typedef enum _cmd_type{
+    E_CMD_TYPE_JSON = 0,
+    E_CMD_TYPE_LUA_SCRIPT = 1
+}E_JLCMDType_t;
+
+typedef enum _lan_ctrl_type{
+    E_LAN_CTRL_DISABLE = 0,
+    E_LAN_CTRL_ENABLE = 1
+}E_JLLanCtrlType_t;
+
+typedef enum _lan_snap_short{
+    E_SNAPSHOT_YES = 0,
+    E_SNAPSHOT_NO = 1
+}E_JLLanSnapShort_t;
+
+typedef struct {
+	int isUsed;
+	short version;
+	char ip[JL_MAX_IP_LEN];
+	int port;		
+
+	char mac[JL_MAX_MAC_LEN];
+	char uuid[JL_MAX_UUID_LEN];
+	int lancon;			            // 1 suport Lan 
+	int cmd_tran_type;			    // 0:bin, 1:Lua, 2:Js
+	int devtype;
+	int protocol;                   // 0:WIFI 1:zigbee 2:bluetooth 3:433
+
+	char feedid[JL_MAX_FEEDID_LEN];
+	char accesskey[33];
+    	char localkey[33];
+
+	char prikey[65];
+
+	char joySdkVersion[8]; 
+    	char noSnapshot;
+
+	uint8_t pubkeyC[JL_MAX_KEY_BIN_LEN];
+	char pubkeyS[JL_MAX_KEY_STR_LEN];
+
+	char devdbg[JL_MAX_DBG_LEN];
+	char servropt[JL_MAX_OPT_LEN];
+
+	uint8_t sharedkey[uECC_BYTES];
+	uint8_t sessionKey[33];
+
+	char joylink_server[JL_MAX_SERVER_NAME_LEN];
+	int server_port;
+
+	char javs_server[64];
+	char opengw_server[64];
+	char router_server[64];
+
+	char CID[10];
+	char firmwareVersion[10];
+	char modelCode[66];
+	char is_actived;
+
+	int batchBind;
+
+	char devSn[65];
+
+	char ps_th_d2c[1024];
+	char ps_th_c2d[1024];
+
+	unsigned int crc32;
+}JLPInfo_t;
+
+#define IDT_D_PK_LEN            (34)
+#define IDT_C_PK_LEN            (67)
+#define IDT_D_SIG_LEN           (65)
+#define IDT_D_RNAD_LEN          (33)
+#define IDT_F_SIG_LEN           (65)
+#define IDT_F_PK_LEN            (34)
+#define IDT_A_RNAD_SIG_LEN      (33)
+#define IDT_C_SIG_LEN           (65)
+
+typedef struct {
+    int      type;
+	char	 cloud_pub_key[IDT_C_PK_LEN];
+	char	 pub_key[IDT_D_PK_LEN];
+	char	 sig[IDT_D_SIG_LEN];
+	char	 rand[IDT_D_RNAD_LEN];
+	char	 f_sig[IDT_F_SIG_LEN];
+	char	 f_pub_key[IDT_F_PK_LEN];
+	char     a_rand_sig[IDT_A_RNAD_SIG_LEN];		
+	char     cloud_sig[IDT_C_SIG_LEN];		
+}jl2_d_idt_t;
+
+typedef struct {
+    JLPInfo_t jlp;
+    int server_socket;
+    int lan_socket;
+    int server_st;	                // 0:Socket init 1:Auth 2:HB
+    int hb_lost_count;
+    short local_port;
+
+    uint8_t dev_detail[JL_MAX_PACKET_LEN];
+    uint8_t send_buff[JL_MAX_PACKET_LEN];
+
+    /**
+     *only for package bigger than 1400
+     */
+    char *send_p;
+    int payload_total;
+    jl2_d_idt_t idt;
+
+    int cloud_serial;
+    int cloud_timestamp;
+
+    int model_code_flag;
+}JLDevice_t;
+
+typedef enum _dev_type{
+    E_JLDEV_TYPE_NORMAL = 0,
+    E_JLDEV_TYPE_GW = 1,
+    E_JLDEV_TYPE_SUB = 2,
+    E_JLDEV_TYPE_AGENT_GW = 3
+}E_JLDevType_t;
+
+typedef enum _dev_state{
+    E_JLDEV_ONLINE = 0,   // dev on line
+    E_JLDEV_OFFLINE = 1,  // dev offline
+    E_JLDEV_UNBIND = 2,   // dev unbind
+    E_JLDEV_UNKNOW = 3    // dev status unknow
+}E_JLDevState_t;
+
+typedef struct {
+    JLPInfo_t jlp;
+    E_JLDevType_t type;
+    int state;
+    char msg[250];
+    void *data;
+}JLDevInfo_t;
+
+typedef struct __dev_enable{
+    char feedid[34];
+    char accesskey[34];
+    char localkey[34];
+    char productuuid[10];
+    char lancon;
+    char cmd_tran_type;
+    char joylink_server[JL_MAX_SERVER_NAME_LEN];
+    int server_port;
+    char javs_server[64];
+    char opengw_server[64];
+    char router_server[64];
+    char opt[JL_MAX_SERVER_NAME_LEN];
+    char cloud_sig[64 * 2 + 1];
+
+    char ps_th_c2d[1024];
+}DevEnable_t;
+
+typedef enum __scan_type{
+    E_SCAN_TYPE_ALL = 0,
+    E_SCAN_TYPE_WAITCONF = 1,
+    E_SCAN_TYPE_CONFIGED = 2
+}E_ScanType_t;
+
+typedef enum _protocol_rec_st{
+    E_PT_REV_ST_MAGIC = 0,
+    E_PT_REV_ST_HEAD = 1,
+    E_PT_REV_ST_DATA = 2,
+    E_PT_REV_ST_END = 3
+}E_PT_REV_ST_t;
+
+typedef struct __lan_scan{
+    char uuid[JL_MAX_UUID_LEN];
+    E_ScanType_t type;
+    char dev_sign[JL_APP_RANDOM_LEN*2];
+    char app_rand[JL_APP_RANDOM_LEN];
+}DevScan_t;
+
+typedef struct {
+    unsigned int timestamp;
+	unsigned int random_unm;
+}JLAuth_t;
+
+typedef struct {
+	unsigned int timestamp;
+	unsigned int random_unm;
+	unsigned char session_key[];
+}JLAuthRsp_t;
+
+typedef struct {
+	unsigned int timestamp; 
+	unsigned short verion;
+	unsigned short rssi;
+}JLHearBeat_t;
+
+typedef struct {
+	unsigned int timestamp;
+	unsigned int code;
+}JLHearBeatRst_t;
+
+typedef struct {
+	unsigned int timestamp;
+	unsigned int biz_code;
+	unsigned int serial;
+    char feedid[JL_MAX_FEEDID_LEN];
+	unsigned char cmd[];
+}JLContrl_t;
+
+typedef struct {
+	unsigned int timestamp;
+	unsigned int biz_code;
+	unsigned int serial;
+	unsigned char resp_length[4];
+	unsigned char resp[1];
+	unsigned char streams[1];
+}JLContrlRsp_t;
+
+typedef struct {
+    unsigned int timestamp;
+    unsigned char data[2];
+}JLDataUpload_t;
+
+typedef struct {
+	unsigned int timestamp;
+	unsigned int code;
+}JLDataUploadRsp_t;
+
+typedef struct{
+	int serial;
+    char feedid[JL_MAX_FEEDID_LEN];
+    char productuuid[JL_MAX_UUID_LEN];
+    int version;
+    char versionname[JL_MAX_VERSION_NAME_LEN];
+    unsigned int crc32;
+    char url[JL_MAX_URL_LEN];
+}JLOtaOrder_t;
+
+typedef struct{
+    char feedid[JL_MAX_FEEDID_LEN];
+    char productuuid[JL_MAX_UUID_LEN];
+    int status;
+    char status_desc[JL_MAX_STATUS_DESC_LEN];
+    int progress;
+}JLOtaUpload_t;
+
+typedef struct {
+	int code;
+	char msg[JL_MAX_MSG_LEN];
+}JLOtaUploadRsp_t;
+
+typedef struct {
+	char feedid[JL_MAX_FEEDID_LEN];
+	char ackey[33];
+}JLAddAgentDev_t;
+
+typedef enum{
+	run_status_fail = -1,
+	run_status_ok 	=  0
+}JLRunStatus_t;
+
+void joylink_server_ota_status_upload_req(JLOtaUpload_t *otaUpload);
+int joylink_active_write_key(DevEnable_t *de,char *randstr);
+
+extern JLDevice_t  *_g_pdev;
+
+typedef struct sockaddr SOCKADDR;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif

+ 346 - 0
joylink/joylink/joylink_cloud_log.c

@@ -0,0 +1,346 @@
+#include <stdint.h>
+#include <string.h>
+#include "joylink.h"
+#include "joylink_log.h"
+#include "cJSON.h"
+#include "joylink_extern.h"
+#include "joylink_auth_md5.h"
+#include "joylink_utils.h"
+#include "joylink_dev_active.h"
+#define HTTPS_POST_LOG_HEADER "POST /dev HTTP/1.1\r\nHost: %s\r\nAccept: */*\r\ncontent-type: application/x-www-form-urlencoded; charset=utf-8\r\nContent-Length:"
+
+#define METHON_CLOUD_LOG     	"jingdong.smart.api.device.logreport"
+
+
+#define LOG_DATA_BODY      		"360buy_param_json"
+#define LOG_DATA_BIZID			"biz_id"
+
+#define LOG_DATA_DEVICE_ID      "device_id"
+#define LOG_DATA_METHOD    		"method"
+#define LOG_DATA_UUID           "pro_uuid"
+#define LOG_DATA_RANDOM      	"random"
+#define LOG_DATA_TIMESTAMP   	"timestamp"
+
+#ifndef JLP_UUID
+#define JLP_UUID JOYLINK_SAMPLE_UUID
+#endif
+
+static char gLogURLStr[32+1] = {0};
+static char gLogTokenStr[16+1] = {0};
+
+extern int 
+joylink_sdk_feedid_get(char *buf,char buflen);
+
+extern int 
+joylink_dev_https_post( char* host, char* query ,char *revbuf,int buflen);
+
+static char *joylink_cloud_log_post_json_gen(char *tagId, char *result,char *time,char *payload,char *duration,char *feedid)
+{
+	cJSON *arrary;
+	char *jsonOut = NULL;
+
+	cJSON *jsonbody;
+	jsonbody = cJSON_CreateObject();
+    if(NULL == jsonbody){
+    	goto RET;
+    }	
+	
+	arrary = cJSON_CreateArray();
+	if(arrary == NULL){
+		log_error("cJSON_CreateArray error");
+		goto RET;
+	}
+
+	cJSON_AddItemToObject(jsonbody,"log_body", arrary);
+	cJSON_AddStringToObject(jsonbody,"biz_id","softAp_conf_log");
+	
+	cJSON *json;
+    json = cJSON_CreateObject();
+    if(NULL == json){
+    	log_error("cJSON_CreateObject error");
+		goto RET;
+    }
+	cJSON_AddItemToArray(arrary, json);
+
+	if(tagId != NULL){
+		cJSON_AddStringToObject(json, "tagId", tagId);
+	}
+	if(result != NULL){
+		cJSON_AddStringToObject(json, "result", result);
+	}
+	if(time != NULL){
+		cJSON_AddStringToObject(json, "time", time);
+	}
+	if(strlen(gLogTokenStr) != 0){
+		cJSON_AddStringToObject(json, "token", gLogTokenStr);
+	}
+	
+	if(payload != NULL){
+		cJSON_AddStringToObject(json, "payload", payload);
+	}
+
+	if(duration != NULL){
+		cJSON_AddStringToObject(json, "duration", duration);
+	}
+	if(feedid != NULL){
+		cJSON_AddStringToObject(json, "feedId", feedid);
+	}
+
+	cJSON_AddStringToObject(json, "uuid", JLP_UUID);
+
+	char macstr[32] = {0};
+	memset(macstr,0,sizeof(macstr));
+	if(joylink_dev_get_user_mac(macstr) < 0){
+		log_error("device id get error");
+
+	}else{
+		log_info("device id->%s",macstr);
+		cJSON_AddStringToObject(json, "deviceId", macstr);
+	}
+	
+	jsonOut =cJSON_Print(jsonbody);
+
+RET:
+	if(jsonbody!= NULL){
+		cJSON_Delete(jsonbody);
+	}
+
+	return jsonOut;
+}
+
+static char *joylink_cloud_log_post_sign_gen(char *cjson,char *rstr)
+{
+	MD5_CTX ctx;
+	char randomstr[33] = {0};
+	char md5_out[16] = {0};
+
+	int i = 0;
+
+	char *temp = (char *)malloc(1024);
+	char *sign = (char *)malloc(33);
+	char tmp[16] = {0};
+
+	srand((unsigned int)time(NULL));
+
+	for(i = 0; i < sizeof(tmp); i++){
+	    tmp[i] = (char)rand();
+	}
+	memset(randomstr,0,sizeof(randomstr));
+
+	joylink_util_byte2hexstr(tmp,sizeof(tmp),randomstr,sizeof(randomstr));
+
+	memset(temp, 0, 1024);
+	memset(sign, 0, 33);
+	char macstr[32] = {0};
+	memset(macstr,0,sizeof(macstr));
+	if(joylink_dev_get_user_mac(macstr) < 0){
+		log_error("device id get error");
+
+	}else{
+		log_info("device id->%s",macstr);
+	}
+	
+	char privatekey[128];
+	memset(privatekey,0,sizeof(privatekey));
+	joylink_dev_get_private_key(privatekey);
+
+	sprintf(temp+strlen(temp), "%s", privatekey);
+	sprintf(temp+strlen(temp), "%s%s", LOG_DATA_BODY, cjson);
+	sprintf(temp+strlen(temp), "%s%s", "device_id", macstr);
+	sprintf(temp+strlen(temp), "%s%s", LOG_DATA_METHOD, METHON_CLOUD_LOG);
+	sprintf(temp+strlen(temp), "%s%s", "pro_uuid", JLP_UUID);
+	sprintf(temp+strlen(temp), "%s%s", "random", rstr);
+	sprintf(temp+strlen(temp), "%s%s", "timestamp", "2018-12-21 17:20:20");
+	sprintf(temp+strlen(temp), "%s%s", "v", "2.0");
+	
+	
+	sprintf(temp+strlen(temp), "%s", privatekey);
+
+
+	printf("sign: %s\n\n", temp);
+
+	memset(&ctx, 0, sizeof(MD5_CTX));
+
+	JDMD5Init(&ctx);
+	JDMD5Update(&ctx, (unsigned char*)temp, strlen(temp));
+	JDMD5Final(&ctx, (unsigned char*)md5_out);
+
+	for(i = 0; i < 16; i++){
+		sign[2*i] = (md5_out[i] & 0xf0) >> 4;
+		sign[2*i+1] = (md5_out[i] & 0x0f);
+
+		if(sign[2*i] >= 0 && sign[2*i] <= 9){
+			sign[2*i] += '0';
+		}
+		else if(sign[2*i] >= 0x0a && sign[2*i] <= 0x0f){
+			sign[2*i] = (sign[2*i] - 10) + 'A';
+		}
+		if(sign[2*i+1] >= 0 && sign[2*i+1] <= 9){
+			sign[2*i+1] += '0';
+		}
+		else if(sign[2*i+1] >= 0x0a && sign[2*i+1] <= 0x0f){
+			sign[2*i+1] = (sign[2*i+1] - 10) + 'A';
+		}
+	}
+	
+	if(temp != NULL){
+		free(temp);
+	}
+
+	return sign;
+}
+
+char *joylink_cloud_log_postbody_gen(char *cjson)
+{	
+	char *temp = NULL ;
+	char *sign = NULL;
+	char randstr[33] = {0};
+	
+	if(cjson == NULL){
+		log_error("param NULL");
+		return NULL;
+	}
+	
+	temp = (char *)malloc(1024);
+	if(temp == NULL){
+		log_error("malloc NULL");
+		return NULL;
+	}
+
+	
+	joylink_util_randstr_gen(randstr,sizeof(randstr) - 1);
+	sign = joylink_cloud_log_post_sign_gen(cjson,randstr);
+	if(sign == NULL){
+		log_error("sign gen error");
+		free(temp);
+		return NULL;
+	}
+
+	
+	memset(temp, 0, 1024);
+	char macstr[32] = {0};
+	memset(macstr,0,sizeof(macstr));
+	if(joylink_dev_get_user_mac(macstr) < 0){
+		log_error("device id get error");
+	}else{
+		log_info("device id->%s",macstr);
+	}
+
+	sprintf(temp+strlen(temp), "&%s=%s", LOG_DATA_BODY, cjson);
+	sprintf(temp+strlen(temp), "&%s=%s", "device_id", macstr);
+	sprintf(temp+strlen(temp), "&%s=%s", LOG_DATA_METHOD, METHON_CLOUD_LOG);
+	sprintf(temp+strlen(temp), "&%s=%s", "pro_uuid", JLP_UUID);
+	sprintf(temp+strlen(temp), "&%s=%s", "random", randstr);
+	sprintf(temp+strlen(temp), "&%s=%s", "timestamp", "2018-12-21 17:20:20");
+	sprintf(temp+strlen(temp), "&%s=%s", "v", "2.0");
+	
+	
+	sprintf(temp+strlen(temp), "&%s=%s", "sign", sign);
+
+	if(sign != NULL){
+		free(sign);
+	}
+	
+	return temp;
+}
+
+
+
+int joylink_cloud_log_post(char *tagId, char *result,char *time,char *payload,char *duration,char *feedid)
+{
+	int ret = -1;
+	char *json = NULL;
+	char txbuf[1400] = {0};
+	char txheader[512] = {0};
+	char countbuf[1400] = {0};
+	char *postbody = NULL;
+	
+	char token[16+1] = {0};
+	char url[32+1] = {0};
+
+	if(tagId == NULL || result == NULL){
+
+		log_error("Para NULL");
+		return -1;
+	}
+	memset(token,0,sizeof(token));
+	memset(url,0,sizeof(url));
+
+	if(strlen(gLogURLStr) == 0){
+		log_error("url NULL");
+		return -1;
+	}else{
+		strcpy(url,gLogURLStr);
+		log_info("url->%s",url);
+	}
+
+	if(strlen(gLogTokenStr) == 0){
+		log_error("token NULL");
+	}else{
+		strcpy(token,gLogTokenStr);
+		log_info("token->%s",token);
+	}
+	
+
+	json = joylink_cloud_log_post_json_gen(tagId,result,time,payload,duration,feedid);
+	
+
+	if(json == NULL){
+		log_error("json gen error");
+		ret = -1;
+		goto RET;
+	}
+	
+	log_info("cloud log post json: %s", json);
+
+	postbody = joylink_cloud_log_postbody_gen(json);
+	if(postbody == NULL){
+		log_error("post body gen error");
+		ret = -1;
+		goto RET;
+	}
+	log_info("postbody ,len = %d,body=%s",(int)strlen(postbody),postbody);
+
+	memset(txbuf,0,sizeof(txbuf));
+	memset(txheader,0,sizeof(txheader));
+	
+	sprintf(txheader,HTTPS_POST_LOG_HEADER,url);
+	sprintf(txbuf,"%s%d%s%s",txheader,(int)strlen(postbody),"\r\n\r\n",postbody);
+
+	log_info("http txbuf = \r\n%s",txbuf);
+	
+
+	ret = joylink_dev_https_post(url,txbuf,countbuf,sizeof(countbuf));
+	if(ret < 0){
+		log_error("https error");
+		ret = -1;
+		goto RET;
+	}
+
+RET:
+	if(json != NULL){
+		free(json);
+	}
+	if(postbody != NULL){
+		free(postbody);
+	}
+	return ret;
+}
+
+
+int joylink_cloud_log_param_set(char *urlstr,char *tokenstr)
+{
+	if(urlstr == NULL || tokenstr == NULL){
+		log_error("para NULL");
+		return -1;
+	}
+	
+	memset(gLogURLStr,0,sizeof(gLogURLStr));
+	memset(gLogTokenStr,0,sizeof(gLogTokenStr));
+	strcpy(gLogURLStr,urlstr);
+	strcpy(gLogTokenStr,tokenstr);
+	log_info("set cloud log para,url=%s,token=%s",gLogURLStr,gLogTokenStr);
+	return 0;
+}
+
+

+ 15 - 0
joylink/joylink/joylink_cloud_log.h

@@ -0,0 +1,15 @@
+#ifndef _JOYLINK_CLOUD_LOG_H_
+#define _JOYLINK_CLOUD_LOG_H_
+#define TAGID_LOG_REV_SSID				"D1"
+#define TAGID_LOG_AP_CONNECTED			"D2"
+#define TAGID_LOG_AP_GET_FEEDID_RES		"D3"
+#define TAGID_LOG_AP_WRITE_FEEDID_RES	"D4"
+#define TAGID_LOG_AP_FULL_RES			"D5"
+
+#define RES_LOG_SUCCES					"1"
+#define RES_LOG_FAIL					"-1"
+
+int joylink_cloud_log_param_set(char *urlstr,char *tokenstr);
+int joylink_cloud_log_post(char *tagId, char *result,char *time,char *payload,char *duration,char *feedid);
+
+#endif

+ 497 - 0
joylink/joylink/joylink_dev_active.c

@@ -0,0 +1,497 @@
+#include <string.h>
+#include "joylink.h"
+#include "joylink_log.h"
+#include "cJSON.h"
+#include "joylink_extern.h"
+#include "joylink_auth_md5.h"
+#include "joylink_utils.h"
+#include "joylink_dev_active.h"
+#include "joylink_cloud_log.h"
+#include "joylink_dev_active.h"
+
+
+#define METHON_ACTIVATE     "jingdong.smart.api.activeAndBindForDevice"
+
+#define DATA_METHOD    		"method"
+#define DATA_BODY      		"360buy_param_json"
+#define DATA_APP_KEY        "app_key"
+
+#define DATA_DEVICE_ID      "device_id"
+#define DATA_UUID           "pro_uuid"
+
+#define DATA_RANDOM      	"random"
+#define DATA_TIMESTAMP   	"timestamp"
+#define DATA_V           	"v"
+#define DATA_SIGN			"sign"
+
+#define VERSION_JOY			"2.0"
+
+#define TIME_TEST    "2018-12-21 17:20:20"
+
+#define HTTPS_POST_HEADER "POST /dev HTTP/1.1\r\nHost: %s\r\nAccept: */*\r\ncontent-type: application/x-www-form-urlencoded; charset=utf-8\r\nContent-Length:"
+
+#ifndef JLP_UUID
+#define JLP_UUID JOYLINK_SAMPLE_UUID
+#endif
+
+extern int 
+joylink_sdk_feedid_get(char *buf,char buflen);
+
+extern int 
+joylink_dev_https_post( char* host, char* query ,char *revbuf,int buflen);
+
+char gRandomStr[33] = {0};
+char gRandomAStr[33] = {0};
+char gURLStr[LEN_URL_MAX+1] = {0};
+char gTokenStr[LEN_TOKEN_MAX+1] = {0};
+
+//#include "joylink_syshdr.h"
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+static int joylink_dev_bind_info_parse(char *msg, DevEnable_t *dev)
+{
+	int ret = -1;
+	if(NULL == msg || NULL == dev){
+		printf("--->:ERROR: pMsg is NULL\n");
+		goto RET;
+	}
+	cJSON * pJson = cJSON_Parse(msg);
+
+	if(NULL == pJson){
+		printf("--->:cJSON_Parse is error!\n");
+		goto RET;
+	}
+	cJSON * reponse = cJSON_GetObjectItem(pJson, "jingdong_smart_api_activeAndBindForDevice_response");
+	if(reponse == NULL){
+		printf("--->:reponse is error!\n");
+		goto RET;
+	}
+	cJSON * result = cJSON_GetObjectItem(reponse, "result");
+	if(result == NULL){
+		printf("--->:reuslt is error!\n");
+		goto RET;
+	}
+
+	cJSON * code = cJSON_GetObjectItem(reponse, "code");
+	if(code == NULL){
+		printf("--->:code is error!\n");
+		goto RET;
+	}
+
+	if(code->valueint != 0){
+		log_error("jingdong_smart_api_activeAndBindForDevice_response code error");
+		goto RET;
+	}
+
+	cJSON *code_result = cJSON_GetObjectItem(result, "code");
+	if(code_result == NULL){
+		log_error("jingdong_smart_api_activeAndBindForDevice_response result code error");
+		goto RET;
+	}
+	if(strcmp(code_result->valuestring,"200") != 0){
+		log_error("jingdong_smart_api_activeAndBindForDevice_response result code error");
+		goto RET;
+	}
+
+	
+	
+	cJSON * data = cJSON_GetObjectItem(result, "data");
+	if(result == NULL){
+		printf("--->:data is error!\n");
+		goto RET;
+	}
+	
+	cJSON * activate = cJSON_GetObjectItem(data, "activate");
+	if(activate != NULL){
+		cJSON * pSub = cJSON_GetObjectItem(activate, "feed_id");
+		if(NULL != pSub){
+		    strcpy(dev->feedid, pSub->valuestring);
+		}
+		pSub = cJSON_GetObjectItem(activate, "access_key");
+		if(NULL != pSub){
+		    strcpy(dev->accesskey, pSub->valuestring);
+		}
+		pSub = cJSON_GetObjectItem(activate, "c_idt");
+		if(NULL != pSub){
+			cJSON *sig = cJSON_GetObjectItem(pSub, "device_random_sig");
+			if(sig != NULL){
+				strcpy(dev->cloud_sig, sig->valuestring);
+			}
+		}
+		pSub = cJSON_GetObjectItem(activate, "servers_info");
+		if(pSub != NULL){                                      
+			cJSON *server = cJSON_GetObjectItem(pSub, "joylink_server");
+			if(NULL != server){
+			    if(cJSON_GetArraySize(server) > 0){
+				cJSON *pv;
+				pv = cJSON_GetArrayItem(server, 0);
+				if(NULL != pv){
+				    strcpy(dev->joylink_server, pv->valuestring);
+				}
+			    }
+			}	
+		}
+	}
+	ret = 0;
+RET:
+	if(pJson != NULL){
+		cJSON_Delete(pJson);
+	}
+	return 0;
+}
+
+
+
+int joylink_dev_bind_info_parse_write(char *json, char *randstr)
+{
+	int ret = -1;
+	DevEnable_t dev;
+	if(json == NULL){
+		log_error("json data null");
+		return ret;
+	}
+	log_info("json->%s",json);
+	
+	memset(&dev, 0, sizeof(DevEnable_t));
+	ret = joylink_dev_bind_info_parse(json,&dev);
+	if(ret < 0){
+		log_error("json parse error");
+		joylink_cloud_log_post(TAGID_LOG_AP_GET_FEEDID_RES, RES_LOG_FAIL,"2018-12-21 17:20:20","[CloudLog]Get active data failed","0",NULL);
+		return E_RET_ERROR;
+	}else{
+		log_info("json parse success");
+		joylink_cloud_log_post(TAGID_LOG_AP_GET_FEEDID_RES, RES_LOG_SUCCES,"2018-12-21 17:20:20","[CloudLog]Get active data success","0",dev.feedid);
+	}
+	
+	ret = joylink_active_write_key(&dev,randstr);
+
+	return ret;
+}
+
+
+
+static char *joylink_dev_active_post_json_gen(char *token, char *signaure, char *rand)
+{
+	cJSON *root;
+	char *out = NULL;
+
+	char macstr[32] = {0};
+	char feedid[64] = {0};
+	root = cJSON_CreateObject();
+	if(NULL == root){
+		return NULL;
+	}
+
+	cJSON *json;
+    json = cJSON_CreateObject();
+    if(NULL == json){
+    	return NULL;
+    }
+
+	memset(macstr,0,sizeof(macstr));
+	if(joylink_dev_get_user_mac(macstr) < 0){
+		log_error("device id get error");
+	}else{
+		log_info("device id->%s",macstr);
+	}
+
+	cJSON_AddStringToObject(json, "device_id", macstr);
+	cJSON_AddStringToObject(json, "device_add_info", "");
+
+	cJSON_AddNumberToObject(json, "is_iot_alpha", 1);
+	cJSON_AddStringToObject(json, "product_uuid", JLP_UUID);
+	cJSON_AddStringToObject(json, "sdk_version", _VERSION_);
+	cJSON_AddStringToObject(json, "token", token);
+
+	if(joylink_sdk_feedid_get(feedid,sizeof(feedid)) < 0){
+		cJSON_AddNumberToObject(json, "feed_id", 0);
+	}else{
+		cJSON_AddStringToObject(json, "feed_id", feedid);
+	}
+	
+	cJSON_AddItemToObject(root,"json", json);
+	
+
+    cJSON *idt;
+    idt = cJSON_CreateObject();
+    if(NULL == idt){
+    	return NULL;
+    }
+
+	cJSON_AddNumberToObject(idt, "t", 0);
+	cJSON_AddStringToObject(idt, "d_r", rand);
+	cJSON_AddStringToObject(idt, "d_s", signaure);
+
+    cJSON_AddStringToObject(idt, "version", "2.0");
+	cJSON_AddStringToObject(idt, "app_rand", "12345678901234567890123456789012");
+
+    cJSON_AddItemToObject(json,"d_idt", idt);
+
+	out=cJSON_Print(root);
+	cJSON_Delete(root);
+
+	return out;
+}
+
+
+
+static char *joylink_dev_active_post_sign_gen(char *cjson,char *random_d)
+{
+	MD5_CTX ctx;
+	char randomstr[33] = {0};
+	char md5_out[16] = {0};
+
+	int i = 0;
+
+	char *temp = (char *)malloc(1024);
+	char *sign = (char *)malloc(33);
+	char tmp[16] = {0};
+
+	srand((unsigned int)time(NULL));
+
+	for(i = 0; i < sizeof(tmp); i++){
+	    tmp[i] = (char)rand();
+	}
+	memset(randomstr,0,sizeof(randomstr));
+
+	joylink_util_byte2hexstr(tmp,sizeof(tmp),randomstr,sizeof(randomstr));
+
+	memset(temp, 0, 1024);
+	memset(sign, 0, 33);
+
+	char macstr[32];
+	memset(macstr,0,sizeof(macstr));
+	if(joylink_dev_get_user_mac(macstr) < 0){
+		log_error("device id get error");
+	}else{
+		log_info("device id->%s",macstr);
+	}
+
+	char privatekey[128];
+	memset(privatekey,0,sizeof(privatekey));
+	if(joylink_dev_get_private_key(privatekey)<0){
+		log_error("private key get error");
+		
+	}
+	
+	sprintf(temp+strlen(temp), "%s", privatekey);
+	sprintf(temp+strlen(temp), "%s%s", DATA_BODY, cjson);
+	sprintf(temp+strlen(temp), "%s%s", DATA_DEVICE_ID, macstr);
+	sprintf(temp+strlen(temp), "%s%s", DATA_METHOD, METHON_ACTIVATE);
+	sprintf(temp+strlen(temp), "%s%s", DATA_UUID, JLP_UUID);
+	//sprintf(temp+strlen(temp), "%s%s", DATA_RANDOM, random_d);
+	sprintf(temp+strlen(temp), "%s%s", DATA_RANDOM, gRandomAStr);
+
+	sprintf(temp+strlen(temp), "%s%s", DATA_TIMESTAMP, TIME_TEST);
+	sprintf(temp+strlen(temp), "%s%s", DATA_V, VERSION_JOY);
+	//sprintf(temp+strlen(temp), "%s%s", DATA_V, TIME_TEST);
+	sprintf(temp+strlen(temp), "%s", privatekey);
+
+	printf("sign: %s\n\n", temp);
+
+	memset(&ctx, 0, sizeof(MD5_CTX));
+
+	JDMD5Init(&ctx);
+	JDMD5Update(&ctx, (unsigned char*)temp, strlen(temp));
+	JDMD5Final(&ctx, (unsigned char*)md5_out);
+
+	for(i = 0; i < 16; i++){
+		sign[2*i] = (md5_out[i] & 0xf0) >> 4;
+		sign[2*i+1] = (md5_out[i] & 0x0f);
+
+		if(sign[2*i] >= 0 && sign[2*i] <= 9){
+			sign[2*i] += '0';
+		}
+		else if(sign[2*i] >= 0x0a && sign[2*i] <= 0x0f){
+			sign[2*i] = (sign[2*i] - 10) + 'A';
+		}
+		if(sign[2*i+1] >= 0 && sign[2*i+1] <= 9){
+			sign[2*i+1] += '0';
+		}
+		else if(sign[2*i+1] >= 0x0a && sign[2*i+1] <= 0x0f){
+			sign[2*i+1] = (sign[2*i+1] - 10) + 'A';
+		}
+	}
+	
+	if(temp != NULL){
+		free(temp);
+	}
+
+	return sign;
+}
+
+
+char *joylink_dev_active_postbody_gen(char *cjson,char *random_d)
+{	
+	char *temp = NULL ;
+	char *sign = NULL;
+	
+	if(cjson == NULL){
+		log_error("param NULL");
+		return NULL;
+	}
+	sign = joylink_dev_active_post_sign_gen(cjson,random_d);
+	if(sign == NULL){
+		log_error("sign NULL");
+		return NULL;
+	}
+
+	temp = (char *)malloc(1024);
+	if(temp == NULL){
+		log_error("malloc NULL");
+		free(sign);
+		return NULL;
+	}
+
+	memset(temp, 0, 1024);
+	
+	char macstr[32] = {0};
+	memset(macstr,0,sizeof(macstr));
+	if(joylink_dev_get_user_mac(macstr) < 0){
+		log_error("device id get error");
+	}else{
+		log_info("device id->%s",macstr);
+	}
+
+	sprintf(temp+strlen(temp), "&%s=%s", DATA_BODY, cjson);
+	sprintf(temp+strlen(temp), "&%s=%s", DATA_DEVICE_ID, macstr);
+	sprintf(temp+strlen(temp), "&%s=%s", DATA_METHOD, METHON_ACTIVATE);
+	sprintf(temp+strlen(temp), "&%s=%s", DATA_UUID, JLP_UUID);
+
+	sprintf(temp+strlen(temp), "&%s=%s", DATA_RANDOM, gRandomAStr);
+	sprintf(temp+strlen(temp), "&%s=%s", DATA_TIMESTAMP, TIME_TEST);
+	sprintf(temp+strlen(temp), "&%s=%s", DATA_V, VERSION_JOY);
+
+	sprintf(temp+strlen(temp), "&%s=%s", DATA_SIGN, sign);
+		
+	if(sign != NULL)
+		free(sign);
+	
+	return temp;
+}
+
+
+static int joylink_dev_active_post(char *token, char *url)
+{
+	int ret = -1;
+	char *json = NULL;
+	char txbuf[1400] = {0};
+	char txheader[512] = {0};
+	char countbuf[1400] = {0};
+	char *postbody = NULL;
+	
+	uint8_t signaure[129] = {0};
+
+	if(token == NULL || url == NULL){
+		return -1;
+	}
+	
+	joylink_util_randstr_gen(gRandomStr,sizeof(gRandomStr) - 1);
+	joylink_util_randstr_gen(gRandomAStr,sizeof(gRandomAStr) - 1);
+	log_info("random->%s",gRandomStr);
+	
+	if(strlen(token) != 0 && strlen(url) != 0){
+		int ret_sign = 0;
+		uint8_t prikey_buf[65] = {0};
+		uint8_t sign_buf[65] = {0};
+
+		log_info("test prikey: %s", _g_pdev->jlp.prikey);
+		log_info("test token: %s, len: %d", token, (int)strlen(token));
+		
+        joylink_util_hexStr2bytes(_g_pdev->jlp.prikey, prikey_buf, 32);
+		
+		ret_sign = jl3_uECC_sign(prikey_buf, token, strlen(token), sign_buf, uECC_secp256r1());
+		if(ret_sign == 1){
+			log_info("gen devsigature to cloud random success");
+		}else{
+			log_error("gen dev sigature to cloud random error");
+			return -1;
+		}
+
+		joylink_util_byte2hexstr(sign_buf, 64, signaure, 64*2);
+	}else{
+		ret = -1;
+		goto RET;
+	}
+
+	json = joylink_dev_active_post_json_gen(token, (char *)signaure, gRandomStr);
+	if(json == NULL){
+		log_error("json gen error");
+		ret = -1;
+		goto RET;
+	}
+	
+	log_info("activate req json: %s", json);
+
+	postbody = joylink_dev_active_postbody_gen(json,gRandomStr);
+	if(postbody == NULL){
+		log_error("post body gen error");
+		ret = -1;
+		goto RET;
+	}
+	log_info("postbody ,len = %d,body=%s",(int)strlen(postbody),postbody);
+
+	memset(txbuf,0,sizeof(txbuf));
+	memset(txheader,0,sizeof(txheader));
+
+	sprintf(txheader,HTTPS_POST_HEADER,url);
+	sprintf(txbuf,"%s%d%s%s",txheader,(int)strlen(postbody),"\r\n\r\n",postbody);
+
+	log_info("http txbuf = \n%s",txbuf);
+	
+
+	ret = joylink_dev_https_post(url,txbuf,countbuf,sizeof(countbuf));
+	if(ret < 0){
+		log_error("https error");
+		ret = -1;
+		goto RET;
+	}
+
+	ret = joylink_dev_bind_info_parse_write(countbuf,gRandomStr);
+	if(ret < 0){
+		log_error("dev active error");
+		ret = -1;
+		joylink_cloud_log_post(TAGID_LOG_AP_FULL_RES, RES_LOG_FAIL,"2018-12-21 17:20:20","[CloudLog]device active failed","0",NULL);
+		
+		goto RET;
+	}else{
+			char feedid[64] = {0};
+			if(joylink_sdk_feedid_get(feedid,sizeof(feedid)) >= 0){
+				joylink_cloud_log_post(TAGID_LOG_AP_FULL_RES, RES_LOG_SUCCES,"2018-12-21 17:20:20","[CloudLog]device active success","0",feedid);
+			}
+	}
+	ret = 0;
+RET:
+	if(json != NULL){
+		free(json);
+	}
+	if(postbody != NULL){
+		free(postbody);
+	}
+	return ret;
+}
+
+int joylink_dev_active_param_set(char *urlstr,char *tokenstr)
+{
+	if(urlstr == NULL || tokenstr == NULL){
+		log_error("para NULL");
+		return -1;
+	}
+	
+	memset(gURLStr,0,sizeof(gURLStr));
+	memset(gTokenStr,0,sizeof(gTokenStr));
+	strcpy(gURLStr,urlstr);
+	strcpy(gTokenStr,tokenstr);
+	log_info("set active para,url=%s,token=%s",gURLStr,gTokenStr);
+	return 0;
+}
+
+int joylink_dev_active_req(void)
+{
+	return joylink_dev_active_post(gTokenStr,gURLStr);
+}
+
+

+ 14 - 0
joylink/joylink/joylink_dev_active.h

@@ -0,0 +1,14 @@
+#ifndef _JOYLINK_DEV_ACTIVE_H_
+#define _JOYLINK_DEV_ACTIVE_H_
+#include "joylink.h"
+
+#define LEN_URL_MAX			32
+#define LEN_TOKEN_MAX		16
+
+int joylink_dev_active_param_set(char *urlstr,char *tokenstr);
+
+
+int joylink_dev_active_req(void);
+
+
+#endif

+ 777 - 0
joylink/joylink/joylink_dev_lan.c

@@ -0,0 +1,777 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(__RT_THREAD__)
+#include <stdint.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#elif defined(__MTK_7687__)
+#include <stdint.h>
+#include "lwip/sockets.h"
+#else
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#endif
+
+#include "joylink.h"
+#include "joylink_utils.h"
+#include "joylink_packets.h"
+#include "joylink_crypt.h"
+#include "joylink_json.h"
+#include "joylink_sub_dev.h"
+#include "joylink_join_packet.h"
+#include "auth/joylink_auth_crc.h"
+#include "joylink_dev.h"
+#include "joylink_extern.h"
+#include "auth/joylink3_auth_uECC.h"
+#ifdef _IS_DEV_REQUEST_ACTIVE_SUPPORTED_
+#include "joylink_cloud_log.h"
+#endif
+#include "joylink_auth_md5.h"
+
+#define USR_TIMESTAMP_MAX      (4)
+
+typedef struct _u_t{
+    int id;
+    uint32_t timestamp;
+}usr_ts_t;
+
+usr_ts_t _g_UT[USR_TIMESTAMP_MAX];
+
+extern int joylink_server_upload_req();
+
+extern int joylink_server_st_close();
+
+/**
+ * brief: 
+ *
+ * @Param: str
+ *
+ * @Returns: 
+ */
+static int32_t  
+joylink_util_RSHash(const char * str)
+{
+    if(NULL == str){
+        return E_RET_ERROR;
+    }
+    int32_t  b  =   378551 ;
+    int32_t  a  =   63689 ;
+    int32_t  hash  =   0 ;
+
+    while(* str){
+        hash = hash * a + (*str++);
+        a *= b;
+    }
+
+    return (hash  & 0x7FFFFFFF );
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int
+joylink_cloud_timestamp_sync_check_reset_timecache()
+{
+    static uint32_t refresh_time = 0;
+
+    if(_g_pdev->cloud_timestamp - refresh_time > 300){
+        if(_g_pdev->cloud_timestamp & 0xFFFFF  < 300){
+            refresh_time = _g_pdev->cloud_timestamp;
+            memset(_g_UT, 0, sizeof(_g_UT));
+        }
+    }
+}
+
+/**
+ * brief: 
+ *
+ * @Param: id
+ * @Param: timestamp
+ *
+ * @Returns: 
+ */
+int
+joylink_is_usr_timestamp_ok(char *usr, uint32_t org_timestamp)
+{
+    char ip[64] = {0};
+    int port;
+    joylink_util_cut_ip_port(usr, ip, &port);
+
+    int id = joylink_util_RSHash(ip);
+    int i;
+
+    /*1 */
+    uint32_t timestamp = 0;
+    timestamp = org_timestamp & 0xFFFFFFFF;
+
+    log_info("timestamp info:->%s:%u\n", usr, timestamp);
+
+
+    for(i=0; i < USR_TIMESTAMP_MAX; i++){
+        /*update the timestamp*/
+        if((_g_UT[i].id & 0x7FFFFFFF) == (id & 0x7FFFFFFF)){
+            if(_g_UT[i].timestamp < timestamp){
+                _g_UT[i].timestamp = timestamp;
+                return 1;
+            }else{
+                log_error("timstamp error:->%s\n", usr);
+                log_error("usr timestamp:%u, cache timestamp:%u\n", timestamp, _g_UT[i].timestamp);
+                return 0;
+            }
+        }
+    }
+    if(i == USR_TIMESTAMP_MAX){
+        /*no find usr add a usr to empty sapce*/
+        for(i=0; i < USR_TIMESTAMP_MAX; i++){
+            if((_g_UT[i].id & 0x80000000) == 0){
+                _g_UT[i].timestamp = timestamp;
+                _g_UT[i].id = id | 0x80000000; 
+                return 1;
+            }
+        }
+    }
+    if(i == USR_TIMESTAMP_MAX){
+        /*no find no empty , add a usr to timeout space*/
+        for(i=0; i < USR_TIMESTAMP_MAX; i++){
+            if(_g_UT[i].timestamp < (_g_pdev->cloud_timestamp - 60*60)){
+                _g_UT[i].timestamp = timestamp;
+                _g_UT[i].id = id | 0x80000000; 
+
+                return 1;
+            }
+        }
+    }
+	if(i == USR_TIMESTAMP_MAX){
+		return 0;
+	}
+    log_error("JSon Control timstamp error: no space->%s\n", usr);
+    log_error("usr timestamp:%u, cache timestamp:%u\n", timestamp, _g_UT[i].timestamp);
+    /*no space to add*/
+    return 0;    
+}
+
+/**
+ * brief: 1 get packet head and opt
+ *        2 cut big packet as JL_MAX_CUT_PACKET_LEN 
+ *        3 join phead, opt and paload
+ *        4 crc
+ *        5 send
+ */
+void
+joylink_send_big_pkg(struct sockaddr_in *sin_recv, socklen_t addrlen)
+{
+    int ret = -1;
+    int len;
+    int i;
+    int offset = 0;
+
+	JLPacketHead_t *org_pt = (JLPacketHead_t*)_g_pdev->send_p;
+    short res = rand()&0xFF;
+
+    int total = (int)(org_pt->payloadlen/JL_MAX_CUT_PACKET_LEN) 
+        + (org_pt->payloadlen%JL_MAX_CUT_PACKET_LEN? 1:0);
+
+    for(i = 1; i <= total; i ++){
+        if(i == total){
+            len = org_pt->payloadlen%JL_MAX_CUT_PACKET_LEN;
+            log_info("payloadlen::%d :len:%d",org_pt->payloadlen, len);
+        }else{
+            len = JL_MAX_CUT_PACKET_LEN;
+        }
+        
+        offset = 0;
+        bzero(_g_pdev->send_buff, sizeof(_g_pdev->send_buff));
+
+        memcpy(_g_pdev->send_buff, _g_pdev->send_p, sizeof(JLPacketHead_t) + org_pt->optlen);
+        offset  = sizeof(JLPacketHead_t) + org_pt->optlen;
+
+        memcpy(_g_pdev->send_buff + offset, 
+                _g_pdev->send_p + offset + JL_MAX_CUT_PACKET_LEN * (i -1), len);
+
+	    JLPacketHead_t *pt; 
+        pt = (JLPacketHead_t*)_g_pdev->send_buff; 
+        pt->total = total;
+        pt->index = i;
+        pt->payloadlen = len;
+        pt->crc = CRC16(_g_pdev->send_buff + sizeof(JLPacketHead_t), pt->optlen + pt->payloadlen);
+        pt->reserved = (unsigned char)res;
+
+        ret = sendto(_g_pdev->lan_socket, 
+                _g_pdev->send_buff,
+                len + sizeof(JLPacketHead_t) + pt->optlen, 0,
+                (SOCKADDR*)sin_recv, addrlen);
+
+        if(ret < 0){
+            log_error("send error");
+        }
+        log_info("send to:%s:ret:%d:total:%d", _g_pdev->jlp.ip, ret, total);
+    }
+
+    if(NULL != _g_pdev->send_p){
+        free(_g_pdev->send_p);
+        _g_pdev->send_p = NULL;
+    }
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: sin_recv
+ * @Param: addrlen
+ */
+
+static void
+joylink_proc_lan_scan(uint8_t *src, struct sockaddr_in *sin_recv, socklen_t addrlen)
+{
+    int ret = -1;
+    int len = -1;
+    DevScan_t scan;
+    int ret_sign = 0;
+
+
+    bzero(&scan, sizeof(scan));
+
+    if(E_RET_OK != joylink_parse_scan(&scan, (const char *)src)){
+    }else{
+#ifdef JOYLINK_CLOUD_AUTH
+	if(strlen(scan.app_rand) != 0){
+		uint8_t prikey_buf[65] = {0};
+		uint8_t sign_buf[65] = {0};
+		uint8_t rand_buf[33] = {0};
+		int i = 0;
+
+		log_info("cloud rand: %s", scan.app_rand);
+        	joylink_util_hexStr2bytes(_g_pdev->jlp.prikey, prikey_buf, 32);
+
+		ret_sign = jl3_uECC_sign(prikey_buf, scan.app_rand, strlen(scan.app_rand), sign_buf, uECC_secp256r1());
+		if(ret_sign == 1){
+			log_info("gen devsigature to cloud random success");
+		}else{
+			log_error("gen dev sigature to cloud random error");
+			return;
+		}
+
+		joylink_util_byte2hexstr(sign_buf, 64, scan.dev_sign, 64*2);
+	}
+#endif
+        len = joylink_packet_lan_scan_rsp(&scan);
+    }
+
+    if(len > 0){ 
+        if(len < JL_MAX_CUT_PACKET_LEN){
+            ret = sendto(_g_pdev->lan_socket, 
+                    _g_pdev->send_buff,
+                    len, 0,
+                    (SOCKADDR*)sin_recv, addrlen);
+            if(ret < 0){
+                perror("send error");
+            }
+            log_info("send to:%s:ret:%d", _g_pdev->jlp.ip, ret);
+        }else{
+            joylink_send_big_pkg(sin_recv, addrlen);
+            log_info("SEND PKG IS TOO BIG:ip:%s", _g_pdev->jlp.ip);
+        }
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: sin_recv
+ * @Param: addrlen
+ */
+
+extern int jl3_uECC_verify_256r1(const uint8_t *public_key,
+                const uint8_t *message_hash,
+                unsigned hash_size,
+                const uint8_t *signature);
+
+static void
+joylink_proc_lan_write_key(uint8_t *src, struct sockaddr_in *sin_recv, socklen_t addrlen)
+{
+    int ret = -1;
+    int len = 0;
+    DevEnable_t de;
+    bzero(&de, sizeof(de));
+
+    uint8_t sig[64] = {0}; 
+    uint8_t pubkey[33] = {0}; 
+
+    joylink_parse_lan_write_key(&de, (const char*)src + 4);
+
+    joylink_util_hexStr2bytes(_g_pdev->idt.cloud_pub_key, pubkey, sizeof(pubkey));
+    joylink_util_hexStr2bytes(de.cloud_sig, sig, sizeof(sig));
+
+#ifdef JOYLINK_DEVICE_AUTH
+    if(1 == jl3_uECC_verify_256r1((uint8_t *)pubkey, 
+                (uint8_t *)_g_pdev->idt.rand, 
+                strlen(_g_pdev->idt.rand), 
+                (uint8_t *)sig)){
+#else
+    if(1){
+#endif
+        if(_g_pdev->jlp.is_actived && (strcmp(_g_pdev->jlp.feedid, de.feedid) || strcmp(_g_pdev->jlp.accesskey, de.accesskey) \
+            || strcmp(_g_pdev->jlp.localkey, de.localkey) || strcmp(_g_pdev->jlp.javs_server, de.javs_server) \
+            || strcmp(_g_pdev->jlp.opengw_server, de.opengw_server) || strcmp(_g_pdev->jlp.router_server, de.router_server))){
+            len = joylink_packet_lan_write_key_rsp(E_RET_ERROR_DEV_ACTIVED, "dev is alread actived");
+            log_error("dev is alread actived, not response write key");
+        }else{
+            strcpy(_g_pdev->jlp.feedid, de.feedid);
+            strcpy(_g_pdev->jlp.accesskey, de.accesskey);
+            strcpy(_g_pdev->jlp.localkey, de.localkey);
+
+            strcpy(_g_pdev->jlp.javs_server, de.javs_server);
+            strcpy(_g_pdev->jlp.opengw_server, de.opengw_server);
+            strcpy(_g_pdev->jlp.router_server, de.router_server);
+
+            joylink_util_cut_ip_port(de.joylink_server, _g_pdev->jlp.joylink_server, &_g_pdev->jlp.server_port);
+
+            _g_pdev->jlp.is_actived = 1;
+            joylink_dev_set_attr_jlp(&_g_pdev->jlp);
+            len = joylink_packet_lan_write_key_rsp(0, "write accesskey ok");
+
+            joylink_server_st_close();
+
+            //memset(_g_pdev->idt.rand, 0, sizeof(_g_pdev->idt.rand));
+	    log_info("\nWrite accesskey ok!\n");
+	}
+    }else{
+        len = joylink_packet_lan_write_key_rsp(-1, "verify cloud sig error");
+        log_error("-->verify cloud sig error:%s\n cloud_public_key:%s", de.cloud_sig, _g_pdev->idt.cloud_pub_key);
+    }
+    
+    if(len > 0 && len < JL_MAX_PACKET_LEN){ 
+        ret = sendto(_g_pdev->lan_socket, _g_pdev->send_buff, len, 0, (SOCKADDR*)sin_recv, addrlen);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+	ret = sendto(_g_pdev->lan_socket, _g_pdev->send_buff, len, 0, (SOCKADDR*)sin_recv, addrlen);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+	ret = sendto(_g_pdev->lan_socket, _g_pdev->send_buff, len, 0, (SOCKADDR*)sin_recv, addrlen);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+}
+#ifdef _IS_DEV_REQUEST_ACTIVE_SUPPORTED_
+/**
+ * @name:joylink_active_write_key 
+ *
+ * @param: de
+ * @param: randstr
+ *
+ * @returns:   
+ */
+int joylink_active_write_key(DevEnable_t *de,char *randstr)
+{
+    int ret = -1;
+    int len = 0;
+    uint8_t sig[64] = {0}; 
+    uint8_t pubkey[33] = {0}; 
+	log_info("-->feedid:%s:accesskey:%s\n", de->feedid, de->accesskey);
+	log_info("-->localkey:%s\n", de->localkey);
+	log_info("-->joylink_server:%s\n", de->joylink_server);
+	log_info("-->cloud sig:%s\n", de->cloud_sig);
+
+	memset(_g_pdev->idt.rand,0,sizeof(_g_pdev->idt.rand));
+	strcpy(_g_pdev->idt.rand,randstr);
+	
+	joylink_util_hexStr2bytes(_g_pdev->idt.cloud_pub_key, pubkey, sizeof(pubkey));
+	joylink_util_hexStr2bytes(de->cloud_sig, sig, sizeof(sig));
+	if(1 == jl3_uECC_verify_256r1((uint8_t *)pubkey, (uint8_t *)_g_pdev->idt.rand, strlen(_g_pdev->idt.rand), (uint8_t *)sig)){
+
+		uint8_t temp[32] = {0};
+		uint8_t localkey[33] = {0};
+		MD5_CTX md5buf;
+	
+		memset(&md5buf, 0, sizeof(MD5_CTX));
+		JDMD5Init(&md5buf);
+		JDMD5Update(&md5buf, de->accesskey, strlen(de->accesskey));
+		JDMD5Final(&md5buf, temp);
+		joylink_util_byte2hexstr(temp, 16, localkey, 32);
+
+		strcpy(_g_pdev->jlp.feedid, de->feedid);
+		strcpy(_g_pdev->jlp.accesskey, de->accesskey);
+		strcpy(_g_pdev->jlp.localkey, localkey);
+	
+		joylink_util_cut_ip_port(de->joylink_server,
+						_g_pdev->jlp.joylink_server,
+						&_g_pdev->jlp.server_port);
+	
+		_g_pdev->jlp.is_actived = 1;
+		ret = joylink_dev_set_attr_jlp(&_g_pdev->jlp);
+		if(ret != E_RET_OK){
+			log_error("write active data fail");
+			joylink_cloud_log_post(TAGID_LOG_AP_WRITE_FEEDID_RES, RES_LOG_FAIL,"2018-12-21 17:20:20","[CloudLog]write active data to flash fail","0",de->feedid);
+			goto RET;
+		}
+		memset(_g_pdev->idt.rand, 0, sizeof(_g_pdev->idt.rand));
+
+		joylink_server_st_close();
+
+		log_info("active write success");
+		joylink_cloud_log_post(TAGID_LOG_AP_WRITE_FEEDID_RES, RES_LOG_SUCCES,"2018-12-21 17:20:20","[CloudLog]write active data success","0",de->feedid);
+		ret = E_RET_OK;
+	}else{
+		log_error("-->verify cloud sig error:%s\n cloud_public_key:%s", de->cloud_sig, _g_pdev->idt.cloud_pub_key);
+		joylink_cloud_log_post(TAGID_LOG_AP_WRITE_FEEDID_RES, RES_LOG_FAIL,"2018-12-21 17:20:20","[CloudLog]verify cloud signature fail","0",de->feedid);
+		ret = E_RET_ERROR;
+	}
+RET:
+	return ret;
+}
+#endif
+/**
+ * brief: 
+ *
+ * @Param: json_cmd
+ * @Param: sin_recv
+ * @Param: addrlen
+ */
+static void
+joylink_proc_lan_json_ctrl(uint8_t *json_cmd, struct sockaddr_in *sin_recv, socklen_t addrlen)
+{
+    int ret = -1;
+    int len = 0;
+    char data[JL_MAX_PACKET_LEN] = {0};
+    char feedid[JL_MAX_FEEDID_LEN] = {0};
+    time_t tt = time(NULL);
+
+    joylink_parse_json_ctrl(feedid, (char*)json_cmd);
+    ret = joylink_dev_lan_json_ctrl((char *)json_cmd);
+   
+    memcpy(data, &tt, 4);
+    ret = joylink_dev_get_json_snap_shot(data + 4, sizeof(data) - 4, ret, feedid);
+
+    log_info("rsp data:%s:len:%d", data + 4 , ret);
+
+    len = joylink_encrypt_lan_basic(_g_pdev->send_buff, JL_MAX_PACKET_LEN,
+            ET_ACCESSKEYAES, PT_SCRIPTCONTROL,
+            (uint8_t*)_g_pdev->jlp.localkey, (const uint8_t*)data, ret + 4);
+
+    if(len > 0 && len < JL_MAX_PACKET_LEN){ 
+        ret = sendto(_g_pdev->lan_socket, _g_pdev->send_buff, len, 0,
+                (SOCKADDR*)sin_recv, addrlen);
+
+        if(ret < 0){
+            log_error(" 1 send error ret:%d", ret);
+        }else{
+            log_info("rsp to:%s:len:%d", _g_pdev->jlp.ip, ret);
+        }
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    joylink_server_upload_req();
+} 
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ * @Param: sin_recv
+ * @Param: addrlen
+ */
+static void
+joylink_proc_lan_script_ctrl(uint8_t *src, uint8_t src_len, struct sockaddr_in *sin_recv, socklen_t addrlen)
+{
+    int ret = -1;
+    int len = 0;
+    char data[JL_MAX_PACKET_LEN] = {0};
+    JLContrl_t ctr;
+    bzero(&ctr, sizeof(ctr));
+
+    if(-1 == joylink_dev_script_ctrl((const char *)src, src_len, &ctr, 0)){
+        return;
+    }
+    ret = joylink_packet_script_ctrl_rsp(data, sizeof(data), &ctr);
+    log_info("rsp data:%s:len:%d", data + 12, ret);
+    len = joylink_encrypt_lan_basic(_g_pdev->send_buff, JL_MAX_PACKET_LEN,
+            ET_ACCESSKEYAES, PT_SCRIPTCONTROL,
+            (uint8_t*)_g_pdev->jlp.localkey, (const uint8_t*)data, ret);
+
+    if(len > 0 && len < JL_MAX_PACKET_LEN){ 
+        ret = sendto(_g_pdev->lan_socket, _g_pdev->send_buff, len, 0,
+                (SOCKADDR*)sin_recv, addrlen);
+
+        if(ret < 0){
+            log_error(" 1 send error ret:%d", ret);
+        }else{
+            log_info("rsp to:%s:len:%d", _g_pdev->jlp.ip, ret);
+        }
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    // Porting: fix LAN control upload data to server error
+    if (_g_pdev->server_st == JL_SERVER_ST_WORK)
+    {
+        joylink_server_upload_req();
+    }
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ * @Param: sin_recv
+ * @Param: addrlen
+ */
+static void
+joylink_proc_lan_ctrl_timestamp_error_rsp(uint8_t *src, uint8_t src_len, struct sockaddr_in *sin_recv, socklen_t addrlen)
+{
+    int ret = -1;
+    int len = 0;
+    char data[JL_MAX_PACKET_LEN] = {0};
+
+    ret = joylink_packet_script_ctrl_error_rsp(data, sizeof(data));
+
+    log_info("rsp data:%s:len:%d", data + 12, ret);
+    len = joylink_encrypt_lan_basic(_g_pdev->send_buff, JL_MAX_PACKET_LEN,
+            ET_ACCESSKEYAES, PT_SCRIPTCONTROL,
+            (uint8_t*)_g_pdev->jlp.localkey, (const uint8_t*)data, ret);
+
+    if(len > 0 && len < JL_MAX_PACKET_LEN){ 
+        ret = sendto(_g_pdev->lan_socket, _g_pdev->send_buff, len, 0,
+                (SOCKADDR*)sin_recv, addrlen);
+
+        if(ret < 0){
+            log_error(" 1 send error ret:%d", ret);
+        }else{
+            log_info("rsp to:%s:len:%d", _g_pdev->jlp.ip, ret);
+        }
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+}
+/**
+ * brief: 
+ *
+ * @Param: data
+ * @Param: len
+ * @Param: sin_recv
+ * @Param: addrlen
+ *
+ * @Returns: 
+ */
+E_JLRetCode_t 
+joylink_proc_lan_rsp_send(uint8_t* data, int len,  struct sockaddr_in *sin_recv, socklen_t addrlen)
+{
+    int ret = E_RET_ERROR;
+    int en_len = 0;
+    en_len = joylink_encrypt_lan_basic(_g_pdev->send_buff, JL_MAX_PACKET_LEN,
+            ET_ACCESSKEYAES, PT_SCRIPTCONTROL,
+            (uint8_t*)_g_pdev->jlp.localkey, (const uint8_t*)data, len);
+
+    if(en_len > 0 && en_len < JL_MAX_PACKET_LEN){ 
+        ret = sendto(_g_pdev->lan_socket, _g_pdev->send_buff, en_len, 0,
+                (SOCKADDR*)sin_recv, addrlen);
+
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }else{
+            log_info("rsp to:%s:len:%d", _g_pdev->jlp.ip, ret);
+        }
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    joylink_server_upload_req();
+
+    return ret;
+}
+
+/**
+ * brief: 
+ */
+void
+joylink_proc_lan()
+{
+    int ret;
+    uint8_t recBuffer[JL_MAX_PACKET_LEN] = { 0 };
+    uint8_t recPainBuffer[JL_MAX_PACKET_LEN] = { 0 };
+    uint8_t *recPainText = NULL;
+
+    struct sockaddr_in sin_recv;
+    JLPacketHead_t* pHead = NULL;
+    JLPacketParam_t param;
+
+    bzero(&sin_recv, sizeof(sin_recv));
+    bzero(&param, sizeof(param));
+    socklen_t addrlen = sizeof(SOCKADDR);
+
+    ret = recvfrom(_g_pdev->lan_socket, recBuffer, 
+            sizeof(recBuffer), 0, (SOCKADDR*)&sin_recv, &addrlen);
+
+    int len = ret;
+
+    if(ret == -1){
+        goto RET;
+    }
+
+    joylink_util_get_ipstr(&sin_recv, _g_pdev->jlp.ip);
+
+    ret = joylink_dencypt_lan_req(&param, recBuffer, ret, recPainBuffer, JL_MAX_PACKET_LEN);
+    if (ret <= 0){
+        goto RET;
+    }
+
+    pHead = (JLPacketHead_t*)recBuffer;
+
+    if(pHead->total > 1){
+        log_info("PACKET WAIT TO JOIN!!!!!!:IP:%s", _g_pdev->jlp.ip);
+    }else{
+        recPainText = recPainBuffer;
+    }
+
+    if(NULL == recPainText){
+        goto RET;
+    }
+
+    log_info("------------- lan ctrl --------------");
+    switch (param.type){
+        case PT_SCAN:
+            if(param.version == 1){
+                log_info("PT_SCAN:%s (Scan->Type:%d, Version:%d)", 
+                        _g_pdev->jlp.ip, param.type, param.version);
+                joylink_proc_lan_scan(recPainText, &sin_recv, addrlen);
+            }
+            break;
+        case PT_WRITE_ACCESSKEY:
+            if(param.version == 1 &&
+                joylink_is_usr_timestamp_ok(_g_pdev->jlp.ip,*((int*)(recPainText)))){
+                log_info("PT_WRITE_ACCESSKEY");
+                log_info("-->write key org:%s", recPainText + 4);
+                joylink_proc_lan_write_key(recPainText, &sin_recv, addrlen);
+            }
+            break;
+        case PT_JSONCONTROL:
+            if(param.version == 1 &&
+                    joylink_is_usr_timestamp_ok(_g_pdev->jlp.ip,*((int*)(recPainText)))){
+                log_info("JSon Control->%s\n", recPainText + 4);
+                joylink_proc_lan_json_ctrl(recPainText + 4, &sin_recv, addrlen);
+            }
+            break;
+        case PT_SCRIPTCONTROL:
+            log_debug("SCRIPT Control serial->%d", *((int*)(recPainText + 8)));
+
+            int32_t biz_code = (int)(*((int *)(recPainText  + 4)));
+            if(biz_code == JL_BZCODE_GET_SNAPSHOT || biz_code == JL_BZCODE_CTRL){
+                if(param.version == 1 &&
+                        joylink_is_usr_timestamp_ok(_g_pdev->jlp.ip,*((int*)(recPainText)))){
+                    log_debug("SCRIPT Control->%s", recPainText + 12);
+                    joylink_proc_lan_script_ctrl(recPainText, ret,  &sin_recv, addrlen);
+                }else{
+                    //joylink_proc_lan_ctrl_timestamp_error_rsp(recPainText, ret,  &sin_recv, addrlen);
+                }
+            }else{
+                log_error("SCRIPT Control biz_code error:%d", biz_code);
+            }
+
+            break;
+        case PT_SUB_AUTH:
+            if(param.version == 1 &&
+                    joylink_is_usr_timestamp_ok(_g_pdev->jlp.ip,*((int*)(recPainText)))){
+                log_info("PT_SUB_AUTH");
+                log_debug("Control->%s", recPainText + 4);
+                joylink_proc_lan_sub_auth(recPainText + 4, &sin_recv, addrlen);
+            }
+            break;
+        case PT_SUB_LAN_JSON:
+            if(param.version == 1 &&
+                    joylink_is_usr_timestamp_ok(_g_pdev->jlp.ip,*((int*)(recPainText)))){
+                log_debug("Control->%s", recPainText + 4);
+                joylink_proc_lan_json_ctrl(recPainText + 4, &sin_recv, addrlen);
+            }
+            break;
+        case PT_SUB_LAN_SCRIPT:
+            if(param.version == 1 &&
+                    joylink_is_usr_timestamp_ok(_g_pdev->jlp.ip,*((int*)(recPainText)))){
+                log_info("PT_SUB_LAN_SCRIPT");
+                log_debug("localkey->%s", _g_pdev->jlp.localkey);
+                //log_debug("Control->%s", recPainText + 12 + 32);
+                joylink_proc_lan_sub_script_ctrl(recPainText, ret,
+                            &sin_recv, addrlen);
+            }
+            break;
+        case PT_SUB_ADD:
+            if(param.version == 1 &&
+                joylink_is_usr_timestamp_ok(_g_pdev->jlp.ip,*((int*)(recPainText)))){
+                log_info("PT_SUB_ADD");
+                log_debug("Sub add->%s", recPainText + 4);
+		{
+			int i = 0;
+			printf("test: \n");
+			for(i = 0; i < 32; i++)
+			{
+				printf("%02x ", recPainText[i]);
+			}
+			printf("\n");
+		}
+                joylink_proc_lan_sub_add(recPainText + 4, &sin_recv, addrlen);
+            }
+            break;
+#ifdef _AGENT_GW_
+        case PT_AGENT_ADD_SUBDEV:
+            if(param.version == 1 &&
+                joylink_is_usr_timestamp_ok(_g_pdev->jlp.ip,*((int*)(recPainText)))){
+                log_info("PT_AGENT_ADD_SUBDEV");
+                log_debug("PT_AGENT_ADD_SUBDEV->%s", recPainText + 4);
+                joylink_agent_proc_dev_add(recPainText + 4, &sin_recv, addrlen);
+            }
+        break;
+        case PT_AGENT_DEL_SUBDEV:
+            if(param.version == 1 &&
+                joylink_is_usr_timestamp_ok(_g_pdev->jlp.ip,*((int*)(recPainText)))){
+                log_debug("PT_AGENT_DEL_SUBDEV->%s", recPainText + 4);
+                joylink_agent_proc_dev_del(recPainText + 4, &sin_recv, addrlen);
+            }
+        break;
+        case PT_AGENT_GET_DEV_LIST:
+            if(param.version == 1 &&
+                joylink_is_usr_timestamp_ok(_g_pdev->jlp.ip, *((int*)(recPainText)))){
+                log_debug("PT_AGENT_GET_LIST->%s", recPainText + 4);
+                joylink_agent_proc_get_dev_list(recPainText + 4, 
+                        &sin_recv, addrlen);
+            }
+        break;
+#endif
+
+        default:
+            break;
+    }
+
+RET:
+/*
+    if(NULL != pHead
+            && pHead->total > 1
+            && NULL != recPainText){
+            free(recPainText);
+    }
+*/
+    return;
+}
+

+ 509 - 0
joylink/joylink/joylink_dev_sdk.c

@@ -0,0 +1,509 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(__RT_THREAD__)
+#include <stdint.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <netdb.h>
+#else
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#endif
+
+#include "joylink.h"
+#include "joylink_utils.h"
+#include "joylink_packets.h"
+#include "joylink_crypt.h"
+#include "joylink_json.h"
+#include "joylink_dev.h"
+#include "joylink_sub_dev.h"
+#include "joylink_config_handle.h"
+#include "joylink_extern.h"
+#ifdef JOYLINK_USING_SOFTAP
+#include "joylink_softap_start.h"
+#include "joylink_softap.h"
+#ifdef _IS_DEV_REQUEST_ACTIVE_SUPPORTED_
+#include "joylink_cloud_log.h"
+#include "joylink_dev_active.h"
+#endif /* _IS_DEV_REQUEST_ACTIVE_SUPPORTED_ */
+#endif /* JOYLINK_USING_SOFTAP  */
+JLDevice_t  _g_dev = {
+    .server_socket = -1,
+    .server_st = 0,
+    .hb_lost_count = 0,
+    .lan_socket = -1,
+    .local_port = 80
+};
+
+JLDevice_t  *_g_pdev = &_g_dev;
+
+static rt_bool_t is_start = RT_FALSE;
+static rt_sem_t jlp_sem = NULL;
+
+extern int
+joylink_proc_server_st();
+
+extern void
+joylink_proc_lan();
+
+extern void
+joylink_proc_server();
+
+extern int
+joylink_ecc_contex_init(void);
+
+extern void
+joylink_cloud_fd_lock();
+
+extern void
+joylink_cloud_fd_unlock();
+
+extern void
+joylink_agent_gw_thread_start();
+
+extern int
+joylink_softap_is_need_active(void);
+
+extern int
+joylink_softap_active_clear(void);
+
+extern void
+jl3_uECC_set_rng(uECC_RNG_Function rng_function);
+
+extern int
+joylink_is_usr_timestamp_ok(char *usr, int timestamp);
+
+extern void
+joylink_agent_req_cloud_proc();
+
+/**
+ * brief:
+ *
+ * @Param: ver
+ */
+void
+joylink_dev_set_ver(short ver)
+{
+    _g_pdev->jlp.version = ver;
+    joylink_dev_set_attr_jlp(&_g_pdev->jlp);
+}
+
+/**
+ * brief:
+ *
+ * @Returns:
+ */
+short
+joylink_dev_get_ver()
+{
+    return _g_pdev->jlp.version;
+}
+
+void
+joylink_lan_entry(void *param)
+{
+    int maxFd = 0, ret = 0;
+    fd_set  readfds;
+    struct timeval selectTimeOut;
+
+    while(is_start)
+    {
+        if (!joylink_dev_is_net_ok()){
+            rt_thread_mdelay(10);
+            continue;
+        }
+
+        FD_ZERO(&readfds);
+        FD_SET(_g_pdev->lan_socket, &readfds);
+        maxFd = (int)_g_pdev->lan_socket;
+
+        selectTimeOut.tv_usec = 0L;
+        selectTimeOut.tv_sec = (long)1;
+
+        ret = select(maxFd + 1, &readfds, NULL, NULL, &selectTimeOut);
+        if (ret < 0){
+            log_error("Lan socket select error: %s!\r\n", strerror(errno));
+            goto _exit;
+        }else if (ret == 0){
+        }else{
+            if (FD_ISSET(_g_pdev->lan_socket, &readfds)){
+                joylink_proc_lan();
+                rt_thread_mdelay(10);
+            }
+        }
+    }
+_exit:
+    if (_g_pdev->lan_socket >= 0) {
+        closesocket(_g_pdev->lan_socket);
+        _g_pdev->lan_socket = -1;
+    }
+}
+
+void
+joylink_lan_loop(void)
+{
+    int broadcastEnable = 1;
+    struct sockaddr_in sin;
+    rt_thread_t lan_tid = RT_NULL;
+
+    bzero(&sin, sizeof(sin));
+    sin.sin_addr.s_addr = htonl(INADDR_ANY);
+    sin.sin_family = AF_INET;
+    sin.sin_port = htons(_g_pdev->local_port);
+    _g_pdev->lan_socket = socket(AF_INET, SOCK_DGRAM, 0);
+
+    if (_g_pdev->lan_socket < 0){
+        log_error("lan socket() failed!");
+        return;
+    }
+
+    if (setsockopt(_g_pdev->lan_socket,
+                SOL_SOCKET, SO_BROADCAST,
+                (uint8_t *)&broadcastEnable,
+                sizeof(broadcastEnable)) < 0){
+        log_error("SO_BROADCAST ERR");
+    }
+
+    if(0 > bind(_g_pdev->lan_socket, (SOCKADDR*)&sin, sizeof(SOCKADDR))){
+        log_error("Bind lan socket error!");
+    }
+
+    lan_tid = rt_thread_create("joy_lan", joylink_lan_entry, RT_NULL, 10 * 1024, 10, 10);
+    if (lan_tid)
+    {
+        rt_thread_startup(lan_tid);
+    }
+}
+
+extern void
+joylink_agent_req_cloud_proc();
+
+char getin_config_flag = 0;
+
+/**
+ * brief:
+ */
+void
+joylink_main_loop(void)
+{
+    int ret;
+    struct timeval  selectTimeOut;
+    static uint32_t serverTimer;
+    static uint32_t runTimer;
+
+    static int interval = 0;
+    int active_req_count = 0;
+
+    joylink_util_timer_reset(&serverTimer);
+    joylink_util_timer_reset(&runTimer);
+
+    // init joylink semaphore
+    if (jlp_sem == NULL) {
+        jlp_sem = rt_sem_create("jlp_sem", 0, RT_IPC_FLAG_FIFO);
+        if (jlp_sem == RT_NULL)
+        {
+            log_error("sem create failed!\n");
+            return;
+        }
+    }
+
+    // start work
+    is_start = RT_TRUE;
+
+    // start lan socket loop
+    joylink_lan_loop();
+
+    while (is_start){
+            joylink_cloud_fd_lock();
+#if defined(JOYLINK_USING_SOFTAP)
+        if (getin_config_flag == 1) {
+            getin_config_flag = 0;
+            joylink_softap_start();
+        }
+#ifdef _IS_DEV_REQUEST_ACTIVE_SUPPORTED_
+
+        if(!joylink_dev_is_net_ok())
+        {
+            rt_thread_mdelay(10);
+            continue;
+        }
+
+        if(joylink_softap_is_need_active()){
+            joylink_cloud_log_post(TAGID_LOG_AP_CONNECTED, RES_LOG_SUCCES,NULL,"[CloudLog]Connect Ap Success","0",NULL);
+            log_info("dev active begin");
+            ret = joylink_dev_active_req();
+            if(ret >= 0){
+                log_info("dev active success");
+                joylink_softap_active_clear();
+            }else{
+                log_error("dev active failed try again");
+            }
+            active_req_count++;
+            log_info("active_req_count = %d",active_req_count);
+            if(active_req_count > 5){
+                joylink_softap_active_clear();
+                active_req_count = 0;
+                joylink_cloud_log_post(TAGID_LOG_AP_FULL_RES, RES_LOG_FAIL,NULL,"[CloudLog]device active failed,timeout","0",NULL);
+            }
+        }
+
+#endif /* _IS_DEV_REQUEST_ACTIVE_SUPPORTED_ */
+#elif defined(JOYLINK_USING_SMARTCONFIG) || defined(JOYLINK_USING_THUNDER_SLAVE)
+            if (getin_config_flag == 1) {
+                getin_config_flag = 0;
+                joylink_config_start(60 * 1000);
+            } else if (getin_config_flag == 2) {
+                getin_config_flag = 0;
+                joylink_config_stop();
+            }
+#endif /* JOYLINK_USING_SOFTAP || JOYLINK_USING_SMARTCONFIG */
+
+        if (joylink_util_is_time_out(serverTimer, interval)){
+            joylink_util_timer_reset(&serverTimer);
+            if(joylink_dev_is_net_ok()){
+                interval = joylink_proc_server_st();
+            }else{
+                interval = 100;
+            }
+        }
+
+        int maxFd;
+        fd_set  readfds;
+
+
+        FD_ZERO(&readfds);
+        if (_g_pdev->server_socket != -1
+               && _g_pdev->server_st > 0){
+            FD_SET(_g_pdev->server_socket, &readfds);
+        }
+        maxFd = (int)_g_pdev->server_socket;
+
+        selectTimeOut.tv_usec = 0L;
+        selectTimeOut.tv_sec = (long)1;
+
+        ret = select(maxFd + 1, &readfds, NULL, NULL, &selectTimeOut);
+        if (ret < 0){
+            log_error("Select ERR: %s!\r\n", strerror(errno));
+            goto UNLOOK_FD;
+        }else if (ret == 0){
+            goto UNLOOK_FD;
+        }else{
+            if((_g_pdev->server_socket != -1) &&
+                (FD_ISSET(_g_pdev->server_socket, &readfds))){
+                joylink_proc_server();
+            }
+        }
+
+        UNLOOK_FD:
+        joylink_cloud_fd_unlock();
+#ifdef _AGENT_GW_
+        if(E_RET_TRUE == is_joylink_server_st_work()){
+            /*log_debug("proc agent_req_cloud proc");*/
+            joylink_agent_req_cloud_proc();
+        }
+#endif
+    }
+
+    // clean interval timer
+    interval = 0;
+
+    // close socket and free memory
+    if (_g_pdev->server_socket >= 0) {
+        closesocket(_g_pdev->server_socket);
+        _g_pdev->server_socket = -1;
+    }
+
+#ifdef JOYLINK_USING_SOFTAP
+    extern int joylink_softap_stop(void);
+    joylink_softap_stop();
+#elif defined(JOYLINK_USING_THUNDER_SLAVE)
+    joylink_config_stop();
+#endif
+
+    // release a semaphore for joylink_main_stop()
+    rt_sem_release(jlp_sem);
+}
+
+
+/**
+ * brief:
+ */
+int
+joylink_check_cpu_mode(void)
+{
+    union
+    {
+        int data_int;
+        char data_char;
+    } temp;
+
+    temp.data_int = 1;
+
+    if(temp.data_char != 1){
+    return -1;
+    }else{
+    return 0;
+    }
+}
+
+int
+joylink_check_mac_capital(char *mac)
+{
+	int i = 0;
+
+	if(mac == NULL || strlen(mac) > 32){
+		return -1;
+	}
+	for(i = 0; i < strlen(mac); i++){
+		if(mac[i] >= 'a' && mac[i] <= 'f'){
+			mac[i] = mac[i] - 'a' + 'A';
+		}
+	}
+	//printf("Mac must are written in capitals!\n");
+}
+
+/**
+ * brief:
+ */
+static void
+joylink_dev_init()
+{
+    /**
+     *NOTE: If your model_code_flag is configed in cloud,
+     *Please set _g_pdev->model_code_flag = 1.
+     */
+    /*_g_pdev->model_code_flag = 1;*/
+    char mac[16] = {0};
+    char key[68] = {0};
+    char uuid[JOY_UUID_LEN] = {0};
+    char public_key[IDT_C_PK_LEN] = {0};
+
+    printf("\n/**************info********************/\n\n");
+    printf("sdk version: %s\n\n", _VERSION_);
+    printf("dev version: %d\n",JLP_VERSION);
+
+    printf("dev type: %d\n", JLP_DEV_TYPE);
+    printf("dev lan strl: %d\n", JLP_LAN_CTRL);
+    printf("dev cmd type: %d\n\n", JLP_CMD_TYPE);
+
+    if(joylink_dev_get_uuid(uuid) < 0){
+        printf("dev uuid: error!\n");
+    }else{
+        printf("dev uuid: %s\n", uuid);
+    }
+
+    if(joylink_dev_get_public_key(public_key) < 0){
+        printf("dev public key: error!\n\n");
+    }else{
+        printf("dev public key: %s\n\n", public_key);
+    }
+
+    if(joylink_dev_get_user_mac(mac) < 0){
+            printf("dev mac: error!\n");
+    }else{
+		joylink_check_mac_capital(mac);
+        printf("dev mac: %s\n", mac);
+    }
+    if(joylink_dev_get_private_key(key) < 0){
+            printf("dev private key: error!\n\n");
+    }else{
+        printf("dev private key: %s\n\n", key);
+    }
+    if(joylink_check_cpu_mode() == 0){
+            printf("plt mode: --ok! little-endian--\n\n");
+    }else{
+        printf("plt mode: --error! big-endian--\n\n");
+    }
+    printf("/*************************************/\n\n");
+
+    joylink_dev_get_jlp_info(&_g_pdev->jlp);
+    joylink_dev_get_idt(&_g_pdev->idt);
+    log_debug("--->feedid:%s", _g_pdev->jlp.feedid);
+    log_debug("--->uuid:%s", _g_pdev->jlp.uuid);
+    log_debug("--->accesskey:%s", _g_pdev->jlp.accesskey);
+    log_debug("--->localkey:%s", _g_pdev->jlp.localkey);
+}
+
+/**
+ * brief:
+ *
+ * @Returns:
+ */
+
+static int default_random(uint8_t *dest, unsigned size) {
+
+    char *ptr = (char *)dest;
+    size_t left = size;
+    while (left > 0) {
+        *ptr = (uint8_t)joylink_dev_get_random();
+        left--;
+        ptr++;
+    }
+    return 1;
+}
+
+int
+joylink_main_start(void)
+{
+    jl3_uECC_set_rng((uECC_RNG_Function) &default_random);
+    joylink_ecc_contex_init();
+    joylink_dev_init();
+
+#ifdef _AGENT_GW_
+    joylink_agent_devs_load();
+    joylink_agent_gw_thread_start();
+#endif
+    joylink_main_loop();
+    return 0;
+}
+
+int
+joylink_main_stop(void)
+{
+#define JOYLINK_SEM_TIMO   (5 * RT_TICK_PER_SECOND)
+    if (is_start == RT_TRUE) {
+        // stop work
+        is_start = RT_FALSE;
+
+        // get close success semaphore
+        if (rt_sem_take(jlp_sem, JOYLINK_SEM_TIMO) < 0)
+        {
+            return -1;
+        }
+
+        // clean local server sattus
+        _g_pdev->server_st = 0;
+        _g_pdev->hb_lost_count = 0;
+    }
+
+    return 0;
+}
+
+int joylink_sdk_feedid_get(char *buf,char buflen)
+{
+    if(strlen(_g_pdev->jlp.feedid) == 0){
+        return -1;
+    }
+    if(buflen < (strlen(_g_pdev->jlp.feedid) + 1)){
+        log_error("buflen error");
+        return -1;
+    }
+
+    memset(buf,0,buflen);
+    strcpy(buf,_g_pdev->jlp.feedid);
+    return 0;
+
+}
+

+ 1021 - 0
joylink/joylink/joylink_dev_server.c

@@ -0,0 +1,1021 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(__RT_THREAD__)
+#include <stdint.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#elif defined(__MTK_7687__)
+#include <stdint.h>
+#include "lwip/sockets.h"
+#include "lwip/netdb.h"
+#else
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <fcntl.h>
+#endif
+
+#include "joylink.h"
+#include "joylink_utils.h"
+#include "joylink_packets.h"
+#include "joylink_crypt.h"
+#include "joylink_json.h"
+#include "joylink_sub_dev.h"
+#include "joylink_dev_timer.h"
+#include "joylink_dev.h"
+#include "joylink_extern_sub_dev.h"
+
+extern int _g_model_code_flag;
+
+extern void
+joylink_agent_cloud_rsp(int32_t type, char * src, int32_t src_len);
+
+#ifdef _AGENT_GW_
+pthread_mutex_t    fd_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+/**
+ * brief:
+ */
+void joylink_cloud_fd_lock()
+{
+#ifdef _AGENT_GW_
+    pthread_mutex_lock(&fd_lock);
+#endif
+}
+
+/**
+ * brief:
+ */
+void joylink_cloud_fd_unlock()
+{
+#ifdef _AGENT_GW_
+    pthread_mutex_unlock(&fd_lock);
+#endif
+}
+
+/**
+ * brief:
+ */
+int
+joylink_server_st_close()
+{
+    _g_pdev->hb_lost_count = 0;
+    _g_pdev->server_st = JL_SERVER_ST_INIT;
+    close(_g_pdev->server_socket);
+    _g_pdev->server_socket = -1;
+}
+
+/**
+ * brief:
+ */
+static void
+joylink_server_st_time_out_check()
+{
+    log_debug("server st :%d", _g_pdev->server_st);
+    if(_g_pdev->hb_lost_count >= JL_MAX_SERVER_HB_LOST){
+        if(_g_pdev->server_st == JL_SERVER_ST_WORK){
+            log_info("Server HB Lost, Reconnect!\r\n");
+            joylink_server_st_close();
+        }
+    }
+}
+
+/**
+ * brief:
+ */
+static char joylink_server_ip[32] = {0};
+static char joylink_server_url[128] = {0};
+
+static int
+joylink_server_st_init()
+{
+    int ret = -1;
+    struct sockaddr_in saServer;
+
+    struct hostent *host = NULL;
+
+    bzero(&saServer, sizeof(saServer));
+
+    saServer.sin_family = AF_INET;
+
+    saServer.sin_port = htons(_g_pdev->jlp.server_port);
+
+#ifdef _GET_HOST_BY_NAME_
+    if(strcmp(joylink_server_url, _g_pdev->jlp.joylink_server) != 0){
+	memset(joylink_server_url, 0, 128);
+	memcpy(joylink_server_url, _g_pdev->jlp.joylink_server, strlen(_g_pdev->jlp.joylink_server));
+	memset(joylink_server_ip, 0, sizeof(joylink_server_ip));
+    }
+    if(strlen(joylink_server_ip) == 0){
+	    log_info("gethostbyname: start");
+	    if((host = gethostbyname(joylink_server_url)) == NULL) {
+		log_info("gethostbyname: error");
+		return -1;
+	    }
+	    log_info("gethostbyname: ok!");
+
+    	    saServer.sin_addr = *((struct in_addr *)host->h_addr);
+	    log_info("Joylink server: %s, ip: %s\n", joylink_server_url, inet_ntoa(saServer.sin_addr));
+    }else{
+	    saServer.sin_addr.s_addr = inet_addr(joylink_server_ip);
+	    log_info("Joylink server: %s, ip: %s\n", joylink_server_url, joylink_server_ip);
+    }
+#else
+    saServer.sin_addr.s_addr = inet_addr(_g_pdev->jlp.joylink_server);
+#endif
+    _g_pdev->server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+    if (_g_pdev->server_socket < 0 ){
+        perror("socket error");
+        log_error("socket() failed!\n");
+        return -1;
+    }
+
+    ret = connect(_g_pdev->server_socket,
+            (struct sockaddr *)&saServer,
+            sizeof(saServer));
+
+    if(ret < 0){
+        log_error("connect() server failed!:%d\n", ret);
+        close(_g_pdev->server_socket);
+        _g_pdev->server_st = 0;
+    }else{
+        log_info("joylink server connect success!\n");
+        _g_pdev->server_st = 1;
+    }
+    _g_pdev->hb_lost_count = 0;
+
+    memset(joylink_server_ip, 0, sizeof(joylink_server_ip));
+    strcpy(joylink_server_ip, inet_ntoa(saServer.sin_addr));
+
+	if (ret >= 0)
+    {
+        int32_t fd  = _g_pdev->server_socket;
+        int32_t flags;
+        if ((flags = fcntl(fd, F_GETFL)) == -1) {
+            log_error("server fd set failed!");
+        }
+        if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)
+                == -1) {
+            log_error("server fd set failed!");
+        }
+    }
+    return ret;
+}
+
+/**
+ * brief:
+ */
+static void
+joylink_server_st_auth()
+{
+    int ret;
+    int len = joylink_packet_server_auth_rsp();
+
+    ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+    if(ret < 0){
+        log_error("send error ret:%d", ret);
+    }
+    log_debug("Auth with server----->ret:%d\n", ret);
+}
+
+/**
+ * brief:
+ */
+static void
+joylink_server_st_work()
+{
+    int ret;
+    int len = 0;
+	int i = 0;
+
+    if(E_JLDEV_TYPE_GW != _g_pdev->jlp.devtype){
+        len = joylink_packet_server_hb_req();
+    }else{
+	len = joylink_packet_server_sub_hb_req();
+	if(len <= 0){
+		len = joylink_packet_server_hb_req();
+	}
+    }
+
+    ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+    if(ret < 0){
+        log_error("send error ret:%d", ret);
+    }
+
+    log_debug("HB----->");
+    _g_pdev->hb_lost_count ++;
+}
+
+/**
+ * brief:
+ *
+ * @Returns:
+ */
+int
+joylink_proc_server_st()
+{
+    int ret = 0;
+    int interval = 5000;
+    if(!strlen(_g_pdev->jlp.feedid)){
+        log_debug("feedid is empty");
+        return interval;
+    }
+
+    joylink_server_st_time_out_check();
+
+    switch (_g_pdev->server_st){
+        case JL_SERVER_ST_INIT:
+            ret = joylink_server_st_init();
+            if(ret < 0){
+            	interval = 2000;
+            }else{
+                interval = 100;
+            }
+            break;
+        case JL_SERVER_ST_AUTH:
+            joylink_server_st_auth();
+            if (_g_pdev->hb_lost_count == 0){
+                interval = 500;
+            }
+            interval = 500;
+            _g_pdev->hb_lost_count++;
+            break;
+        case JL_SERVER_ST_WORK:
+            joylink_server_st_work();
+            interval = 15000;
+	        //interval = 5000;
+            break;
+        default:
+            log_debug("Unknow server st:%d", _g_pdev->server_st);
+            break;
+    }
+
+    joylink_dev_set_connect_st(_g_pdev->server_st);
+
+	return interval;
+}
+
+/**
+ * brief:
+ *
+ * @Returns:
+ */
+E_JLBOOL_t
+is_joylink_server_st_work()
+{
+    return _g_pdev->server_st == JL_SERVER_ST_WORK? E_RET_TRUE:E_RET_FAIL;
+}
+
+/**
+ * brief:
+ *
+ * @Returns:
+ */
+int
+joylink_server_upload_modelcode_req()
+{
+    int ret = -1;
+    int time_v;
+    int len;
+    char data[JL_MAX_PACKET_LEN] = {0};
+
+    ret = joylink_dev_get_modelcode(data + 4, JL_MAX_PACKET_LEN - 4);
+
+    if(ret > 0){
+        time_v = time(NULL);
+        memcpy(data, &time_v, 4);
+
+        len = joylink_encypt_server_rsp(
+                _g_pdev->send_buff,
+                JL_MAX_PACKET_LEN, PT_MODEL_CODE,
+                _g_pdev->jlp.sessionKey,
+                (uint8_t*)&data,
+                ret + 4);
+
+        if(len > 0 && len < JL_MAX_PACKET_LEN){
+            ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+            if(ret < 0){
+                log_error("send error ret:%d", ret);
+            }
+            log_debug("send to server len:%d:ret:%d\n", len, ret);
+        }else{
+            log_error("send data too big or packe error:ret:%d", ret);
+        }
+    }
+
+    return ret;
+}
+
+/**
+ * brief:
+ *
+ * @Returns:
+ */
+int
+joylink_server_upload_req()
+{
+    int ret = -1;
+    int time_v;
+    int len;
+    char data[JL_MAX_PACKET_LEN] = {0};
+
+    ret = joylink_dev_get_snap_shot(data + 4, JL_MAX_PACKET_LEN - 4);
+
+    if(ret > 0){
+        time_v = time(NULL);
+        memcpy(data, &time_v, 4);
+
+        len = joylink_encypt_server_rsp(
+                _g_pdev->send_buff,
+                JL_MAX_PACKET_LEN, PT_UPLOAD,
+                _g_pdev->jlp.sessionKey,
+                (uint8_t*)&data,
+                ret + 4);
+
+        if(len > 0 && len < JL_MAX_PACKET_LEN){
+            ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+            if(ret < 0){
+                log_error("send error ret:%d", ret);
+            }
+            log_debug("send to server len:%d:ret:%d\n", len, ret);
+        }else{
+            log_error("send data too big or packe error:ret:%d", ret);
+        }
+    }
+
+    return ret;
+}
+
+/**
+ * brief:
+ *
+ * @Returns:
+ */
+static int
+joylink_server_subdev_upload_req()
+{
+    int ret = -1;
+    int time_v;
+    int len;
+    char data[JL_MAX_PACKET_LEN] = {0};
+    int i;
+    JLSubDevData_t *alldevinfo = NULL;
+    int count;
+    int scan_type = 0;
+    char *snap_shot = NULL;
+
+    alldevinfo = joylink_dev_sub_devs_get(&count);
+
+    for(i = 0; i < count; i++){
+        snap_shot = joylink_dev_sub_get_snap_shot(alldevinfo[i].feedid, &ret);
+
+        if(snap_shot != NULL){
+            ret = joylink_encrypt_sub_dev_data(
+                    (uint8_t*)(data + 4 + 32),
+                    sizeof(data) - 4 -32,
+                    ET_ACCESSKEYAES,
+                    (uint8_t*)alldevinfo[i].accesskey,
+                    (uint8_t*)snap_shot,
+                    ret);
+
+            free(snap_shot);
+            snap_shot = NULL;
+        }
+
+        if(ret > 0){
+            time_v = time(NULL);
+            memcpy(data, &time_v, 4);
+            memcpy(data+4, alldevinfo[i].feedid, 32);
+
+            len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN,
+                PT_SUB_UPLOAD, _g_pdev->jlp.sessionKey,
+                (uint8_t*)data, ret + 4 + 32) ;
+
+            if(len > 0 && len < JL_MAX_PACKET_LEN){
+                ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+                if(ret < 0){
+                    log_error("send error ret:%d", ret);
+                }
+                log_debug("send to server len:%d:ret:%d\n", len, ret);
+            }else{
+                log_error("send data too big or packet error:ret:%d", ret);
+            }
+        }
+    }
+
+    if(NULL != alldevinfo){
+        free(alldevinfo);
+    }
+
+    return ret;
+}
+
+
+/**
+ * brief:
+ *
+ * @Returns:
+ */
+static int
+joylink_server_subdev_upload_req_alone(char *feedid)
+{
+	int ret = -1;
+	int time_v;
+	int len;
+	char data[JL_MAX_PACKET_LEN] = {0};
+	int scan_type = 0;
+	char *snap_shot = NULL;
+
+	JLSubDevData_t dev;
+
+	memset(&dev, 0, sizeof(JLSubDevData_t));
+
+	ret = joylink_dev_sub_get_by_feedid(feedid, &dev);
+	if(ret < 0){
+		log_error("Can't find the suddev, ret:%d", ret);
+		return ret;
+	}
+
+	snap_shot = joylink_dev_sub_get_snap_shot(feedid, &ret);
+
+	if(snap_shot != NULL){
+		ret = joylink_encrypt_sub_dev_data(
+			(uint8_t*)(data + 4 + 32),
+			sizeof(data) - 4 -32,
+			ET_ACCESSKEYAES,
+			(uint8_t*)dev.accesskey,
+			(uint8_t*)snap_shot,
+			ret);
+
+		free(snap_shot);
+		snap_shot = NULL;
+	}
+
+	if(ret > 0){
+		time_v = time(NULL);
+		memcpy(data, &time_v, 4);
+		memcpy(data+4, feedid, 32);
+
+		len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN,
+			PT_SUB_UPLOAD, _g_pdev->jlp.sessionKey,
+			(uint8_t*)data, ret + 4 + 32) ;
+
+		if(len > 0 && len < JL_MAX_PACKET_LEN){
+			ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+			if(ret < 0){
+				log_error("send error ret:%d", ret);
+			}
+			log_debug("send to server len:%d:ret:%d\n", len, ret);
+		}else{
+			log_error("send data too big or packet error:ret:%d", ret);
+		}
+	}
+	return ret;
+}
+
+
+/**
+ * brief:
+ *
+ * @Param: recPainText
+ */
+static void
+joylink_proc_server_auth(uint8_t* recPainText)
+{
+    JLAuthRsp_t* p = (JLAuthRsp_t*)recPainText;
+    bzero(_g_pdev->jlp.sessionKey, 33);
+    memcpy(_g_pdev->jlp.sessionKey, p->session_key, 32);
+
+    log_debug("OK===>Rand=%u,Time:%u!\r\n",
+            p->random_unm, p->timestamp);
+
+    _g_pdev->cloud_timestamp = p->timestamp;
+    _g_pdev->cloud_serial = 0;
+
+    log_info("AUTH OK\n");
+
+    if(E_JLDEV_TYPE_GW != _g_pdev->jlp.devtype){
+        joylink_server_upload_req();
+    }
+    _g_pdev->server_st = JL_SERVER_ST_WORK;
+}
+
+extern int
+joylink_cloud_timestamp_sync_check_reset_timecache();
+
+/**
+ * brief:
+ *
+ * @Param: recPainText
+ */
+static void
+joylink_proc_server_hb(uint8_t* recPainText)
+{
+    _g_pdev->server_st = JL_SERVER_ST_WORK;
+    JLHearBeatRst_t* p = (JLHearBeatRst_t*)recPainText;
+    _g_pdev->hb_lost_count = 0;
+
+    _g_pdev->cloud_timestamp = p->timestamp;
+    log_info("HEAT BEAT OK===>Code=%u,Time:%u!\r\n",
+            p->code, p->timestamp);
+
+    if(_g_pdev->model_code_flag == 1) {
+    	joylink_server_upload_modelcode_req();
+    }
+
+    joylink_cloud_timestamp_sync_check_reset_timecache();
+
+    if(E_JLDEV_TYPE_GW != _g_pdev->jlp.devtype){
+        joylink_server_upload_req();
+    }else{
+        int ret = joylink_server_subdev_upload_req();
+	if(ret <= 0){
+		joylink_server_upload_req();
+	}
+    }
+}
+
+/**
+ * brief:
+ *
+ * @Param: recPainText
+ * @Param: src_len
+ */
+static void
+joylink_proc_server_ctrl(uint8_t* recPainText, int32_t src_len)
+{
+    int ret = -1;
+    int len;
+    char data[JL_MAX_PACKET_LEN] = {0};
+    JLContrl_t ctr;
+    bzero(&ctr, sizeof(ctr));
+
+    log_debug("Control from server:%s:len:%d\n",
+            recPainText + 12, (int)strlen((char*)(recPainText + 12)));
+
+    if(-1 == joylink_dev_script_ctrl((const char *)recPainText, src_len, &ctr, 2)){
+        return;
+    }
+    ret = joylink_packet_script_ctrl_rsp(data, sizeof(data), &ctr);
+    log_debug("rsp data:%s:len:%d",
+            (char *)(data + 12),
+            (int)strlen((char *)(data + 12)));
+
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN,
+            PT_SERVERCONTROL, _g_pdev->jlp.sessionKey,
+            (uint8_t*)data, ret);
+
+    if(len > 0 &&  len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+}
+
+/**
+ * brief:
+ *
+ * @Param: recPainText
+ */
+static void
+joylink_proc_server_upload(uint8_t* recPainText)
+{
+    JLDataUploadRsp_t* p = (JLDataUploadRsp_t *)recPainText;
+    log_info("UPLOAD OK timestamp %d code %d\r\n", (int)p->timestamp, (int)p->code);
+}
+
+/**
+ * brief:
+ *
+ * @Param: recPainText
+ */
+static void
+joylink_proc_server_sub_hb(uint8_t* recPainText)
+{
+    JLDataSubHbRsp_t* p = (JLDataSubHbRsp_t *)recPainText;
+    log_info("SUB_HB OK -->timestamp %d code %d\r\n", (int)p->timestamp, (int)p->code);
+
+    _g_pdev->server_st = JL_SERVER_ST_WORK;
+    _g_pdev->hb_lost_count = 0;
+
+    if(E_JLDEV_TYPE_GW != _g_pdev->jlp.devtype){
+        joylink_server_upload_req();
+    }else{
+        joylink_server_subdev_upload_req();
+    }
+}
+
+/**
+ * brief:
+ *
+ * @Param: recPainText
+ */
+static void
+joylink_proc_server_sub_upload(uint8_t* recPainText)
+{
+    JLDataSubUploadRsp_t* p = (JLDataSubUploadRsp_t *)recPainText;
+    log_info("SUB DEV UPLOAD OK timestamp %d feedid %s code %d\r\n",
+        (int)p->timestamp, p->feedid, (int)p->code);
+}
+
+/**
+ * brief:
+ *
+ * @Param: recPainText
+ * @Param: payloadlen
+ */
+static void
+joylink_proc_server_sub_ctrl(uint8_t* recPainText, unsigned short payloadlen)
+{
+    int ret = -1;
+    int len;
+    char data[JL_MAX_PACKET_LEN] = {0};
+    JLSubContrl_t ctr;
+    bzero(&ctr, sizeof(ctr));
+
+    if(-1 == joylink_subdev_script_ctrl(recPainText, &ctr, payloadlen)){
+        return;
+    }
+
+    ret = joylink_packet_subdev_script_ctrl_rsp(data, sizeof(data), &ctr);
+
+    int *org_s = (int*)(recPainText + 8);
+    int *p_ser = (int*)(data + 8);
+    log_debug("---org serial:%d:packet serial:%d, %d", *org_s, *p_ser,  (int)ctr.serial);
+
+    log_debug("rsp data:%s:len:%d",
+            (char *)(data + 12),
+            (int)strlen((char *)(data + 12)));
+
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN,
+            PT_SUB_CLOUD_CTRL, _g_pdev->jlp.sessionKey,
+            (uint8_t*)data, ret);
+
+    if(len > 0 &&  len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+}
+
+/**
+ * brief:
+ *
+ * @Param: recPainText
+ * @Param: payloadlen
+ */
+static void
+joylink_proc_server_sub_unbind(uint8_t* recPainText, unsigned short payloadlen)
+{
+    int ret = -1;
+    int len;
+    char data[JL_MAX_PACKET_LEN] = {0};
+
+    int i = 0;
+    for(i =0; i < payloadlen; i++){
+        printf("%02x ", (int)recPainText[i]);
+    }
+    printf("\n");
+
+    JLSubUnbind_t unbind;
+    bzero(&unbind, sizeof(unbind));
+
+    if(-1 == joylink_subdev_unbind(recPainText, &unbind)){
+        return;
+    }
+    ret = joylink_packet_subdev_unbind_rsp(data, sizeof(data), &unbind);
+    if(-1 == ret){
+        return;
+    }
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN,
+        PT_SUB_UNBIND, _g_pdev->jlp.sessionKey,
+        (uint8_t*)data, payloadlen);
+
+    if(len > 0 &&  len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    if(NULL != unbind.info){
+        free(unbind.info);
+    }
+}
+
+/**
+ * brief:
+ *
+ * @Param: otaUpload
+ */
+void
+joylink_server_ota_status_upload_req(JLOtaUpload_t *otaUpload)
+{
+    int ret = -1;
+    int len = 0;
+    len = joylink_package_ota_upload_req(otaUpload);
+
+    if(len > 0 && len <JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d\n", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d\n", ret);
+    }
+}
+
+#ifdef _AGENT_GW_
+extern void
+joylink_agent_cloud_ota_to_dev(char * feedid,
+        uint8_t* recPainText, int32_t src_len,
+        uint8_t* o_result, int32_t o_max, int32_t *o_len);
+
+#endif
+
+/**
+ * brief:
+ *
+ * @Param: json
+ * @Param: json_len
+ */
+static void
+joylink_proc_server_ota_order(uint8_t* src, int src_len)
+{
+    int ret = -1;
+    int len = 0;
+    JLOtaOrder_t otaOrder;
+    bzero(&otaOrder, sizeof(otaOrder));
+
+    ret = joylink_parse_server_ota_order_req(&otaOrder,
+            (char *)(src + 4));
+    if(ret != 0){
+        return;
+    }
+
+    #ifdef _AGENT_GW_
+    joylink_agent_cloud_ota_to_dev(otaOrder.feedid, src, src_len, _g_pdev->send_buff, sizeof(_g_pdev->send_buff), &len);
+    #else
+    len = joylink_packet_server_ota_order_rsp(&otaOrder);
+    #endif
+
+    if(len > 0 && len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }else{
+            log_info("send to server len:%d:ret:%d\n", len, ret);
+        }
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    ret = joylink_dev_ota(&otaOrder);
+    if(ret != 0){
+        log_error("dev ota error:ret:%d\n", ret);
+        return;
+    }
+
+
+    if(!strcmp(_g_pdev->jlp.feedid, otaOrder.feedid)){
+        joylink_dev_ota_status_upload();
+    }
+}
+
+
+/**
+ * brief:
+ *
+ * @Param: json
+ */
+static void
+joylink_proc_server_ota_upload(uint8_t* json)
+{
+    int ret = -1;
+    JLOtaUploadRsp_t otaUpload;
+    bzero(&otaUpload, sizeof(JLOtaUploadRsp_t));
+
+    ret = joylink_parse_server_ota_upload_req(&otaUpload, (const char*)json);
+
+    if(ret != 0){
+        return;
+    }
+
+    log_info("OTA UPLOAD ACK code %d msg %s\r\n",
+        otaUpload.code, otaUpload.msg);
+}
+
+/**
+ * brief:
+ *
+ * @Param: fd
+ * @Param: rec_buff
+ * @Param: max
+ *
+ * @Returns:
+ */
+int
+joylink_server_recv(char fd, char *rec_buff, int max)
+{
+    JLPacketHead_t head;
+    bzero(&head, sizeof(head));
+    E_PT_REV_ST_t st = E_PT_REV_ST_MAGIC;
+    int ret;
+
+    do{
+        switch(st){
+            case E_PT_REV_ST_MAGIC:
+                ret = recv(fd, &head.magic, sizeof(head.magic), 0);
+                if(head.magic == 0x123455CC){
+                    st = E_PT_REV_ST_HEAD;
+                }
+                break;
+            case E_PT_REV_ST_HEAD:
+                ret = recv(fd, &head.optlen, sizeof(head) - sizeof(head.magic), 0);
+                if(ret > 0){
+                    st = E_PT_REV_ST_DATA;
+                }
+                break;
+            case E_PT_REV_ST_DATA:
+                if(head.optlen + head.payloadlen < max - sizeof(head)){
+                    ret = recv(fd, rec_buff + sizeof(head), head.optlen + head.payloadlen , 0);
+                    if(ret > 0){
+                        memcpy(rec_buff, &head, sizeof(head));
+                        ret = ret + sizeof(head);
+                        st = E_PT_REV_ST_END;
+                    }
+
+                }else{
+                    ret = -1;
+                    log_fatal("recev buff is too small");
+                }
+                break;
+            default:
+                break;
+        }
+    }while(ret>0 && st != E_PT_REV_ST_END);
+
+    if (ret == -1 || ret == 0){
+        return -1;
+    }
+
+    return ret;
+}
+
+/**
+ * brief:
+ */
+int
+joylink_is_server_timestamp_ok(uint8_t *data)
+{
+	int timestamp_now = 0;
+	int serial_now = 0;
+
+	memcpy((char *)&timestamp_now, data, 4);
+	memcpy((char *)&serial_now, data+8, 4);
+
+	// printf("time now: %d, time old: %d\n", timestamp_now, _g_pdev->cloud_timestamp);
+	// printf("serial now: %d, serial old: %d\n", serial_now, _g_pdev->cloud_serial);
+
+	if(timestamp_now >= _g_pdev->cloud_timestamp && serial_now > _g_pdev->cloud_serial){
+		_g_pdev->cloud_timestamp = timestamp_now;
+		_g_pdev->cloud_serial = serial_now;
+		return 0;
+	}
+	return -1;
+}
+
+/**
+ * brief:
+ */
+int
+joylink_is_ota_timestamp_ok(uint8_t *data)
+{
+	int timestamp_now = 0;
+
+	memcpy((char *)&timestamp_now, data, 4);
+
+	printf("time now: %d, time old: %d\n", timestamp_now, _g_pdev->cloud_timestamp);
+
+	if(timestamp_now > _g_pdev->cloud_timestamp){
+		_g_pdev->cloud_timestamp = timestamp_now;
+		return 0;
+	}
+	return -1;
+}
+
+/**
+ * brief:
+ */
+void
+joylink_proc_server()
+{
+    uint8_t recBuffer[JL_MAX_PACKET_LEN * 2 ] = { 0 };
+    uint8_t recPainText[JL_MAX_PACKET_LEN * 2 + 16] = { 0 };
+    int ret;
+
+    ret = joylink_server_recv(_g_pdev->server_socket, (char*)recBuffer, JL_MAX_PACKET_LEN * 2);
+    if (ret == -1 || ret == 0){
+        close(_g_pdev->server_socket);
+        _g_pdev->server_socket = -1;
+        _g_pdev->server_st = 0;
+        log_info("Server close, Reconnect!\r\n");
+        return;
+    }
+
+    JLPacketParam_t param;
+    ret = joylink_dencypt_server_req(&param, recBuffer,
+            ret, recPainText, JL_MAX_PACKET_LEN, NULL);
+
+    if (ret < 1){
+        return;
+    }
+
+    log_info("Server org ctrl type:%d:", param.type);
+    switch (param.type){
+        case PT_AUTH:
+            joylink_proc_server_auth(recPainText);
+            break;
+        case PT_BEAT:
+            joylink_proc_server_hb(recPainText);
+            break;
+        case PT_MODEL_CODE:
+            /*model code only report once, reset the flag*/
+            _g_pdev->model_code_flag = 0;
+            break;
+        case PT_SERVERCONTROL:
+	    if(joylink_is_server_timestamp_ok(recPainText) != 0){
+		return;
+	    }
+            joylink_proc_server_ctrl(recPainText, ret);
+            break;
+        case PT_UPLOAD:
+            joylink_proc_server_upload(recPainText);
+            break;
+        case PT_SUB_HB:
+            joylink_proc_server_sub_hb(recPainText);
+            break;
+        case PT_SUB_UPLOAD:
+            joylink_proc_server_sub_upload(recPainText);
+            break;
+        case PT_SUB_CLOUD_CTRL:
+	    if(joylink_is_server_timestamp_ok(recPainText) != 0){
+		return;
+	    }
+            joylink_proc_server_sub_ctrl(recPainText, ret);
+            break;
+        case PT_SUB_UNBIND:
+	    if(joylink_is_server_timestamp_ok(recPainText) != 0){
+		return;
+	    }
+            joylink_proc_server_sub_unbind(recPainText, ret);
+            break;
+        case PT_OTA_ORDER:
+	    if(joylink_is_ota_timestamp_ok(recPainText) != 0){
+		return;
+	    }
+            joylink_proc_server_ota_order(recPainText, ret);
+            break;
+        case PT_OTA_UPLOAD:
+            joylink_proc_server_ota_upload(recPainText + 4);
+            break;
+        case PT_TIME_TASK:
+            joylink_proc_time_task((char *)recPainText, ret);
+            break;
+#ifdef _AGENT_GW_
+        case PT_AGENT_AUTH:
+        case PT_AGENT_HB:
+        case PT_AGENT_UPLOAD:
+        case PT_AGENT_DEV_CTRL:
+            joylink_agent_cloud_rsp(param.type, (char *)recPainText, ret);
+            break;
+#endif
+        default:
+            log_debug("Unknow param type.\r\n");
+            break;
+    }
+}

+ 992 - 0
joylink/joylink/joylink_dev_timer.c

@@ -0,0 +1,992 @@
+#include <stdio.h>
+
+#ifdef __LINUX_UB2__
+#include <stdint.h>
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "joylink.h"
+#include "joylink_utils.h"
+#include "joylink_packets.h"
+#include "joylink_crypt.h"
+#include "joylink_dev_timer.h"
+#include "joylink_json.h"
+
+/**
+ * brief: 
+ *
+ * @Param: req
+ *
+ * @Returns: 
+ */
+static E_JLRetCode_t
+joylink_dev_time_task_add(JLTimeTaskReq_t *req)
+{
+    int ret = E_RET_OK;
+
+    //FIXME: must to do
+    int i;
+    for(i=0; i<req->task_num; i++)
+    {
+        log_debug("joylink_dev_time_task_add req->tasks[%d].mode =%d, task_num = %d\n", i, req->tasks[i].mode, req->task_num);
+        switch(req->tasks[i].mode)
+        {
+            case BASE_MODE:
+                log_info("BASE_MODE\r\n");
+            break;
+            case PERIOD_MODE:
+                log_info("PERIOD_MODE\r\n");
+            break;
+
+            case CYCLE_MODE:
+                log_info("CYCLE_MODE\r\n");
+            break;
+            case COUNTDOWN_MODE:
+                log_info("COUNTDOWN_MODE\r\n");
+            break;
+            
+            default:
+            ;      
+        }
+
+    }
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ *
+ * @Returns: 
+ */
+static int
+joylink_time_task_get_biz_code(char *src)
+{
+    int pret_code = *(int*)(src + 4);
+    return pret_code; 
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+//-------BIZ_CODE_TIME_TASK_CHECK_REQ ------ 
+static E_JLBOOL_t
+joylink_dev_is_support_time_task()
+{
+    /**
+     *FIXME:must to do
+     */
+    int ret = E_RET_TRUE;
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+static int
+joylink_packet_is_support_time_task_rsp()
+{
+    int32_t support = E_RET_ERROR;
+
+    JLTimeTaskRsp_t rsp;
+
+    rsp.ch.timestamp = time(NULL);
+    rsp.ch.biz_code = BIZ_CODE_TIME_TASK_CHECK_RSP;
+    bzero(_g_pdev->dev_detail, sizeof(_g_pdev->dev_detail));
+
+    memcpy(_g_pdev->dev_detail, &rsp, 12);
+
+    if(E_RET_TRUE == joylink_dev_is_support_time_task()){
+        support = 0;
+    }
+
+    memcpy(_g_pdev->dev_detail + 12, &support, 4);
+
+    return 16;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ *
+ * @Returns: 
+ */
+static int
+joylink_proc_is_support_time_task(char *src, int src_len)
+{
+    if(NULL == src){
+        return E_RET_ERROR;
+    }
+    int ret = -1;
+    int len;
+
+    log_debug("Check is support time task\n");
+
+    ret = joylink_packet_is_support_time_task_rsp();
+
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN, 
+            PT_TIME_TASK, _g_pdev->jlp.sessionKey, 
+            (uint8_t *)_g_pdev->dev_detail, ret);
+
+    if(len > 0 &&  len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    return ret;
+}
+
+//-------BIZ_CODE_TIME_TASK_ADD_REQ ------ 
+/**
+ * brief: 
+ *
+ * @Param: req
+ * @Param: ret_code
+ *
+ * @Returns: 
+ */
+int
+joylink_packet_time_task_add_rsp(JLTimeTaskReq_t *req, int32_t ret_code)
+{
+    JLTimeTaskRsp_t rsp;
+    rsp.ch.timestamp = time(NULL);
+    rsp.ch.biz_code = BIZ_CODE_TIME_TASK_ADD_RSP;
+    rsp.ch.serial = req->ch.serial;
+    rsp.code = ret_code;
+
+    bzero(_g_pdev->dev_detail, sizeof(_g_pdev->dev_detail));
+
+    memcpy(_g_pdev->dev_detail, &rsp, sizeof(rsp));
+
+    return sizeof(rsp);
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ *
+ * @Returns: 
+ */
+int
+joylink_proc_time_task_add(char *src, int src_len)
+{
+    if(NULL == src){
+        return E_RET_ERROR;
+    }
+    int ret = -1;
+    int len;
+    int ret_code = E_RET_ERROR;
+
+    JLTimeTaskReq_t *req = (JLTimeTaskReq_t *)src;
+
+    log_debug("add task, sizeof(JLTimeTask_t) = %d\r\n", (int)sizeof(JLTimeTask_t));
+    log_info("add task, sizeof(JLTimeTask_u) = %d\r\n", (int)sizeof(JLTimeTask_u));
+    log_debug("add task, sizeof(JLTimeTask_base_t) = %d\r\n", (int)sizeof(JLTimeTask_base_t));
+    log_info("add task, sizeof(JLTimeTask_period_t) = %d\r\n", (int)sizeof(JLTimeTask_period_t));
+    log_debug("add task, sizeof(JLTimeTask_cycle_t) = %d\r\n", (int)sizeof(JLTimeTask_cycle_t));
+    log_info("add task, sizeof(JLTimeTask_countdown_t) = %d\r\n", (int)sizeof(JLTimeTask_countdown_t));
+
+    if(E_RET_OK == joylink_dev_time_task_add(req)){
+        ret_code = E_RET_OK;
+    }
+     
+    ret = joylink_packet_time_task_add_rsp(req, ret_code);
+     log_info("add task 3, \r\n");
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN, 
+            PT_TIME_TASK, _g_pdev->jlp.sessionKey, 
+            (uint8_t *)_g_pdev->dev_detail, ret);
+
+    if(len > 0 &&  len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    return ret;
+}
+
+//-------BIZ_CODE_TIME_TASK_UPD_REQ ------ 
+/**
+ * brief: 
+ *
+ * @Param: req
+ *
+ * @Returns: 
+ */
+static E_JLRetCode_t
+joylink_dev_time_task_update(JLTimeTaskReq_t *req)
+{
+    //FIXME: must to do
+    int i;
+    for(i=0; i<req->task_num; i++)
+    {
+        switch(req->tasks[i].mode)
+        {
+            case BASE_MODE:
+                //need hanfeng's code
+                log_info("BASE_MODE\r\n");
+            break;
+
+
+            case PERIOD_MODE:
+                log_info("PERIOD_MODE\r\n");
+                //need hanfeng's code
+            break;
+            case CYCLE_MODE:
+                log_info("CYCLE_MODE\r\n");
+                //need hanfeng's code
+            break;
+            case COUNTDOWN_MODE:
+                log_info("COUNTDOWN_MODE\r\n");
+                //need hanfeng's code
+            break;
+            
+            default:
+            ;      
+        }
+
+    }
+    int ret = E_RET_OK;
+
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: req
+ * @Param: ret_code
+ *
+ * @Returns: 
+ */
+int
+joylink_packet_time_task_update_rsp(JLTimeTaskReq_t *req, int32_t ret_code)
+{
+    JLTimeTaskRsp_t rsp;
+    rsp.ch.timestamp = time(NULL);
+    rsp.ch.biz_code = BIZ_CODE_TIME_TASK_UPD_RSP;
+    rsp.ch.serial = req->ch.serial;
+    rsp.code = ret_code;
+
+    bzero(_g_pdev->dev_detail, sizeof(_g_pdev->dev_detail));
+
+    memcpy(_g_pdev->dev_detail, &rsp, sizeof(rsp));
+
+    return sizeof(rsp);
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ *
+ * @Returns: 
+ */
+int
+joylink_proc_time_task_update(char *src, int src_len)
+{
+    if(NULL == src){
+        return E_RET_ERROR;
+    }
+    int ret = -1;
+    int len;
+    int ret_code = E_RET_ERROR;
+    JLTimeTaskReq_t *req;
+
+    req = (JLTimeTaskReq_t *)src;
+
+    log_debug("Check is support time task\n");
+
+    if(E_RET_OK == joylink_dev_time_task_update(req)){
+        ret_code = E_RET_OK;
+    }
+
+    ret = joylink_packet_time_task_update_rsp(req, ret_code);
+
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN, 
+            PT_TIME_TASK, _g_pdev->jlp.sessionKey, 
+            (uint8_t *)_g_pdev->dev_detail, ret);
+
+    if(len > 0 &&  len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    return ret;
+}
+
+//-------BIZ_CODE_TIME_TASK_DEL_REQ ------ 
+/**
+ * brief: 
+ *
+ * @Param: req
+ *
+ * @Returns: 
+ */
+static E_JLRetCode_t
+joylink_dev_time_task_del(JLTimeTaskIdsReq_t *req)
+{
+    //FIXME: 
+    int ret = E_RET_OK;
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: req
+ * @Param: ret_code
+ *
+ * @Returns: 
+ */
+static int
+joylink_packet_time_task_del_rsp(JLTimeTaskIdsReq_t *req, int32_t ret_code)
+{
+    JLTimeTaskIdsRsp_t rsp;
+    rsp.ch.timestamp = time(NULL);
+    rsp.ch.biz_code = BIZ_CODE_TIME_TASK_DEL_RSP;
+    rsp.code = ret_code;
+    rsp.ch.serial = req->ch.serial;
+    bzero(_g_pdev->dev_detail, sizeof(_g_pdev->dev_detail));
+
+    //FIXME: how to transfer ids?
+    memcpy(_g_pdev->dev_detail, &rsp, sizeof(JLTimeTaskIdsRsp_t));
+
+    return sizeof(JLTimeTaskIdsRsp_t);
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ *
+ * @Returns: 
+ */
+static int
+joylink_proc_time_task_del(char *src, int src_len)
+{
+    if(NULL == src){
+        return E_RET_ERROR;
+    }
+    int ret = -1;
+    int len;
+    int ret_code = E_RET_ERROR;
+
+    JLTimeTaskIdsReq_t *req = (JLTimeTaskIdsReq_t *)src;
+
+    log_debug("del time task\n");
+
+    if(E_RET_OK == joylink_dev_time_task_del(req)){
+        ret_code = E_RET_OK;
+    }
+
+    ret = joylink_packet_time_task_del_rsp(req, ret_code);
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN, 
+            PT_TIME_TASK, _g_pdev->jlp.sessionKey, 
+            (uint8_t *)_g_pdev->dev_detail, ret);
+
+    if(len > 0 &&  len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+    return ret;
+}
+
+//-------BIZ_CODE_TIME_TASK_STOP_REQ ------ 
+/**
+ * brief: 
+ *
+ * @Param: req
+ *
+ * @Returns: 
+ */
+static E_JLRetCode_t
+joylink_dev_time_task_stop(JLTimeTaskIdsReq_t *req)
+{
+    /**
+     *FIXME:must to do
+     */
+    int ret = E_RET_OK;
+
+    /**
+     *debug
+     */
+
+    if(NULL == req->ids){
+        return ret;
+    }
+
+    log_debug("req task num: 3 %d", req->ids_num);
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: req
+ * @Param: ret_code
+ *
+ * @Returns: 
+ */
+static int
+joylink_packet_time_task_stop_rsp(JLTimeTaskIdsReq_t *req, int32_t ret_code)
+{
+    JLTimeTaskIdsRsp_t rsp;
+    rsp.ch.timestamp = time(NULL);
+    rsp.ch.biz_code = BIZ_CODE_TIME_TASK_STOP_RSP;
+    rsp.ch.serial = req->ch.serial;
+    rsp.code = ret_code;
+    rsp.ids_num = 0;
+
+    bzero(_g_pdev->dev_detail, sizeof(_g_pdev->dev_detail));
+
+    memcpy(_g_pdev->dev_detail, &rsp, sizeof(rsp));
+
+    return sizeof(rsp);
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ *
+ * @Returns: 
+ */
+static int
+joylink_proc_time_task_stop(char *src, int src_len)
+{
+    if(NULL == src){
+        return E_RET_ERROR;
+    }
+    int ret = -1;
+    int len;
+    int ret_code = E_RET_ERROR;
+
+    JLTimeTaskIdsReq_t *req = (JLTimeTaskIdsReq_t *)src;
+
+    log_debug("stop time task\n");
+
+    if(E_RET_OK == joylink_dev_time_task_stop(req)){
+        ret_code = E_RET_OK;
+    }
+
+    ret = joylink_packet_time_task_stop_rsp(req, ret_code);
+
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN, 
+            PT_TIME_TASK, _g_pdev->jlp.sessionKey, 
+            (uint8_t *)_g_pdev->dev_detail, ret);
+
+    if(len > 0 &&  len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    return ret;
+}
+
+//-------BIZ_CODE_TIME_TASK_RESTART_REQ ------ 
+/**
+ * brief: 
+ *
+ * @Param: req
+ *
+ * @Returns: 
+ */
+static E_JLRetCode_t
+joylink_dev_time_task_restart(JLTimeTaskIdsReq_t *req)
+{
+    /**
+     *FIXME:must to do
+     */
+    int ret = E_RET_OK;
+
+    if(NULL == req->ids){
+        return ret;
+    }
+
+    log_debug("req task num 2:%d", req->ids_num);
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: req
+ * @Param: ret_code
+ *
+ * @Returns: 
+ */
+static int
+joylink_packet_time_task_restart_rsp(JLTimeTaskIdsReq_t *req, int32_t ret_code)
+{
+    JLTimeTaskIdsRsp_t rsp;
+
+    rsp.ch.timestamp = time(NULL);
+    rsp.ch.biz_code = BIZ_CODE_TIME_TASK_RESTART_RSP;
+    rsp.ch.serial = req->ch.serial;
+    rsp.code = 0;
+    rsp.ids_num = 0;
+
+    bzero(_g_pdev->dev_detail, sizeof(_g_pdev->dev_detail));
+
+    memcpy(_g_pdev->dev_detail, &rsp, sizeof(rsp));
+
+    return sizeof(rsp);
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ *
+ * @Returns: 
+ */
+static int
+joylink_proc_time_task_restart(char *src, int src_len)
+{
+    if(NULL == src){
+        return E_RET_ERROR;
+    }
+    int ret = -1;
+    int len;
+    int ret_code = E_RET_ERROR;
+    JLTimeTaskIdsReq_t *req = (JLTimeTaskIdsReq_t *)src;
+
+    log_debug("restart time task\n");
+
+    if(E_RET_OK == joylink_dev_time_task_restart(req)){
+        ret_code = E_RET_OK;
+    }
+
+    ret = joylink_packet_time_task_restart_rsp(req, ret_code);
+
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN, 
+            PT_TIME_TASK, _g_pdev->jlp.sessionKey, 
+            (uint8_t *)_g_pdev->dev_detail, ret);
+
+    if(len > 0 &&  len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: req
+ * @Param: task_detail
+ *
+ * @Returns: 
+ */
+int 
+joylink_dev_time_task_get(JLTimeTaskIdsReq_t *req, JLTimeTaskReq_t* task_detail)
+{
+    //FIXME: must to do
+    bzero(_g_pdev->dev_detail, sizeof(_g_pdev->dev_detail));
+    task_detail->ch.timestamp = time(NULL);
+    task_detail->ch.biz_code = BIZ_CODE_TIME_TASK_GET_RSP;
+    task_detail->ch.serial = req->ch.serial;
+    task_detail->task_num = 0;
+
+    return sizeof(JLTimeTaskReq_t);
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ *
+ * @Returns: 
+ */
+static int
+joylink_proc_time_task_get(char *src, int src_len)
+{
+    if(NULL == src){
+        return E_RET_ERROR;
+    }
+    int ret = -1;
+    int len;
+
+    JLTimeTaskIdsReq_t *req = (JLTimeTaskIdsReq_t *)src;
+
+    log_debug("get time task \n");
+
+    ret = joylink_dev_time_task_get(req, (JLTimeTaskReq_t*)(_g_pdev->dev_detail));
+
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN, 
+            PT_TIME_TASK, _g_pdev->jlp.sessionKey, 
+            (uint8_t *)_g_pdev->dev_detail, ret);
+
+    if(len > 0 &&  len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ *
+ * @Returns: 
+ */
+static int
+joylink_proc_time_task_report_result_rsp(char *src, int src_len)
+{
+    JLTimeTaskResultReportRsp_t *rsp = (JLTimeTaskResultReportRsp_t *)src;
+    rsp+=4;
+    //FIXME: logic:
+    //(1)judge if rsp equals to send
+    //(2)if does not receive rsp, then create a new send.
+    //
+    int ret = -1;
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ *
+ * @Returns: 
+ */
+static int
+joylink_proc_time_task_report_new_task_rsp(char *src, int src_len)
+{
+    JLTimeTaskNewReportRsp_t *rsp = (JLTimeTaskNewReportRsp_t *)src;
+    rsp+=4;
+    //FIXME: must to do
+    int ret = -1;
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ *
+ * @Returns: 
+ */
+static int
+joylink_proc_time_task_report_del_task_rsp(char *src, int src_len)
+{
+    JLTimeTaskIdsRsp_t *rsp = (JLTimeTaskIdsRsp_t *)src;
+    rsp+=4;
+    //FIXME: must to do
+    int ret = -1;
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ *
+ * @Returns: 
+ */
+static int
+joylink_proc_time_task_report_update_task_rsp(char *src, int src_len)
+{
+    JLTimeTaskRsp_t *rsp = (JLTimeTaskRsp_t *)src;
+    rsp+=4;
+    //FIXME: must to do
+    int ret = -1;
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ *
+ * @Returns: 
+ */
+static int
+joylink_proc_time_task_report_snapshot_task_rsp(char *src, int src_len)
+{
+
+    JLTimeTaskIdsRsp_t *rsp = (JLTimeTaskIdsRsp_t *)src;
+    rsp+=4;
+    //FIXME: must to do
+    int ret = -1;
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: src
+ * @Param: src_len
+ *
+ * @Returns: 
+ */
+int
+joylink_proc_time_task(char *src, int src_len)
+{
+    if(NULL == src){
+        return E_RET_ERROR;
+    }
+    
+    {
+        int i=0;
+        for(i=0; i<src_len; i++)
+        {
+             if(i%16 == 0)
+             {
+                printf("\r\n");
+             }
+             printf("%02x ", *(unsigned char*)(src+i));
+
+        }
+
+    }
+    switch (joylink_time_task_get_biz_code(src)){
+        case BIZ_CODE_TIME_TASK_CHECK_REQ: 
+            joylink_proc_is_support_time_task(src, src_len);
+            break;
+        case BIZ_CODE_TIME_TASK_ADD_REQ: 
+            joylink_proc_time_task_add(src, src_len);
+            break;
+        case BIZ_CODE_TIME_TASK_DEL_REQ: 
+            joylink_proc_time_task_del(src, src_len);
+            break;
+        case BIZ_CODE_TIME_TASK_UPD_REQ: 
+            joylink_proc_time_task_update(src, src_len);
+            break;          
+        case BIZ_CODE_TIME_TASK_GET_REQ: 
+            joylink_proc_time_task_get(src, src_len);
+            break;
+        case BIZ_CODE_TIME_TASK_STOP_REQ: 
+            joylink_proc_time_task_stop(src, src_len);
+            break;
+        case BIZ_CODE_TIME_TASK_RESTART_REQ: 
+            joylink_proc_time_task_restart(src, src_len);
+            break;
+
+        case BIZ_CODE_TIME_TASK_REPORT_RESULT_RSP: 
+            joylink_proc_time_task_report_result_rsp(src, src_len);
+            break;
+        case BIZ_CODE_TIME_TASK_REPORT_NEW_TASK_RSP: 
+            joylink_proc_time_task_report_new_task_rsp(src, src_len);
+            break;          
+        case BIZ_CODE_TIME_TASK_REPORT_DEL_TASK_RSP: 
+            joylink_proc_time_task_report_del_task_rsp(src, src_len);
+            break;
+        case BIZ_CODE_TIME_TASK_REPORT_UPDATE_TASK_RSP: 
+            joylink_proc_time_task_report_update_task_rsp(src, src_len);
+            break;
+        case BIZ_CODE_TIME_TASK_REPORT_SNAPSHOT_TASK_RSP: 
+            joylink_proc_time_task_report_snapshot_task_rsp(src, src_len);
+            break;
+
+        default:
+            log_error("No found biz_code!\n");
+            break;
+    }
+
+    return E_RET_OK;
+}
+
+//------- BIZ_CODE_TIME_TASK_REPORT_NEW_TASK_REQ =1098 ------
+/**
+ * brief: 
+ *
+ * @Param: task_req
+ * @Param: task_num
+ *
+ * @Returns: 
+ */
+int
+joylink_time_task_new_task_report_req(JLTimeTaskReq_t *task_req, int task_num)
+{
+    int ret = E_RET_OK;
+    int len;
+
+    bzero(_g_pdev->dev_detail, sizeof(_g_pdev->dev_detail));
+
+    memcpy(_g_pdev->dev_detail, task_req, 20+sizeof(JLTimeTask_u)*task_num); 
+
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN, 
+            PT_TIME_TASK, _g_pdev->jlp.sessionKey, 
+            (uint8_t *)_g_pdev->dev_detail, 20+sizeof(JLTimeTask_u)*task_num);
+
+    if(len > 0 &&  len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: task_req
+ *
+ * @Returns: 
+ */
+int
+joylink_time_task_del_task_report_req(JLTimeTaskIdsReq_t *task_req)
+{
+    int ret = E_RET_OK;
+    int len;
+
+    bzero(_g_pdev->dev_detail, sizeof(_g_pdev->dev_detail));
+
+    memcpy(_g_pdev->dev_detail, task_req, 20+4*task_req->ids_num); 
+
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN, 
+            PT_TIME_TASK, _g_pdev->jlp.sessionKey, 
+            (uint8_t *)_g_pdev->dev_detail, 20+4*task_req->ids_num);
+
+    if(len > 0 &&  len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: task_req
+ * @Param: task_num
+ *
+ * @Returns: 
+ */
+int
+joylink_time_task_update_task_report_req(JLTimeTaskReq_t *task_req, int task_num)
+{
+    int ret = E_RET_OK;
+    int len;
+
+    bzero(_g_pdev->dev_detail, sizeof(_g_pdev->dev_detail));
+
+    memcpy(_g_pdev->dev_detail, task_req, 20+sizeof(JLTimeTask_u)*task_num); 
+
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN, 
+            PT_TIME_TASK, _g_pdev->jlp.sessionKey, 
+            (uint8_t *)_g_pdev->dev_detail, 20+sizeof(JLTimeTask_u)*task_num);
+
+    if(len > 0 &&  len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    return ret;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: task_req
+ * @Param: task_num
+ *
+ * @Returns: 
+ */
+int
+joylink_time_task_snapshot_task_report_req(JLTimeTaskReq_t *task_req, int task_num)
+{
+    int ret = E_RET_OK;
+    int len;
+
+    bzero(_g_pdev->dev_detail, sizeof(_g_pdev->dev_detail));
+
+    memcpy(_g_pdev->dev_detail, task_req, 20+sizeof(JLTimeTask_u)*task_num); 
+
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN, 
+            PT_TIME_TASK, _g_pdev->jlp.sessionKey, 
+            (uint8_t *)_g_pdev->dev_detail, 20+sizeof(JLTimeTask_u)*task_num);
+
+    if(len > 0 &&  len < JL_MAX_PACKET_LEN){
+        ret = send(_g_pdev->server_socket, _g_pdev->send_buff, len, 0);
+        if(ret < 0){
+            log_error("send error ret:%d", ret);
+        }
+        log_info("send to server len:%d:ret:%d\n", len, ret);
+    }else{
+        log_error("packet error ret:%d", ret);
+    }
+
+    return ret;
+}

+ 177 - 0
joylink/joylink/joylink_dev_timer.h

@@ -0,0 +1,177 @@
+#ifndef _DEV_TIMER_H
+#define _DEV_TIMER_H
+
+#ifdef __cplusplus
+extern "C"{
+#endif /* __cplusplus */
+
+#ifdef __LINUX_UB2__
+#include <stdint.h>
+#endif
+
+#include "joylink.h"
+
+#define SUPPORT_TIMER 0
+#define NOT_SUPPORT_TIMER 1   
+
+#pragma pack(1)
+
+typedef struct {
+    int len;
+    char cmd[1];   //streamid + value
+}JLCmd_t;
+
+typedef struct {
+    int len;
+    char num;
+    JLCmd_t cmds[1];
+}JLCmdTrank_t;
+
+typedef struct {
+    char len;
+    char exp[1];
+}JLTimeExp_t;
+
+typedef struct {
+    char feedid[32];
+    char name[128];
+    int id;
+    char state;  //0: start 1:stop
+    char type;   //0:joylink timer task  1:dev self time task
+    JLTimeExp_t time_exp;
+    JLCmdTrank_t cmd_trank;
+}JLTimeTask_base_t;
+
+typedef struct {
+    char feedid[32];
+    char name[128];
+    int id;
+    char state;  //0: start 1:stop
+    char type;   //0:joylink timer task  1:dev self time task
+    JLTimeExp_t start_time_exp;
+    JLTimeExp_t stop_time_exp;
+    char repeat_flag;
+    char period_type;
+    char period[31];
+    JLCmdTrank_t start_cmd_trank;
+    JLCmdTrank_t stop_cmd_trank;
+}JLTimeTask_period_t;
+
+typedef struct {
+    char feedid[32];
+    char name[128];
+    int id;
+    char state;  //0: start 1:stop
+    char type;   //0:joylink timer task  1:dev self time task
+    int action_interval;
+    int sleep_interval;
+    int times;
+    JLCmdTrank_t action_c_trank;
+    JLCmdTrank_t sleep_c_trank;
+}JLTimeTask_cycle_t;
+
+typedef struct {
+    char feedid[32];
+    char name[128];
+    int id;
+    char state;  //0: start 1:stop
+    char type;   //0:joylink timer task  1:dev self time task
+    int interval;
+    JLCmdTrank_t action_c_trank;
+    JLCmdTrank_t stop_c_trank;
+}JLTimeTask_countdown_t;
+
+typedef union {
+    JLTimeTask_base_t base_task;
+    JLTimeTask_period_t period_task;
+    JLTimeTask_cycle_t cycle_task;
+    JLTimeTask_countdown_t contdown_task;
+}JLTimeTask_u;
+
+typedef struct {
+    int mode;   //0:base 1:period 2:cycle 3:countdown
+    JLTimeTask_u type;
+}JLTimeTask_t;
+
+typedef struct {
+    unsigned int timestamp;
+    unsigned int biz_code;    
+    unsigned int serial; 
+}JLTimeTaskComHead_t;
+
+typedef struct {
+    JLTimeTaskComHead_t ch;
+    int task_num;
+    JLTimeTask_t tasks[1];
+}   JLTimeTaskReq_t;
+
+typedef struct {
+    JLTimeTaskComHead_t ch;
+    int code;
+}JLTimeTaskRsp_t;
+
+typedef struct {
+    JLTimeTaskComHead_t ch;
+    int ids_num;
+    int ids[1];
+}JLTimeTaskIdsReq_t;
+
+typedef struct {
+    JLTimeTaskComHead_t ch;
+    int code;
+    int ids_num;
+    int ids[1];
+}JLTimeTaskIdsRsp_t;
+
+typedef struct {
+    int id;
+    char step;
+    int code;
+}result_t;
+
+typedef struct {
+    JLTimeTaskComHead_t ch;
+    int num;
+    result_t results[1];
+}JLTimeTaskResultReportReq_t;
+
+typedef struct {
+    int id;
+    char step;
+}received_t;
+
+typedef struct {
+    JLTimeTaskComHead_t ch;
+    int num;
+    received_t received[1];
+}JLTimeTaskResultReportRsp_t;
+
+typedef struct {
+    JLTimeTaskComHead_t ch;
+    int code;
+    int id;
+}JLTimeTaskNewReportRsp_t;
+
+#pragma pack()
+
+typedef enum{
+    TIME_TASK_ST_START = 0,
+    TIME_TASK_ST_STOP
+}E_TimeTaskState;
+
+typedef enum{
+    TIME_TASK_TYPE_JOYLINK = 0,
+    TIME_TASK_TYPE_DEV_SELF
+}E_TimeTaskType;
+
+#define BASE_MODE 0
+#define PERIOD_MODE 1
+#define CYCLE_MODE 2
+#define COUNTDOWN_MODE 3
+
+int joylink_proc_time_task(char *src, int src_len);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif

+ 228 - 0
joylink/joylink/joylink_join_packet.c

@@ -0,0 +1,228 @@
+#include <stdio.h>
+
+#ifdef __LINUX_UB2__
+#include <stdint.h>
+#endif
+
+#include <unistd.h>
+
+#include "joylink.h"
+#include "joylink_list.h"
+
+typedef struct  __join_packet{
+    char name[256];
+    int current_count;
+    int total_len;
+    int id;
+    int is_run;
+    LHead_t lhead;
+    JLPacketHead_t phead;
+}JLJoinPacket_t;
+
+#define JL_MAX_JOIN_PKG_ARRARY              (20)
+#define JL_MAX_JOIN_PKG_TOTAL_LEN           (20 * 1024)
+#define JL_JOIN_PKG_RUN                     (1)
+#define JL_JOIN_PKG_STOP                    (0)
+
+JLJoinPacket_t _g_jps[JL_MAX_JOIN_PKG_ARRARY];
+
+/**
+ * brief: get _g_jps index by name id. 
+ *
+ * @Param: name
+ * @Param: id
+ *
+ * @Returns: 1 index of _g_jps
+ *           2 E_RET_ERROR_NO_EXIST
+ *           3 E_RET_ERROR_PARAM_INVAID
+ */
+static int
+joylink_join_pkg_get_index_by_name_id(char *name, int id)
+{
+    if(NULL == name){
+        return E_RET_ERROR_PARAM_INVAID;
+    }
+    int ret = E_RET_ERROR_NO_EXIST;
+    int i; 
+    for(i = 0; i < JL_MAX_JOIN_PKG_ARRARY; i++){
+        if(_g_jps[i].is_run == JL_JOIN_PKG_RUN){
+            if(!strcmp(name, _g_jps[i].name) 
+                    && id == _g_jps[i].id){
+                ret = i;
+                break;
+            }
+        }
+    }
+
+    return ret;
+}
+
+
+/**
+ * brief: 
+ * @Returns: 1 index of _g_jps
+ *           2 E_RET_ERROR_PKG_BREAK_ARRAY
+ */
+static int
+joylink_join_pkg_get_idle_index()
+{
+    int ret = E_RET_ERROR_PKG_BREAK_ARRAY;
+    int i; 
+    for(i = 0; i < JL_MAX_JOIN_PKG_ARRARY; i++){
+        if(_g_jps[i].is_run != JL_JOIN_PKG_RUN){
+            ret = i;
+            break;
+        }
+    }
+    return ret;
+}
+
+/**
+ * brief: 1 find a idle index 
+ *        2 save JLPacketHead_t 
+ *        3 init JLJoinPacket_t
+ *          must care name, id, is_run, total_len, lhead, lphead. 
+ *
+ * @Returns: 1 E_RET_ERROR_PARAM_INVAID
+             2 E_RET_ERROR_PKG_NUM_BREAK_MAX
+             3 E_RET_ERROR_PKG_BREAK_ARRAY
+             4 index of _g_jps
+ */
+static int
+joylink_join_pkg_cache_new_node(char *name, int id, JLPacketHead_t *phead, char *data, int len)
+{
+    if(NULL == name || NULL == phead
+            || NULL == data){
+        return E_RET_ERROR_PARAM_INVAID;
+    }
+    int ret;
+
+    JLJoinPacket_t *jp;
+    if(0 <= (ret = joylink_join_pkg_get_idle_index())){
+        jp = &_g_jps[ret];
+        INIT_LIST_HEAD(&jp->lhead);
+        if(E_LIST_RET_OK == joylink_idnode_add(phead->index, data, len, &jp->lhead)){
+            strcpy(jp->name, name);
+            jp->id = id;
+            jp->is_run = JL_JOIN_PKG_RUN;
+            memcpy(&jp->phead, phead, sizeof(JLPacketHead_t));
+            jp->total_len  = len;
+        }else{
+            ret = E_RET_ERROR;
+        }
+    }
+
+    return ret;
+}
+
+/**
+ * brief: 1 find index by name and id
+ *        2 if no exist ,cache idle node, add data
+ *        3 if exist add data
+ *
+ * @Returns: 1 E_RET_ERROR_PARAM_INVAID
+             2 E_RET_ERROR_PKG_NUM_BREAK_MAX
+             3 E_RET_ERROR_PKG_BREAK_ARRAY
+             4 E_RET_OK 
+             5 E_RET_ALL_DATA_HIT
+ */
+int
+joylink_join_pkg_add_data(char *name, int id, JLPacketHead_t *phead, char *data, int len)
+{
+    if(NULL == name || NULL == phead
+            || NULL == data){
+        return E_RET_ERROR_PARAM_INVAID;
+    }
+    int ret = joylink_join_pkg_get_index_by_name_id(name, id);
+    JLJoinPacket_t *jp = NULL;
+    if(ret >= 0){
+        jp = &_g_jps[ret];
+        if(E_LIST_RET_OK == joylink_idnode_add(phead->index, data, len, &jp->lhead)){
+            jp->total_len += len;
+        }else{
+            ret = E_RET_ERROR;
+        }
+    }else if(ret == E_RET_ERROR_NO_EXIST){
+        ret = joylink_join_pkg_cache_new_node(name, id, phead, data, len);
+        jp = &_g_jps[ret];
+    }
+    
+    if(ret >= 0){
+        if(jp->current_count == jp->phead.total){
+            ret = E_RET_ALL_DATA_HIT;
+        }else{
+            ret = E_RET_OK;
+        }
+    }
+
+    return ret;
+}
+
+/**
+ * brief: 1 malloc a buffer 
+ *        2 find all data by 1 to phead->total 
+ *        3 copy all data to buffer
+ *
+ * @Returns: 1 NULL 
+ *           2 A malloc buffer point, rember to free it.
+ */
+char *
+joylink_join_pkg_join_data(char *name, int id, int *out_len)
+{
+    if(NULL == name){ 
+        return NULL;
+    }
+    char *p_data = NULL;
+    int offset = 0;
+    JLJoinPacket_t *jp;
+    IDNode_t *pkg;
+    int i;
+    int ret = joylink_join_pkg_get_index_by_name_id(name, id);
+
+    if(ret >= 0){
+        jp = &_g_jps[ret];
+        p_data = (char *)malloc(jp->total_len);
+        *out_len = jp->total_len;
+        if(NULL !=  p_data){
+            for(i = 1; i <= jp->phead.total; i ++){
+                if(NULL == (pkg = joylink_idnode_get_by_id(i, &jp->lhead))){
+                    free(p_data);
+                    p_data = NULL;
+                    goto RET;
+                }else{
+                    memcpy(p_data + offset, pkg->data, pkg->len); 
+                    offset += pkg->len;
+                }
+            }
+        }
+    }
+
+RET:
+    return p_data;
+}
+
+/**
+ * brief: 1 clean all pkg data
+ *        2 set JLJoinPacket_t as 0 
+ *
+ * @Returns: 1 E_RET_ERROR_PARAM_INVAID 
+ *           2 E_RET_ERROR 
+ *           3 E_RET_OK
+ */
+int
+joylink_join_pkg_clean_node_by_name_id(char *name, int id)
+{
+    if(NULL == name){ 
+        return E_RET_ERROR_PARAM_INVAID;
+    }
+    JLJoinPacket_t *jp;
+    int ret = joylink_join_pkg_get_index_by_name_id(name, id);
+    if(ret >= 0){
+        jp = &_g_jps[ret];
+        joylink_idnode_list_clear(&jp->lhead);
+        bzero(jp, sizeof(JLJoinPacket_t));
+        ret = E_RET_OK;
+    }
+
+    return ret;
+}

+ 46 - 0
joylink/joylink/joylink_join_packet.h

@@ -0,0 +1,46 @@
+#ifndef _JOIN_PKG_H
+#define _JOIN_PKG_H
+
+#ifdef __LINUX_UB2__
+#include <stdint.h>
+#endif
+
+#include "joylink.h"
+
+/**
+ * brief: 
+ *
+ * @Param: name
+ * @Param: id
+ * @Param: phead
+ * @Param: data
+ * @Param: len
+ *
+ * @Returns: 
+ */
+int
+joylink_join_pkg_add_data(char *name, int id, JLPacketHead_t *phead, char *data, int len);
+
+/**
+ * brief: 
+ *
+ * @Param: name
+ * @Param: id
+ * @Param: out_len
+ *
+ * @Returns: 
+ */
+char *
+joylink_join_pkg_join_data(char *name, int id, int *out_len);
+
+/**
+ * brief: 
+ *
+ * @Param: name
+ * @Param: id
+ *
+ * @Returns: 
+ */
+int
+joylink_join_pkg_clean_node_by_name_id(char *name, int id);
+#endif

+ 113 - 0
joylink/joylink/joylink_log.h

@@ -0,0 +1,113 @@
+#ifndef __JOYLINK_LOG_H__
+#define __JOYLINK_LOG_H__
+
+#include <stdio.h>
+
+#if defined(__RT_THREAD__)
+#include <string.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <rtthread.h>
+#elif defined(__MTK_7687__)
+#else
+#include <errno.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <time.h>
+#include <locale.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <dirent.h>
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define JL_LOG_LEVEL_FATAL      (0)
+#define JL_LOG_LEVEL_NOTICE     (1)
+#define JL_LOG_LEVEL_INFO       (2)
+#define JL_LOG_LEVEL_ERROR      (3)
+#define JL_LOG_LEVEL_WARN       (4)
+#define JL_LOG_LEVEL_DEBUG      (5)
+
+#define Black   0;30
+#define Red     0;31
+#define Green   0;32
+#define Brown   0;33
+#define Blue    0;34
+#define Purple  0;35
+#define Cyan    0;36
+
+#ifdef __RT_THREAD__
+#define DBG_TAG              "jl"
+#define DBG_LVL              DBG_LOG
+#include <rtdbg.h>
+
+#if defined(JOYLINK_OUTPUT_LEVEL_DEBUG)
+#define JL_LOG_LEVEL         JL_LOG_LEVEL_DEBUG
+#elif defined(JOYLINK_OUTPUT_LEVEL_WARN)
+#define JL_LOG_LEVEL         JL_LOG_LEVEL_WARN
+#elif defined(JOYLINK_OUTPUT_LEVEL_ERROR)
+#define JL_LOG_LEVEL         JL_LOG_LEVEL_ERROR
+#elif defined(JOYLINK_OUTPUT_LEVEL_INFO)
+#define JL_LOG_LEVEL         JL_LOG_LEVEL_INFO
+#elif defined(JOYLINK_OUTPUT_LEVEL_NOTICE)
+#define JL_LOG_LEVEL         JL_LOG_LEVEL_NOTICE
+#elif defined(JOYLINK_OUTPUT_LEVEL_FATAL)
+#define JL_LOG_LEVEL         JL_LOG_LEVEL_FATAL
+#endif 
+
+#endif
+
+#define log_fatal(format, ...) \
+    do{\
+        if(JL_LOG_LEVEL >= JL_LOG_LEVEL_FATAL){\
+            LOG_I("[%s][%d] " format, __FUNCTION__, __LINE__, ##__VA_ARGS__);\
+        }\
+    }while(0)
+
+#define log_notice(format, ...) \
+    do{\
+        if(JL_LOG_LEVEL >= JL_LOG_LEVEL_NOTICE){\
+            LOG_I("[%s][%d] " format, __FUNCTION__, __LINE__, ##__VA_ARGS__);\
+        }\
+    }while(0)
+
+#define log_info(format, ...) \
+    do{\
+        if(JL_LOG_LEVEL >= JL_LOG_LEVEL_INFO){\
+            LOG_I("[%s][%d] " format, __FUNCTION__, __LINE__, ##__VA_ARGS__);\
+        }\
+    }while(0)
+
+#define log_error(format, ...) \
+    do{\
+        if(JL_LOG_LEVEL >= JL_LOG_LEVEL_ERROR){\
+            LOG_E("[%s][%d] " format, __FUNCTION__, __LINE__, ##__VA_ARGS__);\
+        }\
+    }while(0)
+
+#define log_warn(format, ...) \
+    do{\
+        if(JL_LOG_LEVEL >= JL_LOG_LEVEL_WARN){\
+            LOG_W("[%s][%d] " format, __FUNCTION__, __LINE__, ##__VA_ARGS__);\
+        }\
+    }while(0)
+
+#define log_debug(format, ...) \
+    do{\
+        if(JL_LOG_LEVEL >= JL_LOG_LEVEL_DEBUG){\
+            LOG_D("[%s][%d] " format, __FUNCTION__, __LINE__, ##__VA_ARGS__);\
+        }\
+    }while(0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LOGGING_H__ */

+ 334 - 0
joylink/joylink/joylink_packets.c

@@ -0,0 +1,334 @@
+#include <stdio.h>
+#include "joylink_packets.h"
+#include "joylink_crypt.h"
+#include "joylink_auth_uECC.h"
+#include "joylink_auth_crc.h"
+#include "joylink.h"
+#include "joylink_dev.h"
+#include "joylink_utils.h"
+
+#ifdef __LINUX_UB2__
+#include <stdint.h>
+#endif
+
+#include <unistd.h>
+
+/**
+ * brief: 
+ *
+ * @Param: scan
+ *
+ * @Returns: 
+ */
+int 
+joylink_packet_lan_scan_rsp(DevScan_t *scan)
+{
+    int len = 0;
+    if(!strcmp(_g_pdev->idt.rand, "")){
+        /*1 signature the app_random*/
+        /*2 get a dev random*/
+        int ran[8];
+        int i;
+        ran[0] = joylink_dev_get_random();
+        ran[1] = time(NULL);
+        for(i = 2; i < 8; i++){
+           ran[i] = ran[i-1] ^ ran[i-0]; 
+        }
+
+        joylink_util_byte2hexstr((uint8_t *)&ran[0], 
+                        sizeof(ran), 
+                        (uint8_t *)(&_g_pdev->idt.rand[0]), 
+                        sizeof(_g_pdev->idt.rand) - 1);
+    }
+
+    char * scan_rsp_data = joylink_package_scan("scan ok", 
+            0,
+            scan,
+            _g_pdev);
+
+    char *pout = NULL;
+    int max_out = 0;
+
+    if(scan_rsp_data != NULL){
+        _g_pdev->payload_total = strlen(scan_rsp_data); 
+    
+        if(_g_pdev->payload_total < JL_MAX_CUT_PACKET_LEN){
+            pout = (char*)_g_pdev->send_buff;
+            max_out = JL_MAX_PACKET_LEN;
+        }else{
+            _g_pdev->send_p = (char *)malloc(_g_pdev->payload_total + JL_MAX_AES_EXTERN);
+            if(_g_pdev->send_p == NULL){
+                goto RET;
+            }
+
+            pout = _g_pdev->send_p;
+            max_out = _g_pdev->payload_total + JL_MAX_AES_EXTERN;
+        }
+        log_debug("new scan rsp data:%s", scan_rsp_data);
+
+        len = joylink_encrypt_lan_basic(
+                (uint8_t*)pout, 
+                max_out, ET_NOTHING, 
+                PT_SCAN, (uint8_t*)1, 
+                (uint8_t*)scan_rsp_data, 
+                strlen(scan_rsp_data));
+
+    }
+
+RET:
+    if(scan_rsp_data != NULL){
+        free(scan_rsp_data);
+    }
+
+	return len;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int 
+joylink_packet_lan_write_key_rsp(int code, char *msg)
+{
+    char data[100] = {0};
+    sprintf(data, "{\"code\":%d, \"msg\":\"%s\"}", code, msg);
+
+	int len = joylink_encrypt_lan_basic(
+            _g_pdev->send_buff, 
+            JL_MAX_PACKET_LEN, ET_NOTHING, 
+            PT_WRITE_ACCESSKEY, 
+            NULL, 
+            (uint8_t*)&data, 
+            strlen(data));
+
+	return len;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int 
+joylink_packet_server_auth_rsp(void)
+{
+    JLAuth_t auth;
+    bzero(&auth, sizeof(auth));
+
+    auth.random_unm = 1;
+    auth.timestamp = time(NULL);
+
+    log_debug("accesskey key:%s", _g_pdev->jlp.accesskey);
+
+    int len = joylink_encypt_server_rsp(
+        _g_pdev->send_buff,
+        JL_MAX_PACKET_LEN, PT_AUTH, 
+        (uint8_t*)_g_pdev->jlp.accesskey, 
+        (uint8_t*)&auth, sizeof(auth));
+
+    return len;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int 
+joylink_packet_server_hb_req(void)
+{
+	JLHearBeat_t heartbeat;
+    bzero(&heartbeat, sizeof(heartbeat));
+
+	heartbeat.rssi = 1;
+	heartbeat.verion = _g_pdev->jlp.version;
+	heartbeat.timestamp = time(NULL);
+
+	int len = joylink_encypt_server_rsp(
+            _g_pdev->send_buff, 
+            JL_MAX_PACKET_LEN, PT_BEAT, 
+            _g_pdev->jlp.sessionKey, 
+            (uint8_t*)&heartbeat, 
+            sizeof(JLHearBeat_t));
+
+	return len;
+}
+
+extern int joylink_encypt_server_xxx_rsp(
+        uint8_t* pBuf, 
+        int buflen, 
+        E_PacketType cmd, 
+        uint8_t* key, 
+        const uint8_t* payload, 
+        int payloadLen);
+int 
+joylink_packet_server_hb_xxx_req(void)
+{
+	JLHearBeat_t heartbeat;
+    bzero(&heartbeat, sizeof(heartbeat));
+
+	heartbeat.rssi = 1;
+	heartbeat.verion = _g_pdev->jlp.version;
+	heartbeat.timestamp = time(NULL);
+
+	int len = joylink_encypt_server_xxx_rsp(
+            _g_pdev->send_buff, 
+            JL_MAX_PACKET_LEN, PT_BEAT, 
+            _g_pdev->jlp.sessionKey, 
+            (uint8_t*)&heartbeat, 
+            sizeof(JLHearBeat_t));
+
+	return len;
+}
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int 
+ddjoylink_packet_server_upload_req(void)
+{
+	JLDataUpload_t data = { 0 };
+	data.timestamp = 10;
+
+	int len = joylink_encypt_server_rsp(
+            _g_pdev->send_buff, 
+            JL_MAX_PACKET_LEN, PT_UPLOAD, 
+            _g_pdev->jlp.sessionKey, 
+            (uint8_t*)&data, 
+            sizeof(data));
+
+	return len;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: data
+ * @Param: max
+ * @Param: ctrl
+ *
+ * @Returns: 
+ */
+int 
+joylink_packet_script_ctrl_rsp(char *data, int max, JLContrl_t *ctrl)
+{
+    if(NULL == data || NULL == ctrl){
+        return -1;
+    }
+    int ret = -1;
+    if(ctrl->biz_code == JL_BZCODE_GET_SNAPSHOT){
+        ctrl->biz_code = 104;
+    }else if(ctrl->biz_code == JL_BZCODE_CTRL){
+        ctrl->biz_code = 102;
+    }
+
+    int time_v = time(NULL);
+    memcpy(data, &time_v, 4);
+    memcpy(data + 4, &ctrl->biz_code , 4);
+    memcpy(data + 8, &ctrl->serial, 4);
+
+    ret = joylink_dev_get_snap_shot(data + 12, JL_MAX_PACKET_LEN - 12);
+
+    //printf("XXXX :len:%d:%s\n", ret, data+12);
+    return ret > 0 ? ret + 12 : 0;
+}
+
+extern int
+joylink_dev_get_snap_shot_with_retcode(int32_t ret_code, 
+        char *out_snap, int32_t out_max);
+
+/**
+ * brief: 
+ *
+ * @Param: data
+ * @Param: max
+ *
+ * @Returns: 
+ */
+int 
+joylink_packet_script_ctrl_error_rsp(char *data, int max)
+{
+    if(NULL == data){
+        return -1;
+    }
+    int ret = -1;
+    int time_v = time(NULL);
+    int32_t biz_code = JL_BZCODE_GET_SNAPSHOT;
+
+    memcpy(data, &time_v, 4);
+    memcpy(data + 4, &biz_code, 4);
+    /*memcpy(data + 8, &biz_code, 4);*/
+
+    ret = joylink_dev_get_snap_shot_with_retcode(-1, 
+            data + 12, JL_MAX_PACKET_LEN - 12);
+
+    //printf("XXXX :len:%d:%s\n", ret, data+12);
+    return ret > 0 ? ret + 12 : 0;
+}
+/**
+ * brief: 
+ *
+ * @Param: otaOrder
+ *
+ * @Returns: 
+ */
+int
+joylink_packet_server_ota_order_rsp(JLOtaOrder_t *otaOrder)
+{
+    int len = 0;
+    char data[100] = {0};    
+    time_t tt = time(NULL);
+    bzero(_g_pdev->dev_detail, sizeof(_g_pdev->dev_detail));
+	
+    memcpy((char*)_g_pdev->dev_detail, &tt, 4);
+	
+    if(!strcmp(_g_pdev->jlp.feedid, otaOrder->feedid)){
+	sprintf(data, "{\"code\":0,\"serial\":%d,\"msg\":\"success\"}", otaOrder->serial);
+    }
+    else{
+	sprintf(data, "{\"code\":0,\"serial\":%d,\"msg\":\"success\",\"sub_feedid\":\"%s\"}", otaOrder->serial, otaOrder->feedid);
+    }
+	
+    memcpy((char*)_g_pdev->dev_detail + 4, data, strlen(data));
+
+    len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN,
+            PT_OTA_ORDER, (uint8_t*)_g_pdev->jlp.sessionKey, _g_pdev->dev_detail, strlen(data) + 4);
+
+    return len;
+}
+
+/**
+ * brief: 
+ *
+ * @Param: otaUpload
+ *
+ * @Returns: 
+ */
+int 
+joylink_package_ota_upload_req(JLOtaUpload_t *otaUpload)
+{    
+    time_t tt = time(NULL);
+    char * ota_upload_rsp_data = joylink_package_ota_upload(otaUpload);
+    bzero(_g_pdev->dev_detail, sizeof(_g_pdev->dev_detail));
+    bzero(_g_pdev->send_buff, sizeof(_g_pdev->send_buff));
+    
+    memcpy((char *)_g_pdev->dev_detail, &tt, 4);
+    if(ota_upload_rsp_data != NULL){
+        memcpy((char *)_g_pdev->dev_detail + 4, ota_upload_rsp_data, strlen(ota_upload_rsp_data));
+        log_debug("new ota upload rsp data:%s", (char *)_g_pdev->dev_detail + 4);
+    }
+
+    int len = joylink_encypt_server_rsp(_g_pdev->send_buff, JL_MAX_PACKET_LEN, 
+        PT_OTA_UPLOAD, (uint8_t*)_g_pdev->jlp.sessionKey, 
+        _g_pdev->dev_detail, strlen(ota_upload_rsp_data) + 4);
+
+    if(ota_upload_rsp_data != NULL){
+        free(ota_upload_rsp_data);
+        ota_upload_rsp_data = NULL;
+    }
+
+    return len;
+}

+ 96 - 0
joylink/joylink/joylink_packets.h

@@ -0,0 +1,96 @@
+#ifndef _PACKETS_H
+#define _PACKETS_H
+
+#ifdef __LINUX_UB2__
+#include <stdint.h>
+#endif
+
+#include "joylink.h"
+#include "joylink_json.h"
+#include "joylink_security.h"
+
+/**
+ * brief: 
+ *
+ * @Param: scan
+ *
+ * @Returns: 
+ */
+int 
+joylink_packet_lan_scan_rsp(DevScan_t *scan);
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int 
+joylink_packet_lan_write_key_rsp(int code, char *msg);
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int 
+joylink_packet_server_auth_rsp(void);
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int 
+joylink_packet_server_hb_req(void);
+
+/**
+ * brief: 
+ *
+ * @Returns: 
+ */
+int 
+joylink_packet_server_upload_req(void);
+
+/**
+ * brief: 
+ *
+ * @Param: otaOrder
+ *
+ * @Returns: 
+ */
+int 
+joylink_packet_server_ota_order_rsp(JLOtaOrder_t *otaOrder);
+
+/**
+ * brief: 
+ *
+ * @Param: otaUpload
+ *
+ * @Returns: 
+ */
+int 
+joylink_package_ota_upload_req(JLOtaUpload_t *otaUpload);
+
+/**
+ * brief: 
+ *
+ * @Param: data
+ * @Param: max
+ * @Param: ctrl
+ *
+ * @Returns: 
+ */
+int 
+joylink_packet_script_ctrl_rsp(char *data, int max, JLContrl_t *ctrl);
+
+/**
+ * brief: 
+ *
+ * @Param: data
+ * @Param: max
+ *
+ * @Returns: 
+ */
+int 
+joylink_packet_script_ctrl_error_rsp(char *data, int max);
+#endif

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