Browse Source

first commit

RL 2 months ago
commit
342eef0583
100 changed files with 27157 additions and 0 deletions
  1. 54 0
      .gitee/ISSUE_TEMPLATE/bug.yaml
  2. 5 0
      .gitee/ISSUE_TEMPLATE/config.yaml
  3. 37 0
      .gitee/ISSUE_TEMPLATE/feature.yaml
  4. 17 0
      .gitee/ISSUE_TEMPLATE/share.yaml
  5. 38 0
      .github/ISSUE_TEMPLATE/bug_report.md
  6. 20 0
      .github/ISSUE_TEMPLATE/feature_request.md
  7. 58 0
      .gitignore
  8. 1927 0
      .vscode/c_cpp_properties.json
  9. 10 0
      .vscode/settings.json
  10. 25 0
      .vscode/tasks.json
  11. 3 0
      .vscode/winmk.bat
  12. 201 0
      LICENSE
  13. 142 0
      Makefile
  14. 107 0
      README-en.md
  15. 103 0
      README.md
  16. 754 0
      apps/common/audio/audio_digital_vol.c
  17. 79 0
      apps/common/audio/audio_digital_vol.h
  18. 11 0
      apps/common/audio/audio_noise_gate.h
  19. 10 0
      apps/common/audio/audio_plc.h
  20. 28 0
      apps/common/audio/audio_utils.c
  21. 18 0
      apps/common/audio/audio_utils.h
  22. 325 0
      apps/common/audio/decode/decode.c
  23. 212 0
      apps/common/audio/demo/audio_decoder_test.c
  24. 110 0
      apps/common/audio/demo/audio_encoder_test.c
  25. 78 0
      apps/common/audio/encode/encode_write.h
  26. 390 0
      apps/common/audio/sine_make.c
  27. 22 0
      apps/common/audio/sine_make.h
  28. 246 0
      apps/common/bt_common/bt_test_api.c
  29. 1528 0
      apps/common/cJSON/cJSON.c
  30. 150 0
      apps/common/cJSON/cJSON.h
  31. 326 0
      apps/common/code_switch/code_switch.c
  32. 19 0
      apps/common/code_switch/include/code_switch.h
  33. 121 0
      apps/common/config/include/bt_profile_cfg.h
  34. 63 0
      apps/common/debug/debug.c
  35. 22 0
      apps/common/device/gSensor/fmy/Motion_api.h
  36. 178 0
      apps/common/device/gSensor/fmy/SC7A20_E.c
  37. 219 0
      apps/common/device/gSensor/fmy/SC7A20_TR.c
  38. 33 0
      apps/common/device/gSensor/fmy/SC7A20_TR.h
  39. 225 0
      apps/common/device/gSensor/fmy/gSensor_manage.c
  40. 84 0
      apps/common/device/gSensor/fmy/gSensor_manage.h
  41. 109 0
      apps/common/device/gSensor/fmy/gsensor_api.c
  42. 18 0
      apps/common/device/gSensor/fmy/gsensor_api.h
  43. 227 0
      apps/common/device/gSensor/fmy/msa310.c
  44. 52 0
      apps/common/device/gSensor/fmy/msa310.h
  45. 776 0
      apps/common/device/gSensor/fmy/msa310_function.c
  46. 113 0
      apps/common/device/gSensor/fmy/msa310_function.h
  47. 97 0
      apps/common/device/in_ear_detect/in_ear_manage.h
  48. 157 0
      apps/common/device/key/adkey.c
  49. 61 0
      apps/common/device/key/ctmu_touch_key.c
  50. 289 0
      apps/common/device/key/iokey.c
  51. 78 0
      apps/common/device/key/irkey.c
  52. 506 0
      apps/common/device/key/key_driver.c
  53. 351 0
      apps/common/device/key/matrix_keyboard.c
  54. 510 0
      apps/common/device/key/matrix_keyboard_ex_mcu.c
  55. 62 0
      apps/common/device/key/touch_key.c
  56. 923 0
      apps/common/device/norflash/norflash.c
  57. 193 0
      apps/common/device/optical_mouse_sensor/OMSensor_manage.c
  58. 553 0
      apps/common/device/optical_mouse_sensor/hal3205/hal3205.c
  59. 540 0
      apps/common/device/optical_mouse_sensor/hal3212/hal3212.c
  60. 17 0
      apps/common/device/optical_mouse_sensor/include/OMSensor_config.h
  61. 50 0
      apps/common/device/optical_mouse_sensor/include/OMSensor_manage.h
  62. 37 0
      apps/common/device/optical_mouse_sensor/include/hal3205/hal3205.h
  63. 46 0
      apps/common/device/optical_mouse_sensor/include/hal3212/hal3212.h
  64. 115 0
      apps/common/device/touch_pad/SYD9557M.c
  65. 24 0
      apps/common/device/touch_pad/SYD9557M.h
  66. 483 0
      apps/common/device/usb/device/cdc.c
  67. 23 0
      apps/common/device/usb/device/cdc.h
  68. 457 0
      apps/common/device/usb/device/cdc_defs.h
  69. 307 0
      apps/common/device/usb/device/custom_hid.c
  70. 215 0
      apps/common/device/usb/device/descriptor.c
  71. 335 0
      apps/common/device/usb/device/hid.c
  72. 1117 0
      apps/common/device/usb/device/msd.c
  73. 75 0
      apps/common/device/usb/device/msd_upgrade.c
  74. 352 0
      apps/common/device/usb/device/task_pc.c
  75. 1396 0
      apps/common/device/usb/device/uac1.c
  76. 507 0
      apps/common/device/usb/device/uac_stream.c
  77. 31 0
      apps/common/device/usb/device/uac_stream.h
  78. 251 0
      apps/common/device/usb/device/usb_device.c
  79. 223 0
      apps/common/device/usb/device/user_setup.c
  80. 459 0
      apps/common/device/usb/host/adb.c
  81. 73 0
      apps/common/device/usb/host/adb.h
  82. 115 0
      apps/common/device/usb/host/adb_rsa_key.c
  83. 232 0
      apps/common/device/usb/host/aoa.c
  84. 20 0
      apps/common/device/usb/host/aoa.h
  85. 8 0
      apps/common/device/usb/host/apple_mfi.h
  86. 820 0
      apps/common/device/usb/host/audio.c
  87. 56 0
      apps/common/device/usb/host/audio.h
  88. 111 0
      apps/common/device/usb/host/audio_demo.c
  89. 657 0
      apps/common/device/usb/host/hid.c
  90. 83 0
      apps/common/device/usb/host/hid.h
  91. 296 0
      apps/common/device/usb/host/usb_bulk_transfer.c
  92. 120 0
      apps/common/device/usb/host/usb_bulk_transfer.h
  93. 622 0
      apps/common/device/usb/host/usb_ctrl_transfer.c
  94. 380 0
      apps/common/device/usb/host/usb_ctrl_transfer.h
  95. 363 0
      apps/common/device/usb/host/usb_hid_keys.h
  96. 744 0
      apps/common/device/usb/host/usb_host.c
  97. 2038 0
      apps/common/device/usb/host/usb_storage.c
  98. 131 0
      apps/common/device/usb/host/usb_storage.h
  99. 155 0
      apps/common/device/usb/usb_common_def.h
  100. 0 0
      apps/common/device/usb/usb_config.c

+ 54 - 0
.gitee/ISSUE_TEMPLATE/bug.yaml

@@ -0,0 +1,54 @@
+name: Bug 反馈
+description: 如发现项目存在的问题,请给予反馈,我们将及时跟进和处理,感谢!
+title: "[Bug]: "
+labels: ["bug"]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        感谢对项目的支持与关注。在提出问题之前,请确保你已查看相关开发或使用文档:
+        - https://doc.zh-jieli.com/AC63/zh-cn/master/index.html
+        - https://gitee.com/Jieli-Tech/fw-AC63_BT_SDK/tree/master/doc/FAQ
+  - type: checkboxes
+    attributes:
+      label: 这个问题是否已经存在?
+      options:
+        - label: 是否搜索过现有的问题 (https://gitee.com/Jieli-Tech/fw-AC63_BT_SDK/issues)
+          required: true
+  - type: textarea
+    attributes:
+      label: 如何复现
+      description: 请详细告诉我们如何复现你遇到的问题,如涉及代码,可提供最小代码示例,并使用反引号```附上它
+      placeholder: |
+        1. ...
+        2. ...
+        3. ...
+    validations:
+      required: true
+  - type: textarea
+    attributes:
+      label: 预期结果
+      description: 请告诉我们你预期会发生什么。
+    validations:
+      required: true
+  - type: textarea
+    attributes:
+      label: 实际结果
+      description: 请告诉我们实际发生了什么。
+    validations:
+      required: true
+  - type: dropdown
+    id: version
+    attributes:
+      label: 版本
+      description: 你当前正在使用我们软件的哪个版本/分支?
+      options:
+        - master(默认)
+        - 2.3.0
+        - 2.2.1 
+        - 2.1.0 
+        - 2.0.0 
+        - 1.0.0 
+        - 其他版本
+    validations:
+      required: true

+ 5 - 0
.gitee/ISSUE_TEMPLATE/config.yaml

@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+  - name: 杰理开源文档
+    url: https://doc.zh-jieli.com/AC63/zh-cn/master/index.html
+    about: 提供杰理开源多款芯片的基本功能使用、介绍和常见问题解答

+ 37 - 0
.gitee/ISSUE_TEMPLATE/feature.yaml

@@ -0,0 +1,37 @@
+name: 功能建议
+description: 对本项目提出一个功能建议
+title: "[功能建议]: "
+labels: ["enhancement"]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        感谢提出功能建议,我们将仔细考虑!
+  - type: textarea
+    id: related-problem
+    attributes:
+      label: 你的功能建议是否和某个问题相关?
+      description: 清晰并简洁地描述问题是什么。
+    validations:
+      required: false
+  - type: textarea
+    id: desired-solution
+    attributes:
+      label: 你希望看到什么解决方案?
+      description: 清晰并简洁地描述。
+    validations:
+      required: true
+  - type: textarea
+    id: alternatives
+    attributes:
+      label: 有对比的方案参考?
+      description: 清晰并简洁地描述解决方案或功能。
+    validations:
+      required: false
+  - type: textarea
+    id: additional-context
+    attributes:
+      label: 示例代码上下文或截图?
+      description: 添加有关功能请求的上下文或截图。
+    validations:
+      required: false

+ 17 - 0
.gitee/ISSUE_TEMPLATE/share.yaml

@@ -0,0 +1,17 @@
+name: 技术与研发经验分享
+description: 对本项目技术特点、研发经验等内容分享
+title: "[分享内容]: "
+labels: ["enhancement"]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        感谢分享!
+  - type: textarea
+    id: related-problem
+    attributes:
+      label: 你的分享内容标题?
+      description: 清晰并详细地描述分享内容。
+    validations:
+      required: true
+

+ 38 - 0
.github/ISSUE_TEMPLATE/bug_report.md

@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
+
+**Smartphone (please complete the following information):**
+ - Device: [e.g. iPhone6]
+ - OS: [e.g. iOS8.1]
+ - Browser [e.g. stock browser, safari]
+ - Version [e.g. 22]
+
+**Additional context**
+Add any other context about the problem here.

+ 20 - 0
.github/ISSUE_TEMPLATE/feature_request.md

@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.

+ 58 - 0
.gitignore

@@ -0,0 +1,58 @@
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+# *.ld
+sdk.ld
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.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
+tags
+filenametags
+cscope.out
+*.bc
+*.ufw

File diff suppressed because it is too large
+ 1927 - 0
.vscode/c_cpp_properties.json


+ 10 - 0
.vscode/settings.json

@@ -0,0 +1,10 @@
+{
+    "files.associations": {
+        "update_loader_download.h": "c",
+        "app_config.h": "c",
+        "app_main.h": "c",
+        "app_action.h": "c",
+        "includes.h": "c",
+        "stdlib.h": "c"
+    }
+}

+ 25 - 0
.vscode/tasks.json

@@ -0,0 +1,25 @@
+{
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "ac632n_spp_and_le",
+            "type": "shell",
+            "windows": {
+                "command": ".vscode/winmk.bat ac632n_spp_and_le"
+            },
+            "command": "make ac632n_spp_and_le -j`nproc`",
+            "problemMatcher": [],
+            "group": "build"
+        },
+        {
+            "label": "clean_ac632n_spp_and_le",
+            "type": "shell",
+            "windows": {
+                "command": ".vscode/winmk.bat clean_ac632n_spp_and_le"
+            },
+            "command": "make clean_ac632n_spp_and_le -j`nproc`",
+            "problemMatcher": [],
+            "group": "build"
+        }
+    ]
+}

+ 3 - 0
.vscode/winmk.bat

@@ -0,0 +1,3 @@
+SET SCRIPT_PATH=%~dp0%
+SET PATH=%SCRIPT_PATH%\..\tools\utils;%PATH%
+make "%1" -j %NUMBER_OF_PROCESSORS%

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

File diff suppressed because it is too large
+ 142 - 0
Makefile


+ 107 - 0
README-en.md

@@ -0,0 +1,107 @@
+
+[tag download]:https://github.com/Jieli-Tech/fw-AC63_BT_SDK/tags
+[tag_badgen]:https://img.shields.io/github/v/tag/Jieli-Tech/fw-AC63_BT_SDK?style=plastic&logo=bluetooth&labelColor=ffffff&color=informational&label=Tag&logoColor=blue
+
+# fw-AC63_BT_SDK   [![tag][tag_badgen]][tag download]
+
+[中文](./README.md) | EN
+
+firmware for Generic bluetooth SDK(AC63 series)
+
+This repository contains the Jieli source code additions to open
+source projects (Zephyr RTOS).
+It must be combined with lib.a and the repositories that use the same
+naming convention to build the provided samples and to use the additional
+subsystems and libraries.
+
+Getting Started
+------------
+
+Welcome to JL open source! See the `Introduction to SDK` for a high-level overview,
+and the documentation's `Getting Started Guide` to start developing.
+
+
+Toolchain
+------------
+
+How to get the `JL Toolchain` and setup the build enviroment,see below
+
+* Complie Tool :install the JL complie tool to setup the build enviroment, [download link](https://doc.zh-jieli.com/Tools/zh-cn/dev_tools/dev_env/index.html) 
+
+* USB updater : program flash tool to download the `hex` file to the target board, please accquire the tool form the [link](https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22883854875.5.504d246bXKwyeH&id=620295020803) and check the related configuration and [document](https://doc.zh-jieli.com/AC63/zh-cn/master/getting_started/project_download/INI_config.html)
+
+
+Documentation
+------------
+
+* Chipset brief : [SoC datasheet](https://doc.zh-jieli.com/vue/#/docs/ac63), [download link](./doc/datasheet)
+
+* SDK Version: [SDK History](https://doc.zh-jieli.com/AC63/zh-cn/master/other/version/index.html)
+
+* SDK introduction : [SDK quick start guide](https://doc.zh-jieli.com/AC63/zh-cn/master/index.html)
+
+* SDK architure : [SDK module architure ](./doc/architure)
+
+Build
+-------------
+Select a project to build. The following folders contains buildable projects:
+
+* APP_Bluetooth : [SPP_LE](./apps/spp_and_le), usage: data transfer, centeral devices, boardcast devices, beacon, FindMy, multi-link, Dongle(usb / bt). [document](https://doc.zh-jieli.com/AC63/zh-cn/master/module_demo/spple/index.html)
+
+* APP_Bluetooth : [HID](./apps/hid), usage: remote control, keyboard, mouse, game box, Voice remote control. [document](https://doc.zh-jieli.com/AC63/zh-cn/master/module_demo/hid/index.html)
+
+* APP_Bluetooth : [Mesh](./apps/mesh), usage: Mesh nodes. [document](https://doc.zh-jieli.com/AC63/zh-cn/master/module_demo/mesh/index.html)
+
+See Tags for the released versions.
+
+Comming Soon:
+
+* APP_Bluetooth :`IoT (ipv6 / 6lowpan)`
+
+* 2.4G_APP : `Vendor Wireless`
+
+SDK support Codeblock & Make to build to project,make sure you already setup the enviroment
+
+* Codeblock build : enter the project directory and find the `.cbp`,double click and build.
+
+* Makefile build : double click the `tools/make_prompt.bat` and excute `make target`(see `makfile`)
+
+  `before build the project make sure the USB updater is connect and enter the update mode correctly`
+
+* Bluetooth OTA : [OTA](https://doc.zh-jieli.com/AC63/zh-cn/master/module_demo/ota/index.html) , usage: Single/Double bank bluetooth update.
+
+Certification
+-------------
+
+Bluetooth Classic LMP /LE Link Layer protocol stack implementing Bluetooth 5.0/5.1/5.4 specification
+
+* Core v5.0 [QDID 134104](https://launchstudio.bluetooth.com/ListingDetails/88799)
+
+* Core v5.1 [QDID 136145](https://launchstudio.bluetooth.com/ListingDetails/91371)
+
+* Core v5.4 [QDID 222830](https://launchstudio.bluetooth.com/ListingDetails/193923)
+
+
+Hardware
+-------------
+
+* EV Board :[link](https://shop321455197.taobao.com/?spm=a230r.7195193.1997079397.2.2a6d391d3n5udo)
+
+* Production Tool : massive prodution and program the SoC, please accquire the tool from the [link](https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22883854875.8.504d246bXKwyeH&id=620941819219) and check the releated [doc](./doc/stuff/烧写器使用说明文档.pdf)
+
+* Wireless Tester : Over the air update/RF Calibration/Fast production test, please accuire the tool from the [link](https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22883854875.10.504d246bXKwyeH&id=620942507511),check [doc](https://doc.zh-jieli.com/Tools/zh-cn/mass_prod_tools/testbox_1tuo2/index.html) for more infomation.
+
+
+Community
+--------------
+
+* [Dingtalk Group] ID: `3375034077`
+
+* [Q&A](./doc/FAQ)
+
+Disclaimer
+------------
+
+AC630N_BT_SDK supports development with AC63 series devices.
+AC63 Series devices (which are pre-production) and Bluetooth Mesh protocols are supported for development in tag v0.5.0 for prototyping and evaluation.
+Support for production and deployment in end products is coming soon.

File diff suppressed because it is too large
+ 103 - 0
README.md


+ 754 - 0
apps/common/audio/audio_digital_vol.c

@@ -0,0 +1,754 @@
+#include "audio_digital_vol.h"
+
+
+#define DIGITAL_FADE_EN 	1
+#define DIGITAL_FADE_STEP 	4
+
+#define BG_DVOL_MAX			14
+#define BG_DVOL_MID			10
+#define BG_DVOL_MIN		    6
+#define BG_DVOL_MAX_FADE	5	/*>= BG_DVOL_MAX:自动淡出BG_DVOL_MAX_FADE*/
+#define BG_DVOL_MID_FADE	3	/*>= BG_DVOL_MID:自动淡出BG_DVOL_MID_FADE*/
+#define BG_DVOL_MIN_FADE	1	/*>= BG_DVOL_MIN:自动淡出BG_DVOL_MIN_FADE*/
+
+#define ASM_ENABLE			1
+#define  L_sat(b,a)       __asm__ volatile("%0=sat16(%1)(s)":"=&r"(b) : "r"(a));
+#define  L_sat32(b,a,n)       __asm__ volatile("%0=%1>>%2(s)":"=&r"(b) : "r"(a),"r"(n));
+
+typedef struct {
+    u8 bg_dvol_fade_out;
+    struct list_head dvol_head;
+} dvol_t;
+static dvol_t dvol_attr;
+
+//static struct digital_volume d_volume;
+/*
+ *数字音量级数 DIGITAL_VOL_MAX
+ *数组长度 DIGITAL_VOL_MAX + 1
+ */
+#define DIGITAL_VOL_MAX		31
+const u16 dig_vol_table[DIGITAL_VOL_MAX + 1] = {
+    0	, //0
+    93	, //1
+    111	, //2
+    132	, //3
+    158	, //4
+    189	, //5
+    226	, //6
+    270	, //7
+    323	, //8
+    386	, //9
+    462	, //10
+    552	, //11
+    660	, //12
+    789	, //13
+    943	, //14
+    1127, //15
+    1347, //16
+    1610, //17
+    1925, //18
+    2301, //19
+    2751, //20
+    3288, //21
+    3930, //22
+    4698, //23
+    5616, //24
+    6713, //25
+    8025, //26
+    9592, //27
+    11466,//28
+    15200,//29
+    16000,//30
+    16384 //31
+};
+
+int audio_digital_vol_init(void)
+{
+    INIT_LIST_HEAD(&dvol_attr.dvol_head);
+    return 0;
+}
+
+/*背景音乐淡出使能*/
+void audio_digital_vol_bg_fade(u8 fade_out)
+{
+    printf("audio_digital_vol_bg_fade:%d", fade_out);
+    dvol_attr.bg_dvol_fade_out = fade_out;
+}
+
+/*
+ *fade_step一般不超过两级数字音量的最小差值
+ *(1)通话如果用数字音量,一般步进小一点,音量调节的时候不会有杂音
+ *(2)淡出的时候可以快一点,尽快淡出到0
+ */
+dvol_handle *audio_digital_vol_open(u8 vol, u8 vol_max, u16 fade_step)
+{
+    dvol_handle *dvol = NULL;
+    dvol = zalloc(sizeof(dvol_handle));
+    if (dvol) {
+        u8 vol_level;
+        dvol->fade 		= DIGITAL_FADE_EN;
+        dvol->vol 		= (vol > vol_max) ? vol_max : vol;
+        if (vol > vol_max) {
+            printf("[warning]cur digital_vol(%d) > digital_vol_max(%d)!!", vol, vol_max);
+        }
+        dvol->vol_max 	= vol_max;
+        vol_level 			= dvol->vol * DIGITAL_VOL_MAX / vol_max;
+        dvol->vol_target = dig_vol_table[vol_level];
+        dvol->vol_fade 	= dvol->vol_target;
+        dvol->fade_step 	= fade_step;
+        dvol->toggle 	= 1;
+#if BG_DVOL_FADE_ENABLE
+        dvol->vol_bk = -1;
+        local_irq_disable();
+        list_add(&dvol->entry, &dvol_attr.dvol_head);
+        if (dvol_attr.bg_dvol_fade_out) {
+            dvol_handle *hdl;
+            list_for_each_entry(hdl, &dvol_attr.dvol_head, entry) {
+                if (hdl != dvol) {
+                    hdl->vol_bk = hdl->vol;
+                    if (hdl->vol >= BG_DVOL_MAX) {
+                        hdl->vol -= BG_DVOL_MAX_FADE;
+                    } else if (hdl->vol >= BG_DVOL_MID) {
+                        hdl->vol -= BG_DVOL_MID_FADE;
+                    } else if (hdl->vol >= BG_DVOL_MIN) {
+                        hdl->vol -= BG_DVOL_MIN_FADE;
+                    } else {
+                        hdl->vol_bk = -1;
+                        continue;
+                    }
+                    u8 vol_level = hdl->vol * DIGITAL_VOL_MAX / hdl->vol_max;
+                    hdl->vol_target = dig_vol_table[vol_level];
+                    //y_printf("bg_dvol fade_out:%x,vol_bk:%d,vol_set:%d,tartget:%d",hdl,hdl->vol_bk,hdl->vol,hdl->vol_target);
+                }
+            }
+        }
+        local_irq_enable();
+#endif
+        printf("digital_vol_open:%x-%d-%d-%d\n", dvol, dvol->vol, dvol->vol_max, fade_step);
+    }
+    return dvol;
+}
+
+void audio_digital_vol_close(dvol_handle *dvol)
+{
+    printf("digital_vol_close:%x\n", dvol);
+    if (dvol) {
+#if BG_DVOL_FADE_ENABLE
+        local_irq_disable();
+        list_del(&dvol->entry);
+        dvol_handle *hdl;
+        list_for_each_entry(hdl, &dvol_attr.dvol_head, entry) {
+            if ((hdl != dvol) && (hdl->vol_bk >= 0)) {
+                //y_printf("bg_dvol fade_in:%x,%d",hdl,hdl->vol_bk);
+                hdl->vol =  hdl->vol_bk;
+                u8 vol_level = hdl->vol_bk * DIGITAL_VOL_MAX / hdl->vol_max;
+                hdl->vol_target = dig_vol_table[vol_level];
+                hdl->vol_bk = -1;
+            }
+        }
+        local_irq_enable();
+#endif
+        free(dvol);
+        dvol = NULL;
+    }
+}
+
+/* u8 audio_digital_vol_get(void)
+{
+    return d_volume.vol;
+} */
+
+void audio_digital_vol_set(dvol_handle *dvol, u8 vol)
+{
+    if (dvol == NULL) {
+        return;
+    }
+    if (dvol->toggle == 0) {
+        return;
+    }
+    dvol->vol = (vol > dvol->vol_max) ? dvol->vol_max : vol;
+#if BG_DVOL_FADE_ENABLE
+    if (dvol->vol_bk != -1) {
+        dvol->vol_bk = vol;
+    }
+#endif
+    dvol->fade = DIGITAL_FADE_EN;
+    u8 vol_level = dvol->vol * DIGITAL_VOL_MAX / dvol->vol_max;
+    dvol->vol_target = dig_vol_table[vol_level];
+    printf("digital_vol:%d-%d-%d-%d\n", vol, vol_level, dvol->vol_fade, dvol->vol_target);
+}
+
+void audio_digital_vol_reset_fade(dvol_handle *dvol)
+{
+    if (dvol) {
+        dvol->vol_fade = 0;
+    }
+}
+
+int audio_digital_vol_run(dvol_handle *dvol, void *data, u32 len)
+{
+    s32 valuetemp;
+    s16 *buf;
+
+    if (dvol->toggle == 0) {
+        return -1;
+    }
+
+    buf = data;
+    len >>= 1; //byte to point
+
+    for (u32 i = 0; i < len; i += 2) {
+        ///left channel
+        if (dvol->fade) {
+            if (dvol->vol_fade > dvol->vol_target) {
+                dvol->vol_fade -= dvol->fade_step;
+                if (dvol->vol_fade < dvol->vol_target) {
+                    dvol->vol_fade = dvol->vol_target;
+                }
+            } else if (dvol->vol_fade < dvol->vol_target) {
+                dvol->vol_fade += dvol->fade_step;
+                if (dvol->vol_fade > dvol->vol_target) {
+                    dvol->vol_fade = dvol->vol_target;
+                }
+            }
+        } else {
+            dvol->vol_fade = dvol->vol_target;
+        }
+
+        valuetemp = buf[i];
+        if (valuetemp < 0) {
+            valuetemp = -valuetemp;
+            valuetemp = (valuetemp * dvol->vol_fade) >> 14 ;
+            valuetemp = -valuetemp;
+        } else {
+            valuetemp = (valuetemp * dvol->vol_fade) >> 14 ;
+        }
+        if (valuetemp < -32768) {
+            valuetemp = -32768;
+        } else if (valuetemp > 32767) {
+            valuetemp = 32767;
+        }
+        buf[i] = (s16)valuetemp;
+
+        ///right channel
+        valuetemp = buf[i + 1];
+        if (valuetemp < 0) {
+            valuetemp = -valuetemp;
+            valuetemp = (valuetemp * dvol->vol_fade) >> 14 ;
+            valuetemp = -valuetemp;
+        } else {
+            valuetemp = (valuetemp * dvol->vol_fade) >> 14 ;
+        }
+        if (valuetemp < -32768) {
+            valuetemp = -32768;
+        } else if (valuetemp > 32767) {
+            valuetemp = 32767;
+        }
+        buf[i + 1] = (s16)valuetemp;
+    }
+    return 0;
+}
+
+
+/*************************支持重入的数字音量调节****************************/
+
+
+
+/*
+ *fade_step一般不超过两级数字音量的最小差值
+ *(1)通话如果用数字音量,一般步进小一点,音量调节的时候不会有杂音
+ *(2)淡出的时候可以快一点,尽快淡出到0
+ */
+void *user_audio_digital_volume_open(u8 vol, u8 vol_max, u16 fade_step)
+{
+    struct digital_volume *d_volume = zalloc(sizeof(struct digital_volume));
+    if (!d_volume) {
+        log_e("d_volume NULL\n");
+        return NULL;
+    }
+    u8 vol_level;
+    d_volume->fade 		= 0;
+    d_volume->vol 		= vol;
+    d_volume->vol_max 	= vol_max;
+    vol_level 			= vol * DIGITAL_VOL_MAX / vol_max;
+    d_volume->vol_target = dig_vol_table[vol_level];
+    //d_volume->vol_fade 	= 0;//d_volume->vol_target;//打开时,从0开始淡入
+    d_volume->vol_fade 	= d_volume->vol_target;
+    d_volume->fade_step 	= fade_step;
+    d_volume->toggle 	= 1;
+    d_volume->ch_num    = 2;//默认双声道
+    d_volume->user_vol_tab = NULL;
+    d_volume->user_vol_max = 0;
+
+    os_mutex_create(&d_volume->mutex);
+    printf("digital_vol_open:%d-%d-%d\n", vol, vol_max, fade_step);
+    return d_volume;
+}
+
+int user_audio_digital_volume_close(void *_d_volume)
+{
+    struct digital_volume *d_volume = (struct digital_volume *)_d_volume;
+    if (!d_volume) {
+        log_e("d_volume NULL\n");
+        return -1;
+    }
+    /* os_mutex_pend(&d_volume->mutex, 0); */
+    d_volume->toggle = 0;
+    d_volume->user_vol_tab = NULL;
+    d_volume->user_vol_max = 0;
+
+    if (d_volume) {
+        free(d_volume);
+        d_volume = NULL;
+    }
+    /* os_mutex_post(&d_volume->mutex); */
+    printf("digital_vol_close\n");
+    return 0;
+}
+
+u8 user_audio_digital_volume_get(void *_d_volume)
+{
+    struct digital_volume *d_volume = (struct digital_volume *)_d_volume;
+    if (!d_volume) {
+        log_e("d_volume NULL\n");
+        return 0;
+    }
+    /* os_mutex_pend(&d_volume->mutex, 0); */
+    u8 vol = d_volume->vol;
+    /* os_mutex_post(&d_volume->mutex); */
+    return vol;
+}
+
+int user_audio_digital_volume_set(void *_d_volume, u8 vol)
+{
+    struct digital_volume *d_volume = (struct digital_volume *)_d_volume;
+    if (!d_volume) {
+        log_e("d_volume NULL\n");
+        return -1;
+    }
+
+    u8 vol_level;
+    if (d_volume->toggle == 0) {
+        return 0;
+    }
+    /* os_mutex_pend(&d_volume->mutex, 0); */
+    d_volume->vol = vol;
+    d_volume->fade = DIGITAL_FADE_EN;
+    if (!d_volume->user_vol_tab) {
+        vol_level = d_volume->vol * DIGITAL_VOL_MAX / d_volume->vol_max;
+        d_volume->vol_target = dig_vol_table[vol_level];
+    } else {
+        u8 d_vol_max = d_volume->user_vol_max - 1;
+        vol_level = d_volume->vol * d_vol_max / d_volume->vol_max;
+        d_volume->vol_target = d_volume->user_vol_tab[vol_level];
+    }
+
+    /* os_mutex_post(&d_volume->mutex); */
+    /* printf("digital_vol:%d-%d-%d-%d\n", vol, vol_level, d_volume->vol_fade, d_volume->vol_target); */
+    return 0;
+}
+
+int user_audio_digital_volume_reset_fade(void *_d_volume)
+{
+    struct digital_volume *d_volume = (struct digital_volume *)_d_volume;
+    if (!d_volume) {
+        log_e("d_volume NULL\n");
+        return -1;
+    }
+
+    os_mutex_pend(&d_volume->mutex, 0);
+    d_volume->vol_fade = 0;
+    os_mutex_post(&d_volume->mutex);
+    return 0;
+}
+
+#if ASM_ENABLE
+
+#define  audio_vol_mix(data,len, ch_num,volumeNOW,volumeDest,step){  \
+	int i, j;              \
+	int fade = 0;             \
+	if (volumeNOW != volumeDest)  \
+	{                         \
+		fade = 1;               \
+	}            \
+	if(d_volume->fade == 0)\
+	{\
+		fade = 0;\
+		d_volume->vol_fade = d_volume->vol_target;\
+	}\
+	if (ch_num == 2)  \
+	{                         \
+		len = len >> 1;            \
+	}                              \
+	else if (ch_num == 3)         \
+	{                                \
+		len = (len*5462)>>14;             /*等效除3,因为5462向上取整得到的*/\
+	}      \
+	else if(ch_num == 4)               \
+	{                \
+		len = len >> 2; \
+	}        \
+	if (fade)            \
+	{                           \
+		short *in_ptr = data;              \
+		for (i = 0; i < len; i++)               \
+		{                                      \
+			if (volumeNOW < volumeDest)            \
+			{                                         \
+				volumeNOW = volumeNOW + step;           \
+				if (volumeNOW > volumeDest)              \
+				{                                 \
+					volumeNOW = volumeDest;          \
+				}                                 \
+			}         \
+			else if (volumeNOW > volumeDest)    \
+			{     \
+				volumeNOW = volumeNOW - step; \
+				if (volumeNOW < volumeDest)         \
+				{      \
+					volumeNOW = volumeDest; \
+				} \
+			}  \
+			{                \
+				int tmp;     \
+				int reptime = ch_num;  \
+				__asm__ volatile(  \
+					" 1 : \n\t"         \
+					" rep %0 {  \n\t"  \
+					"   %1 = h[%2](s) \n\t" \
+					"   %1 =%1* %3  \n\t "\
+					"   %1 =%1 >>>14 \n\t"\
+					"   h[%2++=2]= %1 \n\t"\
+					" }\n\t" \
+					" if(%0!=0 )goto 1b \n\t" \
+					: "=&r"(reptime),      \
+					"=&r"(tmp),        \
+					"=&r"(in_ptr)  \
+					:"r"(volumeNOW),  \
+					"0"(reptime),\
+					"2"(in_ptr)\
+					: "cc", "memory");  \
+			} \
+		} \
+	}  \
+	else  \
+	{  \
+		for (i = 0; i < ch_num; i++) \
+		{  \
+			short *in_ptr = &data[i]; \
+			{  \
+				int tmp;  \
+				int chnumv=ch_num*2;\
+				int reptime = len;\
+				__asm__ volatile(\
+					" 1 : \n\t"\
+					" rep %0 {  \n\t"\
+					"   %1 = h[%2](s) \n\t"\
+					"   %1 = %1 *%3  \n\t "\
+					"   %1=  %1 >>>14 \n\t"\
+					"   h[%2++=%4]= %1 \n\t"\
+					" }\n\t"\
+					" if(%0!=0 )goto 1b \n\t"\
+					: "=&r"(reptime),\
+					"=&r"(tmp),\
+					"=&r"(in_ptr) \
+					:"r"(volumeNOW),  \
+					"r"(chnumv),\
+					"0"(reptime),\
+					"2"(in_ptr)\
+					: "cc", "memory");\
+			}  \
+		}\
+	}\
+}
+
+#else
+
+#define  audio_vol_mix(data,len, ch_num,volumeNOW,volumeDest,step){  \
+	int i, j;              \
+	int fade = 0;             \
+	if (volumeNOW != volumeDest)  \
+	{                         \
+		fade = 1;               \
+	}            \
+	if(d_volume->fade == 0)\
+	{\
+		fade = 0;\
+		d_volume->vol_fade = d_volume->vol_target;\
+	}\
+	if (ch_num == 2)  \
+	{                         \
+		len = len >> 1;            \
+	}                              \
+	else if (ch_num == 3)         \
+	{                                \
+		len = (len*5462)>>14;             /*等效除3,因为5462向上取整得到的*/\
+	}      \
+	else if(ch_num == 4)               \
+	{                \
+		len = len >> 2; \
+	}        \
+	if (fade)            \
+	{                           \
+		short *in_ptr = data;              \
+		for (i = 0; i < len; i++)               \
+		{                                      \
+			if (volumeNOW < volumeDest)            \
+			{                                         \
+				volumeNOW = volumeNOW + step;           \
+				if (volumeNOW > volumeDest)              \
+				{                                 \
+					volumeNOW = volumeDest;          \
+				}                                 \
+			}         \
+			else if (volumeNOW > volumeDest)    \
+			{     \
+				volumeNOW = volumeNOW - step; \
+				if (volumeNOW < volumeDest)         \
+				{      \
+					volumeNOW = volumeDest; \
+				} \
+			}  \
+			for (j = 0; j < ch_num; j++)  \
+			{          \
+				int tmp = (*in_ptr*volumeNOW) >> 14;  \
+				L_sat(tmp, tmp);  \
+				*in_ptr = tmp; \
+				in_ptr++; \
+			} \
+		} \
+	}  \
+	else  \
+	{  \
+		for (i = 0; i < ch_num; i++) \
+		{  \
+			short *in_ptr = &data[i]; \
+			for (j = 0; j < len; j++)\
+			{\
+				int tmp= (*in_ptr*volumeNOW) >> 14;  \
+				L_sat(tmp, tmp);  \
+				*in_ptr = tmp;\
+				in_ptr += ch_num;\
+			}\
+		}\
+	}\
+}
+
+#endif
+
+
+
+int user_audio_digital_volume_run(void *_d_volume, void *data, u32 len, u8 ch_num)
+{
+
+    struct digital_volume *d_volume = (struct digital_volume *)_d_volume;
+    if (!d_volume) {
+        log_e("d_volume NULL\n");
+        return -1;
+    }
+
+    s32 valuetemp;
+    s16 *buf;
+
+    if (d_volume->toggle == 0) {
+        return -1;
+    }
+    if (ch_num > 4) {
+        return -1;
+    }
+    os_mutex_pend(&d_volume->mutex, 0);
+
+
+    if (ch_num) {
+        d_volume->ch_num = ch_num;
+    }
+    buf = data;
+    len >>= 1; //byte to point
+    /* printf("d_volume->vol_target %d %d %d %d\n", d_volume->vol_target, ch_num, d_volume->vol_fade, d_volume->fade_step); */
+#if 1
+    audio_vol_mix(buf, len, ch_num, d_volume->vol_fade, d_volume->vol_target, d_volume->fade_step);
+#else
+
+    /* printf("d_volume->vol_target %d %d\n", d_volume->vol_target, ch_num); */
+    for (u32 i = 0; i < len; i += d_volume->ch_num) {//ch_num 1/2/3/4
+        ///FL channel
+        if (d_volume->fade) {
+            if (d_volume->vol_fade > d_volume->vol_target) {
+                d_volume->vol_fade -= d_volume->fade_step;
+                if (d_volume->vol_fade < d_volume->vol_target) {
+                    d_volume->vol_fade = d_volume->vol_target;
+                }
+            } else if (d_volume->vol_fade < d_volume->vol_target) {
+                d_volume->vol_fade += d_volume->fade_step;
+                if (d_volume->vol_fade > d_volume->vol_target) {
+                    d_volume->vol_fade = d_volume->vol_target;
+                }
+            }
+        } else {
+            d_volume->vol_fade = d_volume->vol_target;
+        }
+
+        valuetemp = buf[i];
+        if (valuetemp < 0) {
+            valuetemp = -valuetemp;
+            valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
+            valuetemp = -valuetemp;
+        } else {
+            valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
+        }
+        if (valuetemp < -32768) {
+            valuetemp = -32768;
+        } else if (valuetemp > 32767) {
+            valuetemp = 32767;
+        }
+        buf[i] = (s16)valuetemp;
+
+        if (d_volume->ch_num > 1) { //双声道
+            ///FR channel
+            valuetemp = buf[i + 1];
+            if (valuetemp < 0) {
+                valuetemp = -valuetemp;
+                valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
+                valuetemp = -valuetemp;
+            } else {
+                valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
+            }
+
+            if (valuetemp < -32768) {
+                valuetemp = -32768;
+            } else if (valuetemp > 32767) {
+                valuetemp = 32767;
+            }
+            buf[i + 1] = (s16)valuetemp;
+
+            if (d_volume->ch_num > 2) { //三声道
+                //RL channel
+                valuetemp = buf[i + 2];
+                if (valuetemp < 0) {
+                    valuetemp = -valuetemp;
+                    valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
+                    valuetemp = -valuetemp;
+                } else {
+                    valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
+                }
+                if (valuetemp < -32768) {
+                    valuetemp = -32768;
+                } else if (valuetemp > 32767) {
+                    valuetemp = 32767;
+                }
+                buf[i + 2] = (s16)valuetemp;
+
+
+                if (d_volume->ch_num > 3) { //四声道
+                    ///RR channel
+                    valuetemp = buf[i + 3];
+                    if (valuetemp < 0) {
+                        valuetemp = -valuetemp;
+                        valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
+                        valuetemp = -valuetemp;
+                    } else {
+                        valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
+                    }
+                    if (valuetemp < -32768) {
+                        valuetemp = -32768;
+                    } else if (valuetemp > 32767) {
+                        valuetemp = 32767;
+                    }
+                    buf[i + 3] = (s16)valuetemp;
+                }
+            }
+        }
+    }
+#endif
+    os_mutex_post(&d_volume->mutex);
+    return 0;
+}
+
+
+
+/*
+ *user_vol_max:音量级数
+ *user_vol_tab:自定义音量表,自定义表长user_vol_max+1
+ */
+void user_audio_digital_set_volume_tab(void *_d_volume, u16 *user_vol_tab, u8 user_vol_max)
+{
+    struct digital_volume *d_volume = (struct digital_volume *)_d_volume;
+    if (!d_volume) {
+        log_e("d_volume NULL\n");
+        return ;
+    }
+
+    os_mutex_pend(&d_volume->mutex, 0);
+    if (user_vol_tab) {
+        d_volume->user_vol_tab = user_vol_tab;
+        d_volume->user_vol_max = user_vol_max;
+    }
+    os_mutex_post(&d_volume->mutex);
+}
+
+
+
+/*
+ *priv:用户自定义指针
+ *void (*handler)(void *priv, void *data, int len, u8 ch_num):用户自定义回调
+ * */
+void *user_audio_process_open(void *parm, void *priv, void (*handler)(void *priv, void *data, int len, u8 ch_num))
+{
+    struct user_audio_parm *user_hdl = zalloc(sizeof(struct user_audio_parm));
+    if (!user_hdl) {
+        log_e("user_hdl NULL\n");
+        return NULL;
+    }
+    user_hdl->priv = priv;
+    user_hdl->handler = handler;
+
+    struct user_audio_digital_parm *dvol_parm = (struct user_audio_digital_parm *)parm;
+    if (dvol_parm->en) {
+        log_i("vol :%d vol_max:%d fade_step:%d\n", dvol_parm->vol, dvol_parm->vol_max, dvol_parm->fade_step);
+        user_hdl->dvol_hdl = user_audio_digital_volume_open(dvol_parm->vol, dvol_parm->vol_max, dvol_parm->fade_step);
+    }
+    log_i("%s ok\n", __FUNCTION__);
+    return user_hdl;
+}
+
+
+int user_audio_process_close(void *_uparm_hdl)
+{
+    struct user_audio_parm *user_hdl = (struct user_audio_parm *)_uparm_hdl;
+    if (!user_hdl) {
+        log_e("user_hdl NULL\n");
+        return -1;
+    }
+    if (user_hdl->dvol_hdl) {
+        user_audio_digital_volume_close(user_hdl->dvol_hdl);
+        user_hdl->dvol_hdl = NULL;
+    }
+    free(user_hdl);
+    user_hdl = NULL;
+    log_i("%s ok\n", __FUNCTION__);
+    return 0;
+}
+
+void user_audio_process_handler_run(void *_uparm_hdl, void *data, u32 len, u8 ch_num)
+{
+    struct user_audio_parm *user_hdl = (struct user_audio_parm *)_uparm_hdl;
+    if (!user_hdl) {
+        log_e("user_hdl NULL\n");
+        return;
+    }
+
+
+    if (user_hdl->handler) {
+        user_hdl->handler(user_hdl->priv, data, len, ch_num);
+    }
+
+    if (user_hdl->dvol_hdl) {
+        user_audio_digital_volume_run(user_hdl->dvol_hdl, data, len, ch_num);
+    }
+
+}
+
+
+
+
+

+ 79 - 0
apps/common/audio/audio_digital_vol.h

@@ -0,0 +1,79 @@
+#ifndef _AUDIO_DIGITAL_VOL_H_
+#define _AUDIO_DIGITAL_VOL_H_
+
+#include "generic/typedef.h"
+#include "os/os_type.h"
+#include "os/os_api.h"
+#include "generic/list.h"
+
+#define BG_DVOL_FADE_ENABLE		1	/*多路声音叠加,背景声音自动淡出小声*/
+
+typedef struct {
+    u8 toggle;					/*数字音量开关*/
+    u8 fade;					/*淡入淡出标志*/
+    u8 vol;						/*淡入淡出当前音量(level)*/
+    u8 vol_max;					/*淡入淡出最大音量(level)*/
+    s16 vol_fade;				/*淡入淡出对应的起始音量*/
+#if BG_DVOL_FADE_ENABLE
+    s16 vol_bk;					/*后台自动淡出前音量值*/
+    struct list_head entry;
+#endif
+    volatile s16 vol_target;	/*淡入淡出对应的目标音量*/
+    volatile u16 fade_step;		/*淡入淡出的步进*/
+} dvol_handle;
+
+
+int audio_digital_vol_init(void);
+void audio_digital_vol_bg_fade(u8 fade_out);
+dvol_handle *audio_digital_vol_open(u8 vol, u8 vol_max, u16 fade_step);
+void audio_digital_vol_close(dvol_handle *dvol);
+void audio_digital_vol_set(dvol_handle *dvol, u8 vol);
+u8 audio_digital_vol_get(void);
+int audio_digital_vol_run(dvol_handle *dvol, void *data, u32 len);
+void audio_digital_vol_reset_fade(dvol_handle *dvol);
+
+/*************************自定义支持重入的数字音量调节****************************/
+void *user_audio_digital_volume_open(u8 vol, u8 vol_max, u16 fade_step);
+int user_audio_digital_volume_close(void *_d_volume);
+u8 user_audio_digital_volume_get(void *_d_volume);
+int user_audio_digital_volume_set(void *_d_volume, u8 vol);
+int user_audio_digital_volume_reset_fade(void *_d_volume);
+int user_audio_digital_volume_run(void *_d_volume, void *data, u32 len, u8 ch_num);
+void user_audio_digital_handler_run(void *_d_volume, void *data, u32 len);
+void user_audio_digital_set_volume_tab(void *_d_volume, u16 *user_vol_tab, u8 user_vol_max);
+
+void *user_audio_process_open(void *parm, void *priv, void (*handler)(void *priv, void *data, int len, u8 ch_num));
+int user_audio_process_close(void *_uparm_hdl);
+void user_audio_process_handler_run(void *_uparm_hdl, void *data, u32 len, u8 ch_num);
+
+struct user_audio_digital_parm {
+    u8 en;
+    u8 vol;
+    u8 vol_max;
+    u16 fade_step;
+};
+
+struct digital_volume {
+    u8 toggle;					/*数字音量开关*/
+    u8 fade;					/*淡入淡出标志*/
+    u8 vol;						/*淡入淡出当前音量*/
+    u8 vol_max;					/*淡入淡出最大音量*/
+    s16 vol_fade;				/*淡入淡出对应的起始音量*/
+    volatile s16 vol_target;	/*淡入淡出对应的目标音量*/
+    volatile u16 fade_step;				/*淡入淡出的步进*/
+
+    OS_MUTEX mutex;
+    u8 ch_num;
+    void *priv;
+    u8 user_vol_max;                                 /*自定义音量表级数*/
+    volatile s16 *user_vol_tab;	                     /*自定义音量表*/
+
+};
+
+struct user_audio_parm {
+    void *priv;
+    void (*handler)(void *priv, void *data, int len, u8 ch_num);/*用户自定义回调处理*/
+    struct digital_volume *dvol_hdl;
+};
+
+#endif

+ 11 - 0
apps/common/audio/audio_noise_gate.h

@@ -0,0 +1,11 @@
+#ifndef _AUDIO_LIMITER_NOISE_GATE_H_
+#define _AUDIO_LIMITER_NOISE_GATE_H_
+
+#include "generic/typedef.h"
+
+
+int audio_noise_gate_open(u16 sample_rate, int limiter_thr, int noise_gate, int noise_gain);
+void audio_noise_gate_run(void *in, void *out, u16 len);
+void audio_noise_gate_close();
+
+#endif/*_AUDIO_NOISE_GATE_H_*/

+ 10 - 0
apps/common/audio/audio_plc.h

@@ -0,0 +1,10 @@
+#ifndef _AUDIO_PLC_H_
+#define _AUDIO_PLC_H_
+
+#include "generic/typedef.h"
+
+int audio_plc_open(u16 sr);
+void audio_plc_run(s16 *dat, u16 len, u8 repair_flag);
+int audio_plc_close(void);
+
+#endif/*_AUDIO_PLC_H_*/

+ 28 - 0
apps/common/audio/audio_utils.c

@@ -0,0 +1,28 @@
+/*
+ ************************************************************
+ *					Audio Utils
+ * 数字信号处理常用模块合集
+ *
+ ************************************************************
+ */
+
+#include "audio_utils.h"
+
+/*
+*********************************************************************
+*                  Audio Digital Phase Inverter
+* Description: 数字反相器,用来反转数字音频信号的相位
+* Arguments  : dat  数据buf地址
+*			   len	数据长度(unit:byte)
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void digital_phase_inverter_s16(s16 *dat, int len)
+{
+    for (int i = 0; i < len / 2; i++) {
+        dat[i] = (dat[i] == -32768) ? 32767 : -dat[i];
+        /* dat[i] = -1 - dat[i]; */
+    }
+}
+

+ 18 - 0
apps/common/audio/audio_utils.h

@@ -0,0 +1,18 @@
+#ifndef _AUDIO_UTILS_H_
+#define _AUDIO_UTILS_H_
+
+#include "generic/typedef.h"
+
+/*
+*********************************************************************
+*                  Audio Digital Phase Inverter
+* Description: 数字反相器,用来反转数字音频信号的相位
+* Arguments  : dat  数据buf地址
+*			   len	数据长度(unit:byte)
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void digital_phase_inverter_s16(s16 *dat, int len);
+
+#endif/*_AUDIO_UTILS_H_*/

+ 325 - 0
apps/common/audio/decode/decode.c

@@ -0,0 +1,325 @@
+
+#include "application/audio_dec_app.h"
+#include "app_config.h"
+#include "audio_config.h"
+#include "app_main.h"
+
+
+//////////////////////////////////////////////////////////////////////////////
+extern struct audio_decoder_task decode_task;
+extern struct audio_mixer mixer;
+extern struct audio_dac_hdl dac_hdl;
+#if AUDIO_DAC_MULTI_CHANNEL_ENABLE
+extern struct audio_dac_channel default_dac;
+#endif
+
+extern const int audio_dec_app_mix_en;
+
+extern u32 audio_output_channel_num(void);
+
+//////////////////////////////////////////////////////////////////////////////
+struct audio_dec_app_audio_state_hdl {
+    struct audio_mixer 			*p_mixer;
+    u32 dec_mix : 1;	// 1:叠加模式
+    u32 flag;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+const struct audio_dec_format_hdl decode_format_list[] = {
+    {"wtg", AUDIO_CODING_G729},
+    {"msbc", AUDIO_CODING_MSBC},
+    {"msb", AUDIO_CODING_MSBC},
+    {"sbc", AUDIO_CODING_SBC},
+    {"mty", AUDIO_CODING_MTY},
+    {"aac", AUDIO_CODING_AAC},
+    {"mp3", AUDIO_CODING_MP3},
+    {"wma", AUDIO_CODING_WMA},
+    {"wav", AUDIO_CODING_WAV},
+#if (defined(TCFG_DEC_MIDI_ENABLE) && TCFG_DEC_MIDI_ENABLE)
+    //midi 文件播放,需要对应音色文件配合
+    {"midi", AUDIO_CODING_MIDI},
+    {"mid", AUDIO_CODING_MIDI},
+#endif //TCFG_DEC_MIDI_ENABLE
+
+#if TCFG_DEC_WTGV2_ENABLE
+    {"wts", AUDIO_CODING_WTGV2},
+#endif
+    {"speex", AUDIO_CODING_SPEEX},
+    {"opus", AUDIO_CODING_OPUS},
+    {0, 0},
+};
+
+#if defined(CONFIG_MEDIA_DEVELOP_ENABLE)
+static struct audio_stream_entry *audio_dec_app_entries[2] = {NULL};
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+
+/*----------------------------------------------------------------------------*/
+/**@brief    解码创建参数初始化
+   @param    *dec: 解码句柄
+   @return   0-正常
+   @note     弱函数重定义
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_app_create_param_init(struct audio_dec_app_hdl *dec)
+{
+    dec->p_decode_task = &decode_task;
+#if defined(CONFIG_MEDIA_DEVELOP_ENABLE)
+    if (!audio_dec_app_mix_en) {
+#if AUDIO_DAC_MULTI_CHANNEL_ENABLE
+        audio_dec_app_entries[0] = &default_dac.entry;
+#else
+        audio_dec_app_entries[0] = &dac_hdl.entry;
+#endif
+        dec->entries = audio_dec_app_entries;
+    } else
+#endif
+    {
+        dec->p_mixer = &mixer;
+    }
+#if defined(CONFIG_MEDIA_DEVELOP_ENABLE)
+    u8 dac_connect_mode =  app_audio_output_mode_get();
+    if (dac_connect_mode == DAC_OUTPUT_FRONT_LR_REAR_LR) {
+        dec->out_ch_num = 4;
+    } else {
+        dec->out_ch_num = audio_output_channel_num();
+    }
+#else
+    u8 dac_connect_mode =  audio_dac_get_channel(&dac_hdl);
+    switch (dac_connect_mode) {
+    /* case DAC_OUTPUT_DUAL_LR_DIFF: */
+    case DAC_OUTPUT_LR:
+        dec->out_ch_num = 2;
+        break;
+    /* case DAC_OUTPUT_FRONT_LR_REAR_LR: */
+    /* dec->out_ch_num = 4; */
+    /* break; */
+    default :
+        dec->out_ch_num = 1;
+        break;
+    }
+#endif
+    return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief    文件解码创建参数初始化
+   @param    *file_dec: 文件解码句柄
+   @return   0-正常
+   @note     弱函数重定义
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_file_app_create_param_init(struct audio_dec_file_app_hdl *file_dec)
+{
+    file_dec->format = (struct audio_dec_format_hdl *)decode_format_list;
+    return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief    解码输出状态设置
+   @param    *dec: 解码句柄
+   @param    flag: 解码标签
+   @return   0-正常
+   @note
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_app_audio_state_switch(struct audio_dec_app_hdl *dec, u32 flag)
+{
+    u8 need_set_audio = 1;
+    /* if ((dec->dec_mix) && (audio_mixer_get_ch_num(dec->p_mixer) > 1)) { */
+    /* need_set_audio = 0; */
+    /* } */
+    if (app_audio_get_state() == APP_AUDIO_STATE_IDLE) {
+        need_set_audio = 1;
+    }
+    if (need_set_audio) {
+        if (flag == AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MUSIC) {
+            app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
+        } else {
+#ifdef TCFG_WTONT_ONCE_VOL
+            extern u8 get_tone_once_vol(void);
+            app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_once_vol());
+#else
+            app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_vol());
+#endif
+        }
+    }
+    return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief    解码输出状态退出
+   @param    *p_aud_state: 输出状态
+   @return   0-正常
+   @note
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_app_audio_state_exit(struct audio_dec_app_audio_state_hdl *p_aud_state)
+{
+    u8 need_set_audio = 1;
+    /* if ((p_aud_state->dec_mix) && (audio_mixer_get_ch_num(p_aud_state->p_mixer) > 1)) { */
+    /* need_set_audio = 0; */
+    /* } */
+    /* if (app_audio_get_state() == APP_AUDIO_STATE_IDLE) { */
+    /* need_set_audio = 1; */
+    /* } */
+    if (need_set_audio) {
+        if (p_aud_state->flag == AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MUSIC) {
+            app_audio_state_exit(APP_AUDIO_STATE_MUSIC);
+        } else {
+            app_audio_state_exit(APP_AUDIO_STATE_WTONE);
+        }
+    }
+    return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief    文件解码初始化完成
+   @param    *file_dec: 文件解码句柄
+   @return   0-正常
+   @note     弱函数重定义
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_file_app_init_ok(struct audio_dec_file_app_hdl *file_dec)
+{
+    audio_dec_app_audio_state_switch(file_dec->dec, file_dec->flag & AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MASK);
+    return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief    文件解码结束
+   @param    *file_dec: 文件解码句柄
+   @return   0-正常
+   @note     弱函数重定义
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_file_app_play_end(struct audio_dec_file_app_hdl *file_dec)
+{
+    struct audio_dec_app_audio_state_hdl aud_state = {0};
+    aud_state.p_mixer = file_dec->dec->p_mixer;
+    aud_state.dec_mix = file_dec->dec->dec_mix;
+    aud_state.flag = file_dec->flag & AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MASK;
+    audio_dec_file_app_close(file_dec);
+    audio_dec_app_audio_state_exit(&aud_state);
+    return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**@brief    正弦波解码初始化完成
+   @param    *sine_dec: 正弦波解码句柄
+   @return   0-正常
+   @note     弱函数重定义
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_sine_app_init_ok(struct audio_dec_sine_app_hdl *sine_dec)
+{
+    audio_dec_app_audio_state_switch(sine_dec->dec, sine_dec->flag & AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MASK);
+    return 0;
+}
+/*----------------------------------------------------------------------------*/
+/**@brief    正弦波解码结束
+   @param    *sine_dec: 正弦波解码句柄
+   @return   0-正常
+   @note     弱函数重定义
+*/
+/*----------------------------------------------------------------------------*/
+int audio_dec_sine_app_play_end(struct audio_dec_sine_app_hdl *sine_dec)
+{
+    struct audio_dec_app_audio_state_hdl aud_state = {0};
+    aud_state.p_mixer = sine_dec->dec->p_mixer;
+    aud_state.dec_mix = sine_dec->dec->dec_mix;
+    aud_state.flag = sine_dec->flag & AUDIO_DEC_FILE_FLAG_AUDIO_STATE_MASK;
+    audio_dec_sine_app_close(sine_dec);
+    audio_dec_app_audio_state_exit(&aud_state);
+    return 0;
+}
+
+#if (!defined(CONFIG_MEDIA_DEVELOP_ENABLE))
+void audio_dec_app_output_sr_set(struct audio_dec_app_hdl *dec)
+{
+    /* #if defined(CONFIG_CPU_BR23) */
+    /* extern u32 audio_output_rate(int input_rate); */
+    /* dec->src_out_sr = audio_output_rate(dec->src_out_sr); */
+    /* #endif */
+    if (dec->src_out_sr == 0) {
+        dec->src_out_sr = audio_dac_get_sample_rate(&dac_hdl);
+        if (dec->src_out_sr == 0) {
+            dec->src_out_sr = 16000;
+            log_w("src out is zero \n");
+        }
+    }
+    if (dec->sample_rate == 0) {
+        dec->sample_rate = dec->src_out_sr;
+    }
+}
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////////
+// test
+#if 0
+#include "tone_player.h"
+
+void audio_dec_file_test(void)
+{
+    struct audio_dec_file_app_hdl *hdl;
+    hdl = audio_dec_file_app_create(TONE_POWER_ON, 1);
+    if (hdl) {
+        audio_dec_file_app_open(hdl);
+    }
+    os_time_dly(2);
+    hdl = audio_dec_file_app_create(TONE_POWER_OFF, 1);
+    if (hdl) {
+        audio_dec_file_app_open(hdl);
+    }
+    os_time_dly(300);
+}
+
+static const struct audio_sin_param sine_test[] = {
+    /*{0, 1000, 0, 100},*/
+    {200 << 9, 4000, 0, 100},
+};
+static const struct audio_sin_param sine_test1[] = {
+    {450 << 9, 24960, 1, 16.667 * 512},
+    {0, 16000, 0, 100},
+};
+void audio_dec_sine_test(void)
+{
+    struct audio_dec_sine_app_hdl *hdl;
+    /* hdl = audio_dec_sine_app_create(SDFILE_RES_ROOT_PATH"tone/vol_max.sin", 1); */
+    hdl = audio_dec_sine_app_create_by_parm(sine_test1, ARRAY_SIZE(sine_test1), 1);
+    if (hdl) {
+        audio_dec_sine_app_open(hdl);
+    }
+    os_time_dly(2);
+    hdl = audio_dec_sine_app_create_by_parm(sine_test, ARRAY_SIZE(sine_test), 1);
+    if (hdl) {
+        audio_dec_sine_app_open(hdl);
+    }
+    /* os_time_dly(300); */
+}
+
+void audio_dec_usb_file_test(void)
+{
+    tone_play_stop();
+    clk_set("sys", 192 * 1000000L);
+
+    struct audio_dec_file_app_hdl *hdl;
+    /* hdl = audio_dec_file_app_create("storage/udisk/C/1.mp3", 1); */
+    hdl = audio_dec_file_app_create("storage/udisk/C/1.wav", 1);
+    if (hdl) {
+        audio_dec_file_app_open(hdl);
+    }
+    os_time_dly(2);
+    /* hdl = audio_dec_file_app_create("storage/udisk/C/2.mp3", 1); */
+    hdl = audio_dec_file_app_create("storage/udisk/C/2.wav", 1);
+    if (hdl) {
+        audio_dec_file_app_open(hdl);
+    }
+    os_time_dly(300);
+}
+
+#endif /*test*/
+
+

+ 212 - 0
apps/common/audio/demo/audio_decoder_test.c

@@ -0,0 +1,212 @@
+/*
+ ****************************************************************
+ *							AUDIO DECODER TEST
+ * File  : audio_decoder_test.c
+ * By    :
+ * Notes : 解码测试
+ *         before和after之间就是解码对应功能的处理,
+ *         可以在before和after中分别翻转IO来卡一下处理时间
+ ****************************************************************
+ */
+
+
+#include "media/includes.h"
+
+
+#define DEC_IO_DEBUG_1(i,x)       {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT |= BIT(x);}
+#define DEC_IO_DEBUG_0(i,x)       {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT &= ~BIT(x);}
+
+
+/*
+*********************************************************************
+*                  Audio Decoder test output before
+* Description: 解码输出
+* Arguments  : *dec		解码句柄
+*              *buff	输出buf
+*              len		输出长度
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_decoder_test_out_before(struct audio_decoder *dec, void *buff, int len)
+{
+    DEC_IO_DEBUG_1(C, 3);
+}
+/*
+*********************************************************************
+*                  Audio Decoder test output after
+* Description: 解码输出
+* Arguments  : *dec		解码句柄
+*              wlen		实际输出长度
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_decoder_test_out_after(struct audio_decoder *dec, int wlen)
+{
+    DEC_IO_DEBUG_0(C, 3);
+}
+
+/*
+*********************************************************************
+*                  Audio Decoder test read file before
+* Description: 解码获取文件数据
+* Arguments  : *dec		解码句柄
+*              len		获取数据长度
+*              offset 	获取数据偏移地址
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_decoder_test_read_before(struct audio_decoder *dec, int len, u32 offset)
+{
+    DEC_IO_DEBUG_1(C, 2);
+}
+/*
+*********************************************************************
+*                  Audio Decoder test read file after
+* Description: 解码获取文件数据
+* Arguments  : *dec		解码句柄
+*              *data 	获取到的数据
+*              rlen		获取到的数据长度
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_decoder_test_read_after(struct audio_decoder *dec, u8 *data, int rlen)
+{
+    DEC_IO_DEBUG_0(C, 2);
+}
+
+/*
+*********************************************************************
+*                  Audio Decoder test get frame before
+* Description: 解码获取帧数据
+* Arguments  : *dec		解码句柄
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_decoder_test_get_frame_before(struct audio_decoder *dec)
+{
+    DEC_IO_DEBUG_1(C, 2);
+}
+/*
+*********************************************************************
+*                  Audio Decoder test get frame after
+* Description: 解码获取帧数据
+* Arguments  : *dec		解码句柄
+*              *frame 	获取到的帧数据
+*              rlen		获取到的帧数据长度
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_decoder_test_get_frame_after(struct audio_decoder *dec, u8 *frame, int rlen)
+{
+    DEC_IO_DEBUG_0(C, 2);
+}
+
+/*
+*********************************************************************
+*                  Audio Decoder test fetch frame before
+* Description: 解码检查帧数据
+* Arguments  : *dec		解码句柄
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_decoder_test_fetch_before(struct audio_decoder *dec)
+{
+    DEC_IO_DEBUG_1(C, 2);
+}
+/*
+*********************************************************************
+*                  Audio Decoder test fetch frame after
+* Description: 解码检查帧数据
+* Arguments  : *dec		解码句柄
+*              *frame 	获取到的帧数据
+*              rlen		获取到的帧数据长度
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_decoder_test_fetch_after(struct audio_decoder *dec, u8 *frame, int rlen)
+{
+    DEC_IO_DEBUG_0(C, 2);
+}
+
+/*
+*********************************************************************
+*                  Audio Decoder test run before
+* Description: 解码处理
+* Arguments  : *dec		解码句柄
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_decoder_test_run_before(struct audio_decoder *dec)
+{
+    DEC_IO_DEBUG_1(C, 1);
+}
+/*
+*********************************************************************
+*                  Audio Decoder test run after
+* Description: 解码处理
+* Arguments  : *dec		解码句柄
+*              err 		解码处理返回值
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_decoder_test_run_after(struct audio_decoder *dec, int err)
+{
+    DEC_IO_DEBUG_0(C, 1);
+}
+
+
+/*
+ * 数据流节点统计时间示例
+ * 这里的时间是数据流节点运行的时间加上输出的时间
+ * 数据流节点的运行时间约等于当前统计的时间减去下一个节点的统计时间
+ * */
+#if 0
+
+// 保存原来的数据流数据处理
+static void *demo_data_handler_save;
+// 数据流data_handler处理
+static int demo_new_data_handler(struct audio_stream_entry *entry,
+                                 struct audio_data_frame *in,
+                                 struct audio_data_frame *out)
+{
+    DEC_IO_DEBUG_1(C, 1);
+
+    // 调用原来的接口输出
+    int wlen = ((int (*)(struct audio_stream_entry *, struct audio_data_frame *, struct audio_data_frame *))demo_data_handler_save)(entry, in, out);
+
+    DEC_IO_DEBUG_0(C, 1);
+    return wlen;
+}
+
+
+void test_start(void)
+{
+#if 1
+    // 用变量保存原来的数据处理接口,然后重新赋值新的数据处理
+    // 这里以获取mix节点的数据为例
+    demo_data_handler_save = (void *)bt_a2dp_dec->mix_ch.entry.data_handler;
+    bt_a2dp_dec->mix_ch.entry.data_handler = demo_new_data_handler;
+#endif
+
+    // 数据流串联
+    struct audio_stream_entry *entries[8] = {NULL};
+    u8 entry_cnt = 0;
+    entries[entry_cnt++] = &dec->dec.decoder.entry;
+    entries[entry_cnt++] = &dec->mix_ch.entry;
+    // ...
+}
+
+
+#endif
+
+

+ 110 - 0
apps/common/audio/demo/audio_encoder_test.c

@@ -0,0 +1,110 @@
+/*
+ ****************************************************************
+ *							AUDIO ENCODE TEST
+ * File  : audio_encoder_test.c
+ * By    :
+ * Notes : 编码测试
+ *         before和after之间就是编码对应功能的处理,
+ *         可以在before和after中分别翻转IO来卡一下处理时间
+ ****************************************************************
+ */
+
+
+#include "media/includes.h"
+
+
+#define ENC_IO_DEBUG_1(i,x)       {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT |= BIT(x);}
+#define ENC_IO_DEBUG_0(i,x)       {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT &= ~BIT(x);}
+
+
+
+/*
+*********************************************************************
+*                  Audio encoder test output before
+* Description: 编码输出
+* Arguments  : *enc		编码句柄
+*              *buff	输出buf
+*              len		输出长度
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_encoder_test_out_before(struct audio_encoder *enc, void *buff, int len)
+{
+    ENC_IO_DEBUG_1(C, 3);
+}
+/*
+*********************************************************************
+*                  Audio encoder test output after
+* Description: 编码输出
+* Arguments  : *enc		编码句柄
+*              wlen		实际输出长度
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_encoder_test_out_after(struct audio_encoder *enc, int wlen)
+{
+    ENC_IO_DEBUG_0(C, 3);
+}
+
+/*
+*********************************************************************
+*                  Audio encoder test get frame before
+* Description: 编码获取帧数据
+* Arguments  : *enc		编码句柄
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_encoder_test_get_frame_before(struct audio_encoder *enc, u16 frame_len)
+{
+    ENC_IO_DEBUG_1(C, 2);
+}
+/*
+*********************************************************************
+*                  Audio encoder test get frame after
+* Description: 编码获取帧数据
+* Arguments  : *enc		编码句柄
+*              *frame 	获取到的帧数据
+*              rlen		获取到的帧数据长度
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_encoder_test_get_frame_after(struct audio_encoder *enc, s16 *frame, int rlen)
+{
+    ENC_IO_DEBUG_0(C, 2);
+}
+
+/*
+*********************************************************************
+*                  Audio encoder test run before
+* Description: 编码处理
+* Arguments  : *enc		编码句柄
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_encoder_test_run_before(struct audio_encoder *enc)
+{
+    ENC_IO_DEBUG_1(C, 1);
+}
+/*
+*********************************************************************
+*                  Audio encoder test run after
+* Description: 编码处理
+* Arguments  : *enc		编码句柄
+*              err 		编码处理返回值
+* Return	 : None.
+* Note(s)    : None.
+*********************************************************************
+*/
+void audio_encoder_test_run_after(struct audio_encoder *enc, int err)
+{
+    ENC_IO_DEBUG_0(C, 1);
+}
+
+
+
+

+ 78 - 0
apps/common/audio/encode/encode_write.h

@@ -0,0 +1,78 @@
+
+#ifndef _ENCODE_WRITE_H
+#define _ENCODE_WRITE_H
+
+#include "app_config.h"
+#include "system/includes.h"
+#include "system/os/os_cpu.h"
+#include "system/fs/fs.h"
+#include "dev_manager.h"
+
+
+enum {
+    ENC_WRITE_FILE_EVT_WRITE_ERR = 0x10,
+    ENC_WRITE_FILE_EVT_FILE_CLOSE,	// 0-err, 非0-起始簇号
+
+    ENC_WRITE_FLASH_EVT_WRITE_ERR = 0x20,
+    ENC_WRITE_FLASH_EVT_OUTOF_LEN,
+};
+
+struct audio_enc_write_input {
+    int (*get)(void *, s16 **frame, u16 frame_len);
+    void (*put)(void *, s16 *frame);
+};
+
+typedef struct enc_tmark_info {
+    unsigned int len;
+    u8      data[0];
+} Tmark_info;
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+int enc_write_file_resume(void *hdl);	// 调用该函数激活写文件
+
+void enc_write_file_close(void *hdl);
+void *enc_write_file_open(char *logo, const char *folder, const char *filename);
+
+int enc_write_file_start(void *hdl);
+void enc_write_file_stop(void *hdl, u32 delay_ms); // delay_ms:超时等待完成
+
+// 录音结束后需要重新写头部数据
+void enc_write_file_set_head_handler(void *hdl, int (*set_head)(void *, char **head), void *set_head_hdl);
+void enc_write_file_set_evt_handler(void *hdl, void (*evt_cb)(void *, int, int), void *evt_hdl);
+void enc_write_file_set_input(void *hdl, struct audio_enc_write_input *input, void *input_hdl, u32 input_frame_len);
+
+int get_enc_file_len(void *hdl);
+// cut_size:结束后砍掉的尾部长度
+// limit_size:文件小于该长度时,不保留文件
+void enc_write_file_set_limit(void *hdl, u32 cut_size, u32 limit_size);
+
+
+//////////////////////////////////////////////////////////////////////////////
+int enc_write_flash_resume(void *hdl);	// 调用该函数激活写
+
+void enc_write_flash_close(void *hdl);
+void *enc_write_flash_open(const char *dev_name, void *arg, u32 addr_start, u32 max_len);
+
+int enc_write_flash_start(void *hdl);
+void enc_write_flash_stop(void *hdl, u32 delay_ms); // delay_ms:超时等待完成
+
+// 录音结束后需要重新写头部数据
+void enc_write_flash_set_head_handler(void *hdl, int (*set_head)(void *, char **head), void *set_head_hdl);
+void enc_write_flash_set_evt_handler(void *hdl, void (*evt_cb)(void *, int, int), void *evt_hdl);
+void enc_write_flash_set_input(void *hdl, struct audio_enc_write_input *input, void *input_hdl, u32 input_frame_len);
+
+// cut_size:结束后砍掉的尾部长度
+// limit_size:文件小于该长度时,不保留文件
+void enc_write_flash_set_limit(void *hdl, u32 cut_size, u32 limit_size);
+
+void last_enc_file_codeing_type_save(u32 type);
+int last_enc_file_path_get(char path[64]);
+
+
+void *get_wfil_head_hdl(void *enc_whdl);
+FILE *get_wfil_file(void *enc_whdl);
+
+#endif
+

+ 390 - 0
apps/common/audio/sine_make.c

@@ -0,0 +1,390 @@
+/*****************************************************************
+>file name : apps/common/sine_make.c
+>author : lichao
+>create time : Sun 05 May 2019 08:37:35 PM CST
+*****************************************************************/
+#include "system/includes.h"
+#include "sine_make.h"
+
+#define SINE_USE_MALLOC			1
+
+struct audio_sin_maker {
+    u8 open;
+    u8 id;
+    u8 sin_num;
+    u8 channel;
+    u8 repeat;
+    u8 next_param;
+    u16 fade_points;
+    /*int sample_rate;*/
+    int volume;
+    int points;
+    int sin_index;
+    int win_sin_index;
+    const struct sin_param *sin;
+};
+
+#ifndef SINE_USE_MALLOC
+static struct audio_sin_maker sin_maker_handle;
+#endif
+
+void *sin_tone_open(const struct sin_param *param, int num, u8 channel, u8 repeat)
+{
+    if (!param || !num) {
+        return NULL;
+    }
+
+#ifdef SINE_USE_MALLOC
+    struct audio_sin_maker *sin = zalloc(sizeof(struct audio_sin_maker));
+#else
+    struct audio_sin_maker *sin = &sin_maker_handle;
+#endif
+
+    if (!sin) {
+        return NULL;
+    }
+    if (sin->open) {
+        return NULL;
+    }
+
+    sin->sin = param;
+    sin->sin_num = num;
+    sin->open = 1;
+    sin->points = param[0].points;
+    sin->id = 0;
+    sin->channel = channel;
+    sin->repeat = repeat;
+#if (defined CONFIG_CPU_BR18 || \
+     defined CONFIG_CPU_BR21)
+    /*这里如果加多fade points,会导致结束的时候有噪声,不是在淡出尾部*/
+    sin->fade_points = 0;
+#else
+    sin->fade_points = 480;
+#endif
+    sin->next_param = 1;
+
+    return (void *)sin;
+}
+#if !defined(SINE_MAKE_IN_MASK)
+const int sf_sin_tab1[513] = {
+    0x00000000, 0x0000c910, 0x0001921f, 0x00025b2d, 0x0003243a, 0x0003ed45, 0x0004b64e, 0x00057f53,
+    0x00064855, 0x00071154, 0x0007da4e, 0x0008a343, 0x00096c33, 0x000a351d, 0x000afe00, 0x000bc6dd,
+    0x000c8fb3, 0x000d5881, 0x000e2147, 0x000eea03, 0x000fb2b7, 0x00107b61, 0x00114401, 0x00120c96,
+    0x0012d521, 0x00139d9f, 0x00146611, 0x00152e77, 0x0015f6d0, 0x0016bf1b, 0x00178758, 0x00184f87,
+    0x001917a7, 0x0019dfb7, 0x001aa7b7, 0x001b6fa7, 0x001c3786, 0x001cff53, 0x001dc70f, 0x001e8eb8,
+    0x001f564e, 0x00201dd1, 0x0020e541, 0x0021ac9b, 0x002273e2, 0x00233b13, 0x0024022e, 0x0024c933,
+    0x00259021, 0x002656f8, 0x00271db7, 0x0027e45f, 0x0028aaed, 0x00297163, 0x002a37bf, 0x002afe01,
+    0x002bc429, 0x002c8a35, 0x002d5026, 0x002e15fb, 0x002edbb4, 0x002fa14f, 0x003066ce, 0x00312c2e,
+    0x0031f170, 0x0032b694, 0x00337b98, 0x0034407c, 0x00350540, 0x0035c9e4, 0x00368e66, 0x003752c6,
+    0x00381705, 0x0038db21, 0x00399f19, 0x003a62ef, 0x003b26a0, 0x003bea2c, 0x003cad94, 0x003d70d7,
+    0x003e33f3, 0x003ef6e9, 0x003fb9b8, 0x00407c60, 0x00413ee0, 0x00420138, 0x0042c367, 0x0043856d,
+    0x0044474a, 0x004508fc, 0x0045ca83, 0x00468be0, 0x00474d11, 0x00480e16, 0x0048ceef, 0x00498f9a,
+    0x004a5019, 0x004b1069, 0x004bd08b, 0x004c907f, 0x004d5043, 0x004e0fd8, 0x004ecf3c, 0x004f8e70,
+    0x00504d72, 0x00510c43, 0x0051cae3, 0x0052894f, 0x00534789, 0x0054058f, 0x0054c362, 0x00558100,
+    0x00563e6a, 0x0056fb9e, 0x0057b89d, 0x00587565, 0x005931f7, 0x0059ee52, 0x005aaa76, 0x005b6662,
+    0x005c2215, 0x005cdd8f, 0x005d98d0, 0x005e53d8, 0x005f0ea5, 0x005fc937, 0x0060838f, 0x00613dab,
+    0x0061f78b, 0x0062b12e, 0x00636a95, 0x006423be, 0x0064dcaa, 0x00659557, 0x00664dc6, 0x006705f5,
+    0x0067bde5, 0x00687595, 0x00692d05, 0x0069e433, 0x006a9b21, 0x006b51cc, 0x006c0836, 0x006cbe5c,
+    0x006d7440, 0x006e29e0, 0x006edf3d, 0x006f9454, 0x00704927, 0x0070fdb5, 0x0071b1fd, 0x007265ff,
+    0x007319ba, 0x0073cd2f, 0x0074805c, 0x00753341, 0x0075e5dd, 0x00769831, 0x00774a3c, 0x0077fbfe,
+    0x0078ad75, 0x00795ea2, 0x007a0f84, 0x007ac01a, 0x007b7065, 0x007c2064, 0x007cd016, 0x007d7f7c,
+    0x007e2e93, 0x007edd5d, 0x007f8bd9, 0x00803a06, 0x0080e7e4, 0x00819573, 0x008242b1, 0x0082ef9f,
+    0x00839c3d, 0x00844889, 0x0084f484, 0x0085a02c, 0x00864b82, 0x0086f686, 0x0087a136, 0x00884b92,
+    0x0088f59b, 0x00899f4e, 0x008a48ad, 0x008af1b7, 0x008b9a6b, 0x008c42c9, 0x008cead0, 0x008d9281,
+    0x008e39da, 0x008ee0db, 0x008f8784, 0x00902dd5, 0x0090d3cd, 0x0091796b, 0x00921eb0, 0x0092c39a,
+    0x0093682a, 0x00940c5f, 0x0094b039, 0x009553b7, 0x0095f6d9, 0x0096999f, 0x00973c07, 0x0097de12,
+    0x00987fc0, 0x0099210f, 0x0099c200, 0x009a6293, 0x009b02c6, 0x009ba299, 0x009c420c, 0x009ce11f,
+    0x009d7fd1, 0x009e1e22, 0x009ebc12, 0x009f599f, 0x009ff6cb, 0x00a09393, 0x00a12ff9, 0x00a1cbfb,
+    0x00a26799, 0x00a302d3, 0x00a39da9, 0x00a4381a, 0x00a4d225, 0x00a56bcb, 0x00a6050a, 0x00a69de3,
+    0x00a73656, 0x00a7ce61, 0x00a86605, 0x00a8fd41, 0x00a99415, 0x00aa2a80, 0x00aac082, 0x00ab561b,
+    0x00abeb4a, 0x00ac800f, 0x00ad1469, 0x00ada859, 0x00ae3bde, 0x00aecef7, 0x00af61a5, 0x00aff3e6,
+    0x00b085bb, 0x00b11722, 0x00b1a81d, 0x00b238aa, 0x00b2c8c9, 0x00b3587a, 0x00b3e7bc, 0x00b4768f,
+    0x00b504f3, 0x00b592e7, 0x00b6206c, 0x00b6ad7f, 0x00b73a23, 0x00b7c655, 0x00b85216, 0x00b8dd65,
+    0x00b96842, 0x00b9f2ac, 0x00ba7ca4, 0x00bb0629, 0x00bb8f3b, 0x00bc17d9, 0x00bca003, 0x00bd27b8,
+    0x00bdaef9, 0x00be35c5, 0x00bebc1b, 0x00bf41fc, 0x00bfc767, 0x00c04c5c, 0x00c0d0da, 0x00c154e1,
+    0x00c1d870, 0x00c25b89, 0x00c2de29, 0x00c36051, 0x00c3e200, 0x00c46337, 0x00c4e3f5, 0x00c56439,
+    0x00c5e403, 0x00c66354, 0x00c6e22a, 0x00c76085, 0x00c7de65, 0x00c85bca, 0x00c8d8b3, 0x00c95521,
+    0x00c9d112, 0x00ca4c87, 0x00cac77f, 0x00cb41fa, 0x00cbbbf8, 0x00cc3578, 0x00ccae79, 0x00cd26fd,
+    0x00cd9f02, 0x00ce1689, 0x00ce8d90, 0x00cf0417, 0x00cf7a1f, 0x00cfefa8, 0x00d064af, 0x00d0d937,
+    0x00d14d3d, 0x00d1c0c2, 0x00d233c6, 0x00d2a649, 0x00d31849, 0x00d389c7, 0x00d3fac3, 0x00d46b3b,
+    0x00d4db31, 0x00d54aa4, 0x00d5b993, 0x00d627fe, 0x00d695e5, 0x00d70348, 0x00d77026, 0x00d7dc7f,
+    0x00d84853, 0x00d8b3a1, 0x00d91e6a, 0x00d988ad, 0x00d9f26a, 0x00da5ba0, 0x00dac450, 0x00db2c79,
+    0x00db941a, 0x00dbfb34, 0x00dc61c7, 0x00dcc7d1, 0x00dd2d53, 0x00dd924d, 0x00ddf6be, 0x00de5aa6,
+    0x00debe05, 0x00df20db, 0x00df8327, 0x00dfe4e9, 0x00e04621, 0x00e0a6cf, 0x00e106f2, 0x00e1668a,
+    0x00e1c598, 0x00e2241a, 0x00e28210, 0x00e2df7b, 0x00e33c5a, 0x00e398ac, 0x00e3f473, 0x00e44fac,
+    0x00e4aa59, 0x00e50479, 0x00e55e0b, 0x00e5b710, 0x00e60f88, 0x00e66771, 0x00e6becc, 0x00e71599,
+    0x00e76bd8, 0x00e7c187, 0x00e816a8, 0x00e86b39, 0x00e8bf3c, 0x00e912ae, 0x00e96591, 0x00e9b7e4,
+    0x00ea09a7, 0x00ea5ad9, 0x00eaab7b, 0x00eafb8c, 0x00eb4b0c, 0x00eb99fb, 0x00ebe858, 0x00ec3624,
+    0x00ec835e, 0x00ecd007, 0x00ed1c1d, 0x00ed67a1, 0x00edb293, 0x00edfcf2, 0x00ee46be, 0x00ee8ff8,
+    0x00eed89e, 0x00ef20b0, 0x00ef6830, 0x00efaf1b, 0x00eff573, 0x00f03b37, 0x00f08066, 0x00f0c501,
+    0x00f10908, 0x00f14c7a, 0x00f18f57, 0x00f1d19f, 0x00f21352, 0x00f25470, 0x00f294f8, 0x00f2d4eb,
+    0x00f31447, 0x00f3530e, 0x00f3913f, 0x00f3ced9, 0x00f40bdd, 0x00f4484b, 0x00f48422, 0x00f4bf62,
+    0x00f4fa0b, 0x00f5341d, 0x00f56d97, 0x00f5a67b, 0x00f5dec6, 0x00f6167a, 0x00f64d97, 0x00f6841b,
+    0x00f6ba07, 0x00f6ef5b, 0x00f72417, 0x00f7583a, 0x00f78bc5, 0x00f7beb7, 0x00f7f110, 0x00f822d1,
+    0x00f853f8, 0x00f88486, 0x00f8b47b, 0x00f8e3d6, 0x00f91298, 0x00f940c0, 0x00f96e4e, 0x00f99b43,
+    0x00f9c79d, 0x00f9f35e, 0x00fa1e84, 0x00fa4910, 0x00fa7302, 0x00fa9c59, 0x00fac516, 0x00faed37,
+    0x00fb14be, 0x00fb3bab, 0x00fb61fc, 0x00fb87b2, 0x00fbaccd, 0x00fbd14d, 0x00fbf531, 0x00fc187a,
+    0x00fc3b28, 0x00fc5d3a, 0x00fc7eb0, 0x00fc9f8a, 0x00fcbfc9, 0x00fcdf6c, 0x00fcfe73, 0x00fd1cdd,
+    0x00fd3aac, 0x00fd57de, 0x00fd7474, 0x00fd906e, 0x00fdabcc, 0x00fdc68c, 0x00fde0b1, 0x00fdfa38,
+    0x00fe1324, 0x00fe2b72, 0x00fe4323, 0x00fe5a38, 0x00fe70b0, 0x00fe868b, 0x00fe9bc9, 0x00feb069,
+    0x00fec46d, 0x00fed7d4, 0x00feea9d, 0x00fefcc9, 0x00ff0e58, 0x00ff1f49, 0x00ff2f9d, 0x00ff3f54,
+    0x00ff4e6d, 0x00ff5ce9, 0x00ff6ac7, 0x00ff7808, 0x00ff84ab, 0x00ff90b1, 0x00ff9c18, 0x00ffa6e3,
+    0x00ffb10f, 0x00ffba9e, 0x00ffc38f, 0x00ffcbe2, 0x00ffd397, 0x00ffdaaf, 0x00ffe129, 0x00ffe705,
+    0x00ffec43, 0x00fff0e3, 0x00fff4e6, 0x00fff84a, 0x00fffb11, 0x00fffd39, 0x00fffec4, 0x00ffffb1,
+    0x00ffffff,
+};
+#else
+extern const int sf_sin_tab1[513] ;
+#endif
+
+
+#define  SINE_INT_ZOOM   16384
+#define  SINE_INT_ZBIT   14
+#define __int64	long long
+/*软件索引实现sin生成*/
+static int get_sine_value(int mx_idx)
+{
+    int ret = 0;
+    int idx = 0;
+    int tm_idx = mx_idx & 0x1FFFFFF;   //2^25
+    int phase = tm_idx & 0x3FFF;
+    int tp_idx0 = tm_idx >> 14;
+    int tp_idx1 = tp_idx0 + 1;
+    int sign = 1, dt0, dt1;
+
+    if (tp_idx0 > 1024) {
+        sign = -1;
+        tp_idx0 = 2048 - tp_idx0;
+    }
+    if (tp_idx0 < 513) {
+        dt0 = sf_sin_tab1[tp_idx0];
+    } else {
+        dt0 = sf_sin_tab1[1024 - tp_idx0];
+    }
+
+    if (tp_idx1 > 1024) {
+        sign = -1;
+        tp_idx1 = 2048 - tp_idx1;
+    }
+    if (tp_idx1 < 513) {
+        dt1 = sf_sin_tab1[tp_idx1];
+    } else {
+        dt1 = sf_sin_tab1[1024 - tp_idx1];
+    }
+
+    ret = ((__int64)dt0 * (SINE_INT_ZOOM - phase) + (__int64)dt1 * phase) >> SINE_INT_ZBIT;
+
+    ret *= sign;
+    return ret;
+}
+
+static void hw_sin_value(int a, int *sin_res, u8 precision)
+{
+    u64 s64 = a;
+
+    *sin_res = __asm_sine(s64, precision);
+}
+
+int sin_tone_make(void *_maker, void *data, int len)
+{
+    struct audio_sin_maker *maker = (struct audio_sin_maker *)_maker;
+    s16 *pcm = (s16 *)data;
+    int sin_value = 0;
+    int win_sin_value = 0;
+    int add_idx = 0, sub_vol = 0, win_add_idx = 0;
+    int offset = 0;
+    u8 id = maker->id;
+    u8 sin_num = maker->sin_num;
+    u8 repeat = maker->repeat;
+    u8 channel = maker->channel;
+    int sin_index;
+    int win_sin_index;
+    int volume;
+    u32 reamin_points = len / 2 / channel;
+
+    do {
+        if (maker->next_param) {
+            maker->volume = SINE_TOTAL_VOLUME;
+            maker->sin_index = 0;
+            maker->win_sin_index = 0;
+            maker->next_param = 0;
+        }
+
+        u8 win = maker->sin[id].win;
+        add_idx = ((u64)(1 << 25) * maker->sin[id].freq / DEFAULT_SINE_SAMPLE_RATE) >> 9;
+        if (win) {
+            win_add_idx = ((u64)(1 << 25) * maker->sin[id].decay / DEFAULT_SINE_SAMPLE_RATE) >> 9;
+            /*sub_vol = 0;*/
+        } else {
+            sub_vol = maker->sin[id].decay;
+        }
+
+        sin_index = maker->sin_index;
+        win_sin_index = maker->win_sin_index;
+        volume = maker->volume;
+        u32 points = 0;
+        if (maker->fade_points) {
+            points = maker->fade_points > reamin_points ? reamin_points : maker->fade_points;
+            sub_vol = 0;
+            maker->fade_points -= points;
+        } else {
+            points = maker->points > reamin_points ? reamin_points : maker->points;
+            maker->points -= points;
+        }
+        reamin_points -= points;
+        while (points--) {
+            /*hw_sin_value(sin_index, &sin_value, 0);*/
+            sin_value = __asm_sine((s64)sin_index, 2);
+            if (win) {
+                /*hw_sin_value(win_sin_index, &win_sin_value, 0);*/
+                win_sin_value = __asm_sine((s64)win_sin_index, 2);
+#if ((defined CONFIG_CPU_BR36) || (defined CONFIG_CPU_BR28))
+                sin_value = ((s64)sin_value * (s64)win_sin_value) >> 44;
+#else
+                sin_value = ((s64)sin_value * (s64)win_sin_value) >> 34;
+#endif
+                win_sin_index += win_add_idx;
+                win_sin_index &= 0x1ffffff;
+            } else {
+#if ((defined CONFIG_CPU_BR36) || (defined CONFIG_CPU_BR28))
+                sin_value = ((s64)volume * sin_value) >> 39;
+#else
+                sin_value = ((s64)volume * sin_value) >> 34;
+#endif
+            }
+            sin_index += add_idx;
+            sin_index &= 0x1ffffff;
+
+            volume -= sub_vol;
+            if (volume < 0) {
+                volume = 0;
+            }
+
+            *pcm++ = sin_value;
+            if (channel == 2) {
+                *pcm++ = sin_value;
+            } else if (channel == 4) {
+                *pcm++ = sin_value;
+                *pcm++ = sin_value;
+                *pcm++ = sin_value;
+            }
+        }
+
+        maker->volume = volume;
+        maker->sin_index = sin_index;
+        maker->win_sin_index = win_sin_index;
+        if (!maker->points) {
+            if (++id >= sin_num) {
+                if (!repeat) {
+                    break;
+                }
+                id = 0;
+            }
+            maker->points = maker->sin[id].points;
+            maker->id = id;
+            maker->next_param = 1;
+        }
+
+        if (!reamin_points) {
+            break;
+        }
+    } while (1);
+
+    return len - (reamin_points * 2 * channel);
+}
+
+int sin_tone_points(void *_maker)
+{
+    struct audio_sin_maker *maker = (struct audio_sin_maker *)_maker;
+    int points = 0;
+    u8 i = 0;
+
+    for (i = 0; i < maker->sin_num; i++) {
+        points += maker->sin[i].points;
+    }
+
+    return points;
+}
+
+void sin_tone_close(void *_maker)
+{
+    struct audio_sin_maker *maker = (struct audio_sin_maker *)_maker;
+
+#ifdef SINE_USE_MALLOC
+    if (maker) {
+        free(maker);
+    }
+#else
+    if (sin_maker_handle.open) {
+        sin_maker_handle.open = 0;
+    }
+#endif
+
+}
+
+#if 0
+#include "MathFunc_float.h"
+
+#ifndef DATA16
+#define DATA16		32767
+#endif
+
+/*********************************
+ * 	 fc 		: 正弦波中心频率
+ * 	 fs 		: 采样频率
+ * FrameSize	:每次计算输出点数
+ *   idx   		:当前计算起始indix
+ *   rst    	:结果存放地址
+ * *******************************/
+void SinWave_Generator(int fc, int fs, int FrameSize, int idx, short *rst)
+{
+    float tmp0, tmp1, tmp2;
+    tmp0 = (float)fc / fs;
+    for (int i = 0; i < FrameSize; i++) {
+        tmp1 = (i + idx) * tmp0 * 2;
+        sin_float(tmp1, &tmp2);
+        *rst = (short)(tmp2 * DATA16);
+        rst++;
+    }
+}
+/*********************************
+ * 	 fs 		: 采样频率
+ * FrameSize	:每次计算输出点数
+ *   idx   		:当前计算起始indix
+ *   ts   		:期望一次扫频所持续时间
+ *   rst    	:结果存放地址
+ * *******************************/
+void SweepSin_Generator(int fs, int FrameSize, int idx, float ts, short *rst)
+{
+    float fp, fc, tmp1, tmp2;
+    int Ncnt, NPoint, DPoint;
+
+    NPoint = fs * ts;
+    // fp = (fs/2)/(fs*ts);
+    fp = 1 / (2 * 2 * ts);
+
+    for (int i = 0; i < FrameSize; i++) {
+        Ncnt = (i + idx) / NPoint;
+        DPoint = (i + idx) - Ncnt * NPoint;
+        //printf("idx:%d \n",DPoint);
+        tmp1 = ((DPoint * fp) / fs) * DPoint * 2;
+        sin_float(tmp1, &tmp2);
+        //printf("Sin[%d]:%d",i,(int)(tmp2*1000));
+        *rst = (short)(tmp2 * DATA16);
+        rst++;
+    }
+}
+
+int sin_idx = 0;
+void sin_pcm_fill(void *buf, u32 len)
+{
+    SinWave_Generator(1000, 16000, len / 2, sin_idx, buf);
+    sin_idx += len / 2;
+}
+
+void sweepsin_pcm_fill(void *buf, u32 len)
+{
+    SweepSin_Generator(16000, len / 2, sin_idx, 25, buf);
+    sin_idx += len / 2;
+}
+#endif

+ 22 - 0
apps/common/audio/sine_make.h

@@ -0,0 +1,22 @@
+#ifndef __SINE_MAKE_H_
+#define __SINE_MAKE_H_
+
+#include "generic/typedef.h"
+
+#define DEFAULT_SINE_SAMPLE_RATE 16000
+#define SINE_TOTAL_VOLUME        26843546//16106128//20132660 //26843546
+
+struct sin_param {
+    //int idx_increment;
+    int freq;
+    int points;
+    int win;
+    int decay;
+};
+
+int sin_tone_make(void *_maker, void *data, int len);
+void *sin_tone_open(const struct sin_param *param, int num, u8 channel, u8 repeat);
+int sin_tone_points(void *_maker);
+void sin_tone_close(void *_maker);
+
+#endif/*__SINE_MAKE_H_*/

+ 246 - 0
apps/common/bt_common/bt_test_api.c

@@ -0,0 +1,246 @@
+
+#include "typedef.h"
+#include "app_config.h"
+#include "task.h"
+#include "btctrler_task.h"
+#include "btcontroller_config.h"
+#include "system/includes.h"
+
+#define LOG_TAG             "[BT_DUT]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+//bredr test api
+extern void ble_enter_dut_tx_mode(void *param);
+extern void bt_ble_adv_enable(u8 enable);
+extern void bredr_fcc_init(u8 mode, u8 fre);
+
+#if 0
+
+static void bt_dut_api(void)
+{
+    log_info("bt in dut \n");
+#if TCFG_AUTO_SHUT_DOWN_TIME
+    extern void sys_auto_shut_down_disable(void);
+    sys_auto_shut_down_disable();
+#endif
+
+#if TCFG_USER_TWS_ENABLE
+    extern 	void tws_cancle_all_noconn();
+    tws_cancle_all_noconn() ;
+#else
+    //sys_timer_del(app_var.auto_stop_page_scan_timer);
+    extern void bredr_close_all_scan();
+    bredr_close_all_scan();
+#endif
+
+#if TCFG_USER_BLE_ENABLE
+#if (CONFIG_BT_MODE == BT_NORMAL)
+    bt_ble_adv_enable(0);
+#endif
+#endif
+}
+
+void bit_clr_ie(unsigned char index);
+/* !!!Notice:when this api is called and sleep mode should be sure to exit; */
+void bt_fix_fre_api(u8 fre)
+{
+    bt_dut_api();
+
+    bit_clr_ie(IRQ_BREDR_IDX);
+    bit_clr_ie(IRQ_BT_CLKN_IDX);
+
+    bredr_fcc_init(BT_FRE, fre);
+}
+#endif
+
+//ble test api
+enum  BLE_DUT_PAYLOAD_TYPE {
+    PAYLOAD_TYPE_PRBS9 = 0,
+    PAYLOAD_TYPE_11110000,
+    PAYLOAD_TYPE_10101010,
+    PAYLOAD_TYPE_PRBS15,
+    PAYLOAD_TYPE_11111111,
+    PAYLOAD_TYPE_00000000,
+    PAYLOAD_TYPE_00001111,
+    PAYLOAD_TYPE_01010101,
+
+    PAYLOAD_TYPE_SINGLE_CARRIER = 0xf0,
+};
+
+enum BLE_DUT_PHY_TYPE {
+    BLE_1M_UNCODED_PHY = 1,
+    BLE_2M_UNCODED_PHY,
+    BLE_1M_CODED_PHY_S8,
+    BLE_1M_CODED_PHY_S2,
+};
+
+struct ble_dut_param_set {
+    u8 ch_index;		//tx ch index;(0~39 -> 2402~2480)
+    u8 payload_type;	//tx payload type
+    u8 payload_len;		//payload_len(0~0xff) when continuous_tx = 0;
+    u8 continuous_tx;	//enable or disable continuous transmission mode(0/1)
+};
+
+/* !!!Notice:when this api is called and sleep mode should be sure to exit; */
+void ble_fix_fre_api()
+{
+#if TCFG_USER_BLE_ENABLE
+#if (CONFIG_BT_MODE == BT_NORMAL)
+    bt_ble_adv_enable(0);
+#endif
+    os_time_dly(10);
+
+    struct ble_dut_param_set dut_param = {
+        .ch_index = 0,
+        .payload_type = PAYLOAD_TYPE_10101010,
+        .payload_len = 0x20,
+        .continuous_tx = 1,
+    };
+    ble_enter_dut_tx_mode(&dut_param);
+#endif
+}
+
+static void *ble_dut_hdl = NULL;
+extern void ll_hci_destory(void);
+void ble_dut_mode_init(void)
+{
+    if (!ble_dut_hdl) {
+        ll_hci_destory();
+        ble_dut_hdl = __ble_dut_ops->init();
+    }
+}
+
+void ble_dut_mode_exit(void)
+{
+    if (ble_dut_hdl) {
+        __ble_dut_ops->exit(ble_dut_hdl);
+        ble_dut_hdl = NULL;
+    }
+}
+
+void ble_dut_tx_fre_api(u8 ch)
+{
+    ble_dut_mode_init();
+    struct ble_dut_tx_param_t tx_param = {
+        .ch_index = ch,
+        .payload_len = 0x20,
+        .payload_type = PAYLOAD_TYPE_PRBS9,
+        .phy_type = BLE_1M_UNCODED_PHY,
+    };
+
+    log_info("BLE_DUT_TX-ch:%x\n", ch);
+    __ble_dut_ops->ioctrl(BLE_DUT_SET_TX_MODE, &tx_param);
+
+}
+
+void ble_dut_rx_fre_api(u8 ch)
+{
+    ble_dut_mode_init();
+    struct ble_dut_rx_param_t rx_param = {
+        .ch_index = ch,
+        .phy_type = BLE_1M_UNCODED_PHY,
+    };
+
+    log_info("BLE_DUT_RX-ch:%x \n", ch);
+    __ble_dut_ops->ioctrl(BLE_DUT_SET_RX_MODE, &rx_param);
+
+}
+
+int ble_dut_test_end(void)
+{
+    int pkt_valid_cnt = 0;
+    int pkt_err_cnt = 0;
+    if (ble_dut_hdl) {
+        __ble_dut_ops->ioctrl(BLE_DUT_SET_TEST_END, &pkt_valid_cnt, NULL);
+
+        log_info("pkt_rx_cnt:%d pkt_err_cnt:%d\n", pkt_valid_cnt, pkt_err_cnt);
+    } else {
+        log_error("ble dut hdl not inited\n");
+    }
+
+    return pkt_valid_cnt;
+}
+
+static volatile u8 bt_test_status = 0;
+
+void ble_bqb_test_thread_init(void);
+static hci_transport_config_uart_t config = {
+    HCI_TRANSPORT_CONFIG_UART,
+    460800,
+    0,  // main baudrate
+    0,  // flow control
+    NULL,
+};
+
+extern void dut_hci_controller_init(const hci_transport_t *transport, const void *config);
+void ble_standard_dut_test_init(void)
+{
+    log_info("%s\n", __FUNCTION__);
+    bt_test_status = 1;
+    ble_dut_mode_init();
+    //ble_bqb_test_thread_init();
+    dut_hci_controller_init((void *)hci_transport_uart_instance(), &config);
+}
+
+void ble_standard_dut_test_close(void)
+{
+    log_info("%s\n", __FUNCTION__);
+    ble_dut_test_end();
+    ble_dut_mode_exit();
+    hci_transport_t *p_uart_trans = hci_transport_uart_instance();
+    p_uart_trans->close();
+    bt_test_status = 0;
+
+}
+
+void ble_dut_mode_key_handle(u8 type, u8 key_val)
+{
+    static u8 rx_ch = 0;
+    static u8 tx_ch = 0;
+    switch (key_val) {
+    case 3:
+        ble_dut_tx_fre_api(tx_ch++);
+        if (tx_ch > 39) {
+            tx_ch = 0;
+        }
+        break;
+
+    case 1:
+        ble_dut_rx_fre_api(rx_ch++);
+        if (rx_ch > 39) {
+            rx_ch = 0;
+        }
+        break;
+
+    case 2:
+        ble_dut_test_end();
+        break;
+
+    case 0:
+        ble_standard_dut_test_init();
+        break;
+
+    case 4:
+        ble_standard_dut_test_close();
+        break;
+
+defualt:
+        break;
+    }
+}
+
+static u8 bt_test_idle_query(void)
+{
+    return !bt_test_status;
+}
+
+REGISTER_LP_TARGET(bt_test_lp_target) = {
+    .name = "bt_test",
+    .is_idle = bt_test_idle_query,
+};
+

File diff suppressed because it is too large
+ 1528 - 0
apps/common/cJSON/cJSON.c


+ 150 - 0
apps/common/cJSON/cJSON.h

@@ -0,0 +1,150 @@
+
+/*
+  Copyright (c) 2009 Dave Gamble
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+#ifndef cJSON__h
+#define cJSON__h
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* cJSON Types: */
+#define cJSON_False 0
+#define cJSON_True 1
+#define cJSON_NULL 2
+#define cJSON_Number 3
+#define cJSON_String 4
+#define cJSON_Array 5
+#define cJSON_Object 6
+
+#define cJSON_IsReference 256
+#define cJSON_StringIsConst 512
+
+/* The cJSON structure: */
+typedef struct cJSON {
+    struct cJSON *next, *prev;	/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+    struct cJSON *child;		/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+
+    int type;					/* The type of the item, as above. */
+
+    char *valuestring;			/* The item's string, if type==cJSON_String */
+    int valueint;				/* The item's number, if type==cJSON_Number */
+    double valuedouble;			/* The item's number, if type==cJSON_Number */
+
+    char *string;				/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+} cJSON;
+
+typedef struct cJSON_Hooks {
+    void *(*malloc_fn)(size_t sz);
+    void (*free_fn)(void *ptr);
+} cJSON_Hooks;
+
+/* Supply malloc, realloc and free functions to cJSON */
+extern void cJSON_InitHooks(cJSON_Hooks *hooks);
+
+
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
+extern cJSON *cJSON_Parse(const char *value);
+/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
+extern char  *cJSON_Print(cJSON *item);
+/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
+extern char  *cJSON_PrintUnformatted(cJSON *item);
+/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
+extern char *cJSON_PrintBuffered(cJSON *item, int prebuffer, int fmt);
+/* Delete a cJSON entity and all subentities. */
+extern void   cJSON_Delete(cJSON *c);
+
+/* Returns the number of items in an array (or object). */
+extern int	  cJSON_GetArraySize(cJSON *array);
+/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
+extern cJSON *cJSON_GetArrayItem(cJSON *array, int item);
+/* Get item "string" from object. Case insensitive. */
+extern cJSON *cJSON_GetObjectItem(cJSON *object, const char *string);
+
+/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
+extern const char *cJSON_GetErrorPtr(void);
+
+/* These calls create a cJSON item of the appropriate type. */
+extern cJSON *cJSON_CreateNull(void);
+extern cJSON *cJSON_CreateTrue(void);
+extern cJSON *cJSON_CreateFalse(void);
+extern cJSON *cJSON_CreateBool(int b);
+extern cJSON *cJSON_CreateNumber(double num);
+extern cJSON *cJSON_CreateString(const char *string);
+extern cJSON *cJSON_CreateArray(void);
+extern cJSON *cJSON_CreateObject(void);
+
+/* These utilities create an Array of count items. */
+extern cJSON *cJSON_CreateIntArray(const int *numbers, int count);
+extern cJSON *cJSON_CreateFloatArray(const float *numbers, int count);
+extern cJSON *cJSON_CreateDoubleArray(const double *numbers, int count);
+extern cJSON *cJSON_CreateStringArray(const char **strings, int count);
+
+/* Append item to the specified array/object. */
+extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
+extern void	cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
+extern void	cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);	/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
+/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
+extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+extern void	cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
+
+/* Remove/Detatch items from Arrays/Objects. */
+extern cJSON *cJSON_DetachItemFromArray(cJSON *array, int which);
+extern void   cJSON_DeleteItemFromArray(cJSON *array, int which);
+extern cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string);
+extern void   cJSON_DeleteItemFromObject(cJSON *object, const char *string);
+
+/* Update array items. */
+extern void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem);	/* Shifts pre-existing items to the right. */
+extern void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
+extern void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem);
+
+/* Duplicate a cJSON item */
+extern cJSON *cJSON_Duplicate(cJSON *item, int recurse);
+/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
+need to be released. With recurse!=0, it will duplicate any children connected to the item.
+The item->next and ->prev pointers are always zero on return from Duplicate. */
+
+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
+extern cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated);
+
+extern void cJSON_Minify(char *json);
+
+/* Macros for creating things quickly. */
+#define cJSON_AddNullToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateNull())
+#define cJSON_AddTrueToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
+#define cJSON_AddFalseToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
+#define cJSON_AddBoolToObject(object,name,b)	cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
+#define cJSON_AddNumberToObject(object,name,n)	cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
+#define cJSON_AddStringToObject(object,name,s)	cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
+
+/* When assigning an integer value, it needs to be propagated to valuedouble too. */
+#define cJSON_SetIntValue(object,val)			((object)?(object)->valueint=(object)->valuedouble=(val):(val))
+#define cJSON_SetNumberValue(object,val)		((object)?(object)->valueint=(object)->valuedouble=(val):(val))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 326 - 0
apps/common/code_switch/code_switch.c

@@ -0,0 +1,326 @@
+#include "system/includes.h"
+#include "code_switch.h"
+#include "app_config.h"
+#include "stdlib.h"
+
+#if TCFG_CODE_SWITCH_ENABLE
+
+#if 1
+#define log_debug          printf
+#else
+#define log_debug(...)
+#endif
+
+#define INPUT_CHANNLE6_SRC_SEL(x)			SFR(JL_IOMAP->CON4, 16, 6, x)
+#define INPUT_CHANNLE7_SRC_SEL(x)			SFR(JL_IOMAP->CON4, 24, 6, x)
+
+static SW_PLATFORM_DATA *sw_pdata = NULL;
+static u8 code_switch_active = 0;
+
+static void code_switch_event_to_usr(u8 event, s8 sw_val);
+static void get_code_value_handler(void *priv);
+/* static void get_code_value_handler(void); */
+static u8 code_switch_idle_query(void);
+
+
+static void code_switch_event_to_usr(u8 event, s8 sw_val)
+{
+    struct sys_event e;
+    e.type                = SYS_DEVICE_EVENT;
+    e.arg                 = "code_switch";
+    e.u.codesw.event      = event;
+    e.u.codesw.value      = sw_val;
+    sys_event_notify(&e);
+}
+
+/* ___interrupt */
+/* static void get_code_value_handler(void) */
+/* { */
+/* 	if (JL_RDEC->CON & 0x80) */
+/* 	{ */
+/* 		mouse_code_switch_event_to_usr(0, JL_RDEC->DAT); */
+/* 		JL_RDEC->CON |= BIT(6); */
+/* 	} */
+/* }	 */
+/*  */
+
+u8 code_postive_list[] = {
+    ((0x00 << 4) | (0x02 << 2) | (0x03 << 0)), \
+    ((0x00 << 4) | (0x02 << 2) | (0x01 << 0)), \
+    ((0x00 << 4) | (0x03 << 2) | (0x01 << 0)), \
+
+    ((0x02 << 4) | (0x03 << 2) | (0x01 << 0)), \
+    ((0x02 << 4) | (0x03 << 2) | (0x00 << 0)), \
+    ((0x02 << 4) | (0x01 << 2) | (0x00 << 0)), \
+
+    ((0x03 << 4) | (0x01 << 2) | (0x00 << 0)), \
+    ((0x03 << 4) | (0x01 << 2) | (0x02 << 0)), \
+    ((0x03 << 4) | (0x00 << 2) | (0x02 << 0)), \
+
+    ((0x01 << 4) | (0x00 << 2) | (0x02 << 0)), \
+    ((0x01 << 4) | (0x00 << 2) | (0x03 << 0)), \
+    ((0x01 << 4) | (0x02 << 2) | (0x03 << 0))
+};
+
+u8 code_negative_list[] = {
+    ((0x00 << 4) | (0x01 << 2) | (0x03 << 0)), \
+    ((0x00 << 4) | (0x01 << 2) | (0x02 << 0)), \
+    ((0x00 << 4) | (0x03 << 2) | (0x02 << 0)), \
+
+    ((0x01 << 4) | (0x03 << 2) | (0x02 << 0)), \
+    ((0x01 << 4) | (0x03 << 2) | (0x00 << 0)), \
+    ((0x01 << 4) | (0x02 << 2) | (0x00 << 0)), \
+
+    ((0x03 << 4) | (0x02 << 2) | (0x00 << 0)), \
+    ((0x03 << 4) | (0x02 << 2) | (0x01 << 0)), \
+    ((0x03 << 4) | (0x00 << 2) | (0x01 << 0)), \
+
+    ((0x02 << 4) | (0x00 << 2) | (0x01 << 0)), \
+    ((0x02 << 4) | (0x00 << 2) | (0x03 << 0)), \
+    ((0x02 << 4) | (0x01 << 2) | (0x03 << 0))
+};
+
+//功能:相位纠正
+static void correct_code(u8 *code_data, u8 *list_data, u8 idx)
+{
+    code_data[2] = (list_data[(idx / 3) * 3] & (0x03 << 4)) >> 4;
+    code_data[1] = (list_data[(idx / 3) * 3] & (0x03 << 2)) >> 2;
+    code_data[0] = (list_data[(idx / 3) * 3] & (0x03 << 0)) >> 0;
+
+    log_debug("lost_phase_recover: %d  %d  %d\n", code_data[2], code_data[1], code_data[0]);
+}
+
+//功能:相位遍历
+static u8 traverse_phase_list(u8 *code_data, u8 *list_data, u8 size)
+{
+    u8 code_num = 0, idx = 0;
+
+    code_num = code_data[2] << 4 | code_data[1] << 2 | code_data[0] << 0;
+
+    for (idx = 0; idx < size; idx++) {
+        if (code_num == list_data[idx]) {
+            if (idx % 3) {
+                /* correct_code(code_data, list_data, idx); */
+            }
+            break;
+        }
+    }
+
+    return idx;
+}
+
+//功能:消抖
+static bool code_phase_debounce(u8 code_val)
+{
+    static u8 filter_value = 0, filter_cnt = 0;
+    const u8 filter_time = 2;
+
+    //当前值与上一次值如果不相等, 重新消抖处理, 注意filter_time != 0;
+    if (code_val != filter_value && filter_time) {
+        filter_cnt = 0; 		//消抖次数清0, 重新开始消抖
+        filter_value = code_val;//记录上一次的值
+        return false; 		    //第一次检测, 返回不做处理
+    }
+
+    //当前值与上一次值相等, filter_cnt开始累加;
+    if (filter_cnt < filter_time) {
+        filter_cnt++;
+        return false;
+    }
+
+    return true;
+}
+
+//功能:获取相位
+static bool get_code_phase(u8 *code_data)
+{
+    static u8 code_now = 0, code_last = 0;
+    static u8 debug_count = 0;
+
+    //获取相位值
+    code_last = code_now;
+    code_now = (gpio_read(sw_pdata->a_phase_io) ? 0x02 : 0x00) + (gpio_read(sw_pdata->b_phase_io) ? 0x01 : 0x00);
+
+    //相位状态出现变化,将相位值存入队列
+    if (code_last != code_now && code_now != code_data[0]) {
+        code_data[2] = code_data[1];
+        code_data[1] = code_data[0];
+        code_data[0] = code_now;
+
+        code_switch_active = 200;//编码开关工作状态标志位
+
+        /* log_debug(">>>%d<<<%d  %d  %d\n", debug_count, code_data[2], code_data[1], code_data[0]); */
+        debug_count++;
+        return true;
+    }
+
+    //相位状态无变化,编码开关工作状态标志位递减
+    else {
+        if (code_switch_active) {
+            code_switch_active--;
+        }
+    }
+
+    return false;
+}
+
+//功能:获取编码值
+u8 get_code_value(u8 *code_data)
+{
+    u8 idx = 0;   //相位序列号
+    static u8 code_val = 0;
+    static u8 move_now = 0, move_last = 0;
+    static u8 idx_pos_last = 0, idx_neg_last = 0;
+    enum {
+        MOVE_POS,
+        MOVE_NEG,
+    };
+
+    //正相位遍历,获取相位序列号
+    idx = traverse_phase_list(code_data, &code_postive_list[0], ARRAY_SIZE(code_postive_list));
+
+    //相位序列号有效,则出现正向滚动动作
+    if (idx < ARRAY_SIZE(code_postive_list)) {
+        move_last = move_now;
+        move_now = MOVE_POS;
+
+        //相位区域限制,避免重复检测
+        if ((idx >= 0 && idx <= 2) || (idx >= 6 && idx <= 8) || (move_now != move_last))
+            /* if (abs(idx_pos_last/3-idx/3)>=2 || (move_now != move_last)) */
+        {
+            code_val++; //正向滚动,编码值+1
+            idx_pos_last = idx;
+            /* log_debug(">>>>>>>>>>>>>>>>>>>>>>>idx = %d  R\n", idx); */
+            /* log_debug("\n"); */
+            return code_val;
+        }
+    }
+
+
+    //负相位遍历,获取相位序列号
+    idx = traverse_phase_list(code_data, &code_negative_list[0], ARRAY_SIZE(code_negative_list));
+
+    //相位序列号有效,则出现负向滚动
+    if (idx < ARRAY_SIZE(code_negative_list)) {
+        move_last = move_now;
+        move_now = MOVE_NEG;
+
+        //相位区域限制,避免重复检测
+        if ((idx >= 3 && idx <= 5) || (idx >= 9 && idx <= 11) || (move_now != move_last))
+            /* if (abs(idx_neg_last/3-idx/3)>=2 || (move_now != move_last)) */
+        {
+            code_val--; //负向滚动,编码值-1
+            idx_neg_last = idx;
+            /* log_debug(">>>>>>>>>>>>>>>>>>>>>>>idx = %d  L\n", idx); */
+            /* log_debug("\n"); */
+
+            return code_val;
+        }
+    }
+
+    return code_val;
+}
+
+//功能:旋转编码开关检测
+static u8 code_switch_detector(void)
+{
+    static u8 code_table[3] = {0}; //相位值存储队列
+    static u8 code_val = 0;
+
+    //相位有变化,进行相位遍历,获取编码值
+    if (get_code_phase(&code_table[0])) {
+        code_val = get_code_value(&code_table[0]);
+    }
+
+    //相位无变化,编码值保持不变
+    else {
+        code_val = code_val;
+    }
+
+    return code_val;
+}
+
+
+//功能:旋转编码开关数据采集
+static void code_switch_handler(void *priv)
+{
+    static u8 code_val_last = 0;
+    static u8 code_val_now  = 0;
+
+    code_val_last = code_val_now;
+    code_val_now = code_switch_detector();
+
+    if (code_val_last != code_val_now) {
+        code_switch_event_to_usr(0, code_val_now - code_val_last);
+    }
+
+    /* if (JL_RDEC->DAT != code) */
+    /* { */
+    /* 	code_switch_event_to_usr(0, JL_RDEC->DAT - code); */
+    /*     code_switch_active = 10; */
+    /* } */
+    /*  */
+    /* else */
+    /* { */
+    /*     code_switch_active--; */
+    /* } */
+    /*  */
+    /* code = JL_RDEC->DAT; */
+
+
+    /* pnd = JL_RDEC->CON & 0x80; */
+    /* if (pnd) */
+    /* { */
+    /* code_switch_event_to_usr(0, JL_RDEC->DAT); */
+    /* JL_RDEC->CON |= BIT(6); */
+    /* putchar('Y'); */
+    /* CODE_IO_DEBUG_TOGGLE(A,2) */
+    /* } */
+}
+
+void code_switch_init(SW_PLATFORM_DATA *priv)
+{
+    sw_pdata = priv;
+
+    /* JL_RDEC->CON |= BIT(0); //Enable RDEC */
+    /* JL_RDEC->CON &= ~BIT(1);//pull up */
+    /* JL_RDEC->CON |= 15<<2; */
+
+    /* JL_IOMAP->CON1 &= ~BIT(12);  //RDES_IOSO = PB4 */
+    /* JL_IOMAP->CON1 &= ~BIT(13);  //RDES_IOS1 = PB5 */
+
+    /* JL_IOMAP->CON1 |= BIT(12); */
+    /* JL_IOMAP->CON1 |= BIT(13); */
+
+    /* INPUT_CHANNLE6_SRC_SEL(sw_pdata->a_phase_io); */
+    /* INPUT_CHANNLE7_SRC_SEL(sw_pdata->b_phase_io); */
+
+    gpio_set_die(sw_pdata->a_phase_io, 1);
+    gpio_set_dieh(sw_pdata->a_phase_io, 1);
+    gpio_set_direction(sw_pdata->a_phase_io, 1);
+    gpio_set_pull_up(sw_pdata->a_phase_io, 0);
+    gpio_set_pull_down(sw_pdata->a_phase_io, 0);
+
+    gpio_set_die(sw_pdata->b_phase_io, 1);
+    gpio_set_dieh(sw_pdata->b_phase_io, 1);
+    gpio_set_direction(sw_pdata->b_phase_io, 1);
+    gpio_set_pull_up(sw_pdata->b_phase_io, 0);
+    gpio_set_pull_down(sw_pdata->b_phase_io, 0);
+
+    /* request_irq(IRQ_RDEC_IDX, 3, code_switch_handler, 0); */
+    sys_s_hi_timer_add(NULL, code_switch_handler, 2); //10ms
+}
+
+
+static u8 code_switch_idle_query(void)
+{
+    /* return !(JL_RDEC->CON & 0x80); */
+    return (!code_switch_active);
+}
+
+REGISTER_LP_TARGET(code_switch_lp_target) = {
+    .name = "code_switch",
+    .is_idle = code_switch_idle_query,
+};
+
+#endif   /* CODE_SWITCH_ENABLE */

+ 19 - 0
apps/common/code_switch/include/code_switch.h

@@ -0,0 +1,19 @@
+#ifndef _SW_H_
+#define _SW_H_
+
+#include "cpu.h"
+
+typedef struct {
+    u8 a_phase_io;
+    u8 b_phase_io;
+} SW_PLATFORM_DATA;
+
+#define SW_PLATFORM_DATA_BEGIN(pdata) \
+	SW_PLATFORM_DATA pdata = {
+
+#define SW_PLATFORM_DATA_END() \
+};
+
+void code_switch_init(SW_PLATFORM_DATA *priv);
+
+#endif

+ 121 - 0
apps/common/config/include/bt_profile_cfg.h

@@ -0,0 +1,121 @@
+
+#ifndef _BT_PROFILE_CFG_H_
+#define _BT_PROFILE_CFG_H_
+
+#include "app_config.h"
+#include "btcontroller_modules.h"
+
+
+#if (TRANS_DATA_EN || RCSP_BTMATE_EN || RCSP_ADV_EN || SMART_BOX_EN || ANCS_CLIENT_EN || LL_SYNC_EN || TUYA_DEMO_EN)
+#ifndef BT_FOR_APP_EN
+#define    BT_FOR_APP_EN             1
+#endif
+#else
+#ifndef BT_FOR_APP_EN
+#define    BT_FOR_APP_EN             0
+#endif
+#ifndef AI_APP_PROTOCOL
+#define    AI_APP_PROTOCOL             0
+#endif
+#endif
+
+
+///---sdp service record profile- 用户选择支持协议--///
+#if (BT_FOR_APP_EN || APP_ONLINE_DEBUG || AI_APP_PROTOCOL)
+#if (LL_SYNC_EN || TUYA_DEMO_EN)
+#undef USER_SUPPORT_PROFILE_SPP
+#define USER_SUPPORT_PROFILE_SPP    0
+#else
+#undef USER_SUPPORT_PROFILE_SPP
+#define USER_SUPPORT_PROFILE_SPP    1
+#endif
+#endif
+
+//ble demo的例子
+#define DEF_BLE_DEMO_NULL                 0 //ble 没有使能
+#define DEF_BLE_DEMO_ADV                  1 //only adv,can't connect
+#define DEF_BLE_DEMO_TRANS_DATA           2 //
+#define DEF_BLE_DEMO_RCSP_DEMO            4 //
+#define DEF_BLE_DEMO_ADV_RCSP             5
+#define DEF_BLE_DEMO_CLIENT               7 //
+#define DEF_BLE_ANCS_ADV				  9
+#define DEF_BLE_DEMO_MULTI                11 //
+#define DEF_BLE_DEMO_LL_SYNC              13 //
+#define DEF_BLE_DEMO_WIRELESS_MIC_SERVER  14 //
+#define DEF_BLE_DEMO_WIRELESS_MIC_CLIENT  15 //
+#define DEF_BLE_DEMO_TUYA                 16 //
+#define DEF_BLE_WL_MIC_1T1_TX             17
+#define DEF_BLE_WL_MIC_1T1_RX             18
+#define DEF_BLE_WL_MIC_1TN_TX             19
+#define DEF_BLE_WL_MIC_1TN_RX             20
+#define DEF_LE_AUDIO_CENTRAL              21
+#define DEF_LE_AUDIO_PERIPHERAL           22
+#define DEF_LE_AUDIO_BROADCASTER          23
+
+#define    LE_AUDIO_EN                    0  //DEF_LE_AUDIO_CENTRAL
+
+//配置选择的demo
+#if TCFG_USER_BLE_ENABLE
+
+#if (SMART_BOX_EN | RCSP_BTMATE_EN)
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_DEMO_RCSP_DEMO
+
+#elif TRANS_DATA_EN
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_DEMO_TRANS_DATA
+
+#elif LL_SYNC_EN
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_DEMO_LL_SYNC
+
+#elif TUYA_DEMO_EN
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_DEMO_TUYA
+
+#elif RCSP_ADV_EN
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_DEMO_ADV_RCSP
+
+#elif BLE_CLIENT_EN
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_DEMO_CLIENT
+
+#elif TRANS_MULTI_BLE_EN
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_DEMO_MULTI
+
+#elif ANCS_CLIENT_EN
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_ANCS_ADV
+
+#elif AI_APP_PROTOCOL
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_DEMO_NULL
+
+#elif (BLE_WIRELESS_CLIENT_EN)
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_DEMO_WIRELESS_MIC_CLIENT
+
+#elif (BLE_WIRELESS_SERVER_EN)
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_DEMO_WIRELESS_MIC_SERVER
+
+#elif (BLE_WIRELESS_1T1_TX_EN)
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_WL_MIC_1T1_TX
+
+#elif (BLE_WIRELESS_1T1_RX_EN)
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_WL_MIC_1T1_RX
+
+#elif (BLE_WIRELESS_1TN_TX_EN)
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_WL_MIC_1TN_TX
+
+#elif (BLE_WIRELESS_1TN_RX_EN)
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_WL_MIC_1TN_RX
+
+#elif (LE_AUDIO_EN)
+#define TCFG_BLE_DEMO_SELECT          LE_AUDIO_EN
+
+#else
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE5_DEMO
+#endif
+
+#else
+#define TCFG_BLE_DEMO_SELECT          DEF_BLE_DEMO_NULL//ble is closed
+#endif
+
+//delete 2021-09-24;删除公共配置,放到各个profile自己配置
+// #define TCFG_BLE_SECURITY_EN          0 /*是否发请求加密命令*/
+
+
+
+#endif

+ 63 - 0
apps/common/debug/debug.c

@@ -0,0 +1,63 @@
+#include "app_config.h"
+#include "typedef.h"
+
+
+
+#ifndef CONFIG_DEBUG_ENABLE
+
+int putchar(int a)
+{
+    return a;
+}
+
+int puts(const char *out)
+{
+    return 0;
+}
+
+int printf(const char *format, ...)
+{
+    return 0;
+}
+
+
+void put_buf(const u8 *buf, int len)
+{
+
+}
+
+void put_u8hex(u8 dat)
+{
+
+}
+
+void put_u16hex(u16 dat)
+{
+
+}
+
+void put_u32hex(u32 dat)
+{
+
+}
+
+void log_print(int level, const char *tag, const char *format, ...)
+{
+
+}
+
+#ifndef CONFIG_DEBUG_LITE_ENABLE
+void log_putbyte(char c)
+{
+
+}
+#endif /* #ifndef CONFIG_DEBUG_LITE_ENABLE */
+
+int assert_printf(const char *format, ...)
+{
+    cpu_assert_debug();
+
+    return 0;
+}
+
+#endif

+ 22 - 0
apps/common/device/gSensor/fmy/Motion_api.h

@@ -0,0 +1,22 @@
+#ifndef MOTION_API_H
+#define MOTION_API_H
+
+#define GSENSOR_PRINTF_ENABLE             0//contrl debug printf
+
+int get_DetectionBuf(int fs);
+void init_MotionDet(void *ptr, short fs, float thread);
+char run_MotionDetection(void *ptr, int len, short *data);
+
+#if WIN32
+#else
+extern inline float add_float(float x, float y);
+extern inline float sub_float(float x, float y);
+extern inline float mul_float(float x, float y);
+extern inline float div_float(float x, float y);
+extern inline float complex_abs_float(float x, float y);
+#endif
+
+
+#endif // !MOTION_API_H
+
+

+ 178 - 0
apps/common/device/gSensor/fmy/SC7A20_E.c

@@ -0,0 +1,178 @@
+#include "app_config.h"
+#include "gSensor_manage.h"
+#include "SC7A20_TR.h"
+#include "includes.h"
+#include "Motion_api.h"
+
+
+#if (TCFG_GSENSOR_ENABLE && TCFG_SC7A20_E_EN)
+
+#if GSENSOR_PRINTF_ENABLE
+#define LOG(fmt,...)      printf("[SC7A20_E] " fmt "\n",##__VA_ARGS__)
+#define log_info_hexdump  put_buf
+#else
+#define LOG(fmt,...)
+#define log_info_hexdump
+#endif
+
+spinlock_t sensor_iic;
+u8 sensor_iic_init_status = 0;
+
+#define ADDR_R   ((0x19U<<1) | 1)
+#define ADDR_W   ((0x19U<<1) | 0)
+
+typedef struct {
+    u8 reg;
+    u8 value;
+} regs_opt_t;
+
+static const regs_opt_t config_sc7a20e[] = {
+    {0x68, 0xa5}, //soft reset
+    {0x57, 0x0C}, //disable sdo_pu/i2c_pu
+    {0x0e, 0x00}, // disable register auto and  enable iic
+    {0x1F, 0x08}, //low power mode
+    {0x20, 0x37}, //odr 1.5hz
+    {0x21, 0x00}, //disable high pass
+    {0x23, 0x10}, //range:+-4g,disable low pass
+    {0x24, 0x40}, //enable fifo
+    {0x2E, 0x9F}, //stream mode
+};
+
+
+static unsigned char sl_write_regs(unsigned char register_address, unsigned char value)
+{
+    return gravity_sensor_command(ADDR_W, register_address, value);
+}
+
+static unsigned int sl_read_regs(unsigned char register_address, unsigned char *destination, unsigned char number_of_bytes)
+{
+    return _gravity_sensor_get_ndata(ADDR_R, register_address, destination, number_of_bytes);
+}
+
+static u8 sl_device_id_get(void)
+{
+    u8 value = 0;
+    sl_read_regs(0x0f, &value, 1);
+    return value;
+}
+
+// extern void mdelay(unsigned int ms);
+static u8 sl_config_register(void)
+{
+    u8 ret = 0;
+
+    for (u8 i = 0; i < sizeof(config_sc7a20e) / sizeof(regs_opt_t); i++) {
+        if (sl_write_regs(config_sc7a20e[i].reg, config_sc7a20e[i].value) != 1) {
+            ret = -1;
+            break;
+        }
+        delay(1);
+    }
+    return ret;
+}
+
+static u8 sl_fifo_length(void)
+{
+    u8 value = 0;
+    sl_read_regs(0x2F, &value, 1);
+    return value & 0x1F;
+}
+
+static u8 sl_fifo_get(axis_info_t *acceler_buf)
+{
+    u8 fifo_data_num  = sl_fifo_length();
+    LOG("the length of fifo is %d", fifo_data_num);
+    u8 regs_data[100] = {0};
+
+    if (fifo_data_num > 0) {
+        sl_read_regs(0x69,  regs_data, fifo_data_num * 3);
+    }
+    for (int i = 0; i < fifo_data_num; i++) {
+        acceler_buf->x = (signed char)regs_data[i * 3 + 2];
+        acceler_buf->y = (signed char)regs_data[i * 3 + 0];
+        acceler_buf->z = (signed char)regs_data[i * 3 + 1];
+
+        acceler_buf->x = acceler_buf->x << 5;
+        acceler_buf->y = acceler_buf->y << 5;
+        acceler_buf->z = acceler_buf->z << 5;
+
+        LOG("7a20e fifo[%d],%d,%d,%d", i, acceler_buf->x, acceler_buf->y, acceler_buf->z);
+        acceler_buf++;
+    }
+    return fifo_data_num;
+}
+
+static void sl_restart_fifo(void)
+{
+    /*after the FIFO data is read, need to switch the FIFO mode to BY-PASS mode,
+    and then switch back to FIFO mode
+    */
+    sl_write_regs(0x2e, 0);
+    sl_write_regs(0x2e, 0x9F);
+}
+
+
+u8 sl_device_check(void)
+{
+    u8 id = sl_device_id_get();
+    LOG("id=0x%02x", id);
+    return id == 0x11;
+}
+
+u8 sl_device_init(void)
+{
+    // gsensor采用IO口供电的时需要增加上电时间来保证其内部电路稳定
+#ifdef GSENSOR_POWER_IO
+    os_time_dly(1); // 10ms
+#endif
+    sl_device_check();
+    return sl_config_register();
+}
+
+u8 sl_device_disable(void)
+{
+    return sl_write_regs(0x20, 0);
+}
+
+
+s32 sl_device_ctl(u8 cmd, void *arg)
+{
+    char res;
+    s32 ret = 0;
+
+    switch (cmd) {
+    case GSENSOR_DISABLE:
+        res = sl_device_disable();
+        memcpy(arg, &res, 1);
+        break;
+    case GSENSOR_RESET_INT:
+        res = sl_device_init();
+        memcpy(arg, &res, 1);
+        break;
+    case GSENSOR_RESUME_INT:
+        break;
+    case GSENSOR_INT_DET:
+        break;
+    case READ_GSENSOR_DATA:
+        ret = sl_fifo_get((axis_info_t *)arg);
+        sl_restart_fifo();
+        break;
+    case SEARCH_SENSOR:
+        res = sl_device_check();
+        memcpy(arg, &res, 1);
+        break;
+    default:
+        break;
+    }
+    return ret;
+}
+
+
+REGISTER_GRAVITY_SENSOR(gSensor) = {
+    .logo = "sc7a20e",
+    .gravity_sensor_init  = sl_device_init,
+    .gravity_sensor_check = NULL,
+    .gravity_sensor_ctl   = sl_device_ctl,
+};
+
+#endif

+ 219 - 0
apps/common/device/gSensor/fmy/SC7A20_TR.c

@@ -0,0 +1,219 @@
+#include "app_config.h"
+#include "gSensor_manage.h"
+#include "SC7A20_TR.h"
+#include "includes.h"
+#include "math.h"
+#include "bank_switch.h"
+#include "gpio.h"
+#include "Motion_api.h"
+/* #pragma bss_seg(".gsport_dev_bss") */
+/* #pragma const_seg(".gsport_dev_const") */
+/* #pragma code_seg(".gsport_dev_code") */
+/*  */
+
+#if (TCFG_GSENSOR_ENABLE && TCFG_SC7A20_EN)
+
+#if GSENSOR_PRINTF_ENABLE
+#define LOG(fmt,...)      printf("[SC7A20] " fmt "\n",##__VA_ARGS__)
+#define log_info_hexdump  put_buf
+#else
+#define LOG(fmt,...)
+#define log_info_hexdump
+#endif
+
+#define SL_SC7A20H_FIFO_CTRL_REG   (unsigned char)0X2E
+#define SL_SC7A20H_FIFO_SRC_REG    (unsigned char)0X2F
+#define SL_SC7A20H_SPI_OUT_X_L     (unsigned char)0X27
+#define SL_SC7A20H_IIC_OUT_X_L     (unsigned char)0XA8
+
+static unsigned char  SL_SPI_IIC_INTERFACE         = 0;
+
+/***使用驱动前请根据实际接线情况配置(7bit)IIC地址******/
+/**SC7A20的SDO 脚接地:            0x18****************/
+/**SC7A20的SDO 脚接电源:           0x19****************/
+#define SC7A20_W_ADDR          (0x19U << 1 | 0x0)
+#define SC7A20_R_ADDR          (0x19U << 1 | 0x1)
+/*******************************************************/
+
+#define SL_SC7A20H_INIT_REG1_NUM 8
+static unsigned char SL_SC7A20H_INIT_REG1[SL_SC7A20H_INIT_REG1_NUM * 3] = {
+    0x24, 0x80, 0x00,
+    0x2E, 0x00, 0x00,
+    0x1f, 0x00, 0x00,
+    0x20, 0x37, 0x00, // 25hz 1s获取25组数据
+    0x21, 0x70, 0x00,
+    0x23, 0x10, 0x00,
+    0x24, 0x40, 0x00, // 使能fifo
+    0x2E, 0x9F, 0x00, // 将fifo设置为stream模式
+};
+
+spinlock_t sensor_iic;
+u8 sensor_iic_init_status = 0;
+
+
+static unsigned char SL_SC7A20H_I2c_Spi_Write(unsigned char sl_spi_iic, unsigned char reg, unsigned char data)
+{
+    return gravity_sensor_command(SC7A20_W_ADDR, reg, data);
+}
+
+static unsigned char SL_SC7A20H_I2c_Spi_Read(unsigned char sl_spi_iic, unsigned char reg, unsigned char len, unsigned char *buf)
+{
+    return _gravity_sensor_get_ndata(SC7A20_R_ADDR, reg, buf, len);
+}
+
+static unsigned char  SL_SC7A20H_Check(void)
+{
+    unsigned char id1 = 0;
+    unsigned char id2 = 0;
+
+    SL_SC7A20H_I2c_Spi_Read(SL_SPI_IIC_INTERFACE, 0x0f, 1, &id1);
+    SL_SC7A20H_I2c_Spi_Read(SL_SPI_IIC_INTERFACE, 0x70, 1, &id2);
+
+    LOG("id1=0x%02x id2=0x%02x", id1, id2);
+    return id1 == 0x11 && (id2 == 0x28 || id2 == 0x11);
+}
+
+static signed char SL_SC7A20H_Driver_Init(unsigned char Sl_spi_iic_init, unsigned char Sl_pull_up_mode)
+{
+    LOG("SL_SC7A20H_Driver_Init");
+    unsigned char i = 0;
+
+    if (Sl_spi_iic_init == 0) {
+        SL_SPI_IIC_INTERFACE  = 0;    //spi
+    } else {
+        SL_SPI_IIC_INTERFACE  = 1;    //iic
+    }
+    // gsensor采用IO口供电时需要增加上电时间来保证其内部电路稳定
+#ifdef GSENSOR_POWER_IO
+    os_time_dly(1); // 10ms
+#endif
+
+    if (!SL_SC7A20H_Check()) {
+        return -1;
+    } else {
+        LOG("read chip sc7a20's id is ok!");
+    }
+
+    SL_SC7A20H_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x57, Sl_pull_up_mode);
+
+    for (i = 0; i < SL_SC7A20H_INIT_REG1_NUM; i++) {
+        SL_SC7A20H_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, SL_SC7A20H_INIT_REG1[3 * i], SL_SC7A20H_INIT_REG1[3 * i + 1]);
+    }
+
+    for (i = 0; i < SL_SC7A20H_INIT_REG1_NUM; i++) {
+        SL_SC7A20H_I2c_Spi_Read(SL_SPI_IIC_INTERFACE, SL_SC7A20H_INIT_REG1[3 * i], 1, &SL_SC7A20H_INIT_REG1[3 * i + 2]);
+    }
+
+    for (i = 2; i < SL_SC7A20H_INIT_REG1_NUM; i++) {
+        if (SL_SC7A20H_INIT_REG1[3 * i + 1] != SL_SC7A20H_INIT_REG1[3 * i + 2]) {
+            break;
+        }
+    }
+
+    if (i != SL_SC7A20H_INIT_REG1_NUM) {
+        if (SL_SPI_IIC_INTERFACE == 0) {
+            return -1;    //reg write and read error by SPI
+        } else {
+            return -2;    //reg write and read error by IIC
+        }
+    }
+
+    return 0;
+}
+
+static unsigned char SL_SC7A20H_Init(void)
+{
+    return SL_SC7A20H_Driver_Init(1, 0);
+}
+
+// 使用FIFO模式读取数据,每次读取缓冲区多个数据(最多32组)
+static unsigned char SL_SC7A20H_Read_FIFO_Buf(axis_info_t *accel)
+{
+    unsigned char  i = 0;
+    unsigned char  sc7a20_data[7];
+    unsigned char  SL_FIFO_ACCEL_NUM;
+    short x, y, z;
+    short x_sum = 0, y_sum = 0, z_sum = 0;
+    SL_SC7A20H_I2c_Spi_Read(SL_SPI_IIC_INTERFACE, SL_SC7A20H_FIFO_SRC_REG, 1, &SL_FIFO_ACCEL_NUM);
+    if (SL_FIFO_ACCEL_NUM & 0x40) {
+        SL_FIFO_ACCEL_NUM = 32;
+    } else {
+        SL_FIFO_ACCEL_NUM = SL_FIFO_ACCEL_NUM & 0x1f;
+    }
+
+    LOG("send data len is %d\n", SL_FIFO_ACCEL_NUM);
+    if (SL_FIFO_ACCEL_NUM == 0) {
+        SL_SC7A20H_Init();
+        return 0;
+    }
+    /* spin_lock() */
+    for (i = 0; i < SL_FIFO_ACCEL_NUM; i++) {
+
+        if (SL_SPI_IIC_INTERFACE == 0) {
+            SL_SC7A20H_I2c_Spi_Read(SL_SPI_IIC_INTERFACE, SL_SC7A20H_SPI_OUT_X_L, 7, &sc7a20_data[0]);
+        } else {
+            SL_SC7A20H_I2c_Spi_Read(SL_SPI_IIC_INTERFACE, SL_SC7A20H_IIC_OUT_X_L, 6, &sc7a20_data[1]);
+        }
+
+        x = (signed short int)(((unsigned char)sc7a20_data[2] * 256) + (unsigned char)sc7a20_data[1]);
+        y = (signed short int)(((unsigned char)sc7a20_data[4] * 256) + (unsigned char)sc7a20_data[3]);
+        z = (signed short int)(((unsigned char)sc7a20_data[6] * 256) + (unsigned char)sc7a20_data[5]);
+
+        accel[i].x = x >> 3;
+        accel[i].y = y >> 3;
+        accel[i].z = z >> 3;
+
+        /* LOG("\nxyz(%d,%d): %d %d %d", SL_FIFO_ACCEL_NUM, i, accel[i].x, accel[i].y,  accel[i].z); */
+    }
+
+    return SL_FIFO_ACCEL_NUM;
+}
+
+
+static unsigned char SL_SC7A20H_Disable(void)
+{
+    return SL_SC7A20H_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x20, 0);
+}
+
+
+s32 SL_SC7A20H_CTL(u8 cmd, void *arg)
+{
+    char res;
+    s32 ret = 0;
+
+    switch (cmd) {
+    case GSENSOR_DISABLE:
+        res = SL_SC7A20H_Disable();
+        memcpy(arg, &ret, 1);
+        break;
+    case GSENSOR_RESET_INT:
+        res = SL_SC7A20H_Init();
+        memcpy(arg, &res, 1);
+        break;
+    case GSENSOR_RESUME_INT:
+        break;
+    case GSENSOR_INT_DET:
+        break;
+    case READ_GSENSOR_DATA:
+        ret = SL_SC7A20H_Read_FIFO_Buf((axis_info_t *)arg);
+        break;
+    case SEARCH_SENSOR:
+        res = SL_SC7A20H_Check();
+        memcpy(arg, &res, 1);
+        break;
+    default:
+        break;
+    }
+    return ret;
+}
+
+
+REGISTER_GRAVITY_SENSOR(gSensor) = {
+    .logo = "sc7a20",
+    .gravity_sensor_init  = SL_SC7A20H_Init,
+    .gravity_sensor_check = NULL,
+    .gravity_sensor_ctl   = SL_SC7A20H_CTL,
+};
+
+#endif
+

+ 33 - 0
apps/common/device/gSensor/fmy/SC7A20_TR.h

@@ -0,0 +1,33 @@
+#ifndef _SL_SC7A20H_DRV_H_
+#define _SL_SC7A20H_DRV_H_
+
+#if TCFG_SC7A20_EN
+
+static  unsigned char SL_SC7A20H_I2c_Spi_Write(unsigned char sl_spi_iic, unsigned char reg, unsigned char data);
+static  unsigned char SL_SC7A20H_I2c_Spi_Read(unsigned char sl_spi_iic, unsigned char reg, unsigned char len, unsigned char *buf);
+/**SL_SC7A20H_I2c_Spi_Write 函数中, sl_spi_iic:0=spi  1=i2c  Reg:寄存器地址   data:寄存器的配置值******************/
+/**SL_SC7A20H_I2c_Spi_Write 函数 是一个单次写的函数******************************************/
+/***SL_SC7A20H_I2c_Spi_Read 函数中, sl_spi_iic:0=spi  1=i2c Reg 同上,len:读取数据长度,buf:存储数据首地址(指针)**/
+/***SL_SC7A20H_I2c_Spi_Read 函数 是可以进行单次读或多次连续读取的函数************************/
+
+/*************驱动初始化函数**************/
+static signed char SL_SC7A20H_Driver_Init(unsigned char Sl_spi_iic_init, unsigned char Sl_pull_up_mode);
+/***输入参数:1,Sl_spi_iic_init:0-1***2,PULL_UP_MODE:0x00 0x08 0x04 0x0c********/
+/****Sl_spi_iic_init=0:SPI MODE, Sl_pull_up_mode config failed****************/
+/****Sl_spi_iic_init=1:IIC MODE***********************************************/
+/****Sl_pull_up_mode=0x00: SDO  I2C  pull up***********************************/
+/****Sl_pull_up_mode=0x08: I2C  pull up and  SDO  open drain*******************/
+/****Sl_pull_up_mode=0x04: SDO  pull up and  I2C  open drain*******************/
+/****Sl_pull_up_mode=0x0C: SDO  I2C  open drain********************************/
+
+/*************返回数据情况如下**************/
+/**return : 0x28 表示CHIP ID 正常***********/
+/**return : 0    表示CHIP ID 异常***********/
+/**return :-1;   SPI 通信问题***************/
+/**return :-2;   IIC 通信问题***************/
+
+#endif
+
+#endif // TCFG_SC7A20_EN
+
+

+ 225 - 0
apps/common/device/gSensor/fmy/gSensor_manage.c

@@ -0,0 +1,225 @@
+#include "gSensor_manage.h"
+#include "device/device.h"
+#include "app_config.h"
+#include "debug.h"
+#include "key_event_deal.h"
+#include "btstack/avctp_user.h"
+#include "app_main.h"
+#include "tone_player.h"
+#include "user_cfg.h"
+#include "system/os/os_api.h"
+#include "Motion_api.h"
+/* #include "audio_config.h" */
+/* #include "app_power_manage.h" */
+/* #include "system/timer.h" */
+/* #include "event.h" */
+
+#if (TCFG_GSENSOR_ENABLE && (TCFG_SC7A20_EN || TCFG_SC7A20_E_EN || TCFG_MSA310_EN))
+
+spinlock_t iic_lock;
+
+/* #define LOG_TAG             "[GSENSOR]" */
+/* #define LOG_ERROR_ENABLE */
+/* #define LOG_DEBUG_ENABLE */
+/* #define LOG_INFO_ENABLE */
+/* #define LOG_DUMP_ENABLE */
+/* #define LOG_CLI_ENABLE */
+/* #include "debug.h" */
+
+#if GSENSOR_PRINTF_ENABLE
+#define log_info(x, ...)  printf("[GSENSOR_MAN]" x "\r\n", ## __VA_ARGS__)
+#define log_info_hexdump  put_buf
+
+#else
+#define log_info(...)
+#define log_info_hexdump(...)
+#endif
+
+static const struct gsensor_platform_data *platform_data;
+G_SENSOR_INTERFACE *gSensor_hdl = NULL;
+G_SENSOR_INFO  __gSensor_info = {.iic_delay = 10};
+#define gSensor_info (&__gSensor_info)
+
+extern spinlock_t sensor_iic;
+extern u8 sensor_iic_init_status;
+
+#if TCFG_GSENOR_USER_IIC_TYPE
+#define iic_init(iic)                       hw_iic_init(iic)
+#define iic_uninit(iic)                     hw_iic_uninit(iic)
+#define iic_start(iic)                      hw_iic_start(iic)
+#define iic_stop(iic)                       hw_iic_stop(iic)
+#define iic_tx_byte(iic, byte)              hw_iic_tx_byte(iic, byte)
+#define iic_rx_byte(iic, ack)               hw_iic_rx_byte(iic, ack)
+#define iic_read_buf(iic, buf, len)         hw_iic_read_buf(iic, buf, len)
+#define iic_write_buf(iic, buf, len)        hw_iic_write_buf(iic, buf, len)
+#define iic_suspend(iic)                    hw_iic_suspend(iic)
+#define iic_resume(iic)                     hw_iic_resume(iic)
+#else
+#define iic_init(iic)                       soft_iic_init(iic)
+#define iic_uninit(iic)                     soft_iic_uninit(iic)
+#define iic_start(iic)                      soft_iic_start(iic)
+#define iic_stop(iic)                       soft_iic_stop(iic)
+#define iic_tx_byte(iic, byte)              soft_iic_tx_byte(iic, byte)
+#define iic_rx_byte(iic, ack)               soft_iic_rx_byte(iic, ack)
+#define iic_read_buf(iic, buf, len)         soft_iic_read_buf(iic, buf, len)
+#define iic_write_buf(iic, buf, len)        soft_iic_write_buf(iic, buf, len)
+#define iic_suspend(iic)                    soft_iic_suspend(iic)
+#define iic_resume(iic)                     soft_iic_resume(iic)
+#endif
+
+//输出三轴数组和数据长度
+int get_gSensor_data(short *buf)
+{
+    axis_info_t accel_data[32];
+    int axis_info_len = gSensor_hdl->gravity_sensor_ctl(READ_GSENSOR_DATA, accel_data);
+    for (int i = 0; i < axis_info_len; i++) {
+        buf[i * 3] = accel_data[i].x;
+        buf[i * 3 + 1] = accel_data[i].y;
+        buf[i * 3 + 2] = accel_data[i].z;
+    }
+    return axis_info_len;
+}
+
+u8 gravity_sensor_command(u8 w_chip_id, u8 register_address, u8 function_command)
+{
+    spin_lock(&sensor_iic);
+    u8 ret = 1;
+    iic_start(gSensor_info->iic_hdl);
+    if (0 == iic_tx_byte(gSensor_info->iic_hdl, w_chip_id)) {
+        ret = 0;
+        log_info("\n gsen iic wr err 0");
+        goto __gcend;
+    }
+
+    delay(gSensor_info->iic_delay);
+
+    if (0 == iic_tx_byte(gSensor_info->iic_hdl, register_address)) {
+        ret = 0;
+        log_info("\n gsen iic wr err 1");
+        goto __gcend;
+    }
+
+    delay(gSensor_info->iic_delay);
+
+    if (0 == iic_tx_byte(gSensor_info->iic_hdl, function_command)) {
+        ret = 0;
+        log_info("\n gsen iic wr err 2\n");
+        goto __gcend;
+    }
+
+__gcend:
+    iic_stop(gSensor_info->iic_hdl);
+    spin_unlock(&sensor_iic);
+    return ret;
+}
+
+u8 _gravity_sensor_get_ndata(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len)
+{
+    spin_lock(&sensor_iic);
+    u8 read_len = 0;
+
+    iic_start(gSensor_info->iic_hdl);
+    if (0 == iic_tx_byte(gSensor_info->iic_hdl, r_chip_id - 1)) {
+        log_info("\n gsen iic rd err 0");
+        read_len = 0;
+        goto __gdend;
+    }
+
+
+    delay(gSensor_info->iic_delay);
+    if (0 == iic_tx_byte(gSensor_info->iic_hdl, register_address)) {
+        log_info("\n gsen iic rd err 1");
+        read_len = 0;
+        goto __gdend;
+    }
+
+    iic_start(gSensor_info->iic_hdl);
+    if (0 == iic_tx_byte(gSensor_info->iic_hdl, r_chip_id)) {
+        log_info("\n gsen iic rd err 2");
+        read_len = 0;
+        goto __gdend;
+    }
+
+    delay(gSensor_info->iic_delay);
+
+    for (; data_len > 1; data_len--) {
+        *buf++ = iic_rx_byte(gSensor_info->iic_hdl, 1);
+        read_len ++;
+    }
+
+    *buf = iic_rx_byte(gSensor_info->iic_hdl, 0);
+    read_len ++;
+
+__gdend:
+
+    iic_stop(gSensor_info->iic_hdl);
+    delay(gSensor_info->iic_delay);
+    spin_unlock(&sensor_iic);
+
+    return read_len;
+}
+
+void gsensor_io_ctl(u8 cmd, void *arg)
+{
+    gSensor_hdl->gravity_sensor_ctl(cmd, arg);
+}
+
+int gravity_sensor_init(void *_data)
+{
+    if (sensor_iic_init_status == 0) {
+        spin_lock_init(&sensor_iic);
+        sensor_iic_init_status = 1;
+    }
+    gSensor_info->init_flag  = 0;
+
+    int retval = 0;
+    platform_data = (const struct gsensor_platform_data *)_data;
+    gSensor_info->iic_hdl = platform_data->iic;
+    retval = iic_init(gSensor_info->iic_hdl);
+
+    /* log_info("\n  gravity_sensor_init\n"); */
+
+    if (retval < 0) {
+        log_info("\n  open iic for gsensor err");
+        return retval;
+    } else {
+        log_info("iic open succ");
+    }
+
+    retval = -EINVAL;
+    list_for_each_gsensor(gSensor_hdl) {
+        if (!memcmp(gSensor_hdl->logo, platform_data->gSensor_name, strlen(platform_data->gSensor_name))) {
+            retval = 0;
+            break;
+        }
+    }
+
+    if (retval < 0) {
+        log_info(">>>gSensor_hdl logo err");
+        return retval;
+    }
+
+    if (gSensor_hdl->gravity_sensor_init()) {
+        log_info(">>>>gSensor_Int ERROR");
+    } else {
+        log_info(">>>>gSensor_Int SUCC");
+        gSensor_info->init_flag  = 1;
+    }
+    return 0;
+}
+
+
+int gsensor_disable(void)
+{
+    if (gSensor_info->init_flag  == 1) {
+        int valid = 0;
+        gSensor_hdl->gravity_sensor_ctl(GSENSOR_DISABLE, &valid);
+        if (valid == 0) {
+            log_info("gsensor_disable_succeed");
+            return 0;
+        }
+    }
+    return -1;
+}
+
+#endif

+ 84 - 0
apps/common/device/gSensor/fmy/gSensor_manage.h

@@ -0,0 +1,84 @@
+#ifndef _GSENSOR_MANAGE_H
+#define _GSENSOR_MANAGE_H
+#include "printf.h"
+#include "cpu.h"
+//#include "iic.h"
+#include "asm/iic_hw.h"
+#include "asm/iic_soft.h"
+#include "timer.h"
+#include "app_config.h"
+#include "event.h"
+#include "system/includes.h"
+
+#define ACCEL_OF_GRAVITY        10
+#define ACCEL_DATA_GAIN         10
+
+enum {
+    GSENSOR_DISABLE = 0,
+    GSENSOR_RESET_INT,
+    GSENSOR_RESUME_INT,
+    GSENSOR_INT_DET,
+    READ_GSENSOR_DATA,
+    GET_ACCEL_DATA,
+    SEARCH_SENSOR,
+};
+
+typedef struct {
+    short x;
+    short y;
+    short z;
+} axis_info_t;
+
+typedef struct {
+    u8   logo[20];
+    u8(*gravity_sensor_init)(void);
+    char (*gravity_sensor_check)(void);
+    int (*gravity_sensor_ctl)(u8 cmd, void *arg);
+} G_SENSOR_INTERFACE;
+
+
+struct gsensor_platform_data {
+    u8    iic;
+    char  gSensor_name[20];
+    u32   gSensor_int_io;
+};
+
+typedef struct {
+    u8   iic_hdl;
+    u8   iic_delay;                 //这个延时并非影响iic的时钟频率,而是2Byte数据之间的延时
+    u8   ctl_flag;
+    int  init_flag;
+    int  check_cnt;
+    int  check_timer_hdl;
+} G_SENSOR_INFO;
+
+int gravity_sensor_init(void *_data);
+int gsensor_disable(void);
+u8 gravity_sensor_command(u8 w_chip_id, u8 register_address, u8 function_command);
+u8 _gravity_sensor_get_ndata(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len);
+int get_gSensor_data(short *buf);
+extern G_SENSOR_INTERFACE  gsensor_dev_begin[];
+extern G_SENSOR_INTERFACE gsensor_dev_end[];
+
+#define REGISTER_GRAVITY_SENSOR(gSensor) \
+	static G_SENSOR_INTERFACE gSensor SEC_USED(.gsensor_dev)
+
+#define list_for_each_gsensor(c) \
+	for (c=gsensor_dev_begin; c<gsensor_dev_end; c++)
+
+#define GSENSOR_PLATFORM_DATA_BEGIN(data) \
+		static const struct gsensor_platform_data data = {
+
+#define GSENSOR_PLATFORM_DATA_END() \
+};
+
+/*
+enum {
+    GSENSOR_EVENT_CLICK = 0,
+    GSENSOR_EVENT_DOUBLE_CLICK,
+    GSENSOR_EVENT_THREE_CLICK,
+};
+
+#define DEVICE_EVENT_GSENSOR	(('G' << 24) | ('S' << 16) | ('R' << 8) | '\0')
+*/
+#endif

+ 109 - 0
apps/common/device/gSensor/fmy/gsensor_api.c

@@ -0,0 +1,109 @@
+#include "includes.h"
+#include "gsensor_api.h"
+#include "Motion_api.h"
+
+#if (TCFG_GSENSOR_ENABLE && (TCFG_SC7A20_EN || TCFG_SC7A20_E_EN || TCFG_MSA310_EN))
+
+#if GSENSOR_PRINTF_ENABLE
+#define log_info(x, ...)  printf("[GSENSOR_API]" x "\r\n", ## __VA_ARGS__)
+#define log_info_hexdump  put_buf
+#else
+#define log_info(...)
+#define log_info_hexdump(...)
+#endif
+
+#ifdef GSENSOR_POWER_IO
+#define  PORT_DIR_OUPUT             0
+#define  PORT_DIR_INPUT             1
+#define  PORT_VALUE_HIGH            1
+#define  PORT_VALUE_LOW             0
+#define PORT_IO_INIT(PORT_IO,DIR)       {gpio_set_die(PORT_IO,1);\
+                                         gpio_set_pull_down(PORT_IO,0);\
+                                         gpio_set_pull_up(PORT_IO,0);\
+                                         gpio_set_direction(PORT_IO,DIR);}
+
+#define PORT_IO_OUPUT(PORT_IO,VALUE)     gpio_write(PORT_IO,VALUE);
+#endif
+
+#if TCFG_SC7A20_EN
+#define GSENSOR_NAME "sc7a20"
+#elif TCFG_SC7A20_E_EN
+#define GSENSOR_NAME "sc7a20e"
+#elif TCFG_MSA310_EN
+#define GSENSOR_NAME "msa310"
+#endif
+
+GSENSOR_PLATFORM_DATA_BEGIN(gSensor_data)
+.iic = 0,
+ .gSensor_int_io = -1,
+  .gSensor_name = GSENSOR_NAME,
+   GSENSOR_PLATFORM_DATA_END();
+
+
+// motion detection 算法配置
+static char *workbuf = NULL;
+static const short fs = 25;
+static const float thread = 2.0f;
+
+
+
+// 获得陀螺仪数据数组
+int sensor_data_get(short *buf)
+{
+    return get_gSensor_data(buf);
+}
+
+bool sensor_motion_detection(void)
+{
+    log_info("run motion detection task!");
+    axis_info_t axis_buffer[32] = {0};
+    int data_len = sensor_data_get(axis_buffer);
+    char flag = run_MotionDetection(workbuf, data_len, axis_buffer);
+    if (flag) {
+        log_info("is moving!!");
+    } else {
+        log_info("is static!!");
+    }
+    return flag;
+}
+
+// enable fmy gsensor
+int sensor_init(void)
+{
+    log_info("%s, %s, %d", __FILE__, __FUNCTION__, __LINE__);
+#ifdef GSENSOR_POWER_IO
+    PORT_IO_INIT(GSENSOR_POWER_IO, PORT_DIR_OUPUT);
+    PORT_IO_OUPUT(GSENSOR_POWER_IO, PORT_VALUE_HIGH);
+#endif
+    int ret = gravity_sensor_init((struct gsensor_platform_data *)&gSensor_data);
+
+    int buff_size = get_DetectionBuf(fs);
+    workbuf = (char *)malloc(buff_size);
+
+    if (!workbuf) {
+        log_info("fmy gsensor workbuf init fail!!");
+        return -1;
+    }
+    init_MotionDet(workbuf, fs, thread);
+
+    return ret;
+}
+
+// disable fmy gsensor
+int sensor_deinit(void)
+{
+    log_info("%s, %s, %d", __FILE__, __FUNCTION__, __LINE__);
+    if (!workbuf) {
+        log_info("sensor is not init so can not deinit!!");
+        return 0;
+    }
+
+    int ret = gsensor_disable();
+
+    free(workbuf);
+    workbuf = NULL;
+
+    return ret;
+}
+
+#endif

+ 18 - 0
apps/common/device/gSensor/fmy/gsensor_api.h

@@ -0,0 +1,18 @@
+#ifndef __SENSOR_API_H__
+#define __SENSOR_API_H__
+#include "gSensor_manage.h"
+
+int sensor_init();
+int sensor_data_get();
+void get_sensor_avg(axis_info_t *axis_avg);
+int sensor_deinit();
+bool sensor_motion_detection(void);
+
+typedef enum {
+    DETECTION_PASSIVE = 0,
+    DETECTION_ACTIVE
+} DETECTION_STATES;
+
+static DETECTION_STATES detection_status = DETECTION_PASSIVE;
+
+#endif

+ 227 - 0
apps/common/device/gSensor/fmy/msa310.c

@@ -0,0 +1,227 @@
+
+#include "gSensor_manage.h"
+#include "app_config.h"
+#include "msa310.h"
+#include "msa310_function.h"
+#include "Motion_api.h"
+
+#if (TCFG_GSENSOR_ENABLE && TCFG_MSA310_EN)
+
+#if GSENSOR_PRINTF_ENABLE
+#define log_info(fmt,...)      printf("[MSA310] " fmt "\n",##__VA_ARGS__)
+#define log_info_hexdump       put_buf
+#else
+#define log_info(fmt,...)
+#define log_info_hexdump
+#endif
+
+// static u8 msa310_is_idle = 1;
+spinlock_t sensor_iic;
+u8 sensor_iic_init_status = 0;
+
+#define MSA310_W_ADDR (0x62 << 1 | 0x0)
+#define MSA310_R_ADDR (0x62 << 1 | 0x1)
+
+uint8_t msa_id = 0;
+
+/*return value: 0: is ok    -1:read is failed*/
+int32_t msa_register_read(uint8_t addr, uint8_t *data)
+{
+    int32_t res = 0;
+
+    res = _gravity_sensor_get_ndata(MSA310_R_ADDR, addr, data, 1); // return:0:err,  1:ok
+    if (res) {
+        return 0;
+    }
+    return -1;
+}
+
+/*return value: 0: is ok    -2:write is failed*/
+int32_t msa_register_write(uint8_t addr, uint8_t data)
+{
+    int32_t res = 0;
+
+    res = gravity_sensor_command(MSA310_W_ADDR, addr, data); // return:0:err,  1:ok
+    if (res) {
+        return 0;
+    }
+    return -2;
+}
+
+// return:0:ok,  -1:err
+int32_t msa_register_read_continuously(uint8_t addr, uint8_t count, uint8_t *data)
+{
+    int32_t res = 0;
+    int32_t i = 0;
+
+    for (i = 0; i < count; i++) {
+        res = msa_register_read(addr + i, data + i);
+        if (res) {
+            return res;
+        }
+    }
+    return res; // ok
+}
+
+// return:0:ok,  -1/-2:err
+int32_t msa_register_mask_write(uint8_t addr, uint8_t mask, uint8_t data)
+{
+    int32_t res = 0;
+    uint8_t tmp_data;
+
+    res = msa_register_read(addr, &tmp_data);
+    if (res) {
+        return res;
+    }
+
+    tmp_data &= ~mask;
+    tmp_data |= data & mask;
+    res = msa_register_write(addr, tmp_data);
+
+    return res;
+}
+
+int32_t msa_read_fifo(axis_info_t *raw_accel)
+{
+    int i = 0;
+    unsigned char data_count = 0;
+    uint8_t temp_buf[192]; // 32*6
+    msa_register_read(0x0d, &data_count);
+    data_count = (data_count & 0x7F);
+    if (data_count > 32) {
+        data_count = 32;
+    }
+    /* log_info("data_count = %d \r\n",data_count); */
+    _gravity_sensor_get_ndata(MSA310_R_ADDR, 0xff, temp_buf, data_count * 6); // return:0:err,  acc_count*6:ok
+
+    for (u8 i = 0; i < data_count; i++) {
+        raw_accel[i].x = ((short)(temp_buf[i * 6 + 1] << 8 | temp_buf[i * 6 + 0])) >> 4;
+        raw_accel[i].y = ((short)(temp_buf[i * 6 + 3] << 8 | temp_buf[i * 6 + 2])) >> 4;
+        raw_accel[i].z = ((short)(temp_buf[i * 6 + 5] << 8 | temp_buf[i * 6 + 4])) >> 4;
+        log_info("%d:   x:%d     y:%d    z:%d\r\n", data_count - i, raw_accel[i].x, raw_accel[i].y, raw_accel[i].z);
+    }
+    return data_count;
+}
+
+extern void msa_param_init(void);
+/*return value: 0: is ok    other: is failed*/
+uint8_t msa310_init(void)
+{
+    int32_t res = 0;
+    uint8_t data = 0;
+
+    msa_register_read(MSA_REG_WHO_AM_I, &msa_id);
+    if (msa_id != 0x13) {
+        log_info("read msa310 id error");
+        return -1;
+    }
+    log_info("msa310 id:0x%x", msa_id);
+
+    // reset
+    res = msa_register_mask_write(MSA_REG_SOFT_RESET, 0x24, 0x24);
+
+    os_time_dly(10); // 10ms
+
+    res |= msa_register_mask_write(MSA_REG_G_RANGE, 0x03, 0x02);	  // 0:2g, 1:4g, 2:8g, 3:16g
+    res |= msa_register_mask_write(MSA_REG_POWERMODE_BW, 0xFF, 0x5e); // low power mode, BW:500hz
+    /* res |= msa_register_mask_write(MSA_REG_ODR_AXIS_DISABLE, 0xFF, 0x04);//xyz enable, odr:15.63hz */
+    /* res |= msa_register_mask_write(MSA_REG_POWERMODE_BW, 0xFF, 0x50);//low power mode, BW:125hz */
+    /* res |= msa_register_mask_write(MSA_REG_POWERMODE_BW, 0xFF, 0x4e);//low power mode, BW:62.5hz */
+    res |= msa_register_mask_write(MSA_REG_ODR_AXIS_DISABLE, 0xFF, 0x07); // xyz enable, odr:125hz
+
+    // fifo config
+    //  bit67:00: bypass mode, 01: FIFO mode, 10: stream mode, 11: trigger mode, WATERMARK_SAMPLES[5:0]:0x20(32)
+    res |= msa_register_mask_write(MSA_REG_FIFO_CTRL, 0xFF, 0xa0);
+    res |= msa_register_mask_write(MSA_REG_FIFO_CTRL1, 0x03, 0x00); // fifo enable xyz data
+
+    // int config
+    res |= msa_register_mask_write(MSA_REG_INTERRUPT_SETTINGS2, 0x78, 0x60); // bit6:OVERRUN_INT_EN, bit5:WATERMARK_INT_EN, bit4:NEW_DATA_INT_EN, bit3:FREEFALL_INT_EN
+    res |= msa_register_mask_write(MSA_REG_INTERRUPT_MAPPING2, 0x07, 0x06);	 // bit2:OVERRUN_INT1, bit1:WATERMARK_INT1, bit0:NEW_DATA_INT1
+    res |= msa_register_mask_write(MSA_REG_INT_PIN_CONFIG, 0x03, 0x00);		 // bit1:INT1 OD mode, bit0:INT1 LEVEL
+    res |= msa_register_mask_write(MSA_REG_INT_LATCH, 0x8f, 0x00);			 // non-latched
+
+    msa_param_init();
+
+    return res;
+}
+/*return value: 0: is ok    other: is failed*/
+uint8_t msa310_stop(void)
+{
+    int32_t res = 0;
+
+    res |= msa_register_mask_write(MSA_REG_POWERMODE_BW, 0xFF, 0xDE); // lkk modify 0x5E
+    res |= msa_register_mask_write(MSA_REG_FIFO_CTRL, 0xFF, 0x00);
+
+    return res;
+}
+
+bool is_msa310_chipid(void)
+{
+    if (msa_id == 0x13) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool msa310_check(void)
+{
+    u8 msa310_d = 0;
+    msa_register_read(MSA_REG_WHO_AM_I, &msa310_d);
+    if (msa310_d == 0x13) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+int msa310_ctl(u8 cmd, void *arg)
+{
+    int res = -1;
+    switch (cmd) {
+    case GSENSOR_DISABLE:
+        res = msa310_stop();
+        memcpy(arg, &res, 1);
+        break;
+    case GSENSOR_RESET_INT:
+        res = msa310_init();
+        memcpy(arg, &res, 1);
+        break;
+    case GSENSOR_RESUME_INT:
+        break;
+    case GSENSOR_INT_DET:
+        /* msa310_int_io_detect(*(u8 *)arg); */
+        res = 0;
+        break;
+    case READ_GSENSOR_DATA:
+        res = msa_read_fifo((axis_info_t *)arg);
+        break;
+    case SEARCH_SENSOR:
+        res = msa310_check();
+        memcpy(arg, &res, 1);
+        break;
+    default:
+
+        break;
+    }
+    return res; //>=0:ok,,<0:err
+}
+
+// static u8 msa310_idle_query(void)
+// {
+//     return msa310_is_idle;
+// }
+
+REGISTER_GRAVITY_SENSOR(gSensor) = {
+    .logo = "msa310",
+    .gravity_sensor_init = msa310_init,
+    .gravity_sensor_check = NULL, // msa310_click_status,
+    .gravity_sensor_ctl = msa310_ctl,
+};
+
+// REGISTER_LP_TARGET(msa310_lp_target) = {
+//     .name = "msa310",
+//     .is_idle = msa310_idle_query,
+// };
+
+#endif

+ 52 - 0
apps/common/device/gSensor/fmy/msa310.h

@@ -0,0 +1,52 @@
+
+#ifndef __MSA310_H__
+#define __MSA310_H__
+
+#if TCFG_MSA310_EN
+#include "gSensor_manage.h"
+
+//msa310 max fre:400Khz(iic)
+#define MSA_REG_SOFT_RESET              0x00
+#define MSA_REG_WHO_AM_I                0x01
+#define MSA_REG_ACC_X_LSB               0x02
+#define MSA_REG_ACC_X_MSB               0x03
+#define MSA_REG_ACC_Y_LSB               0x04
+#define MSA_REG_ACC_Y_MSB               0x05
+#define MSA_REG_ACC_Z_LSB               0x06
+#define MSA_REG_ACC_Z_MSB               0x07
+
+#define MSA_REG_MOTION_FLAG							0x09
+#define MSA_REG_DATA_INT_FLAG							0x0a
+#define MSA_REG_FIFO_SAMPLE_CNT         0x0d
+#define MSA_REG_G_RANGE                 0x0f
+#define MSA_REG_ODR_AXIS_DISABLE        0x10
+#define MSA_REG_POWERMODE_BW            0x11
+#define MSA_REG_SWAP_POLARITY           0x12
+#define MSA_REG_FIFO_CTRL               0x14
+#define MSA_REG_FIFO_CTRL1               0x15
+#define MSA_REG_INTERRUPT_SETTINGS1     0x16
+#define MSA_REG_INTERRUPT_SETTINGS2     0x17
+#define MSA_REG_INTERRUPT_MAPPING1      0x19
+#define MSA_REG_INTERRUPT_MAPPING2      0x1a
+#define MSA_REG_INT_PIN_CONFIG          0x20
+#define MSA_REG_INT_LATCH               0x21
+#define MSA_REG_ACTIVE_DURATION         0x27
+#define MSA_REG_ACTIVE_THRESHOLD        0x28
+
+typedef unsigned char   uint8_t;
+typedef signed char	int8_t;
+typedef unsigned short  uint16_t;
+typedef signed short	int16_t;
+
+int32_t msa_read_data(int16_t *x, int16_t *y, int16_t *z);
+int32_t msa_register_read_continuously(uint8_t addr, uint8_t count, uint8_t *data);
+//int32_t i2c_write_byte_data( uint8_t addr, uint8_t data);
+bool msa_WriteBytes(uint8_t RegAddr, uint8_t Data);
+bool msa_ReadBytes(uint8_t *Data, uint8_t RegAddr);
+// int32_t msa_read_fifo(int16_t *xBuf, int16_t *yBuf, int16_t *zBuf, int len);
+int32_t msa_read_fifo(axis_info_t *raw_accel);
+uint8_t msa_ReadBytes_ACKEND(uint8_t *Data, uint8_t RegAddr);
+uint8_t msa310_init(void);
+
+#endif
+#endif

+ 776 - 0
apps/common/device/gSensor/fmy/msa310_function.c

@@ -0,0 +1,776 @@
+
+/**
+  ******************************************************************************
+  * @file    msa300_app_fixpoint.c
+  * @author  memsensing algorithm team
+  * @version V1.1.0
+  * @date    16- 8 -2018
+  * @brief   This file provides pedometer function of G-sensor MSA30x application
+  ******************************************************************************
+**/
+#include "gSensor_manage.h"
+#include "msa310_function.h"
+
+#if TCFG_MSA310_EN
+
+Step_Typedef Step_Structure;
+Bright_Typedef Bright_Structure;
+Sleep_Typedef Sleep_Structure;
+
+// void sum_Calculate(void);
+// void A_Calculate(void);
+// void sleep_Mode_Calculate(void);
+// void isTurn_Judge(void);
+void find_Turn(void);
+void sleep_Para_Clear(void);
+
+
+static int a1[7] = {16384, -79111, 170817, -209099, 152847, -63295, 11720};
+static int b1[7] = {805, -2623, 2884, 0, -2884, 2623, -806};
+static int a2[7] = {16384, -64148, 119340, -133733, 95028, -40165, 8056};
+static int b2[7] = {1630, -3977, 3285, 0, -3285, 3977, -1630};
+static int beforeFilter[7];
+static int afterFilter[7];
+
+void msa_step_clear(void)//计步清零
+{
+    Step_Structure.step_cnt = 0;
+    Step_Structure.step_sum = 0;
+    Step_Structure.timeCnt 	= 0;
+    Step_Structure.timeNow  = 0;
+    Step_Structure.lastPeakTime = 0;
+    Step_Structure.thisPeakTime = 0;
+    Step_Structure.lastStepTime = 0;
+    Step_Structure.thisStepTime = 0;
+    Step_Structure.ThresholdCnt = 0;
+    Step_Structure.stepMode = 1;
+    Step_Structure.stepModeCnt = 0;
+    Step_Structure.staticModeCnt = 0;
+}
+
+void msa_param_init(void)
+{
+    //Pedometer Structure initial
+    Step_Structure.thisDirectionUp = 0;
+    Step_Structure.timeInterval  = 5;
+    Step_Structure.valueThreshold = 40;
+    Step_Structure.valueThresholdInitial = 25;
+    Step_Structure.stepMode = 1;
+    Step_Structure.stepModeCnt = 0;
+
+    Bright_Structure.autoBrightFlag = 0;
+    Bright_Structure.accSquareSum[0] = 0;
+    Bright_Structure.accSquareSum[1] = 0;
+    Bright_Structure.accSquareMaxLimit = 98304;
+    Bright_Structure.accSquareMinLimit = 23909;//43909
+    Bright_Structure.enableCnt = 0;
+    Bright_Structure.enableCntLimit = 4;
+    Bright_Structure.disableCnt = 0;
+    Bright_Structure.disableCntLimit = 12;
+    Bright_Structure.xzAngel = 0;
+    Bright_Structure.yzAngel = 0;
+    Bright_Structure.xzAngelLimitMax = 35;
+    Bright_Structure.xzAngelLimitMin = -35;
+    Bright_Structure.yzAngelLimitMax = 90;
+    Bright_Structure.yzAngelLimitMin = 5;//25
+    Bright_Structure.lastStatus = 1;
+    Bright_Structure.isLevelRotationCnt = 0;
+    Bright_Structure.autoBrightFromLevelFlag = 0;
+    Bright_Structure.levelRotationEnableCntLimit = 4;
+    Bright_Structure.levelDisableCntLimit = 40;
+    Bright_Structure.isLevelCntLimit = 4;
+
+    Sleep_Structure.Data_Cnt = 0;
+    Sleep_Structure.Minute_Cnt = 0;
+}
+
+static int peak_Search(short int newData, short int oldData)
+{
+    Step_Structure.lastDirectionUp = Step_Structure.thisDirectionUp;
+
+    if (newData > oldData) {
+        Step_Structure.thisDirectionUp = 1;
+        Step_Structure.thisDirectionUpCnt++;
+    }
+
+    else if (newData < oldData) {
+        Step_Structure.lastDirectionUpCnt = Step_Structure.thisDirectionUpCnt;
+        Step_Structure.thisDirectionUpCnt = 0;
+        Step_Structure.thisDirectionUp = 0;
+    }
+
+    if (!Step_Structure.thisDirectionUp && \
+        Step_Structure.lastDirectionUp && \
+        Step_Structure.lastDirectionUpCnt	>= 2 && \
+        oldData >= 0) {
+        Step_Structure.valuePeak = oldData;
+        return 1;
+    } else if (Step_Structure.thisDirectionUp && \
+               !Step_Structure.lastDirectionUp) {
+        Step_Structure.valueValley = oldData;
+        return 0;
+    } else {
+        return 0;
+    }
+}
+
+static void step_Count(void)
+{
+    Step_Structure.lastStepTime =  Step_Structure.thisStepTime;
+    Step_Structure.thisStepTime =  Step_Structure.timeCnt;
+    //2s
+    if (Step_Structure.thisStepTime - Step_Structure.lastStepTime <= 20) { //40
+        if (Step_Structure.step_cnt < 20) { //12
+            Step_Structure.step_cnt++;
+        } else if (Step_Structure.step_cnt == 20) { //12
+            Step_Structure.step_cnt++;
+            Step_Structure.step_sum += Step_Structure.step_cnt;
+            Step_Structure.valueThresholdInitial = 20;
+        } else {
+            Step_Structure.step_sum++;
+        }
+    } else {
+        Step_Structure.step_cnt = 1;
+        Step_Structure.valueThresholdInitial = 40;
+        Step_Structure.valueThreshold = 40;
+    }
+}
+
+static void valueThreshold_Refresh(void)
+{
+    short int average;
+    if (Step_Structure.ThresholdCnt < 4) {
+        Step_Structure.Threshold[Step_Structure.ThresholdCnt] = Step_Structure.valuePeak - Step_Structure.valueValley;
+        Step_Structure.ThresholdCnt++;
+    } else {
+        Step_Structure.Threshold[0] = Step_Structure.Threshold[1];
+        Step_Structure.Threshold[1] = Step_Structure.Threshold[2];
+        Step_Structure.Threshold[2] = Step_Structure.Threshold[3];
+        Step_Structure.Threshold[3] = Step_Structure.valuePeak - Step_Structure.valueValley;
+        average = (Step_Structure.Threshold[0] + Step_Structure.Threshold[1] + \
+                   Step_Structure.Threshold[2] + Step_Structure.Threshold[3]);
+
+        average /= 4;
+
+        if (average > 150) {
+            Step_Structure.valueThreshold = 70;
+        } else if (average > 120) {
+            Step_Structure.valueThreshold = 55;
+        } else if (average > 90) {
+            Step_Structure.valueThreshold = 40;
+        } else if (average > 75) {
+            Step_Structure.valueThreshold = 30;
+        } else if (average > 60) {
+            Step_Structure.valueThreshold = 25;
+        } else {
+            Step_Structure.valueThreshold = 16;
+        }
+    }
+}
+
+void USER_Pedometer(void)
+{
+    if (Step_Structure.valueOld == 0) {
+        Step_Structure.valueOld = Step_Structure.valueNew;
+    } else {
+        if (peak_Search(Step_Structure.valueNew, Step_Structure.valueOld)) {
+            Step_Structure.lastPeakTime = Step_Structure.thisPeakTime;
+            Step_Structure.timeNow = Step_Structure.timeCnt;
+            if (((Step_Structure.timeNow - Step_Structure.lastPeakTime) >= Step_Structure.timeInterval) && \
+                ((Step_Structure.valuePeak - Step_Structure.valueValley) >= Step_Structure.valueThreshold)) {
+                Step_Structure.thisPeakTime = Step_Structure.timeNow;
+                step_Count();
+            }
+            if (((Step_Structure.timeNow - Step_Structure.lastPeakTime) >= Step_Structure.timeInterval) && \
+                ((Step_Structure.valuePeak - Step_Structure.valueValley) >= Step_Structure.valueThresholdInitial)) {
+                valueThreshold_Refresh();
+            }
+        }
+    }
+    Step_Structure.valueOld = Step_Structure.valueNew;
+}
+
+
+static int msa_filterWalk(int data)
+{
+
+    int ret = 0;
+
+    beforeFilter[0] = data * 5;
+
+    for (int i = 0; i < 7; i++) {
+        ret += b1[i] * beforeFilter[i];
+    }
+
+    for (int i = 1; i < 7; i++) {
+        ret -= a1[i] * afterFilter[i];
+    }
+
+    ret /= 16384;
+
+    afterFilter[0] = ret;
+
+    for (int i = 6; i > 0; i--) {
+        afterFilter[i]  = afterFilter[i - 1];
+        beforeFilter[i] = beforeFilter[i - 1];
+    }
+
+    return ret;
+}
+
+static int msa_filterRun(int data)
+{
+    int ret = 0;
+
+    beforeFilter[0] = data * 5;
+
+    for (int i = 0; i < 7; i++) {
+        ret += b2[i] * beforeFilter[i];
+    }
+
+    for (int i = 1; i < 7; i++) {
+        ret -= a2[i] * afterFilter[i];
+    }
+
+    ret /= 16384;
+
+    afterFilter[0] = ret;
+
+    for (int i = 6; i > 0; i--) {
+        afterFilter[i]  = afterFilter[i - 1];
+        beforeFilter[i] = beforeFilter[i - 1];
+    }
+
+    return ret;
+}
+
+//æ±sqrt
+static int msa_sqrt(int val)
+{
+    int r = 0;
+    int shift;
+
+    if (val < 0) {
+        return 0;
+    }
+
+    for (shift = 0; shift < 32; shift += 2) {
+        int x = 0x40000000l >> shift;
+        if (x + r <= val) {
+            val -= x + r;
+            r = (r >> 1) | x;
+        } else {
+            r = r >> 1;
+        }
+    }
+    return r;
+}
+
+/*
+ * 计步器函数,msa_step(),返回的为实际步数,15步开始计数,不满15步停止视为无效步数,不清零一直累加,需要手动清零。//msa_app.c , msa310.c
+50毫秒的timer调用一次msa_get_step,关闭时停止timer。使用FIFO数据(数据长度与ODR相关)。 //未找到 添加到msa310.c
+例如500MS,10组数据,就循环调用10次算法。
+ */
+unsigned int msa_step(short int x, short int y, short int z)
+{
+    Step_Structure.timeCnt++;
+    Step_Structure.valueNew = msa_sqrt(x * x + y * y + z * z);
+
+    if (Step_Structure.stepMode == 1 && Step_Structure.valueNew > 200 && Step_Structure.valueNew < 295) {
+        Step_Structure.staticModeCnt ++;
+        if (Step_Structure.staticModeCnt > 10) {
+            Step_Structure.stepMode = 0;
+        }
+    } else {
+        Step_Structure.staticModeCnt = 0;
+    }
+
+    if (Step_Structure.stepMode == 0 && Step_Structure.valueNew > 295) {
+        Step_Structure.stepMode = 1;
+    }
+
+    if (Step_Structure.stepMode == 1 && Step_Structure.valueNew > 620) {
+        if (Step_Structure.stepModeCnt == 0) {
+            Step_Structure.stepModeTimeCnt = Step_Structure.timeCnt;
+        }
+        Step_Structure.stepModeCnt ++;
+
+        if (Step_Structure.stepModeCnt > 5) {
+            if ((Step_Structure.timeCnt - Step_Structure.stepModeTimeCnt) < 60) {
+                Step_Structure.stepMode = 2;
+                Step_Structure.stepModeCnt = 0;
+            } else {
+                Step_Structure.stepModeCnt = 0;
+            }
+        }
+    }
+    if (Step_Structure.stepMode == 2) {
+        if (Step_Structure.valueNew < 620) {
+            Step_Structure.stepModeCnt ++;
+            if (Step_Structure.stepModeCnt > 50) {
+                Step_Structure.stepMode = 1;
+                Step_Structure.stepModeCnt = 0;
+            }
+        } else {
+            Step_Structure.stepModeCnt = 0;
+        }
+    }
+
+    if (Step_Structure.stepMode == 1) {
+        Step_Structure.valueNew = msa_filterWalk(Step_Structure.valueNew);
+    } else if (Step_Structure.stepMode == 2) {
+        Step_Structure.valueNew = msa_filterRun(Step_Structure.valueNew);
+    }
+
+    if (Step_Structure.stepMode != 0) {
+        USER_Pedometer();
+    }
+    return Step_Structure.step_sum;
+}
+
+static unsigned char isStatic(int val)
+{
+    if (val < Bright_Structure.accSquareMaxLimit && \
+        val > Bright_Structure.accSquareMinLimit) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static unsigned char light_off_detect(short int x, short int y, short int z)
+{
+    if (Bright_Structure.lightOffTimeCnt) {
+        Bright_Structure.lightOffTimeCnt++;
+        if (Bright_Structure.lightOffTimeCnt >= 3) {
+            Bright_Structure.lightOffTimeCnt = 0;
+            Bright_Structure.lastStatus = 0;
+            return 2;
+        }
+    }
+
+    if (Bright_Structure.lastStatus == 1) {
+#ifdef KCT_GSETURE_WAKEUP
+
+        if (isStatic(Bright_Structure.accSquareSum[0]) && \
+            (ABS(x) > 110 || y < -80)) {
+            Bright_Structure.backlightOffCnt = 0;
+
+            if (!Bright_Structure.lightOffTimeCnt) {
+                Bright_Structure.lightOffTimeCnt = 1;
+            }
+            //return 2;
+        }
+#endif
+
+        if (isStatic(Bright_Structure.accSquareSum[0]) && \
+            ABS(x) > 162) {
+            Bright_Structure.backlightOffCnt = 0;
+
+            if (!Bright_Structure.lightOffTimeCnt) {
+                Bright_Structure.lightOffTimeCnt = 1;
+            }
+        }
+        Bright_Structure.backlightOffCnt++;
+
+    }
+
+    return 0;
+}
+
+static unsigned char isLevel_detect(short int x, short int y, short int z)
+{
+    if (ABS(x) < 76 && ABS(y) < 76 && z > 200 && z < 281) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static int msa_atan(int x, int y)
+{
+    const int angle[] = {11520, 6801, 3593, 1824, 916, 458, 229, 115, 57, 29, 14, 7, 4, 2, 1};
+
+    int i = 0;
+    int x_new, y_new;
+    int angleSum = 0;
+
+    x *= 1024;
+    y *= 1024;
+
+    for (i = 0; i < 15; i++) {
+        if (y > 0) {
+            x_new = x + (y >> i);
+            y_new = y - (x >> i);
+            x = x_new;
+            y = y_new;
+            angleSum += angle[i];
+        } else {
+            x_new = x - (y >> i);
+            y_new = y + (x >> i);
+            x = x_new;
+            y = y_new;
+            angleSum -= angle[i];
+        }
+    }
+    return angleSum;
+}
+
+
+
+static unsigned char light_on_detect(short int x, short int y, short int z)
+{
+#ifdef KCT_GSETURE_WAKEUP
+
+    if (Bright_Structure.lightOnTimeCnt) {
+        Bright_Structure.lightOnTimeCnt++;
+        if (Bright_Structure.lightOnTimeCnt >= 4) {
+            Bright_Structure.lightOnTimeCnt = 0;
+            Bright_Structure.lastStatus = 1;
+            return 1;
+        }
+    }
+
+    if (Bright_Structure.autoBrightFromLevelFlag && \
+        isStatic(Bright_Structure.accSquareSum[0]) && \
+        (ABS(x) < 75 && y > 90 && y < 200 && z > 75)
+       ) {
+        Bright_Structure.levelRotationEnableCnt ++;
+        if (Bright_Structure.levelRotationEnableCnt >= Bright_Structure.levelRotationEnableCntLimit) {
+            Bright_Structure.levelDisableCnt = 0;
+            Bright_Structure.levelRotationEnableCnt = 0;
+            Bright_Structure.autoBrightFromLevelFlag = 0;
+            Bright_Structure.accSquareSum[1] = Bright_Structure.accSquareSum[0];
+            if (!Bright_Structure.lightOnTimeCnt) {
+                Bright_Structure.lightOnTimeCnt = 1;
+            }
+            //return 1;
+        }
+    } else {
+        Bright_Structure.levelRotationEnableCnt = 0;
+    }
+
+    Bright_Structure.levelDisableCnt++;
+
+    if (Bright_Structure.levelDisableCnt >= Bright_Structure.levelDisableCntLimit) {
+        Bright_Structure.levelDisableCnt = 0;
+        Bright_Structure.autoBrightFromLevelFlag = 0;
+    }
+#endif
+
+#ifdef  KCT_GSETURE_WAKEUP
+    if (isLevel_detect(x, y, z)) {
+        Bright_Structure.isLevelCnt++;
+        if (Bright_Structure.isLevelCnt >= Bright_Structure.isLevelCntLimit) {
+            if (Bright_Structure.notLevelCnt >= 5) {
+                Bright_Structure.accSquareSum[1] = Bright_Structure.accSquareSum[0];
+                Bright_Structure.lastStatus = 1;
+                Bright_Structure.isLevelCnt = 0;
+                Bright_Structure.notLevelCnt = 0;
+                Bright_Structure.lightOnTimeCnt = 1;
+                //return 1;
+            } else {
+                Bright_Structure.isLevelCnt = 0;
+                Bright_Structure.notLevelCnt = 0;
+            }
+        }
+    } else {
+        Bright_Structure.notLevelCnt++;
+        if (Bright_Structure.notLevelCnt > 20) {
+            Bright_Structure.notLevelCnt = 20;
+        }
+        Bright_Structure.isLevelCnt = 0;
+    }
+#endif
+
+    if (!isStatic(Bright_Structure.accSquareSum[0])) {
+        Bright_Structure.enableCnt = 0;
+    }
+
+    if (isStatic(Bright_Structure.accSquareSum[0]) && \
+        Bright_Structure.accSquareSum[1] > 0 && \
+        !isStatic(Bright_Structure.accSquareSum[1])) {
+        Bright_Structure.autoBrightFlag = 1;
+    }
+
+    if (Bright_Structure.autoBrightFlag) {
+        Bright_Structure.disableCnt ++;
+    }
+    if (Bright_Structure.disableCnt >= Bright_Structure.disableCntLimit) {
+        Bright_Structure.disableCnt = 0;
+        Bright_Structure.autoBrightFlag = 0;
+    }
+
+    if (Bright_Structure.autoBrightFlag && y > 0 &&  z > 0 && \
+        isStatic(Bright_Structure.accSquareSum[0])) {
+        Bright_Structure.enableCnt ++;
+
+        if (Bright_Structure.enableCnt >= Bright_Structure.enableCntLimit) {
+            if (z == 0) {
+                z = 1 ;
+            }
+            Bright_Structure.xzAngel = msa_atan(z, x) / 256;
+            Bright_Structure.yzAngel = msa_atan(z, y) / 256;
+
+            if (z >= 38) {
+                if (Bright_Structure.xzAngel > Bright_Structure.xzAngelLimitMin && \
+                    Bright_Structure.xzAngel < Bright_Structure.xzAngelLimitMax && \
+                    Bright_Structure.yzAngel > Bright_Structure.yzAngelLimitMin && \
+                    Bright_Structure.yzAngel < Bright_Structure.yzAngelLimitMax) {
+                    Bright_Structure.enableCnt = 0;
+                    Bright_Structure.disableCnt = 0;
+                    Bright_Structure.autoBrightFlag = 0;
+                    Bright_Structure.accSquareSum[1] = Bright_Structure.accSquareSum[0];
+                    Bright_Structure.lastStatus = 1;
+                    return 1;
+                }
+            } else if (y > 212) {
+                Bright_Structure.enableCnt = 0;
+                Bright_Structure.disableCnt = 0;
+                Bright_Structure.autoBrightFlag = 0;
+                Bright_Structure.accSquareSum[1] = Bright_Structure.accSquareSum[0];
+                Bright_Structure.lastStatus = 1;
+                return 1;
+            }
+        }
+    } else {
+        Bright_Structure.enableCnt = 0;
+    }
+    return 0;
+}
+
+
+/*50毫秒的timer调用一次msa_light,关闭时停止timer。    //msa_app.c , msa310.c
+   函数返回值: 1 : 亮屏   2:灭屏  0:无动作
+   使用FIFO数据(数据长度与ODR相关)。
+   例如500MS,10组数据,识别有一次抬手动作,开启亮屏,其他无效。
+*/
+unsigned char msa_light(short int x, short int y, short int z)
+{
+    unsigned char ret;
+    Bright_Structure.accSquareSum[0] = x * x + y * y + z * z ;
+
+#ifdef KCT_GSETURE_WAKEUP
+
+    if (!isLevel_detect(x, y, z) && Bright_Structure.isLevelRotationCnt > 9) {
+        Bright_Structure.autoBrightFromLevelFlag = 1;
+    }
+
+#endif
+
+    ret = light_off_detect(x, y, z);
+    if (ret) {
+        return ret;
+    }
+
+    ret = light_on_detect(x, y, z);
+    if (ret) {
+        return ret;
+    }
+
+#ifdef KCT_GSETURE_WAKEUP
+    if (isLevel_detect(x, y, z)) {
+        Bright_Structure.isLevelRotationCnt++;
+        if (Bright_Structure.isLevelRotationCnt++ > 20) {
+            Bright_Structure.isLevelRotationCnt = 20;
+        }
+    } else {
+        if (Bright_Structure.isLevelRotationCnt > 10) {
+            Bright_Structure.isLevelRotationCnt -= 5;
+        } else {
+            Bright_Structure.isLevelRotationCnt = 0;
+        }
+    }
+#endif
+
+    Bright_Structure.accSquareSum[1] = Bright_Structure.accSquareSum[0];
+    return 0;
+}
+
+
+
+static char m_cnt = 20;
+static int sleep_time_cnt = 0;
+static int sleep_this_status = -1;
+static int sleep_ontable_cnt = 0;
+static void sum_Calculate(void)
+{
+    int i = 0;
+    int SumX = 0;
+    int SumY = 0;
+    int SumZ = 0;
+
+    if (Sleep_Structure.Minute_Cnt > 0) {
+        Sleep_Structure.SumX_Last = Sleep_Structure.SumX;
+        Sleep_Structure.SumY_Last = Sleep_Structure.SumY;
+        Sleep_Structure.SumZ_Last = Sleep_Structure.SumZ;
+    }
+
+    for (i = 0; i < m_cnt; i++) {
+        SumX += Sleep_Structure.Acc[0][i];
+        SumY += Sleep_Structure.Acc[1][i];
+        SumZ += Sleep_Structure.Acc[2][i];
+    }
+
+    Sleep_Structure.SumX = SumX;
+    Sleep_Structure.SumY = SumY;
+    Sleep_Structure.SumZ = SumZ;
+}
+
+static void isTurn_Judge(void)
+{
+    int P = 0;
+    int AvgX = 0;
+    int AvgY = 0;
+    int AvgZ = 0;
+    int Mx = 0;
+    int My = 0;
+    int Mz = 0;
+    int i = 0;
+
+    sum_Calculate();
+
+    if (Sleep_Structure.Minute_Cnt > 0) {
+        P = ((Sleep_Structure.SumX - Sleep_Structure.SumX_Last) / m_cnt) * ((Sleep_Structure.SumX - Sleep_Structure.SumX_Last) / m_cnt) + \
+            ((Sleep_Structure.SumY - Sleep_Structure.SumY_Last) / m_cnt) * ((Sleep_Structure.SumY - Sleep_Structure.SumY_Last) / m_cnt) + \
+            ((Sleep_Structure.SumZ - Sleep_Structure.SumZ_Last) / m_cnt) * ((Sleep_Structure.SumZ - Sleep_Structure.SumZ_Last) / m_cnt);
+
+        AvgX = Sleep_Structure.SumX / m_cnt;
+        AvgY = Sleep_Structure.SumY / m_cnt;
+        AvgZ = Sleep_Structure.SumZ / m_cnt;
+        for (i = 0; i < m_cnt; i++) {
+            Mx += ABS(Sleep_Structure.Acc[0][i] - AvgX);
+            My += ABS(Sleep_Structure.Acc[1][i] - AvgY);
+            Mz += ABS(Sleep_Structure.Acc[2][i] - AvgZ);
+        }
+        Mx /= m_cnt;
+        My /= m_cnt;
+        Mz /= m_cnt;
+    }
+
+    if ((P > 7864) && ((Mx > 92) || (My > 92) || (Mz > 92))) {
+        sleep_time_cnt = 0;
+    }
+}
+
+static void A_Calculate(void)
+{
+    int i = 0;
+
+    for (i = 0; i < 4; i++) {
+        Sleep_Structure.A[i] = Sleep_Structure.A[i + 1];
+    }
+    Sleep_Structure.A[4] = 0;
+    for (i = 0; i < m_cnt; i++) {
+        /*	if(Sleep_Structure.accSquareSum[i] > 1386741 || \
+        		 Sleep_Structure.accSquareSum[i] < 757596)
+        	*/
+        if (Sleep_Structure.accSquareSum[i] > 1270000 || \
+            Sleep_Structure.accSquareSum[i] < 840000) {
+            Sleep_Structure.A[4]++;
+        }
+    }
+    Sleep_Structure.A[4] *= 2;
+}
+
+static void sleep_Mode_Calculate(void)
+{
+    int S  = 0;
+    int P  = 92;
+    int X1 = 6;
+    int X2 = 24;
+    int X3 = 100;
+    int X4 = 22;
+    int X5 = 4;
+
+    S = (Sleep_Structure.A[0] * X1 + \
+         Sleep_Structure.A[1] * X2 + \
+         Sleep_Structure.A[2] * X3 + \
+         Sleep_Structure.A[3] * X4 + \
+         Sleep_Structure.A[4] * X5);
+
+    S *= P;
+    if (S < 100000) {
+        sleep_time_cnt ++;
+        if (sleep_time_cnt > 2) {
+            sleep_this_status = MSA_RESTLESS;
+        }
+        if (sleep_time_cnt >= 15) {
+            sleep_this_status = MSA_ASLEEP;
+        }
+    } else {
+        sleep_time_cnt = 0;
+        sleep_this_status = MSA_AWAKE;
+    }
+
+    if (S == 0) {
+        sleep_ontable_cnt ++;
+        if (sleep_ontable_cnt > 30) {
+            sleep_this_status = MSA_ONTABLE;
+        }
+    } else {
+        sleep_ontable_cnt = 0;
+    }
+
+}
+
+/*
+3S采样一次数据给算法msa_sleep,1分钟统计一次数据。
+   开启睡眠检测,7分钟后,每一分中统计一次,7-15分钟浅睡,15分钟以后深睡,否则为清醒,具体参考算法。
+   如果检测到平放,并且超过半个小时,则认为未佩戴
+   函数返回值:  -1: 睡眠采样阶段  0:睡眠质量差   1:睡眠质量一般   2:睡眠质量佳  3:未佩戴
+*/
+static int sleep_last_status = MSA_AWAKE;
+int msa_sleep(short int x, short int y, short int z)
+{
+    x *= 4;
+    y *= 4;
+    z *= 4;
+
+    Sleep_Structure.accSquareSum[Sleep_Structure.Data_Cnt] = x * x + y * y + z * z;
+    Sleep_Structure.Acc[0][Sleep_Structure.Data_Cnt] = x;
+    Sleep_Structure.Acc[1][Sleep_Structure.Data_Cnt] = y;
+    Sleep_Structure.Acc[2][Sleep_Structure.Data_Cnt] = z;
+
+    if (Sleep_Structure.accSquareSum[Sleep_Structure.Data_Cnt] > 3397386) {
+        sleep_time_cnt = 0;
+        sleep_this_status = MSA_AWAKE;
+        return sleep_this_status;
+    }
+
+    Sleep_Structure.Data_Cnt++;
+
+    if (Sleep_Structure.Data_Cnt == m_cnt) {
+        Sleep_Structure.Data_Cnt = 0;
+        isTurn_Judge();
+        A_Calculate();
+        Sleep_Structure.Minute_Cnt++;
+        if (Sleep_Structure.Minute_Cnt >= 1000) {
+            Sleep_Structure.Minute_Cnt = 0;
+        }
+
+        if (Sleep_Structure.Minute_Cnt > 4) {
+            sleep_last_status = sleep_this_status;
+            sleep_Mode_Calculate();
+            if (sleep_last_status != sleep_this_status) {
+                return sleep_this_status;
+            }
+        }
+    }
+    return sleep_this_status;
+}
+
+
+void sleep_Para_Clear(void)
+{
+    Sleep_Structure.Sleep_End_Flag = 0;
+    Sleep_Structure.Data_Cnt = 0;
+    Sleep_Structure.Minute_Cnt = 0;
+    memset(Sleep_Structure.accSquareSum, 0, sizeof(Sleep_Structure.accSquareSum));
+    memset(Sleep_Structure.A, 0, sizeof(Sleep_Structure.A));
+
+}
+
+/************************ (C) COPYRIGHT MEMSENSING *****END OF FILE****/
+#endif
+

+ 113 - 0
apps/common/device/gSensor/fmy/msa310_function.h

@@ -0,0 +1,113 @@
+
+/**
+  ******************************************************************************
+  * @file    msa_app_fixpoint.h
+  * @author  memsensing algorithm team
+  * @version V1.1.0
+  * @date    18- 7 -2017
+  * @brief   This file contains definitions for msa_app_fixpoint.c  firmware
+  ******************************************************************************
+**/
+
+#ifndef _MSA_APP_FIXPOINT_H
+#define _MSA_APP_FIXPOINT_H
+
+#if TCFG_MSA310_EN
+
+#define ABS(x)  ( (x)>0?(x):-(x) )
+#define MSA_AWAKE				 0
+#define MSA_RESTLESS		1
+#define MSA_ASLEEP			2
+#define MSA_ONTABLE			3
+
+typedef struct {
+    int thisDirectionUp;
+    int lastDirectionUp;
+    int thisDirectionUpCnt;
+    int lastDirectionUpCnt;
+    long long timeCnt;
+    long long timeNow;
+    long long lastPeakTime;
+    long long thisPeakTime;
+    long long lastStepTime;
+    long long thisStepTime;
+    int timeInterval;
+    short int valueNew;
+    short int valueOld;
+    short	int valuePeak;
+    short int valueValley;
+    short int valueThreshold;
+    short int valueThresholdInitial;
+    short int ThresholdCnt;
+    short int Threshold[4];
+    int 	step_cnt;
+    int   step_sum;
+    short int stepMode;
+    short int stepModeCnt;
+    long long stepModeTimeCnt;
+    short int staticModeCnt;
+
+} Step_Typedef, *pStep_Typedef;
+
+extern Step_Typedef Step_Structure;
+
+typedef struct {
+    unsigned char autoBrightFlag;
+    unsigned int enableCnt;
+    unsigned int enableCntLimit;
+    unsigned int disableCnt;
+    unsigned int disableCntLimit;
+    unsigned int accSquareSum[2];
+    unsigned int accSquareMaxLimit;
+    unsigned int accSquareMinLimit;
+    unsigned char isLevelRotationCnt;
+    unsigned char isLevelCnt;
+    unsigned char notLevelCnt;
+    unsigned char isLevelCntLimit;
+    unsigned char levelRotationEnableCnt;
+    unsigned char levelRotationEnableCntLimit;
+    unsigned char levelDisableCnt;
+    unsigned char levelDisableCntLimit;
+    unsigned char autoBrightFromLevelFlag;
+    unsigned char lastStatus;
+    unsigned char backlightOffCnt;
+    unsigned char backlightOffCntSum;
+    unsigned char lightOnTimeCnt;
+    unsigned char lightOffTimeCnt;
+    int yzAngel;
+    int xzAngel;
+    int xzAngelLimitMin;
+    int xzAngelLimitMax;
+    int yzAngelLimitMin;
+    int yzAngelLimitMax;
+} Bright_Typedef, *pBright_Typedef;
+
+extern Bright_Typedef Bright_Structure;
+
+typedef struct {
+    unsigned char Sleep_End_Flag;
+    unsigned int  accSquareSum[20];
+    short int Acc[3][20];
+    int  SumX;
+    int  SumY;
+    int  SumZ;
+    int  SumX_Last;
+    int  SumY_Last;
+    int  SumZ_Last;
+    unsigned char Data_Cnt;
+    unsigned char A[5];
+    unsigned short int Minute_Cnt;
+} Sleep_Typedef, *pSleep_Typedef;
+
+extern Sleep_Typedef Sleep_Structure;
+
+void msa_param_init(void);
+unsigned int msa_step(short int x, short int y, short int z);
+unsigned char msa_light(short int x, short int y, short int z);
+int msa_sleep(short int x, short int y, short int z);
+void msa_step_clear(void);
+
+#endif  /*TCFG_MSA310_EN*/
+#endif  /*_MSA_APP_FIXPOINT_H*/
+
+/************************ (C) COPYRIGHT MEMSENSING *****END OF FILE****/

+ 97 - 0
apps/common/device/in_ear_detect/in_ear_manage.h

@@ -0,0 +1,97 @@
+#ifndef _IN_EAR_MANAGE_H
+#define _IN_EAR_MANAGE_H
+
+#include "typedef.h"
+
+#define INEAR_ANC_UI		 	0	//switch anc mode when in_out_ear
+
+enum {
+    EAR_DETECT_EVENT_NULL = 0,
+    EAR_DETECT_EVENT_IN,
+    EAR_DETECT_EVENT_OUT,
+    EAR_DETECT_EVENT_IN_DEAL,
+    EAR_DETECT_EVENT_OUT_DEAL,
+};
+
+enum {
+    MUSIC_STATE_NULL = 0,
+    MUSIC_STATE_PLAY, //音乐播放
+    MUSIC_STATE_PAUSE, //音乐暂停
+};
+
+enum {
+    CMD_EAR_DETECT_MUSIC_PLAY = 0,
+    CMD_EAR_DETECT_MUSIC_PAUSE,
+    CMD_EAR_DETECT_SCO_CONN,
+    CMD_EAR_DETECT_SCO_DCONN,
+};
+
+enum {
+    DETECT_IDLE = 0,
+    DETECT_CHECKING,
+};
+
+#define EAR_DETECT_BY_TOUCH     0  //触摸入耳
+#define EAR_DETECT_BY_IR     	1  //光感入耳
+
+struct ear_detect_platform_data {
+    u8 ear_det_music_ctl_en;				//音乐控制使能
+    u16 ear_det_music_ctl_ms;				//音乐暂停之后,入耳检测控制暂停播放的时间
+    u8 ear_det_in_music_sta;				// 0:入耳播歌  1:入耳不播歌
+    const u16 ear_det_key_delay_time;   	//入耳后按键起效时间ms ( 0 : OFF )
+    u8 ear_det_in_cnt; 						//戴上消抖
+    u8 ear_det_out_cnt;   					//拿下消抖
+    u16 ear_det_ir_enable_time; 			//使能时长
+    u16 ear_det_ir_disable_time;   			//休眠时长
+    u8 ear_det_ir_compensation_en;			//防太阳光干扰
+    u8 ear_det_music_play_cnt;       		//音乐播放检测时间
+    u8 ear_det_music_pause_cnt;    		    //音乐暂停检测时间
+};
+
+struct ear_detect_d {
+    u8 toggle        : 1; //入耳功能开关
+    u8 music_en      : 1;
+    u8 pre_music_sta : 2;
+    u8 pre_state     : 1;
+    u8 cur_state     : 1;
+    u8 tws_state     : 1;
+    u8 bt_init_ok    : 1;
+    u16 music_check_timer;
+    u16 music_sta_cnt;
+    u16 change_master_timer;
+    u16 key_enable_timer;
+    u8 key_delay_able;
+    //TCFG_EAR_DETECT_MUSIC_CTL_EN
+    u8 play_cnt;
+    u8 stop_cnt;
+    u16 music_ctl_timeout;
+    u16 a2dp_det_timer;
+    u8 music_regist_en;
+    //cfg
+    const struct ear_detect_platform_data *cfg;
+};
+
+struct ear_detect_t {
+    //TCFG_EAR_DETECT_TIMER_MODE
+    u8 is_idle;
+    u16 in_cnt;
+    u16 out_cnt;
+    u16 s_hi_timer;
+    volatile u8 check_status;
+    //cfg
+    const struct ear_detect_platform_data *cfg;
+};
+
+// ------------------- fun -----------
+extern void ear_detect_event_handle(u8 state);
+extern void ear_detect_phone_active_deal();
+extern void ear_detect_call_chg_master_deal();
+extern void ear_detect_change_master_timer_del();
+extern void tws_sync_ear_detect_state(u8 need_do);
+extern void ear_detect_init(const struct ear_detect_platform_data *cfg);
+extern void ear_detect_change_state_to_event(u8 state);
+extern u8 is_ear_detect_state_in(void);
+extern void ear_touch_edge_wakeup_handle(u8 index, u8 gpio);
+extern u8 ear_detect_get_key_delay_able(void);
+
+#endif

+ 157 - 0
apps/common/device/key/adkey.c

@@ -0,0 +1,157 @@
+#include "key_driver.h"
+#include "adkey.h"
+#include "gpio.h"
+#include "system/event.h"
+#include "app_config.h"
+
+
+#if TCFG_ADKEY_ENABLE
+
+static const struct adkey_platform_data *__this = NULL;
+
+u8 ad_get_key_value(void);
+//按键驱动扫描参数列表
+struct key_driver_para adkey_scan_para = {
+    .scan_time 	  	  = 10,				//按键扫描频率, 单位: ms
+    .last_key 		  = NO_KEY,  		//上一次get_value按键值, 初始化为NO_KEY;
+    .filter_time  	  = 2,				//按键消抖延时;
+    .long_time 		  = 75,  			//按键判定长按数量
+    .hold_time 		  = (75 + 15),  	//按键判定HOLD数量
+    .click_delay_time = 20,				//按键被抬起后等待连击延时数量
+    .key_type		  = KEY_DRIVER_TYPE_AD,
+    .get_value 		  = ad_get_key_value,
+};
+u8 ad_get_key_value(void)
+{
+    u8 i;
+    u16 ad_data;
+
+    if (!__this->enable) {
+        return NO_KEY;
+    }
+
+    /* ad_data = adc_get_voltage(__this->ad_channel); */
+    ad_data = adc_get_value(__this->ad_channel);
+    /* printf("ad_value = %d \n", ad_data); */
+    for (i = 0; i < ADKEY_MAX_NUM; i++) {
+        if ((ad_data <= __this->ad_value[i]) && (__this->ad_value[i] < 0x3ffL)) {
+            return __this->key_value[i];
+        }
+    }
+    return NO_KEY;
+}
+
+int adkey_init(const struct adkey_platform_data *adkey_data)
+{
+    __this = adkey_data;
+    if (!__this) {
+        return -EINVAL;
+    }
+
+    if (!__this->enable) {
+        return KEY_NOT_SUPPORT;
+    }
+    adc_add_sample_ch(__this->ad_channel);          //注意:初始化AD_KEY之前,先初始化ADC
+#if (TCFG_ADKEY_LED_IO_REUSE || TCFG_ADKEY_IR_IO_REUSE || TCFG_ADKEY_LED_SPI_IO_REUSE)
+#else
+    gpio_set_die(__this->adkey_pin, 0);
+    gpio_set_direction(__this->adkey_pin, 1);
+    gpio_set_pull_down(__this->adkey_pin, 0);
+    if (__this->extern_up_en) {
+        gpio_set_pull_up(__this->adkey_pin, 0);
+    } else {
+        gpio_set_pull_up(__this->adkey_pin, 1);
+    }
+#endif
+
+    return 0;
+}
+
+#if (TCFG_ADKEY_LED_IO_REUSE || TCFG_ADKEY_IR_IO_REUSE || TCFG_ADKEY_LED_SPI_IO_REUSE)
+
+#if TCFG_ADKEY_IR_IO_REUSE
+static u8 ir_io_sus = 0;
+extern u8 ir_io_suspend(void);
+extern u8 ir_io_resume(void);
+#endif
+#if TCFG_ADKEY_LED_IO_REUSE
+static u8 led_io_sus = 0;
+extern u8 led_io_suspend(void);
+extern u8 led_io_resume(void);
+#endif
+#if TCFG_ADKEY_LED_SPI_IO_REUSE
+static u8 led_spi_sus = 0;
+extern u8 led_spi_suspend(void);
+extern u8 led_spi_resume(void);
+#endif
+u8 adc_io_reuse_enter(u32 ch)
+{
+    if (ch == __this->ad_channel) {
+#if TCFG_ADKEY_IR_IO_REUSE
+        if (ir_io_suspend()) {
+            return 1;
+        } else {
+            ir_io_sus = 1;
+        }
+#endif
+#if TCFG_ADKEY_LED_IO_REUSE
+        if (led_io_suspend()) {
+            return 1;
+        } else {
+            led_io_sus = 1;
+        }
+#endif
+#if TCFG_ADKEY_LED_SPI_IO_REUSE
+        if (led_spi_suspend()) {
+            return 1;
+        } else {
+            led_spi_sus = 1;
+        }
+#endif
+        gpio_set_die(__this->adkey_pin, 0);
+        gpio_set_direction(__this->adkey_pin, 1);
+        gpio_set_pull_down(__this->adkey_pin, 0);
+        if (__this->extern_up_en) {
+            gpio_set_pull_up(__this->adkey_pin, 0);
+        } else {
+            gpio_set_pull_up(__this->adkey_pin, 1);
+        }
+    }
+    return 0;
+}
+
+u8 adc_io_reuse_exit(u32 ch)
+{
+    if (ch == __this->ad_channel) {
+#if TCFG_ADKEY_IR_IO_REUSE
+        if (ir_io_sus) {
+            ir_io_sus = 0;
+            ir_io_resume();
+        }
+#endif
+#if TCFG_ADKEY_LED_IO_REUSE
+        if (led_io_sus) {
+            led_io_sus = 0;
+            led_io_resume();
+        }
+#endif
+#if TCFG_ADKEY_LED_SPI_IO_REUSE
+        if (led_spi_sus) {
+            led_spi_sus = 0;
+            led_spi_resume();
+        }
+#endif
+    }
+    return 0;
+}
+
+#endif
+
+
+
+#endif  /* #if TCFG_ADKEY_ENABLE */
+
+
+
+
+

+ 61 - 0
apps/common/device/key/ctmu_touch_key.c

@@ -0,0 +1,61 @@
+#include "key_driver.h"
+#include "app_config.h"
+
+
+
+#if TCFG_CTMU_TOUCH_KEY_ENABLE
+#include "asm/ctmu.h"
+
+#define LOG_TAG_CONST       CTMU
+#define LOG_TAG             "[ctmu]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+/* =========== 触摸键使用说明 ============= */
+//1. 使用ctmu模块作计数;
+
+static const struct ctmu_touch_key_platform_data *__this = NULL;
+
+static u8 ctmu_touch_key_get_value(void);
+//按键驱动扫描参数列表
+struct key_driver_para ctmu_touch_key_scan_para = {
+    .scan_time 	  	  = 10,				//按键扫描频率, 单位: ms
+    .last_key 		  = NO_KEY,  		//上一次get_value按键值, 初始化为NO_KEY;
+    .filter_time  	  = 2,				//按键消抖延时;
+    .long_time 		  = 55,  			//按键判定长按数量
+    .hold_time 		  = (55 + 15),  	//按键判定HOLD数量
+    .click_delay_time = 40,				//按键被抬起后等待连击延时数量
+    .key_type		  = KEY_DRIVER_TYPE_CTMU_TOUCH,
+    .get_value 		  = ctmu_touch_key_get_value,
+};
+
+
+
+static u8 ctmu_touch_key_get_value(void)
+{
+    u8 key = get_ctmu_value();
+
+    if (key != NO_KEY) {
+        log_debug("key = %d %x", key, __this->port_list[key].key_value);
+        return __this->port_list[key].key_value;
+    }
+
+    return NO_KEY;
+}
+
+
+int ctmu_touch_key_init(const struct ctmu_touch_key_platform_data *ctmu_touch_key_data)
+{
+    __this = ctmu_touch_key_data;
+    log_info("ctmu touch_key_init >>>> ");
+
+    return ctmu_init((void *)ctmu_touch_key_data);
+}
+
+
+#endif  /* #if TCFG_CTMU_TOUCH_KEY_ENABLE */
+

+ 289 - 0
apps/common/device/key/iokey.c

@@ -0,0 +1,289 @@
+#include "key_driver.h"
+#include "iokey.h"
+#include "gpio.h"
+#include "system/event.h"
+#include "app_config.h"
+#include "asm/clock.h"
+
+#if TCFG_IOKEY_ENABLE
+
+static const struct iokey_platform_data *__this = NULL;
+
+u8 io_get_key_value(void);
+
+#if MOUSE_KEY_SCAN_MODE
+struct key_driver_para iokey_scan_para = {
+    .scan_time 	  	  = 5,				//按键扫描频率, 单位: ms
+    .last_key 		  = NO_KEY,  		//上一次get_value按键值, 初始化为NO_KEY;
+    .filter_time  	  = 2,				//按键消抖延时;
+    .long_time 		  = 5,  			//按键判定长按数量
+    .hold_time 		  = (5 + 0),   	//按键判定HOLD数量
+    .click_delay_time = 20,				//按键被抬起后等待连击延时数量
+    .key_type		  = KEY_DRIVER_TYPE_IO,
+    .get_value 		  = io_get_key_value,
+};
+#else
+//按键驱动扫描参数列表
+struct key_driver_para iokey_scan_para = {
+    .scan_time 	  	  = 10,				//按键扫描频率, 单位: ms
+    .last_key 		  = NO_KEY,  		//上一次get_value按键值, 初始化为NO_KEY;
+    .filter_time  	  = 4,				//按键消抖延时;
+    .long_time 		  = 75,  			//按键判定长按数量
+    .hold_time 		  = (75 + 15),  	//按键判定HOLD数量
+    .click_delay_time = 20,				//按键被抬起后等待连击延时数量
+    .key_type		  = KEY_DRIVER_TYPE_IO,
+    .get_value 		  = io_get_key_value,
+};
+#endif
+
+#define MARK_BIT_VALUE(b, v) 		do {if ((v & (~BIT(7))) < 7) b |= BIT(v & (~BIT(7)));} while(0)
+
+static void key_io_pull_down_input(u8 key_io)
+{
+    gpio_direction_input(key_io);
+    gpio_set_pull_down(key_io, 1);
+    gpio_set_pull_up(key_io, 0);
+    gpio_set_die(key_io, 1);
+}
+
+
+static void key_io_pull_up_input(u8 key_io)
+{
+    gpio_direction_input(key_io);
+    gpio_set_pull_down(key_io, 0);
+    gpio_set_pull_up(key_io, 1);
+    gpio_set_die(key_io, 1);
+}
+
+static void key_io_output_high(u8 key_io)
+{
+    gpio_set_pull_down(key_io, 0);
+    gpio_set_pull_up(key_io, 0);
+    gpio_direction_output(key_io, 1);
+}
+
+static void key_io_output_low(u8 key_io)
+{
+    gpio_set_pull_down(key_io, 0);
+    gpio_set_pull_up(key_io, 0);
+    gpio_direction_output(key_io, 0);
+}
+
+static int get_io_key_value(u8 key_io)
+{
+    return gpio_read(key_io);
+}
+
+
+static void key_io_reset(void)
+{
+    int i;
+
+    for (i = 0; i < __this->num; i++) {
+        switch (__this->port[i].connect_way) {
+        case ONE_PORT_TO_HIGH:
+            key_io_pull_down_input(__this->port[i].key_type.one_io.port);
+            break;
+
+        case ONE_PORT_TO_LOW:
+#if (TCFG_IO_MULTIPLEX_WITH_SD == ENABLE)
+            if (TCFG_MULTIPLEX_PORT != __this->port[i].key_type.one_io.port) {
+                key_io_pull_up_input(__this->port[i].key_type.one_io.port);
+            }
+#else
+
+            key_io_pull_up_input(__this->port[i].key_type.one_io.port);
+#endif
+            break;
+
+        case DOUBLE_PORT_TO_IO:
+            break;
+
+        default:
+            ASSERT(0, "IO KEY CONNECT ERR!!!");
+            break;
+        }
+    }
+}
+
+
+#if MULT_KEY_ENABLE
+extern const struct key_remap_data iokey_remap_data;
+static u8 iokey_value_remap(u8 bit_mark)
+{
+    for (int i = 0; i < iokey_remap_data.remap_num; i++) {
+        if (iokey_remap_data.table[i].bit_value == bit_mark) {
+            return iokey_remap_data.table[i].remap_value;
+        }
+    }
+
+    return NO_KEY;
+}
+#endif
+
+
+#if TCFG_IO_MULTIPLEX_WITH_SD == ENABLE
+static u8 mult_key_value = 1;
+/* extern const int set_to_close_timer0_delay; */
+static void udelay(u32 usec)
+{
+    /* if (set_to_close_timer0_delay) { */
+    /*     JL_MCPWM->MCPWM_CON0 &= ~BIT(8 + 3); */
+    /*     JL_MCPWM->TMR3_CNT = 0; */
+    /*     JL_MCPWM->TMR3_PR = clk_get("lsb") / 1000000 * usec; */
+    /*     JL_MCPWM->TMR3_CON = BIT(10) | BIT(0); */
+    /*     JL_MCPWM->MCPWM_CON0 |= BIT(8 + 3); */
+    /*     while (!(JL_MCPWM->TMR3_CON & BIT(12))); */
+    /*     JL_MCPWM->TMR3_CON = BIT(10); */
+    /*     JL_MCPWM->MCPWM_CON0 &= ~BIT(8 + 3); */
+    /* } else { */
+    JL_TIMER0->CON = BIT(14);
+    JL_TIMER0->CNT = 0;
+    JL_TIMER0->PRD = 16 * 1000000L / 1000000L  * usec; //1us
+    JL_TIMER0->CON = BIT(0); //sys clk
+    while ((JL_TIMER0->CON & BIT(15)) == 0);
+    JL_TIMER0->CON = BIT(14);
+    /* } */
+}
+extern u8 sd_io_suspend(u8 sdx, u8 sd_io);
+extern u8 sd_io_resume(u8 sdx, u8 sd_io);
+void sd_mult_io_detect(void *arg)
+{
+    static u32 cnt = 0;
+    if (sd_io_suspend(1, 1) == 0) {
+        gpio_set_direction(TCFG_MULTIPLEX_PORT, 0);
+        gpio_write(TCFG_MULTIPLEX_PORT, 0);
+        udelay(10);
+        gpio_set_die(TCFG_MULTIPLEX_PORT, 1);
+        gpio_set_pull_down(TCFG_MULTIPLEX_PORT, 0);
+        gpio_set_pull_up(TCFG_MULTIPLEX_PORT, 1);
+        gpio_set_direction(TCFG_MULTIPLEX_PORT, 1);
+        udelay(10);
+        mult_key_value = gpio_read(TCFG_MULTIPLEX_PORT);
+        sd_io_resume(1, 1);
+    }
+}
+#endif
+
+__attribute__((weak)) u8 iokey_filter_hook(u8 io_state)
+{
+    return 0;
+}
+
+u8 io_get_key_value(void)
+{
+    int i;
+
+    u8 press_value = 0;
+    u8 read_value = 0;
+    u8 read_io;
+    u8 write_io;
+    u8 connect_way;
+    u8 ret_value = NO_KEY;
+    u8 bit_mark = 0;
+
+    if (!__this->enable) {
+        return NO_KEY;
+    }
+
+    //先扫描单IO接按键方式
+    for (i = 0; i < __this->num; i++) {
+        connect_way = __this->port[i].connect_way;
+
+        if (connect_way == ONE_PORT_TO_HIGH) {
+            press_value = 1;
+        } else if (connect_way == ONE_PORT_TO_LOW) {
+            press_value = 0;
+        } else {
+            continue;
+        }
+
+        read_io = __this->port[i].key_type.one_io.port;
+
+#if (TCFG_IO_MULTIPLEX_WITH_SD == ENABLE)
+        if (read_io == TCFG_MULTIPLEX_PORT) {
+            read_value = mult_key_value;
+        } else {
+            read_value = get_io_key_value(read_io);
+        }
+#else
+        read_value = get_io_key_value(read_io);
+#endif
+        if (iokey_filter_hook(read_value)) {
+#ifdef TCFG_IOKEY_TIME_REDEFINE
+            extern struct key_driver_para iokey_scan_user_para;
+            iokey_scan_user_para.filter_cnt = 0;
+            iokey_scan_user_para.press_cnt = 0;
+            iokey_scan_user_para.click_cnt = 0;
+            iokey_scan_user_para.click_delay_cnt = 0;
+            iokey_scan_user_para.last_key = NO_KEY;
+#else
+            iokey_scan_para.filter_cnt = 0;
+            iokey_scan_para.press_cnt = 0;
+            iokey_scan_para.click_cnt = 0;
+            iokey_scan_para.click_delay_cnt = 0;
+            iokey_scan_para.last_key = NO_KEY;
+#endif
+            return NO_KEY;
+        }
+        if (read_value == press_value) {
+            ret_value = __this->port[i].key_value;
+#if MULT_KEY_ENABLE
+            MARK_BIT_VALUE(bit_mark, ret_value);  //标记被按下的按键
+#else
+            goto _iokey_get_value_end;
+#endif
+        }
+    }
+
+    //再扫描两个IO接按键方式, in_port: 上拉输入, out_port: 输出低
+    for (i = 0; i < __this->num; i++) {
+        connect_way = __this->port[i].connect_way;
+        if (connect_way == DOUBLE_PORT_TO_IO) {//标准双io
+            press_value = 0;
+            read_io = __this->port[i].key_type.two_io.in_port;
+            key_io_output_low(__this->port[i].key_type.two_io.out_port);  //输出低
+            key_io_pull_up_input(read_io); 	//上拉
+            read_value = get_io_key_value(read_io);
+            key_io_reset(); //按键初始化为单IO检测状态
+            if (read_value == press_value) {
+                ret_value = __this->port[i].key_value;
+#if MULT_KEY_ENABLE
+                MARK_BIT_VALUE(bit_mark, ret_value);	//标记被按下的按键
+#else
+                goto _iokey_get_value_end;
+#endif
+            }
+        }
+    }
+
+#if MULT_KEY_ENABLE
+    bit_mark = iokey_value_remap(bit_mark);  //组合按键重新映射按键值
+    ret_value = (bit_mark != NO_KEY) ? bit_mark : ret_value;
+#endif
+
+_iokey_get_value_end:
+    return ret_value;
+}
+
+
+
+int iokey_init(const struct iokey_platform_data *iokey_data)
+{
+    int i;
+
+    __this = iokey_data;
+    if (__this == NULL) {
+        return -EINVAL;
+    }
+    if (!__this->enable) {
+        return KEY_NOT_SUPPORT;
+    }
+
+    key_io_reset();
+
+    return 0;
+}
+
+#endif  /* #if TCFG_IOKEY_ENABLE */
+

+ 78 - 0
apps/common/device/key/irkey.c

@@ -0,0 +1,78 @@
+#include "key_driver.h"
+#include "irkey.h"
+#include "gpio.h"
+#include "asm/irflt.h"
+#include "app_config.h"
+
+#if TCFG_IRKEY_ENABLE
+
+u8 ir_get_key_value(void);
+//按键驱动扫描参数列表
+struct key_driver_para irkey_scan_para = {
+    .scan_time 	  	  = 10,				//按键扫描频率, 单位: ms
+    .last_key 		  = NO_KEY,  		//上一次get_value按键值, 初始化为NO_KEY;
+    .filter_time  	  = 2,				//按键消抖延时;
+    .long_time 		  = 75,  			//按键判定长按数量
+    .hold_time 		  = (75 + 15),  	//按键判定HOLD数量
+    .click_delay_time = 20,				//按键被抬起后等待连击延时数量
+    .key_type		  = KEY_DRIVER_TYPE_IR,
+    .get_value 		  = ir_get_key_value,
+};
+
+
+
+const u8 IRTabFF00[] = {
+    NKEY_00, NKEY_01, NKEY_02, NKEY_03, NKEY_04, NKEY_05, NKEY_06, IR_06, IR_15, IR_08, NKEY_0A, NKEY_0B, IR_12, IR_11, NKEY_0E, NKEY_0F,
+    NKEY_10, NKEY_11, NKEY_12, NKEY_13, NKEY_14, IR_07, IR_09, NKEY_17, IR_13, IR_10, NKEY_1A, NKEY_1B, IR_16, NKEY_1D, NKEY_1E, NKEY_1F,
+    NKEY_20, NKEY_21, NKEY_22, NKEY_23, NKEY_24, NKEY_25, NKEY_26, NKEY_27, NKEY_28, NKEY_29, NKEY_2A, NKEY_2B, NKEY_2C, NKEY_2D, NKEY_2E, NKEY_2F,
+    NKEY_30, NKEY_31, NKEY_32, NKEY_33, NKEY_34, NKEY_35, NKEY_36, NKEY_37, NKEY_38, NKEY_39, NKEY_3A, NKEY_3B, NKEY_3C, NKEY_3D, NKEY_3E, NKEY_3F,
+    IR_04, NKEY_41, IR_18, IR_05, IR_03, IR_00, IR_01, IR_02, NKEY_48, NKEY_49, IR_20, NKEY_4B, NKEY_4C, NKEY_4D, NKEY_4E, NKEY_4F,
+    NKEY_50, NKEY_51, IR_19, NKEY_53, NKEY_54, NKEY_55, NKEY_56, NKEY_57, NKEY_58, NKEY_59, IR_17, NKEY_5B, NKEY_5C, NKEY_5D, IR_14, NKEY_5F,
+};
+
+
+/*----------------------------------------------------------------------------*/
+/**@brief   获取ir按键值
+   @param   void
+   @param   void
+   @return  void
+   @note    void get_irkey_value(void)
+*/
+/*----------------------------------------------------------------------------*/
+u8 ir_get_key_value(void)
+{
+    u8 tkey = 0xff;
+    tkey = get_irflt_value();
+    if (tkey == 0xff) {
+        return tkey;
+    }
+    tkey = IRTabFF00[tkey];
+    return tkey;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**@brief   ir按键初始化
+   @param   void
+   @param   void
+   @return  void
+   @note    void ir_key_init(void)
+*/
+/*----------------------------------------------------------------------------*/
+int irkey_init(const struct irkey_platform_data *irkey_data)
+{
+    printf("irkey_init ");
+
+    ir_input_io_sel(irkey_data->port);
+
+    ir_output_timer_sel();
+
+    irflt_config();
+
+    ir_timeout_set();
+
+    return 0;
+}
+
+#endif
+

+ 506 - 0
apps/common/device/key/key_driver.c

@@ -0,0 +1,506 @@
+#include "device/key_driver.h"
+#include "system/event.h"
+#include "system/init.h"
+#include "iokey.h"
+#include "adkey.h"
+#include "slidekey.h"
+#include "irkey.h"
+#include "touch_key.h"
+#include "system/timer.h"
+#include "asm/power_interface.h"
+#include "app_config.h"
+#include "rdec_key.h"
+#include "tent600_key.h"
+#if TCFG_KEY_TONE_EN
+#include "tone_player.h"
+#endif
+
+#if(TCFG_IRSENSOR_ENABLE == 1)
+#include "irSensor/ir_manage.h"
+#endif
+
+#define LOG_TAG_CONST       KEY
+#define LOG_TAG             "[KEY]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+//#define LOG_DUMP_ENABLE
+//#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define KEY_EVENT_CLICK_ONLY_SUPPORT	1 	//是否支持某些按键只响应单击事件
+
+
+#if TCFG_SPI_LCD_ENABLE
+#ifndef ALL_KEY_EVENT_CLICK_ONLY
+#define ALL_KEY_EVENT_CLICK_ONLY	1 	//是否全部按键只响应单击事件
+#endif
+#else
+#ifndef ALL_KEY_EVENT_CLICK_ONLY
+#define ALL_KEY_EVENT_CLICK_ONLY	0 	//是否全部按键只响应单击事件
+#endif
+#endif
+
+static volatile u8 is_key_active = 0;
+static volatile u8 key_poweron_flag = 0;
+
+extern u32 timer_get_ms(void);
+
+//=======================================================//
+// 按键值重新映射函数:
+// 用户可以实现该函数把一些按键值重新映射, 可用于组合键的键值重新映射
+//=======================================================//
+int __attribute__((weak)) key_event_remap(struct sys_event *e)
+{
+    return true;
+}
+
+//=======================================================//
+// 设置按键开机标志位
+//=======================================================//
+void set_key_poweron_flag(u8 flag)
+{
+    key_poweron_flag = flag;
+}
+
+//=======================================================//
+// 获取按键开机标志位
+//=======================================================//
+u8 get_key_poweron_flag(void)
+{
+    return key_poweron_flag;
+}
+
+//=======================================================//
+// 清除按键开机标志位
+//=======================================================//
+void clear_key_poweron_flag(void)
+{
+    key_poweron_flag = 0;
+}
+
+#if TCFG_SOFTOFF_WAKEUP_KEY_DRIVER_ENABLE
+static u8 key_scan_flag = 0, en_key_cnt = 0, en_key_cnt_flag = 1, nonsrc_wakeup_flag = 0, save_notify_flag = 0, key_wk_send_flag = 0;
+struct sys_event e_tmp;
+//=======================================================//
+// 清除保存的key_notify
+//=======================================================//
+void clear_save_key_notify(void)
+{
+    save_notify_flag = 0;
+    memset(&e_tmp, 0, sizeof(struct sys_event));
+}
+//=======================================================//
+// 设置软关机按键唤醒补充发键标志位
+//=======================================================//
+void set_key_wakeup_send_flag(u8 flag)
+{
+    key_wk_send_flag = flag;
+    if (save_notify_flag) {
+        sys_event_notify(&e_tmp);
+        clear_save_key_notify();
+    }
+}
+
+//=======================================================//
+// 获取软关机按键唤醒补充发键标志位
+//=======================================================//
+u8 get_key_wakeup_send_flag(void)
+{
+    return key_wk_send_flag;
+}
+
+//=======================================================//
+// 保存未初始化按键消息前推送的按键notify
+//=======================================================//
+void save_wakeup_key_notify(struct sys_event *event)
+{
+    save_notify_flag = 1;
+
+    e_tmp.type = event->type;
+    e_tmp.arg  = event->arg;
+    e_tmp.u.key.init  = event->u.key.init;
+    e_tmp.u.key.type  = event->u.key.type;
+    e_tmp.u.key.event = event->u.key.event;
+    e_tmp.u.key.value = event->u.key.value;
+    e_tmp.u.key.tmr   = event->u.key.tmr;
+}
+#endif
+
+//=======================================================//
+// 按键扫描函数: 扫描所有注册的按键驱动
+//=======================================================//
+static void key_driver_scan(void *_scan_para)
+{
+    struct key_driver_para *scan_para = (struct key_driver_para *)_scan_para;
+
+    u8 key_event = 0;
+    u8 cur_key_value = NO_KEY;
+    u8 key_value = 0;
+    struct sys_event e;
+    static u8 poweron_cnt = 0;
+
+    //为了滤掉adkey与mic连在一起时电容充放电导致的开机按键误判,一般用于type-c耳机
+    /* if (poweron_cnt <= 250) { */
+    /*     poweron_cnt++; */
+    /*     return; */
+    /* } */
+
+    cur_key_value = scan_para->get_value();
+    /* if (cur_key_value != NO_KEY) { */
+    /*     printf(">>>cur_key_value: %d\n", cur_key_value); */
+    /* } */
+
+#if TCFG_SOFTOFF_WAKEUP_KEY_DRIVER_ENABLE
+    u8 wkup_src = get_wakeup_pnd();
+
+    //按键唤醒后若未按下第二击,推出单击事件
+    //key_driver初始化后未扫描到按键
+    if (key_wk_send_flag && key_scan_flag == 0) {
+        key_scan_flag = 1;
+        //记住唤醒源——识别NO_KEY时的键值
+        if (cur_key_value == NO_KEY) {
+            if (wkup_src == TCFG_WAKEUP_PORT_POWER_SRC) { //唤醒口port1
+                key_value = TCFG_IOKEY_POWER_ONE_PORT_VALUE;
+            } else if (wkup_src == TCFG_WAKEUP_PORT_PREV_SRC) { //唤醒口port2
+                key_value = TCFG_IOKEY_PREV_ONE_PORT_VALUE;
+            } else if (wkup_src == TCFG_WAKEUP_PORT_NEXT_SRC) { //唤醒口port3
+                key_value = TCFG_IOKEY_NEXT_ONE_PORT_VALUE;
+            } else {
+                nonsrc_wakeup_flag = 1;
+                printf("wakeup source err is 0x%x !!!", wkup_src);
+                return;
+            }
+            key_event = KEY_EVENT_CLICK;  //单击
+            goto _notify;
+        }
+        //初始化后扫描到了按键,但是未满足key_driver的单击事件推出,补充推出消息
+    } else if (en_key_cnt && en_key_cnt <= (scan_para->filter_time + 1) && key_scan_flag == 1 && en_key_cnt_flag == 0) {
+        en_key_cnt = 0;
+        key_scan_flag = 0;
+    }
+
+    if (cur_key_value == NO_KEY) {
+        en_key_cnt_flag = 0;
+    } else {
+        key_scan_flag = 1;
+        if (en_key_cnt_flag) {
+            en_key_cnt++;
+        }
+    }
+#endif
+
+    if (cur_key_value != NO_KEY) {
+        is_key_active = 35;      //35*10Ms
+    } else if (is_key_active) {
+        is_key_active --;
+    }
+//===== 按键消抖处理
+    if (cur_key_value != scan_para->filter_value && scan_para->filter_time) {	//当前按键值与上一次按键值如果不相等, 重新消抖处理, 注意filter_time != 0;
+        scan_para->filter_cnt = 0; 		//消抖次数清0, 重新开始消抖
+        scan_para->filter_value = cur_key_value;	//记录上一次的按键值
+        return; 		//第一次检测, 返回不做处理
+    } 		//当前按键值与上一次按键值相等, filter_cnt开始累加;
+    if (scan_para->filter_cnt < scan_para->filter_time) {
+        scan_para->filter_cnt++;
+        return;
+    }
+    //为了滤掉adkey与mic连在一起时电容充放电导致的按键误判,一般用于type-c耳机
+    /* if ((cur_key_value != scan_para->last_key) && (scan_para->last_key != NO_KEY) && (cur_key_value != NO_KEY)) { */
+    /*     return; */
+    /* } */
+//===== 按键消抖结束, 开始判断按键类型(单击, 双击, 长按, 多击, HOLD, (长按/HOLD)抬起)
+    if (cur_key_value != scan_para->last_key) {
+        if (cur_key_value == NO_KEY) {  //cur_key = NO_KEY; last_key = valid_key -> 按键被抬起
+
+#if MOUSE_KEY_SCAN_MODE
+            /* if (scan_para->press_cnt >= scan_para->long_time) {  //长按/HOLD状态之后被按键抬起; */
+            key_event = KEY_EVENT_UP;
+            key_value = scan_para->last_key;
+            goto _notify;  	//发送抬起消息
+            /* } */
+#else
+#if TCFG_SOFTOFF_WAKEUP_KEY_DRIVER_ENABLE
+            if (scan_para->press_cnt >= (scan_para->long_time - TCFG_LONGKEY_SUPPLEMENT_TIME))  //长按/HOLD状态之后被按键抬起, 补充长按时间;
+#else
+            if (scan_para->press_cnt >= scan_para->long_time)  //长按/HOLD状态之后被按键抬起;
+#endif
+            {
+                key_event = KEY_EVENT_UP;
+                key_value = scan_para->last_key;
+                goto _notify;  	//发送抬起消息
+            }
+#endif
+
+            scan_para->click_delay_cnt = 1;  //按键等待下次连击延时开始
+        } else {  //cur_key = valid_key, last_key = NO_KEY -> 按键被按下
+            scan_para->press_cnt = 1;  //用于判断long和hold事件的计数器重新开始计时;
+            if (cur_key_value != scan_para->notify_value) {  //第一次单击/连击时按下的是不同按键, 单击次数重新开始计数
+#if TCFG_SOFTOFF_WAKEUP_KEY_DRIVER_ENABLE
+                if ((en_key_cnt > scan_para->filter_time && en_key_cnt < scan_para->long_time) || key_wk_send_flag || nonsrc_wakeup_flag) {
+                    scan_para->click_cnt = 1;
+                } else {
+                    scan_para->click_cnt = 2;
+                }
+#else
+                scan_para->click_cnt = 1;
+#endif
+                scan_para->notify_value = cur_key_value;
+            } else {
+                scan_para->click_cnt++;  //单击次数累加
+            }
+        }
+        goto _scan_end;  //返回, 等待延时时间到
+    } else { 	//cur_key = last_key -> 没有按键按下/按键长按(HOLD)
+        if (cur_key_value == NO_KEY) {  //last_key = NO_KEY; cur_key = NO_KEY -> 没有按键按下
+            if (scan_para->click_cnt > 0) {  //有按键需要消息需要处理
+
+#if ALL_KEY_EVENT_CLICK_ONLY//彩屏方案支持单击
+                key_event = KEY_EVENT_CLICK;  //单击
+                key_value = scan_para->notify_value;
+                goto _notify;
+
+#endif
+
+#if KEY_EVENT_CLICK_ONLY_SUPPORT 	//是否支持某些按键只响应单击事件
+                if (scan_para->notify_value & BIT(7)) {  //BIT(7)按键特殊处理标志, 只发送单击事件, 也可以用于其它扩展
+                    key_event = KEY_EVENT_CLICK;  //单击
+                    key_value = scan_para->notify_value;
+                    goto _notify;
+                }
+#endif
+                if (scan_para->click_delay_cnt > scan_para->click_delay_time) { //按键被抬起后延时到
+                    //TODO: 在此可以添加任意多击事件
+                    if (scan_para->click_cnt >= 5) {
+                        key_event = KEY_EVENT_FIRTH_CLICK;  //五击
+                    } else if (scan_para->click_cnt >= 4) {
+                        key_event = KEY_EVENT_FOURTH_CLICK;  //4击
+                    } else if (scan_para->click_cnt >= 3) {
+                        key_event = KEY_EVENT_TRIPLE_CLICK;  //三击
+                    } else if (scan_para->click_cnt >= 2) {
+                        key_event = KEY_EVENT_DOUBLE_CLICK;  //双击
+                    } else {
+                        key_event = KEY_EVENT_CLICK;  //单击
+                    }
+                    key_value = scan_para->notify_value;
+                    goto _notify;
+                } else {	//按键抬起后等待下次延时时间未到
+                    scan_para->click_delay_cnt++;
+                    goto _scan_end; //按键抬起后延时时间未到, 返回
+                }
+            } else {
+                goto _scan_end;  //没有按键需要处理
+            }
+        } else {  //last_key = valid_key; cur_key = valid_key, press_cnt累加用于判断long和hold
+            scan_para->press_cnt++;
+#if TCFG_SOFTOFF_WAKEUP_KEY_DRIVER_ENABLE
+            if (scan_para->press_cnt == (scan_para->long_time - TCFG_LONGKEY_SUPPLEMENT_TIME))
+#else
+            if (scan_para->press_cnt == scan_para->long_time)
+#endif
+            {
+                key_event = KEY_EVENT_LONG;
+            } else if (scan_para->press_cnt == scan_para->hold_time) {
+                key_event = KEY_EVENT_HOLD;
+                scan_para->press_cnt = scan_para->long_time;
+            } else {
+                goto _scan_end;  //press_cnt没到长按和HOLD次数, 返回
+            }
+            //press_cnt没到长按和HOLD次数, 发消息
+            key_value = cur_key_value;
+            goto _notify;
+        }
+    }
+
+_notify:
+#if TCFG_IRSENSOR_ENABLE
+    if (get_irSensor_event() == IR_SENSOR_EVENT_FAR) {  //未佩戴的耳机不响应按键
+        return;
+    }
+#endif
+    key_value &= ~BIT(7);  //BIT(7) 用作按键特殊处理的标志
+    e.type = SYS_KEY_EVENT;
+    e.u.key.init = 1;
+    e.u.key.type = scan_para->key_type;//区分按键类型
+    e.u.key.event = key_event;
+    e.u.key.value = key_value;
+    e.u.key.tmr = timer_get_ms();
+
+
+    scan_para->click_cnt = 0;  //单击次数清0
+    scan_para->notify_value = NO_KEY;
+
+    e.arg  = (void *)DEVICE_EVENT_FROM_KEY;
+    /* printf("key_value: 0x%x, event: %d, key_poweron_flag: %d\n", key_value, key_event, key_poweron_flag); */
+    if (key_poweron_flag) {
+        if (key_event == KEY_EVENT_UP) {
+            clear_key_poweron_flag();
+            return;
+        }
+        return;
+    }
+    if (key_event_remap(&e)) {
+#if TCFG_SOFTOFF_WAKEUP_KEY_DRIVER_ENABLE
+        if (key_wk_send_flag) {
+            sys_event_notify(&e);
+        } else {
+            save_wakeup_key_notify(&e);
+        }
+        nonsrc_wakeup_flag = 0;
+#else
+        sys_event_notify(&e);
+#endif
+
+#if TCFG_KEY_TONE_EN
+        audio_key_tone_play();
+#endif
+    }
+_scan_end:
+    scan_para->last_key = cur_key_value;
+    return;
+}
+
+
+//wakeup callback
+void key_active_set(u8 port)
+{
+    /*要用按键宏包住,不用按键功能,唤醒后就再也不进睡眠*/
+#if (TCFG_IOKEY_ENABLE || TCFG_ADKEY_ENABLE || TCFG_TOUCH_KEY_ENABLE)
+    is_key_active = 35;      //35*10Ms
+#endif
+}
+
+//=======================================================//
+// 按键初始化函数: 初始化所有注册的按键驱动
+//=======================================================//
+int key_driver_init(void)
+{
+    int err;
+
+#if TCFG_IOKEY_ENABLE
+    extern const struct iokey_platform_data iokey_data;
+    extern struct key_driver_para iokey_scan_para;
+    err = iokey_init(&iokey_data);
+#ifdef TCFG_IOKEY_TIME_REDEFINE
+    extern struct key_driver_para iokey_scan_user_para;
+    if (err == 0) {
+        sys_s_hi_timer_add((void *)&iokey_scan_user_para, key_driver_scan, iokey_scan_user_para.scan_time); //注册按键扫描定时器
+    }
+#else
+    if (err == 0) {
+        sys_s_hi_timer_add((void *)&iokey_scan_para, key_driver_scan, iokey_scan_para.scan_time); //注册按键扫描定时器
+    }
+#endif
+#endif
+
+#if TCFG_ADKEY_ENABLE
+#ifdef CONFIG_ICRECORDER_CASE_ENABLE
+    extern multi_adkey_init(const struct adkey_platform_data * multi_adkey_data);
+    extern const struct adkey_platform_data multi_adkey_data[];
+    extern struct key_driver_para multi_adkey_scan_para;
+    err = multi_adkey_init(multi_adkey_data);
+    if (err == 0) {
+        sys_s_hi_timer_add((void *)&multi_adkey_scan_para, key_driver_scan, multi_adkey_scan_para.scan_time); //注册按键扫描定时器
+    }
+#else
+    extern const struct adkey_platform_data adkey_data;
+    extern struct key_driver_para adkey_scan_para;
+    err = adkey_init(&adkey_data);
+    if (err == 0) {
+        sys_s_hi_timer_add((void *)&adkey_scan_para, key_driver_scan, adkey_scan_para.scan_time); //注册按键扫描定时器
+    }
+#endif
+#endif
+
+#if TCFG_IRKEY_ENABLE
+    extern const struct irkey_platform_data irkey_data;
+    extern struct key_driver_para irkey_scan_para;
+    err = irkey_init(&irkey_data);
+    if (err == 0) {
+        sys_s_hi_timer_add((void *)&irkey_scan_para, key_driver_scan, irkey_scan_para.scan_time); //注册按键扫描定时器
+    }
+#endif
+
+#if TCFG_TOUCH_KEY_ENABLE
+    extern const struct touch_key_platform_data touch_key_data;
+    extern struct key_driver_para touch_key_scan_para;
+    err = touch_key_init(&touch_key_data);
+    if (err == 0) {
+        sys_s_hi_timer_add((void *)&touch_key_scan_para, key_driver_scan, touch_key_scan_para.scan_time); //注册按键扫描定时器
+    }
+#endif
+
+#if TCFG_ADKEY_RTCVDD_ENABLE
+    extern const struct adkey_rtcvdd_platform_data adkey_rtcvdd_data;
+    extern struct key_driver_para adkey_rtcvdd_scan_para;
+    err = adkey_rtcvdd_init(&adkey_rtcvdd_data);
+    if (err == 0) {
+        sys_s_hi_timer_add((void *)&adkey_rtcvdd_scan_para, key_driver_scan, adkey_rtcvdd_scan_para.scan_time); //注册按键扫描定时器
+    }
+#endif
+
+#if TCFG_RDEC_KEY_ENABLE
+    extern const struct rdec_platform_data rdec_key_data;
+    extern struct key_driver_para rdec_key_scan_para;
+    err = rdec_key_init(&rdec_key_data);
+    if (err == 0) {
+        sys_s_hi_timer_add((void *)&rdec_key_scan_para, key_driver_scan, rdec_key_scan_para.scan_time); //注册按键扫描定时器
+    }
+#endif
+
+#if TCFG_CTMU_TOUCH_KEY_ENABLE
+#include "asm/ctmu.h"
+    extern const struct ctmu_touch_key_platform_data ctmu_touch_key_data;
+    extern struct key_driver_para ctmu_touch_key_scan_para;
+    extern int ctmu_touch_key_init(const struct ctmu_touch_key_platform_data * ctmu_touch_key_data);
+    err = ctmu_touch_key_init(&ctmu_touch_key_data);
+    if (err == 0) {
+        sys_s_hi_timer_add((void *)&ctmu_touch_key_scan_para, key_driver_scan, ctmu_touch_key_scan_para.scan_time); //注册按键扫描定时器
+    }
+#endif /* #if TCFG_CTMU_TOUCH_KEY_ENABLE */
+
+#if TCFG_SLIDE_KEY_ENABLE
+    extern const struct slidekey_platform_data slidekey_data;
+    extern int slidekey_init(const struct slidekey_platform_data * slidekey_data);
+    err = slidekey_init(&slidekey_data);
+    if (err == 0) {
+    }
+#endif//TCFG_SLIDE_KEY_ENABLE
+
+#if TCFG_6083_ADKEY_ENABLE
+    extern int adkey_init_6083();
+    err = adkey_init_6083();
+    if (err == 0) {
+    }
+#endif
+#if TCFG_TENT600_KEY_ENABLE
+    extern const struct tent600_key_platform_data key_data ;
+    extern struct key_driver_para tent600_key_scan_para;
+    err = tent600_key_init(&key_data);
+    if (err == 0) {
+        sys_s_hi_timer_add((void *)&tent600_key_scan_para, key_driver_scan, tent600_key_scan_para.scan_time); //注册按键扫描定时器
+    }
+#endif
+
+    return 0;
+}
+
+static u8 key_idle_query(void)
+{
+    return !is_key_active;
+}
+#if ((!TCFG_LP_TOUCH_KEY_ENABLE) && (TCFG_IOKEY_ENABLE || TCFG_ADKEY_ENABLE))
+REGISTER_LP_TARGET(key_lp_target) = {
+    .name = "key",
+    .is_idle = key_idle_query,
+};
+#endif /* #if !TCFG_LP_TOUCH_KEY_ENABLE */
+
+#if (TCFG_SOFTOFF_WAKEUP_KEY_DRIVER_ENABLE && TCFG_IOKEY_ENABLE)
+//默认0,按键消息使能后置1,避免(软关机唤醒——发送按键消息)这段时间进入睡眠状态
+REGISTER_LP_TARGET(softoff_wake_key) = {
+    .name = "softoff_wake_key",
+    .is_idle = get_key_wakeup_send_flag,
+};
+#endif
+

+ 351 - 0
apps/common/device/key/matrix_keyboard.c

@@ -0,0 +1,351 @@
+#include "matrix_keyboard.h"
+#include "key_driver.h"
+#include "gpio.h"
+#include "system/event.h"
+#include "app_config.h"
+#include "timer.h"
+#include "asm/power_interface.h"
+#include "asm/power/p33.h"
+
+#if TCFG_MATRIX_KEY_ENABLE && !TCFG_EX_MCU_ENABLE
+#define MATRIX_NO_KEY           0x1         //没有按键时的IO电平
+#define MATRIX_LONG_TIME        35
+#define MATRIX_HOLD_TIME        35+10
+#define MATRIX_KEY_FILTER_TIME  2
+
+int (*matrix_key_data_send)(u8 report_id, u8 *data, u16 len) = NULL;
+
+static volatile u8 is_key_active = 0;
+static volatile u8 keep_wakeup_hold = 0;
+static int matrix_key_wakeup_hold_timer = 0;
+static int matrix_key_timer = 0;
+static matrix_key_st key_st[ROW_MAX][COL_MAX];
+static matrix_key_param *this = NULL;
+
+u8 notify_key_array[8] = {0};
+u8 key_map[COL_MAX] = {0};
+static u16 key_status_array[6] = {0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
+
+
+static void full_key_array(u8 row, u8 col, u8 st)
+{
+    u8 offset = 0;
+    u8 mark = 0, mark_offset = 0;
+    //最多推6个按键出来,如果需要推多个按键需要自行修改,每个u16 低八位标识row 高八位标识col
+    u16 key_value = (row | col << 8);
+    for (offset = 0; offset < sizeof(key_status_array) / sizeof(u16); offset++) {
+        if (key_status_array[offset] == key_value && st == MATRIX_KEY_UP) {         //找到列表中有当前按键且按键状态抬起,则将按键移除列表
+            mark = 1;                                                               //记录相同键值所在位置
+            mark_offset = offset;
+            if (mark_offset == sizeof(key_status_array) / sizeof(u16) - 1) {
+                key_status_array[mark_offset] = 0xffff;
+                break;
+            }
+        } else if (key_status_array[offset] == 0xffff) {
+            if (mark) {
+                memcpy(key_status_array + mark_offset, key_status_array + mark_offset + 1, (offset - mark_offset - 1) * 2);
+                key_status_array[offset - 1] = 0xffff;
+            } else if (st == MATRIX_KEY_SHORT) {                                    //需要状态为短按才会把键值填充到数组中,防止按键满了之后把抬起也填充进去
+                key_status_array[offset] = key_value;
+            }
+            break;
+        } else if (mark && (offset == sizeof(key_status_array) / sizeof(u16) - 1)) {
+            memcpy(key_status_array + mark_offset, key_status_array + mark_offset + 1, (sizeof(key_status_array) / sizeof(u16) - mark_offset - 1) * 2);
+            key_status_array[sizeof(key_status_array) / sizeof(u16) - 1] = 0xffff;
+            break;
+        }
+    }
+}
+
+
+void full_key_map(u8 row, u8 col, u8 st)
+{
+    if (st) {
+        key_map[col] |= BIT(row);
+    } else {
+        key_map[col] &= ~BIT(row);
+    }
+}
+
+void P33_AND_WKUP_EDGE(u8 data);
+void P33_OR_WKUP_EDGE(u8 data);
+
+enum {
+    IO_STATUS_HIGH_DRIVER = 0,
+    IO_STATUS_OUTPUT_HIGH,
+    IO_STATUS_OUTPUT_LOW,
+    IO_STATUS_INPUT_PULL_DOWN,
+    IO_STATUS_INPUT_PULL_UP,
+};
+
+void matrix_key_set_io_state(u8 state, u32 *io_table, u8 len)
+{
+    u8 i = 0;
+    u32 porta_value = 0;
+    u32 portb_value = 0;
+    u32 portc_value = 0;
+    u32 portd_value = 0;
+
+    for (; i < len; i++) {
+        switch (io_table[i] / IO_GROUP_NUM) {
+        case 0: //JL_PORTA
+            porta_value |= BIT(io_table[i] % IO_GROUP_NUM);
+            break;
+        case 1: //JL_PORTB
+            portb_value |= BIT(io_table[i] % IO_GROUP_NUM);
+            break;
+        case 2: //JL_PORTC
+            portc_value |= BIT(io_table[i] % IO_GROUP_NUM);
+            break;
+        case 3: //JL_PORTD
+            portd_value |= BIT(io_table[i] % IO_GROUP_NUM);
+            break;
+        default://USB
+
+            break;
+        }
+    }
+    switch (state) {
+    case IO_STATUS_HIGH_DRIVER:
+        JL_PORTA->DIR |= porta_value;
+        JL_PORTA->DIE |= porta_value;
+        JL_PORTA->PU &= ~porta_value;
+        JL_PORTA->PD &= ~porta_value;
+        JL_PORTB->DIR |= portb_value;
+        JL_PORTB->DIE |= portb_value;
+        JL_PORTB->PU &= ~portb_value;
+        JL_PORTB->PD &= ~portb_value;
+        JL_PORTC->DIR |= portc_value;
+        JL_PORTC->DIE |= portc_value;
+        JL_PORTC->PU &= ~portc_value;
+        JL_PORTC->PD &= ~portc_value;
+        JL_PORTD->DIR |= portd_value;
+        JL_PORTD->DIE |= portd_value;
+        JL_PORTD->PU &= ~portd_value;
+        JL_PORTD->PD &= ~portd_value;
+        break;
+    case IO_STATUS_OUTPUT_HIGH:
+        JL_PORTA->DIR &= ~porta_value;
+        JL_PORTA->OUT |= porta_value;
+        JL_PORTB->DIR &= ~portb_value;
+        JL_PORTB->OUT |= portb_value;
+        JL_PORTC->DIR &= ~portc_value;
+        JL_PORTC->OUT |= portc_value;
+        JL_PORTD->DIR &= ~portd_value;
+        JL_PORTD->OUT |= portd_value;
+        break;
+    case IO_STATUS_OUTPUT_LOW:
+        JL_PORTA->DIR &= ~porta_value;
+        JL_PORTA->OUT &= ~porta_value;
+        JL_PORTB->DIR &= ~portb_value;
+        JL_PORTB->OUT &= ~portb_value;
+        JL_PORTC->DIR &= ~portc_value;
+        JL_PORTC->OUT &= ~portc_value;
+        JL_PORTD->DIR &= ~portd_value;
+        JL_PORTD->OUT &= ~portd_value;
+        break;
+    case IO_STATUS_INPUT_PULL_DOWN:
+        JL_PORTA->DIR |= porta_value;
+        JL_PORTA->DIE |= porta_value;
+        JL_PORTA->PU  &= ~porta_value;
+        JL_PORTA->PD  |= porta_value;
+        JL_PORTB->DIR |= portb_value;
+        JL_PORTB->DIE |= portb_value;
+        JL_PORTB->PU  &= ~portb_value;
+        JL_PORTB->PD  |= portb_value;
+        JL_PORTC->DIR |= portc_value;
+        JL_PORTC->DIE |= portc_value;
+        JL_PORTC->PU  &= ~portc_value;
+        JL_PORTC->PD  |= portc_value;
+        JL_PORTD->DIR |= portd_value;
+        JL_PORTD->DIE |= portd_value;
+        JL_PORTD->PU  &= ~portd_value;
+        JL_PORTD->PD  |= portd_value;
+        break;
+    case IO_STATUS_INPUT_PULL_UP:
+        JL_PORTA->DIR |= porta_value;
+        JL_PORTA->DIE |= porta_value;
+        JL_PORTA->PU  |= porta_value;
+        JL_PORTA->PD  &= ~porta_value;
+        JL_PORTB->DIR |= portb_value;
+        JL_PORTB->DIE |= portb_value;
+        JL_PORTB->PU  |= portb_value;
+        JL_PORTB->PD  &= ~portb_value;
+        JL_PORTC->DIR |= portc_value;
+        JL_PORTC->DIE |= portc_value;
+        JL_PORTC->PU  |= portc_value;
+        JL_PORTC->PD  &= ~portc_value;
+        JL_PORTD->DIR |= portd_value;
+        JL_PORTD->DIE |= portd_value;
+        JL_PORTD->PU  |= portd_value;
+        JL_PORTD->PD  &= ~portd_value;
+        break;
+    }
+}
+
+#if 1
+void port_edge_wakeup_control(u16 data);
+void matrix_key_scan(void)
+{
+
+    u8 row, col;
+    u8 cur_key_value = MATRIX_NO_KEY, notify = 0;
+    static u8 wk_toggle = 0;
+
+    //g_printf("scan...\n");
+    //P33_LEVEL_WKUP_EN(0);
+    port_edge_wakeup_control(0);
+    //p33_tx_1byte(P3_WKUP_EN, 0);        //关掉wakeup防止扫描过程一直唤醒
+
+    //不直接调用gpio.c的接口主要是由于想控制扫描时间。这样能把时间从1.8ms缩减到800us
+    matrix_key_set_io_state(IO_STATUS_HIGH_DRIVER, this->col_pin_list, this->col_num);
+
+    is_key_active = 0;
+    for (col = 0; col < this->col_num; col ++) {
+        matrix_key_set_io_state((MATRIX_NO_KEY) ? IO_STATUS_OUTPUT_LOW : IO_STATUS_OUTPUT_HIGH, &(this->col_pin_list[col]), 1);
+        //gpio_direction_output(this->col_pin_list[col], !MATRIX_NO_KEY);
+        for (row = 0; row < this->row_num; row ++) {
+            cur_key_value = gpio_read(this->row_pin_list[row]);
+            if (cur_key_value != MATRIX_NO_KEY) {
+                is_key_active = 1;
+            }
+            if (cur_key_value != (key_st[row][col]).last_st) {
+                if (cur_key_value == MATRIX_NO_KEY) { //按键抬起判断
+                    (key_st[row][col]).press_cnt = 0;
+                    //printf("row:%d  col:%d   [UP]\n", row, col);
+                    (MATRIX_NO_KEY) ? P33_OR_WKUP_EDGE(row) : P33_AND_WKUP_EDGE(row);
+                    //P33_AND_WKUP_EDGE(row);
+                    full_key_map(row, col, 0);
+                    notify = 1;
+                } else {            //按键初次按下
+                    printf("row:%d  col:%d   [SHORT]\n", row, col);
+                    full_key_map(row, col, 1);
+                    (MATRIX_NO_KEY) ? P33_AND_WKUP_EDGE(row) : P33_OR_WKUP_EDGE(row);
+                    //P33_OR_WKUP_EDGE(row);
+                    notify = 1;
+                }
+            } else {        //判断是否按键抬起
+                if (cur_key_value != MATRIX_NO_KEY) {
+                    (key_st[row][col]).press_cnt ++;
+                    if ((key_st[row][col]).press_cnt == MATRIX_LONG_TIME) {
+                        /* printf("row:%d  col:%d   [LONG]\n", row, col);     */
+                    } else if ((key_st[row][col]).press_cnt == MATRIX_HOLD_TIME) {
+                        /* printf("row:%d  col:%d   [HOLD]\n", row, col);     */
+                        (key_st[row][col]).press_cnt = MATRIX_LONG_TIME;
+                    } else {
+                        //press_cnt还未累加够
+                    }
+                }
+            }
+            (key_st[row][col]).last_st = cur_key_value;
+        }
+        //gpio_direction_input(this->col_pin_list[col]);
+        matrix_key_set_io_state(IO_STATUS_HIGH_DRIVER, &(this->col_pin_list[col]), 1);
+    }
+
+    matrix_key_set_io_state((MATRIX_NO_KEY == 1) ? IO_STATUS_OUTPUT_LOW : IO_STATUS_OUTPUT_HIGH, this->col_pin_list, this->col_num);
+
+    port_edge_wakeup_control(0xff);
+    //p33_tx_1byte(P3_WKUP_EN, 0xff);
+    //P33_LEVEL_WKUP_EN(1);
+
+
+    if (notify) {
+        struct sys_event e;
+        e.type = SYS_MATRIX_KEY_EVENT;
+        e.u.matrix_key.map = key_map;
+        e.arg  = (void *)DEVICE_EVENT_FROM_KEY;
+        sys_event_notify(&e);
+    }
+}
+#else
+
+void matrix_key_scan(void)
+{
+    u8 row, col;
+    u8 cur_key_value = MATRIX_NO_KEY, notify = 0;
+    for (row = 0; row < this->row_num; row ++) {
+        gpio_direction_input(this->row_pin_list[row]);
+        gpio_set_die(this->row_pin_list[row], 1);
+        gpio_set_pull_up(this->row_pin_list[row], 1);
+        gpio_set_pull_down(this->row_pin_list[row], 0);
+    }
+
+    for (col = 0; col < this->col_num; col ++) {
+        gpio_direction_output(this->col_pin_list[col], 0);
+        gpio_set_die(this->col_pin_list[col], 1);
+        for (row = 0; row < this->row_num; row ++) {
+            if (gpio_read(this->row_pin_list[row]) == 0) {
+                printf("col:%x  row:%x\n", col, row);
+            }
+
+        }
+        gpio_direction_input(this->col_pin_list[col]);
+        gpio_set_pull_up(this->col_pin_list[col], 0);
+        gpio_set_pull_up(this->col_pin_list[col], 0);
+        gpio_set_die(this->col_pin_list[col], 0);
+    }
+}
+#endif
+
+void matrix_key_wakeup_timeout_handler(void *arg)
+{
+    is_key_active = 1;
+}
+
+void matrix_key_wakeup_keep(void)
+{
+    is_key_active = 1;
+    if (matrix_key_wakeup_hold_timer) {
+        sys_s_hi_timeout_del(matrix_key_wakeup_hold_timer);
+    }
+    matrix_key_wakeup_hold_timer = sys_s_hi_timerout_add(NULL, matrix_key_wakeup_timeout_handler, 10);
+}
+
+void matrix_key_wakeup(u8 idx, u32 gpio)
+{
+    r_printf("matrix_key wkup!\n");
+    matrix_key_wakeup_keep();
+}
+
+int matrix_key_init(matrix_key_param *param)
+{
+    if (!param) {
+        return -1;      //参数无效
+    }
+    this = param;
+    u8 row, col;
+    for (row = 0; row < this->row_num; row ++) {
+        (MATRIX_NO_KEY) ? P33_OR_WKUP_EDGE(row) : P33_AND_WKUP_EDGE(row);
+        for (col = 0; col < this->col_num; col ++) {
+            (key_st[row][col]).last_st = MATRIX_NO_KEY;
+            (key_st[row][col]).press_cnt = 0;
+        }
+    }
+    printf("key_row:%d rol:%d\n", this->row_num, this->col_num);
+    if (matrix_key_timer) {
+        sys_s_hi_timer_del(matrix_key_timer);
+    }
+
+    matrix_key_set_io_state((MATRIX_NO_KEY) ? IO_STATUS_OUTPUT_LOW : IO_STATUS_OUTPUT_HIGH, this->col_pin_list, this->col_num);
+    matrix_key_set_io_state((MATRIX_NO_KEY) ? IO_STATUS_INPUT_PULL_UP : IO_STATUS_INPUT_PULL_DOWN, this->row_pin_list, this->row_num);
+
+
+    port_edge_wkup_set_callback(matrix_key_wakeup);
+    matrix_key_timer = sys_s_hi_timer_add(NULL, matrix_key_scan, 10);
+    return 0;
+}
+
+
+
+static u8 matrix_key_idle_query(void)
+{
+    return !is_key_active;
+}
+
+REGISTER_LP_TARGET(matrix_key_lp_target) = {
+    .name = "matrix_key",
+    .is_idle = matrix_key_idle_query,
+};
+
+#endif

+ 510 - 0
apps/common/device/key/matrix_keyboard_ex_mcu.c

@@ -0,0 +1,510 @@
+#include "matrix_keyboard.h"
+#include "key_driver.h"
+#include "gpio.h"
+#include "system/event.h"
+#include "app_config.h"
+#include "timer.h"
+#include "asm/power_interface.h"
+#include "asm/power/p33.h"
+#include "ex_mcu_uart.h"
+
+//本矩阵按键函数,现主要针对bd19做了修改,别的系列未考虑
+
+#if TCFG_MATRIX_KEY_ENABLE && TCFG_EX_MCU_ENABLE
+#define MATRIX_NO_KEY           0x1         //没有按键时的IO电平
+#define MATRIX_LONG_TIME        35
+#define MATRIX_HOLD_TIME        35+10
+#define MATRIX_KEY_FILTER_TIME  2
+
+static volatile u8 is_key_active = 0;
+u8 notify_key_array[8] = {0};
+u8 key_map[COL_MAX] = {0};
+static u16 key_status_array[6] = {0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
+static int matrix_key_wakeup_hold_timer = 0;
+static int matrix_key_timer = 0;
+static int shake_hands_timer_id = 0;//握手定时器id
+static matrix_key_st key_st[ROW_MAX][COL_MAX];
+static matrix_key_param *this = NULL;
+extern struct ex_mcu_platform_data ex_mcu_data;
+//ex_mcu变量
+static u8 ex_mcu_buf[6] __attribute__((aligned(4), section(".common"))); //串口数据交互buffer
+//ex_mcu通信指令
+static u8 const shake_hands_ack_cmd[5] __attribute((aligned(4))) = {0x55, 0xaa, 0x20, 0x22, 0x08};//从机回应握手指令
+static u8 const shake_hands_send_cmd[5] __attribute((aligned(4))) = {0x05, 0x06, 0x08, 0x05, 0x06}; //向从机握手指令
+static u8 const start_code[5] __attribute((aligned(4))) = {0x05, 0x01, 0x01, 0x01, 0x05};//从机扫描开始指令
+static u8 const powerdown_code[5] __attribute((aligned(4))) = {0x06, 0x01, 0x02, 0x03, 0x10};//从机powerdown指令
+static u8 const poweroff_code[5] __attribute((aligned(4))) = {0x07, 0x01, 0x02, 0x03, 0x10};//不建议放在全局,有4k对其操作
+
+//-------------------------------------------
+static void ex_mcu_key_scan_start(void)
+{
+    ex_mcu_data.tx_buf_client(start_code, sizeof(start_code));
+}
+
+extern void p33_soft_reset(void);
+static void ex_mcu_key_scan_recive(void)
+{
+    static u16 num = 0;
+    u8 ret;
+    ret = ex_mcu_data.rx_buf_client(ex_mcu_buf, 6, 10);
+    if (ret == 0) {
+        num++;
+        if (num == 100) {
+            printf("no ad15 uart data to set reset");
+            p33_soft_reset();
+            while (1);
+        }
+    } else {
+        num = 0;
+    }
+}
+
+void ex_mcu_enter_powerdown(void)
+{
+    ex_mcu_data.tx_buf_client(powerdown_code, sizeof(powerdown_code));
+    /* ex_mcu_matrix_key_set_io_state(IO_STATUS_INPUT_PULL_UP, this->row_pin_list, this->row_num); */
+}
+
+void ex_mcu_exit_powerdown(u32 gpio)
+{
+    //退出powerdown输出下降沿唤醒从机,使用寄存器操作
+    u8 port_value;
+    switch (gpio / IO_GROUP_NUM) {
+    case 0://JL_PORTA
+        port_value = gpio % IO_GROUP_NUM;
+        /* printf("%d---%d ",gpio / IO_GROUP_NUM, port_value); */
+        JL_PORTA->DIR &= ~BIT(port_value);
+        JL_PORTA->OUT |= BIT(port_value);
+        JL_PORTA->OUT &= ~BIT(port_value);
+        break;
+    case 1://JL_PORTB
+        port_value = gpio % IO_GROUP_NUM;
+        JL_PORTB->DIR &= ~BIT(port_value);
+        JL_PORTB->OUT |= BIT(port_value);
+        JL_PORTB->OUT &= ~BIT(port_value);
+        break;
+    case 2://JL_PORTD
+        port_value = gpio % IO_GROUP_NUM;
+        JL_PORTD->DIR &= ~BIT(port_value);
+        JL_PORTD->OUT |= BIT(port_value);
+        JL_PORTD->OUT &= ~BIT(port_value);
+        break;
+    default:
+        break;
+    }
+}
+
+void ex_mcu_enter_poweroff(void)
+{
+    printf("To send power off cmd!!");
+    ex_mcu_data.tx_buf_client(poweroff_code, sizeof(poweroff_code));
+}
+
+static void ex_mcu_full_key_array(u8 row, u8 col, u8 st)
+{
+    u8 offset = 0;
+    u8 mark = 0, mark_offset = 0;
+    //最多推6个按键出来,如果需要推多个按键需要自行修改,每个u16 低八位标识row 高八位标识col
+    u16 key_value = (row | col << 8);
+    for (offset = 0; offset < sizeof(key_status_array) / sizeof(u16); offset++) {
+        if (key_status_array[offset] == key_value && st == MATRIX_KEY_UP) {         //找到列表中有当前按键且按键状态抬起,则将按键移除列表
+            mark = 1;                                                               //记录相同键值所在位置
+            mark_offset = offset;
+            if (mark_offset == sizeof(key_status_array) / sizeof(u16) - 1) {
+                key_status_array[mark_offset] = 0xffff;
+                break;
+            }
+        } else if (key_status_array[offset] == 0xffff) {
+            if (mark) {
+                memcpy(key_status_array + mark_offset, key_status_array + mark_offset + 1, (offset - mark_offset - 1) * 2);
+                key_status_array[offset - 1] = 0xffff;
+            } else if (st == MATRIX_KEY_SHORT) {                                    //需要状态为短按才会把键值填充到数组中,防止按键满了之后把抬起也填充进去
+                key_status_array[offset] = key_value;
+            }
+            break;
+        } else if (mark && (offset == sizeof(key_status_array) / sizeof(u16) - 1)) {
+            memcpy(key_status_array + mark_offset, key_status_array + mark_offset + 1, (sizeof(key_status_array) / sizeof(u16) - mark_offset - 1) * 2);
+            key_status_array[sizeof(key_status_array) / sizeof(u16) - 1] = 0xffff;
+            break;
+        }
+    }
+}
+
+
+void ex_mcu_full_key_map(u8 row, u8 col, u8 st)
+{
+    if (st) {
+        key_map[col] |= BIT(row);
+    } else {
+        key_map[col] &= ~BIT(row);
+    }
+}
+
+void P33_AND_WKUP_EDGE(u8 data);
+void P33_OR_WKUP_EDGE(u8 data);
+
+enum {
+    IO_STATUS_HIGH_DRIVER = 0,
+    IO_STATUS_OUTPUT_HIGH,
+    IO_STATUS_OUTPUT_LOW,
+    IO_STATUS_INPUT_PULL_DOWN,
+    IO_STATUS_INPUT_PULL_UP,
+};
+
+void ex_mcu_matrix_key_set_io_state(u8 state, u32 *io_table, u8 len)
+{
+    u8 i = 0;
+    u8 portdp_value = 0;
+    u8 portdm_value = 0;
+    u32 porta_value = 0;
+    u32 portb_value = 0;
+    u32 portd_value = 0;
+    u32 portpm_value = 0;
+
+    for (; i < len; i++) {
+        switch (io_table[i] / IO_GROUP_NUM) {
+        case 0: //JL_PORTA
+            porta_value |= BIT(io_table[i] % IO_GROUP_NUM);
+            break;
+        case 1: //JL_PORTB
+            portb_value |= BIT(io_table[i] % IO_GROUP_NUM);
+            break;
+        case 2: //JL_PORTD
+            portd_value |= BIT(io_table[i] % IO_GROUP_NUM);
+            break;
+        case 3: //DP1/DM1
+            portpm_value = io_table[i] % IO_GROUP_NUM;
+            if (portpm_value == 3) {
+                portdp_value = 1;
+            } else if (portpm_value == 4) {
+                portdm_value = 1;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+    switch (state) {
+    case IO_STATUS_HIGH_DRIVER:
+        JL_PORTA->DIR |= porta_value;
+        JL_PORTA->DIE &= ~porta_value;
+        JL_PORTA->PU &= ~porta_value;
+        JL_PORTA->PD &= ~porta_value;
+        JL_PORTB->DIR |= portb_value;
+        JL_PORTB->DIE &= ~portb_value;
+        JL_PORTB->PU &= ~portb_value;
+        JL_PORTB->PD &= ~portb_value;
+        JL_PORTD->DIR |= portd_value;
+        JL_PORTD->DIE &= ~portd_value;
+        JL_PORTD->PU &= ~portd_value;
+        JL_PORTD->PD &= ~portd_value;
+        //dp1 dm1操作
+        if (portdp_value == 1) {
+            JL_USB1->CON0 &= ~BIT(0);//USB_PHY_OFF 来自usb1_iomode(1);
+            JL_USB1_IO->CON0 |= BIT(12) | BIT(14);
+            JL_USB1_IO->CON0 &= ~BIT(4);//关闭DP上拉
+            JL_USB1_IO->CON0 &= ~BIT(6);//关闭DP下拉
+            JL_USB1_IO->CON0 |= BIT(2);//DP设置为输入
+            JL_USB1_IO->CON0 &= ~BIT(8);//1.2v DP数字引脚
+            JL_USB1_IO->CON0 &= ~BIT(10);//3.3v DP数字引脚
+        }
+        if (portdm_value == 1) {
+            JL_USB1->CON0 &= ~BIT(0);//USB_PHY_OFF 来自usb1_iomode(1);
+            JL_USB1_IO->CON0 |= BIT(12) | BIT(14);
+            JL_USB1_IO->CON0 &= ~BIT(5);//关闭DM上拉
+            JL_USB1_IO->CON0 &= ~BIT(7);//关闭Dm下拉
+            JL_USB1_IO->CON0 |= BIT(3);//Dm设置为输入
+            JL_USB1_IO->CON0 &= ~BIT(9);//1.2v DM数字引脚
+            JL_USB1_IO->CON0 &= ~BIT(11);//3.3v DM数字引脚
+        }
+        break;
+    case IO_STATUS_OUTPUT_HIGH:
+        JL_PORTA->DIR &= ~porta_value;
+        JL_PORTA->OUT |= porta_value;
+        JL_PORTB->DIR &= ~portb_value;
+        JL_PORTB->OUT |= portb_value;
+        JL_PORTD->DIR &= ~portd_value;
+        JL_PORTD->OUT |= portd_value;
+        //dp1 dm1操作
+        if (portdp_value == 1) {
+            JL_USB1->CON0 &= ~BIT(0);//USB_PHY_OFF 来自usb1_iomode(1);
+            JL_USB1_IO->CON0 |= BIT(12) | BIT(14);
+            JL_USB1_IO->CON0 &= ~BIT(2);//DP设置为输出
+            JL_USB1_IO->CON0 |= BIT(0);//DP输出高电平
+        }
+        if (portdm_value == 1) {
+            JL_USB1->CON0 &= ~BIT(0);//USB_PHY_OFF 来自usb1_iomode(1);
+            JL_USB1_IO->CON0 |= BIT(12) | BIT(14);
+            JL_USB1_IO->CON0 &= ~BIT(3);//DM设置为输出
+            JL_USB1_IO->CON0 |= BIT(1);//DM输出高电平
+        }
+        break;
+    case IO_STATUS_OUTPUT_LOW:
+        JL_PORTA->DIR &= ~porta_value;
+        JL_PORTA->OUT &= ~porta_value;
+        JL_PORTB->DIR &= ~portb_value;
+        JL_PORTB->OUT &= ~portb_value;
+        JL_PORTD->DIR &= ~portd_value;
+        JL_PORTD->OUT &= ~portd_value;
+        //dp1 dm1操作
+        if (portdp_value == 1) {
+            JL_USB1->CON0 &= ~BIT(0);//USB_PHY_OFF 来自usb1_iomode(1);
+            JL_USB1_IO->CON0 |= BIT(12) | BIT(14);
+            JL_USB1_IO->CON0 &= ~BIT(2);//DP设置为输出
+            JL_USB1_IO->CON0 &= ~BIT(0);//DP输出低电平
+        }
+        if (portdm_value == 1) {
+            JL_USB1->CON0 &= ~BIT(0);//USB_PHY_OFF 来自usb1_iomode(1);
+            JL_USB1_IO->CON0 |= BIT(12) | BIT(14);
+            JL_USB1_IO->CON0 &= ~BIT(3);//DM设置为输出
+            JL_USB1_IO->CON0 &= ~BIT(1);//DM输出低电平
+        }
+        break;
+    case IO_STATUS_INPUT_PULL_UP:
+        JL_PORTA->DIR |= porta_value;
+        JL_PORTA->DIE &= ~porta_value;
+        JL_PORTA->DIEH |= porta_value;
+        JL_PORTA->PU  |= porta_value;
+        JL_PORTA->PD  &= ~porta_value;
+        JL_PORTB->DIR |= portb_value;
+        JL_PORTB->DIE &= ~portb_value;
+        JL_PORTB->DIEH |= portb_value;
+        JL_PORTB->PU  |= portb_value;
+        JL_PORTB->PD  &= ~portb_value;
+        JL_PORTD->DIR |= portd_value;
+        JL_PORTD->DIE &= ~portd_value;
+        JL_PORTD->DIEH |= portd_value;
+        JL_PORTD->PU  |= portd_value;
+        JL_PORTD->PD  &= ~portd_value;
+        //dp1 dm1操作
+        if (portdp_value == 1) {
+            JL_USB1->CON0 &= ~BIT(0);//USB_PHY_OFF 来自usb1_iomode(1);
+            JL_USB1_IO->CON0 |= BIT(12) | BIT(14);
+            JL_USB1_IO->CON0 |= BIT(4);//开DP上拉
+            JL_USB1_IO->CON0 &= ~BIT(6);//关闭DP下拉
+            JL_USB1_IO->CON0 |= BIT(2);//DP设置为输入
+            JL_USB1_IO->CON0 &= ~BIT(8);//1.2v DP数字引脚
+            JL_USB1_IO->CON0 |= BIT(10);//3.3v DP数字引脚使能
+        }
+        if (portdm_value == 1) {
+            JL_USB1->CON0 &= ~BIT(0);//USB_PHY_OFF 来自usb1_iomode(1);
+            JL_USB1_IO->CON0 |= BIT(12) | BIT(14);
+            JL_USB1_IO->CON0 |= BIT(5);//打开DM上拉
+            JL_USB1_IO->CON0 &= ~BIT(7);//关闭Dm下拉
+            JL_USB1_IO->CON0 |= BIT(3);//Dm设置为输入
+            JL_USB1_IO->CON0 &= ~BIT(9);//1.2v DM数字引脚
+            JL_USB1_IO->CON0 |= BIT(11);//3.3v DM数字引脚使能
+        }
+        break;
+    }
+}
+
+static u32 key_scan_value_analyse()
+{
+    static u16 count = 0;
+    u32 key_scan_value = 0;
+    key_scan_value = (ex_mcu_buf[2] << 16) | (ex_mcu_buf[3] << 8) | (ex_mcu_buf[4]);
+    if (key_scan_value && (ex_mcu_buf[0] == 0x05) && (ex_mcu_buf[5] == 0x06)) {
+        /* put_buf(ex_mcu_buf, sizeof(ex_mcu_buf)); */
+        /* putchar('%'); */
+        count = 0;
+        return key_scan_value;
+    }
+    return 0;
+}
+
+static void ex_mcu_port_edge_wakeup_control(u16 data)
+{
+
+    if (data) {
+        P3_WKUP_CPND0 = data;
+        P3_WKUP_CPND1 = data >> 8;
+    }
+
+    P3_WKUP_EN0 = data;
+    P3_WKUP_EN1 = data >> 8;
+}
+
+void ex_mcu_matrix_key_scan(void)
+{
+    u8 row, col, cur_col;
+    u32 tmp;
+    u8 cur_key_value = MATRIX_NO_KEY, notify = 0;
+    static u8 wk_toggle = 0;
+    //g_printf("scan...\n");
+    //P33_LEVEL_WKUP_EN(0);
+    extern void P33_DUMP_WKUP(void);
+    extern void P33_PORT_DUMP(void);
+
+    __asm__ volatile("%0 =icfg" : "=r"(tmp));
+    if ((tmp & BIT(9)) == 0) {
+        /* putchar('@'); */
+        return;
+    }
+
+    /* putchar('%'); */
+    ex_mcu_port_edge_wakeup_control(0);
+    //不直接调用gpio.c的接口主要是由于想控制扫描时间。这样能把时间从1.8ms缩减到800us
+    ex_mcu_matrix_key_set_io_state(IO_STATUS_HIGH_DRIVER, this->row_pin_list, this->row_num);
+    is_key_active = 0;
+
+    for (row = 0; row < this->row_num; row ++) {
+        ex_mcu_key_scan_start();
+        ex_mcu_matrix_key_set_io_state(IO_STATUS_OUTPUT_LOW, &(this->row_pin_list[row]), 1);
+        ex_mcu_key_scan_recive();
+        //gpio_direction_output(this->col_pin_list[col], !MATRIX_NO_KEY);
+        for (col = 0; col < this->col_num; col ++) {
+            cur_key_value = !(((key_scan_value_analyse()) >> col)&BIT(0));
+            if (cur_key_value != MATRIX_NO_KEY) {
+                is_key_active = 1;
+            }
+            if (cur_key_value != (key_st[row][col]).last_st) {
+                if (cur_key_value == MATRIX_NO_KEY) { //按键抬起判断
+                    (key_st[row][col]).press_cnt = 0;
+                    printf("row:%d  col:%d   [UP]\n", row, col);
+                    (MATRIX_NO_KEY) ? P33_OR_WKUP_EDGE(row) : P33_AND_WKUP_EDGE(row);//在抬起(上升沿/高电平)之后避免P33识别错误,将P33设置为下降沿/低电平唤醒
+                    //P33_AND_WKUP_EDGE(row);
+                    ex_mcu_full_key_map(row, col, 0);
+                    notify = 1;
+                } else {            //按键初次按下
+                    printf("row:%d  col:%d   [SHORT]\n", row, col);
+                    ex_mcu_full_key_map(row, col, 1);
+                    (MATRIX_NO_KEY) ? P33_AND_WKUP_EDGE(row) : P33_OR_WKUP_EDGE(row);//在抬起下降沿/低电平之后避免P33识别错误,将P33设置为(上升沿/高电平)唤醒
+                    //P33_OR_WKUP_EDGE(row);
+                    notify = 1;
+                }
+            } else {        //判断是否按键抬起
+                if (cur_key_value != MATRIX_NO_KEY) {
+                    (key_st[row][col]).press_cnt ++;
+                    if ((key_st[row][col]).press_cnt == MATRIX_LONG_TIME) {
+                        printf("row:%d  col:%d   [LONG]\n", row, col);
+                        notify = 1;
+                    } else if ((key_st[row][col]).press_cnt == MATRIX_HOLD_TIME) {
+                        printf("row:%d  col:%d   [HOLD]\n", row, col);
+                        notify = 1;
+                        (key_st[row][col]).press_cnt = MATRIX_LONG_TIME;
+                    } else {
+                        //press_cnt还未累加够
+                    }
+                }
+            }
+            (key_st[row][col]).last_st = cur_key_value;
+        }
+        /* gpio_direction_input(this->col_pin_list[col]); */
+        ex_mcu_matrix_key_set_io_state(IO_STATUS_HIGH_DRIVER, this->row_pin_list, this->row_num);
+    }
+
+    ex_mcu_matrix_key_set_io_state(IO_STATUS_INPUT_PULL_UP, this->row_pin_list, this->row_num);
+
+    ex_mcu_port_edge_wakeup_control(0xff);
+
+    if (notify) {
+        struct sys_event e;
+        e.type = SYS_MATRIX_KEY_EVENT;
+        e.u.matrix_key.map = key_map;
+        e.arg  = (void *)DEVICE_EVENT_FROM_KEY;
+        sys_event_notify(&e);
+    }
+    /* extern void P33_PORT_DUMP(void); */
+    /* P33_PORT_DUMP();  */
+    /* return 1; */
+}
+
+void ex_mcu_matrix_key_wakeup_timeout_handler(void *arg)
+{
+    is_key_active = 0;
+}
+
+void ex_mcu_matrix_key_wakeup_keep(void)
+{
+    is_key_active = 1;
+    if (matrix_key_wakeup_hold_timer) {
+        sys_s_hi_timeout_del(matrix_key_wakeup_hold_timer);
+    }
+    matrix_key_wakeup_hold_timer = sys_s_hi_timerout_add(NULL, ex_mcu_matrix_key_wakeup_timeout_handler, 5);
+}
+
+void ex_mcu_matrix_key_wakeup(u8 idx, u32 gpio)
+{
+    //先唤醒ex_mcu设备
+    ex_mcu_exit_powerdown(TCFG_EX_WAKEUP_PORT);
+    /* r_printf("matrix_key wkup!\n"); */
+    ex_mcu_matrix_key_wakeup_keep();
+}
+
+static void key_scan_shake_hands()
+{
+    u32 ret = 0;
+    u8 shake_hands_flag = 0;
+    u8 *__rx_buf;
+
+    ex_mcu_data.tx_buf_client(shake_hands_send_cmd, sizeof(shake_hands_send_cmd));
+    ex_mcu_data.rx_buf_client(ex_mcu_buf, sizeof(shake_hands_ack_cmd), 20);
+    ret = sizeof(ex_mcu_buf) - 1;
+    //收够足够长度内容进行打印
+    printf("ret ======= %d", ret);
+    put_buf(ex_mcu_buf, sizeof(shake_hands_ack_cmd));
+    //接收到的长度为ack_cmd的长度
+    if (ret == sizeof(shake_hands_ack_cmd)) {
+        printf("ack info:\n");
+        __rx_buf = ex_mcu_buf;
+        for (u8 i = 0; i < sizeof(shake_hands_ack_cmd); i++) {
+            if (__rx_buf[i] != shake_hands_ack_cmd[i]) {
+                shake_hands_flag = 0;
+                printf("ack info err\n");
+                break;
+            } else {
+                shake_hands_flag = 1;
+                printf("shake succ");
+            }
+        }
+    } else {
+        shake_hands_flag = 0;
+        printf("ack info err\n");
+    }
+
+    if (matrix_key_timer) {
+        sys_s_hi_timer_del(matrix_key_timer);
+    }
+
+    if (shake_hands_flag == 1 && shake_hands_timer_id) {
+        sys_timer_del(shake_hands_timer_id);
+        matrix_key_timer = sys_s_hi_timer_add(NULL, ex_mcu_matrix_key_scan, 5);
+    }
+}
+
+int ex_mcu_matrix_key_init(matrix_key_param *param)
+{
+    if (!param) {
+        return -1;      //参数无效
+    }
+    this = param;
+    u8 row, col;
+    for (row = 0; row < this->row_num; row ++) {
+        (MATRIX_NO_KEY) ? P33_OR_WKUP_EDGE(row) : P33_AND_WKUP_EDGE(row);
+        for (col = 0; col < this->col_num; col ++) {
+            (key_st[row][col]).last_st = MATRIX_NO_KEY;
+            (key_st[row][col]).press_cnt = 0;
+        }
+    }
+
+    if (shake_hands_timer_id) {
+        sys_timer_del(shake_hands_timer_id);
+    }
+
+    port_edge_wkup_set_callback(ex_mcu_matrix_key_wakeup);
+    shake_hands_timer_id = sys_timer_add(NULL, key_scan_shake_hands, 20);
+    return 0;
+}
+
+static u8 matrix_key_idle_query(void)
+{
+    return !is_key_active;
+}
+
+REGISTER_LP_TARGET(matrix_key_lp_target) = {
+    .name = "matrix_key",
+    .is_idle = matrix_key_idle_query,
+};
+
+#endif

+ 62 - 0
apps/common/device/key/touch_key.c

@@ -0,0 +1,62 @@
+#include "touch_key.h"
+#include "key_driver.h"
+#include "app_config.h"
+
+
+#if TCFG_TOUCH_KEY_ENABLE
+
+
+/* =========== 触摸键使用说明 ============= */
+//1. 使用plcnt模块作计数;
+//2. 配置参数时, 在配置好时钟后, 需要调试no_touch_cnt和touch_cnt的值;
+
+static const struct touch_key_platform_data *__this = NULL;
+
+//按键驱动扫描参数列表
+struct key_driver_para touch_key_scan_para = {
+    .scan_time 	  	  = 10,				//按键扫描频率, 单位: ms
+    .last_key 		  = NO_KEY,  		//上一次get_value按键值, 初始化为NO_KEY;
+    .filter_time  	  = 1,				//按键消抖延时;
+    .long_time 		  = 75,  			//按键判定长按数量
+    .hold_time 		  = (75 + 15),  	//按键判定HOLD数量
+    .click_delay_time = 20,				//按键被抬起后等待连击延时数量
+    .key_type		  = KEY_DRIVER_TYPE_TOUCH,
+    .get_value 		  = touch_key_get_value,
+};
+
+#define TOUCH_KEY_DEBUG 		0
+
+#if TOUCH_KEY_DEBUG
+#define touch_key_debug(fmt, ...) printf("[TOUCH] "fmt, ##__VA_ARGS__)
+#else
+#define touch_key_debug(fmt, ...)
+#endif
+
+
+u8 touch_key_get_value(void)
+{
+    u8 key = get_plcnt_value();
+
+    if (key != NO_KEY) {
+        touch_key_debug("key = %d", key);
+        return __this->port_list[key].key_value;
+    }
+
+    return NO_KEY;
+}
+
+
+int touch_key_init(const struct touch_key_platform_data *touch_key_data)
+{
+    __this = touch_key_data;
+    printf("touch_key_init >>>> ");
+
+    return plcnt_init((void *)touch_key_data);
+}
+
+
+#endif  	/* #if TCFG_TOUCH_KEY_ENABLE */
+
+
+
+

+ 923 - 0
apps/common/device/norflash/norflash.c

@@ -0,0 +1,923 @@
+#include "norflash.h"
+#include "app_config.h"
+#include "asm/clock.h"
+#include "system/timer.h"
+
+#if defined(TCFG_NORFLASH_DEV_ENABLE) && TCFG_NORFLASH_DEV_ENABLE
+
+#undef LOG_TAG_CONST
+#define LOG_TAG     "[FLASH]"
+#define LOG_ERROR_ENABLE
+#define LOG_INFO_ENABLE
+#include "debug.h"
+
+
+#define MAX_NORFLASH_PART_NUM       4
+
+struct norflash_partition {
+    const char *name;
+    u32 start_addr;
+    u32 size;
+    struct device device;
+};
+
+static struct norflash_partition nor_part[MAX_NORFLASH_PART_NUM];
+
+struct norflash_info {
+    u32 flash_id;
+    u32 flash_capacity;
+    int spi_num;
+    int spi_err;
+    u8 spi_cs_io;
+    u8 spi_r_width;
+    u8 part_num;
+    u8 open_cnt;
+    struct norflash_partition *const part_list;
+    OS_MUTEX mutex;
+    u32 max_end_addr;
+};
+
+static struct norflash_info _norflash = {
+    .spi_num = (int) - 1,
+    .part_list = nor_part,
+};
+
+int _norflash_read(u32 addr, u8 *buf, u32 len, u8 cache);
+int _norflash_eraser(u8 eraser, u32 addr);
+static void _norflash_cache_sync_timer(void *priv);
+static int _norflash_write_pages(u32 addr, u8 *buf, u32 len);
+
+
+#define spi_cs_init() \
+    do { \
+        gpio_set_die(_norflash.spi_cs_io, 1); \
+        gpio_set_direction(_norflash.spi_cs_io, 0); \
+        gpio_write(_norflash.spi_cs_io, 1); \
+    } while (0)
+
+#define spi_cs_uninit() \
+    do { \
+        gpio_set_die(_norflash.spi_cs_io, 0); \
+        gpio_set_direction(_norflash.spi_cs_io, 1); \
+        gpio_set_pull_up(_norflash.spi_cs_io, 0); \
+        gpio_set_pull_down(_norflash.spi_cs_io, 0); \
+    } while (0)
+#define spi_cs_h()                  gpio_write(_norflash.spi_cs_io, 1)
+#define spi_cs_l()                  gpio_write(_norflash.spi_cs_io, 0)
+#define spi_read_byte()             spi_recv_byte(_norflash.spi_num, &_norflash.spi_err)
+#define spi_write_byte(x)           spi_send_byte(_norflash.spi_num, x)
+#define spi_dma_read(x, y)          spi_dma_recv(_norflash.spi_num, x, y)
+#define spi_dma_write(x, y)         spi_dma_send(_norflash.spi_num, x, y)
+#define spi_set_width(x)            spi_set_bit_mode(_norflash.spi_num, x)
+
+static struct norflash_partition *norflash_find_part(const char *name)
+{
+    struct norflash_partition *part = NULL;
+    u32 idx;
+    for (idx = 0; idx < MAX_NORFLASH_PART_NUM; idx++) {
+        part = &_norflash.part_list[idx];
+        if (part->name == NULL) {
+            continue;
+        }
+        if (!strcmp(part->name, name)) {
+            return part;
+        }
+    }
+    return NULL;
+}
+
+static struct norflash_partition *norflash_new_part(const char *name, u32 addr, u32 size)
+{
+    struct norflash_partition *part;
+    u32 idx;
+    for (idx = 0; idx < MAX_NORFLASH_PART_NUM; idx++) {
+        part = &_norflash.part_list[idx];
+        if (part->name == NULL) {
+            break;
+        }
+    }
+    if (part->name != NULL) {
+        log_error("create norflash part fail\n");
+        return NULL;
+    }
+    memset(part, 0, sizeof(*part));
+    part->name = name;
+    part->start_addr = addr;
+    part->size = size;
+    if (part->start_addr + part->size > _norflash.max_end_addr) {
+        _norflash.max_end_addr = part->start_addr + part->size;
+    }
+    _norflash.part_num++;
+    return part;
+}
+
+static void norflash_delete_part(const char *name)
+{
+    struct norflash_partition *part;
+    u32 idx;
+    for (idx = 0; idx < MAX_NORFLASH_PART_NUM; idx++) {
+        part = &_norflash.part_list[idx];
+        if (part->name == NULL) {
+            continue;
+        }
+        if (!strcmp(part->name, name)) {
+            part->name = NULL;
+            _norflash.part_num--;
+        }
+    }
+}
+
+static int norflash_verify_part(struct norflash_partition *p)
+{
+    struct norflash_partition *part = NULL;
+    u32 idx;
+    for (idx = 0; idx < MAX_NORFLASH_PART_NUM; idx++) {
+        part = &_norflash.part_list[idx];
+        if (part->name == NULL) {
+            continue;
+        }
+        if ((p->start_addr >= part->start_addr) && (p->start_addr < part->start_addr + part->size)) {
+            if (strcmp(p->name, part->name) != 0) {
+                return -1;
+            }
+        }
+    }
+    return 0;
+}
+
+
+
+#define FLASH_CACHE_ENABLE  1
+
+#if FLASH_CACHE_ENABLE
+static u32 flash_cache_addr;
+static u8 *flash_cache_buf = NULL; //缓存4K的数据,与flash里的数据一样。
+static u8 flash_cache_is_dirty;
+static u16 flash_cache_timer;
+
+#define FLASH_CACHE_SYNC_T_INTERVAL     60
+
+static int _check_0xff(u8 *buf, u32 len)
+{
+    for (u32 i = 0; i < len; i ++) {
+        if ((*(buf + i)) != 0xff) {
+            return 1;
+        }
+    }
+    return 0;
+}
+#endif
+
+
+static u32 _pow(u32 num, int n)
+{
+    u32 powint = 1;
+    int i;
+    for (i = 1; i <= n; i++) {
+        powint *= num;
+    }
+    return powint;
+}
+
+static int _norflash_wait_ok()
+{
+    u32 timeout = 8 * 1000 * 1000 / 100;
+    while (timeout--) {
+        spi_cs_l();
+        spi_write_byte(WINBOND_READ_SR1);
+        u8 reg_1 = spi_read_byte();
+        spi_cs_h();
+        if (!(reg_1 & BIT(0))) {
+            break;
+        }
+        delay(100);
+    }
+    if (timeout == 0) {
+        log_error("norflash_wait_ok timeout!\r\n");
+        return 1;
+    }
+    return 0;
+}
+
+static void _norflash_send_write_enable()
+{
+    spi_cs_l();
+    spi_write_byte(WINBOND_WRITE_ENABLE);
+    spi_cs_h();
+}
+static u8 is4byte_mode;
+static void _norflash_send_addr(u32 addr)
+{
+    if (is4byte_mode) {
+        spi_write_byte(addr >> 24);
+    }
+    spi_write_byte(addr >> 16);
+    spi_write_byte(addr >> 8);
+    spi_write_byte(addr);
+}
+
+static u32 _norflash_read_id()
+{
+    u8 id[3];
+    spi_cs_l();
+    spi_write_byte(WINBOND_JEDEC_ID);
+    for (u8 i = 0; i < sizeof(id); i++) {
+        id[i] = spi_read_byte();
+    }
+    spi_cs_h();
+    return id[0] << 16 | id[1] << 8 | id[2];
+}
+
+int _norflash_init(const char *name, struct norflash_dev_platform_data *pdata)
+{
+    log_info("norflash_init ! %x %x", pdata->spi_cs_port, pdata->spi_read_width);
+    if (_norflash.spi_num == (int) - 1) {
+        _norflash.spi_num = pdata->spi_hw_num;
+        _norflash.spi_cs_io = pdata->spi_cs_port;
+        _norflash.spi_r_width = pdata->spi_read_width;
+        _norflash.flash_id = 0;
+        _norflash.flash_capacity = 0;
+        os_mutex_create(&_norflash.mutex);
+        _norflash.max_end_addr = 0;
+        _norflash.part_num = 0;
+    }
+    ASSERT(_norflash.spi_num == pdata->spi_hw_num);
+    ASSERT(_norflash.spi_cs_io == pdata->spi_cs_port);
+    ASSERT(_norflash.spi_r_width == pdata->spi_read_width);
+    struct norflash_partition *part;
+    part = norflash_find_part(name);
+    if (!part) {
+        part = norflash_new_part(name, pdata->start_addr, pdata->size);
+        ASSERT(part, "not enough norflash partition memory in array\n");
+        ASSERT(norflash_verify_part(part) == 0, "norflash partition %s overlaps\n", name);
+        log_info("norflash new partition %s\n", part->name);
+    } else {
+        ASSERT(0, "norflash partition name already exists\n");
+    }
+    return 0;
+}
+
+static void clock_critical_enter()
+{
+
+}
+static void clock_critical_exit()
+{
+    if (!(_norflash.flash_id == 0 || _norflash.flash_id == 0xffff)) {
+        spi_set_baud(_norflash.spi_num, spi_get_baud(_norflash.spi_num));
+    }
+}
+CLOCK_CRITICAL_HANDLE_REG(spi_norflash, clock_critical_enter, clock_critical_exit);
+
+void norflash_enter_4byte_addr()
+{
+    spi_cs_l();
+    spi_write_byte(0xb7);
+    spi_cs_h();
+}
+void norflash_exit_4byte_addr()
+{
+    spi_cs_l();
+    spi_write_byte(0xe9);
+    spi_cs_h();
+}
+int _norflash_open(void *arg)
+{
+    int reg = 0;
+    os_mutex_pend(&_norflash.mutex, 0);
+    log_info("norflash open\n");
+    if (!_norflash.open_cnt) {
+        spi_cs_init();
+        spi_open(_norflash.spi_num);
+        _norflash.flash_id = _norflash_read_id();
+        log_info("norflash_read_id: 0x%x\n", _norflash.flash_id);
+        if ((_norflash.flash_id == 0) || (_norflash.flash_id == 0xffffff)) {
+            log_error("read norflash id error !\n");
+            reg = -ENODEV;
+            goto __exit;
+        }
+        _norflash.flash_capacity = 64 * _pow(2, (_norflash.flash_id & 0xff) - 0x10) * 1024;
+        log_info("norflash_capacity: 0x%x\n", _norflash.flash_capacity);
+
+        is4byte_mode = 0;
+        if (_norflash.flash_capacity > 16 * 1024 * 1024) {
+            norflash_enter_4byte_addr();
+            is4byte_mode = 1;
+        }
+#if FLASH_CACHE_ENABLE
+        flash_cache_buf = (u8 *)malloc(4096);
+        ASSERT(flash_cache_buf, "flash_cache_buf is not ok\n");
+        flash_cache_addr = 4096;//先给一个大于4096的数
+        _norflash_read(0, flash_cache_buf, 4096, 1);
+        flash_cache_addr = 0;
+#endif
+        log_info("norflash open success !\n");
+    }
+    if (_norflash.flash_id == 0 || _norflash.flash_id == 0xffffff)  {
+        log_error("re-open norflash id error !\n");
+        reg = -EFAULT;
+        goto __exit;
+    }
+    ASSERT(_norflash.max_end_addr <= _norflash.flash_capacity, "max partition end address is greater than flash capacity\n");
+    _norflash.open_cnt++;
+
+__exit:
+    os_mutex_post(&_norflash.mutex);
+    return reg;
+}
+
+int _norflash_close(void)
+{
+    os_mutex_pend(&_norflash.mutex, 0);
+    log_info("norflash close\n");
+    if (_norflash.open_cnt) {
+        _norflash.open_cnt--;
+    }
+    if (!_norflash.open_cnt) {
+#if FLASH_CACHE_ENABLE
+        if (flash_cache_is_dirty) {
+            flash_cache_is_dirty = 0;
+            _norflash_eraser(FLASH_SECTOR_ERASER, flash_cache_addr);
+            _norflash_write_pages(flash_cache_addr, flash_cache_buf, 4096);
+        }
+        free(flash_cache_buf);
+        flash_cache_buf = NULL;
+#endif
+        spi_close(_norflash.spi_num);
+        spi_cs_uninit();
+
+        log_info("norflash close done\n");
+    }
+    os_mutex_post(&_norflash.mutex);
+    return 0;
+}
+
+int _norflash_read(u32 addr, u8 *buf, u32 len, u8 cache)
+{
+    int reg = 0;
+    u32 align_addr;
+    os_mutex_pend(&_norflash.mutex, 0);
+    /* y_printf("flash read  addr = %d, len = %d\n", addr, len); */
+#if FLASH_CACHE_ENABLE
+    if (!cache) {
+        goto __no_cache1;
+    }
+    u32 r_len = 4096 - (addr % 4096);
+    if ((addr >= flash_cache_addr) && (addr < (flash_cache_addr + 4096))) {
+        if (len <= r_len) {
+            memcpy(buf, flash_cache_buf + (addr - flash_cache_addr), len);
+            goto __exit;
+        } else {
+            memcpy(buf, flash_cache_buf + (addr - flash_cache_addr), r_len);
+            addr += r_len;
+            buf += r_len;
+            len -= r_len;
+        }
+    }
+__no_cache1:
+#endif
+    spi_cs_l();
+    if (_norflash.spi_r_width == 2) {
+        spi_write_byte(WINBOND_FAST_READ_DUAL_OUTPUT);
+        _norflash_send_addr(addr);
+        spi_write_byte(0);
+        spi_set_width(SPI_MODE_UNIDIR_2BIT);
+        spi_dma_read(buf, len);
+        spi_set_width(SPI_MODE_BIDIR_1BIT);
+    } else if (_norflash.spi_r_width == 4) {
+        spi_write_byte(0x6b);
+        _norflash_send_addr(addr);
+        spi_write_byte(0);
+        spi_set_width(SPI_MODE_UNIDIR_4BIT);
+        spi_dma_read(buf, len);
+        spi_set_width(SPI_MODE_BIDIR_1BIT);
+    } else {
+        spi_write_byte(WINBOND_FAST_READ_DATA);
+        _norflash_send_addr(addr);
+        spi_write_byte(0);
+        spi_dma_read(buf, len);
+    }
+    spi_cs_h();
+//#if FLASH_CACHE_ENABLE
+//    if (!cache) {
+//        goto __no_cache2;
+//    }
+//    align_addr = (addr + len) / 4096 * 4096;
+//    if ((int)len - (int)((addr + len) - align_addr) >= 4096) {
+//        align_addr -= 4096;
+//        if (flash_cache_addr != align_addr) {
+//            flash_cache_addr = align_addr;
+//            memcpy(flash_cache_buf, buf + (align_addr - addr), 4096);
+//        }
+//    }
+//__no_cache2:
+//#endif
+__exit:
+    os_mutex_post(&_norflash.mutex);
+    return reg;
+}
+
+static int _norflash_write_pages(u32 addr, u8 *buf, u32 len)
+{
+    /* y_printf("flash write addr = %d, num = %d\n", addr, len); */
+
+    int reg;
+    u32 first_page_len = 256 - (addr % 256);
+    first_page_len = len > first_page_len ? first_page_len : len;
+    _norflash_send_write_enable();
+    spi_cs_l();
+    spi_write_byte(WINBOND_PAGE_PROGRAM);
+    _norflash_send_addr(addr) ;
+    spi_dma_write(buf, first_page_len);
+    spi_cs_h();
+    reg = _norflash_wait_ok();
+    if (reg) {
+        return 1;
+    }
+    addr += first_page_len;
+    buf += first_page_len;
+    len -= first_page_len;
+    while (len) {
+        u32 cnt = len > 256 ? 256 : len;
+        _norflash_send_write_enable();
+        spi_cs_l();
+        spi_write_byte(WINBOND_PAGE_PROGRAM);
+        _norflash_send_addr(addr) ;
+        spi_dma_write(buf, cnt);
+        spi_cs_h();
+        reg = _norflash_wait_ok();
+        if (reg) {
+            return 1;
+        }
+        addr += cnt;
+        buf += cnt;
+        len -= cnt;
+    }
+    return 0;
+}
+
+#if FLASH_CACHE_ENABLE
+static void _norflash_cache_sync_timer(void *priv)
+{
+    int reg = 0;
+    os_mutex_pend(&_norflash.mutex, 0);
+    if (flash_cache_is_dirty) {
+        flash_cache_is_dirty = 0;
+        reg = _norflash_eraser(FLASH_SECTOR_ERASER, flash_cache_addr);
+        if (reg) {
+            goto __exit;
+        }
+        reg = _norflash_write_pages(flash_cache_addr, flash_cache_buf, 4096);
+    }
+    if (flash_cache_timer) {
+        sys_timeout_del(flash_cache_timer);
+        flash_cache_timer = 0;
+    }
+__exit:
+    os_mutex_post(&_norflash.mutex);
+}
+#endif
+
+int _norflash_write(u32 addr, void *buf, u32 len, u8 cache)
+{
+    int reg = 0;
+    os_mutex_pend(&_norflash.mutex, 0);
+
+    u8 *w_buf = (u8 *)buf;
+    u32 w_len = len;
+
+    /* y_printf("flash write addr = %d, num = %d\n", addr, len); */
+#if FLASH_CACHE_ENABLE
+    if (!cache) {
+        reg = _norflash_write_pages(addr, w_buf, w_len);
+        goto __exit;
+    }
+    u32 align_addr = addr / 4096 * 4096;
+    u32 align_len = 4096 - (addr - align_addr);
+    align_len = w_len > align_len ? align_len : w_len;
+    if (align_addr != flash_cache_addr) {
+        if (flash_cache_is_dirty) {
+            flash_cache_is_dirty = 0;
+            reg = _norflash_eraser(FLASH_SECTOR_ERASER, flash_cache_addr);
+            if (reg) {
+                goto __exit;
+            }
+            reg = _norflash_write_pages(flash_cache_addr, flash_cache_buf, 4096);
+            if (reg) {
+                goto __exit;
+            }
+        }
+        _norflash_read(align_addr, flash_cache_buf, 4096, 0);
+        flash_cache_addr = align_addr;
+    }
+    memcpy(flash_cache_buf + (addr - align_addr), w_buf, align_len);
+    if ((addr + align_len) % 4096) {
+        flash_cache_is_dirty = 1;
+        if (flash_cache_timer) {
+            sys_timer_re_run(flash_cache_timer);
+        } else {
+            flash_cache_timer = sys_timeout_add(0, _norflash_cache_sync_timer, FLASH_CACHE_SYNC_T_INTERVAL);
+        }
+    } else {
+        flash_cache_is_dirty = 0;
+        reg = _norflash_eraser(FLASH_SECTOR_ERASER, align_addr);
+        if (reg) {
+            goto __exit;
+        }
+        reg = _norflash_write_pages(align_addr, flash_cache_buf, 4096);
+        if (reg) {
+            goto __exit;
+        }
+    }
+    addr += align_len;
+    w_buf += align_len;
+    w_len -= align_len;
+    while (w_len) {
+        u32 cnt = w_len > 4096 ? 4096 : w_len;
+        _norflash_read(addr, flash_cache_buf, 4096, 0);
+        flash_cache_addr = addr;
+        memcpy(flash_cache_buf, w_buf, cnt);
+        if ((addr + cnt) % 4096) {
+            flash_cache_is_dirty = 1;
+            if (flash_cache_timer) {
+                sys_timer_re_run(flash_cache_timer);
+            } else {
+                flash_cache_timer = sys_timeout_add(0, _norflash_cache_sync_timer, FLASH_CACHE_SYNC_T_INTERVAL);
+            }
+        } else {
+            flash_cache_is_dirty = 0;
+            reg = _norflash_eraser(FLASH_SECTOR_ERASER, addr);
+            if (reg) {
+                goto __exit;
+            }
+            reg = _norflash_write_pages(addr, flash_cache_buf, 4096);
+            if (reg) {
+                goto __exit;
+            }
+        }
+        addr += cnt;
+        w_buf += cnt;
+        w_len -= cnt;
+    }
+#else
+    reg = _norflash_write_pages(addr, w_buf, w_len);
+#endif
+__exit:
+    os_mutex_post(&_norflash.mutex);
+    return reg;
+}
+
+int _norflash_eraser(u8 eraser, u32 addr)
+{
+    u8 eraser_cmd;
+    switch (eraser) {
+    case FLASH_PAGE_ERASER:
+        eraser_cmd = WINBOND_PAGE_ERASE;
+        addr = addr / 256 * 256;
+        break;
+    case FLASH_SECTOR_ERASER:
+        eraser_cmd = WINBOND_SECTOR_ERASE;
+        //r_printf(">>>[test]:addr = %d\n", addr);
+        addr = addr / 4096 * 4096;
+        break;
+    case FLASH_BLOCK_ERASER:
+        eraser_cmd = WINBOND_BLOCK_ERASE;
+        addr = addr / 65536 * 65536;
+        break;
+    case FLASH_CHIP_ERASER:
+        eraser_cmd = WINBOND_CHIP_ERASE;
+        break;
+    }
+    _norflash_send_write_enable();
+    spi_cs_l();
+    spi_write_byte(eraser_cmd);
+    if (eraser_cmd != WINBOND_CHIP_ERASE) {
+        _norflash_send_addr(addr);
+    }
+    spi_cs_h();
+    return _norflash_wait_ok();
+}
+
+int _norflash_ioctl(u32 cmd, u32 arg, u32 unit, void *_part)
+{
+    int reg = 0;
+    struct norflash_partition *part = _part;
+    os_mutex_pend(&_norflash.mutex, 0);
+    switch (cmd) {
+    case IOCTL_GET_STATUS:
+        *(u32 *)arg = 1;
+        break;
+    case IOCTL_GET_ID:
+        *((u32 *)arg) = _norflash.flash_id;
+        break;
+    case IOCTL_GET_CAPACITY:
+        if (_norflash.flash_capacity == 0)  {
+            *(u32 *)arg = 0;
+        } else if (_norflash.part_num == 1 && part->start_addr == 0) {
+            *(u32 *)arg = _norflash.flash_capacity / unit;
+        } else {
+            *(u32 *)arg = part->size / unit;
+        }
+        break;
+    case IOCTL_GET_BLOCK_SIZE:
+        *(u32 *)arg = 512;
+        break;
+    case IOCTL_ERASE_PAGE:
+        reg = _norflash_eraser(FLASH_PAGE_ERASER, arg * unit + part->start_addr);
+        break;
+    case IOCTL_ERASE_SECTOR:
+        reg = _norflash_eraser(FLASH_SECTOR_ERASER, arg * unit + part->start_addr);
+        break;
+    case IOCTL_ERASE_BLOCK:
+        reg = _norflash_eraser(FLASH_BLOCK_ERASER, arg * unit + part->start_addr);
+        break;
+    case IOCTL_ERASE_CHIP:
+        reg = _norflash_eraser(FLASH_CHIP_ERASER, 0);
+        break;
+    case IOCTL_FLUSH:
+#if FLASH_CACHE_ENABLE
+        if (flash_cache_is_dirty) {
+            flash_cache_is_dirty = 0;
+            reg = _norflash_eraser(FLASH_SECTOR_ERASER, flash_cache_addr);
+            if (reg) {
+                goto __exit;
+            }
+            reg = _norflash_write_pages(flash_cache_addr, flash_cache_buf, 4096);
+        }
+#endif
+        break;
+    case IOCTL_CMD_RESUME:
+        break;
+    case IOCTL_CMD_SUSPEND:
+        break;
+    case IOCTL_GET_PART_INFO: {
+        u32 *info = (u32 *)arg;
+        u32 *start_addr = &info[0];
+        u32 *part_size = &info[1];
+        *start_addr = part->start_addr;
+        *part_size = part->size;
+    }
+    break;
+    default:
+        reg = -EINVAL;
+        break;
+    }
+__exit:
+    os_mutex_post(&_norflash.mutex);
+    return reg;
+}
+
+
+/*************************************************************************************
+ *                                  挂钩 device_api
+ ************************************************************************************/
+
+static int norflash_dev_init(const struct dev_node *node, void *arg)
+{
+    struct norflash_dev_platform_data *pdata = arg;
+    return _norflash_init(node->name, pdata);
+}
+
+static int norflash_dev_open(const char *name, struct device **device, void *arg)
+{
+    struct norflash_partition *part;
+    part = norflash_find_part(name);
+    if (!part) {
+        log_error("no norflash partition is found\n");
+        return -ENODEV;
+    }
+    *device = &part->device;
+    (*device)->private_data = part;
+    if (atomic_read(&part->device.ref)) {
+        return 0;
+    }
+    return _norflash_open(arg);
+}
+static int norflash_dev_close(struct device *device)
+{
+    return _norflash_close();
+}
+static int norflash_dev_read(struct device *device, void *buf, u32 len, u32 offset)
+{
+    int reg;
+    /* printf("flash read sector = %d, num = %d\n", offset, len); */
+    offset = offset * 512;
+    len = len * 512;
+    struct norflash_partition *part;
+    part = (struct norflash_partition *)device->private_data;
+    if (!part) {
+        log_error("norflash partition invalid\n");
+        return -EFAULT;
+    }
+    offset += part->start_addr;
+    reg = _norflash_read(offset, buf, len, 1);
+    if (reg) {
+        r_printf(">>>[r error]:\n");
+        len = 0;
+    }
+
+    len = len / 512;
+    return len;
+}
+static int norflash_dev_write(struct device *device, void *buf, u32 len, u32 offset)
+{
+    /* printf("flash write sector = %d, num = %d\n", offset, len); */
+    int reg = 0;
+    offset = offset * 512;
+    len = len * 512;
+    struct norflash_partition *part = device->private_data;
+    if (!part) {
+        log_error("norflash partition invalid\n");
+        return -EFAULT;
+    }
+    offset += part->start_addr;
+    reg = _norflash_write(offset, buf, len, 1);
+    if (reg) {
+        r_printf(">>>[w error]:\n");
+        len = 0;
+    }
+    len = len / 512;
+    return len;
+}
+static bool norflash_dev_online(const struct dev_node *node)
+{
+    return 1;
+}
+static int norflash_dev_ioctl(struct device *device, u32 cmd, u32 arg)
+{
+    struct norflash_partition *part = device->private_data;
+    if (!part) {
+        log_error("norflash partition invalid\n");
+        return -EFAULT;
+    }
+    return _norflash_ioctl(cmd, arg, 512, part);
+}
+
+#if 0  //下面这组接口不再使用
+int hook_norflash_init(struct norflash_dev_platform_data *pdata)
+{
+    return _norflash_init("xxxx", pdata);
+}
+
+int hook_norflash_open(void)
+{
+    return  _norflash_open(NULL);
+}
+
+int hook_norflash_spirec_read(u8 *buf, u32 addr, u32 len)
+{
+    /* return _norflash_read(addr, buf,  len); */
+    return _norflash_read(addr, buf, len, 0);
+}
+
+int hook_norflash_spirec_write(u8 *buf, u32 addr, u32 len)
+{
+    return _norflash_write_pages(addr,  buf, len);
+}
+
+void hook_norflash_spirec_eraser(u32 addr)
+{
+    _norflash_eraser(FLASH_SECTOR_ERASER, addr);
+}
+#endif
+
+/*
+ * 1. 外部调用时以512字节为单位的地址和长度,且需要驱动write自己处理擦除,
+ * 请使用norflash_dev_ops接口,否则使用本文件内的其他ops
+ *
+ * 2. 如果不需要驱动自己处理擦除,可以把宏FLASH_CACHE_ENABLE清零,或者把
+ * norflash_dev_read()里面调用的_norflash_read()的实参cache填0,
+ * norflash_dev_write()同理
+ *
+ * 3. norflash_dev_ops可以被多个设备名注册,每个设备名被认为是不同分区,所以
+ * 需要填不同的分区起始地址和大小,若分区地址有重叠或者最大分区结束地址大于
+ * flash容量,会触发ASSERT()
+ *
+ * 4. 关于IOCTL_GET_CAPACITY,有多个分区注册时返回分区的大小,如果只注册了1
+ * 个分区,分区起始地址 == 0时返回flash容量,起始地址 != 0时返回分区大小,
+ * norflash_dev_ops返回的长度以512字节为单位
+ *
+ * 5. 本文件内的各个ops可以同时使用
+ */
+const struct device_operations norflash_dev_ops = {
+    .init   = norflash_dev_init,
+    .online = norflash_dev_online,
+    .open   = norflash_dev_open,
+    .read   = norflash_dev_read,
+    .write  = norflash_dev_write,
+    .ioctl  = norflash_dev_ioctl,
+    .close  = norflash_dev_close,
+};
+
+
+static int norfs_dev_init(const struct dev_node *node, void *arg)
+{
+    struct norflash_dev_platform_data *pdata = arg;
+    return _norflash_init(node->name, pdata);
+}
+
+static int norfs_dev_open(const char *name, struct device **device, void *arg)
+{
+    struct norflash_partition *part;
+    part = norflash_find_part(name);
+    if (!part) {
+        log_error("no norflash partition is found\n");
+        return -ENODEV;
+    }
+    *device = &part->device;
+    (*device)->private_data = part;
+    if (atomic_read(&part->device.ref)) {
+        return 0;
+    }
+    return _norflash_open(arg);
+}
+static int norfs_dev_close(struct device *device)
+{
+    return _norflash_close();
+}
+static int norfs_dev_read(struct device *device, void *buf, u32 len, u32 offset)
+{
+    int reg;
+    /* printf("flash read sector = %d, num = %d\n", offset, len); */
+    struct norflash_partition *part;
+    part = (struct norflash_partition *)device->private_data;
+    if (!part) {
+        log_error("norflash partition invalid\n");
+        return -EFAULT;
+    }
+    offset += part->start_addr;
+    reg = _norflash_read(offset, buf, len, 0);
+    if (reg) {
+        r_printf(">>>[r error]:\n");
+        len = 0;
+    }
+
+    return len;
+}
+static int norfs_dev_write(struct device *device, void *buf, u32 len, u32 offset)
+{
+    /* printf("flash write sector = %d, num = %d\n", offset, len); */
+    int reg = 0;
+    struct norflash_partition *part = device->private_data;
+    if (!part) {
+        log_error("norflash partition invalid\n");
+        return -EFAULT;
+    }
+    offset += part->start_addr;
+    reg = _norflash_write(offset, buf, len, 0);
+    if (reg) {
+        r_printf(">>>[w error]:\n");
+        len = 0;
+    }
+    return len;
+}
+static bool norfs_dev_online(const struct dev_node *node)
+{
+    return 1;
+}
+static int norfs_dev_ioctl(struct device *device, u32 cmd, u32 arg)
+{
+    struct norflash_partition *part = device->private_data;
+    if (!part) {
+        log_error("norflash partition invalid\n");
+        return -EFAULT;
+    }
+    return _norflash_ioctl(cmd, arg, 1, part);
+}
+
+/*
+ * 1. 外部调用时以1字节为单位的地址和长度,且驱动write自己不处理擦除,
+ * 请使用norfs_dev_ops接口,否则使用本文件内的其他ops。注意:有些文件系
+ * 统需要满足这个条件的驱动,如果期望修改成驱动内部处理擦除,需要测试所
+ * 有关联的文件系统是否支持,或者新建一个符合需求的ops
+ *
+ * 2. 如果需要驱动自己处理擦除,需要把宏FLASH_CACHE_ENABLE置1,且
+ * norfs_dev_read()里面调用的_norflash_read()的实参cache填1,
+ * norfs_dev_write()同理
+ *
+ * 3. norfs_dev_ops可以被多个设备名注册,每个设备名被认为是不同分区,所以
+ * 需要填不同的分区起始地址和大小,若分区地址有重叠或者最大分区结束地址大于
+ * flash容量,会触发ASSERT()
+ *
+ * 4. 关于IOCTL_GET_CAPACITY,有多个分区注册时返回分区的大小,如果只注册了1
+ * 个分区,分区起始地址 == 0时返回flash容量,起始地址 != 0时返回分区大小
+ * norfs_dev_ops返回的长度以1字节为单位
+ *
+ * 5. 本文件内的各个ops可以同时使用
+ */
+const struct device_operations norfs_dev_ops = {
+    .init   = norfs_dev_init,
+    .online = norfs_dev_online,
+    .open   = norfs_dev_open,
+    .read   = norfs_dev_read,
+    .write  = norfs_dev_write,
+    .ioctl  = norfs_dev_ioctl,
+    .close  = norfs_dev_close,
+};
+
+/*
+ * 对ops的读写单位有另外需求,或者驱动内部是否支持擦除,可以参照上面的ops,
+ * 不同条件自由组合,建立新的ops
+ */
+
+#endif

+ 193 - 0
apps/common/device/optical_mouse_sensor/OMSensor_manage.c

@@ -0,0 +1,193 @@
+#include "OMSensor_manage.h"
+#include "system/includes.h"
+/* #include "asm/port_wkup.h" */
+#include "app_config.h"
+
+#if TCFG_OMSENSOR_ENABLE
+
+#define LOG_TAG             "[OMSENSOR]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+static const OMSENSOR_INTERFACE *OMSensor_hdl = NULL;
+
+/* static void optical_mouse_sensor_read_motion_handler(void); */
+/* static void optical_mouse_sensor_read_motion_handler(void *priv); */
+
+static s16 avg_filter(s16 *pdata, u8 num)
+{
+    u8 i = 0;
+    s16 sum = 0;
+
+    for (i = 0; i < num; i++) {
+        sum += pdata[i];
+    }
+
+    return (sum / num);
+}
+
+/* __attribute__((interrupt(""))) */
+/* static void port_wkup_isr() */
+/* { */
+/* 	if ((JL_WAKEUP->CON0 & BIT(3)) && (JL_WAKEUP->CON3 & BIT(3))) */
+/*     { */
+/* 		JL_WAKEUP->CON2 |= BIT(3); */
+/* 		#<{(| log_info("optical interrupt\n"); |)}># */
+/* 		#<{(| optical_mouse_sensor_read_motion_handler(); |)}># */
+/* 	} */
+/* } */
+
+static void optical_mouse_sensor_event_to_usr(u8 event, s16 x, s16 y)
+{
+    struct sys_event e;
+    e.type = SYS_DEVICE_EVENT;
+    e.arg = "omsensor_axis";
+    e.u.axis.event = event;
+    e.u.axis.x = x;
+    e.u.axis.y = y;
+    sys_event_notify(&e);
+}
+
+static u8 optical_mouse_sensor_data_ready(void)
+{
+    u8 ret = 0;
+    if (OMSensor_hdl->OMSensor_data_ready) {
+        ret = OMSensor_hdl->OMSensor_data_ready();
+    } else {
+        ret = 0;
+    }
+
+    return ret;
+}
+
+void optical_mouse_sensor_read_motion_handler(void)
+/* static void optical_mouse_sensor_read_motion_handler(void) */
+{
+    s16 x = 0, y = 0;
+    s16 temp = 0;
+
+    if (optical_mouse_sensor_data_ready()) {
+        if (OMSensor_hdl->OMSensor_read_motion) {
+            OMSensor_hdl->OMSensor_read_motion(&x, &y);
+        }
+
+        temp = x;
+        x = y;
+        y = temp;
+
+        VECTOR_REVERS(x);
+        VECTOR_REVERS(y);
+
+#if 0
+        static s16 x_data[3] = {0}, y_data[3] = {0};
+        static u8 count = 0;
+        u8 i = 0;
+
+        if (count < ARRAY_SIZE(x_data)) {
+            x_data[count] = x;
+            y_data[count] = y;
+        } else {
+            for (i = ARRAY_SIZE(x_data) - 1; i > 0; i--) {
+                x_data[i] = x_data[i - 1];
+            }
+            x_data[0] = x;
+
+            for (i = ARRAY_SIZE(y_data) - 1; i > 0; i--) {
+                y_data[i] = y_data[i - 1];
+            }
+            y_data[0] = y;
+        }
+
+        if (count < ARRAY_SIZE(x_data)) {
+            count++;
+        }
+
+        x = avg_filter(&x_data[0], ARRAY_SIZE(x_data));
+        y = avg_filter(&y_data[0], ARRAY_SIZE(y_data));
+#endif
+
+        optical_mouse_sensor_event_to_usr(0, x, y);
+    }
+}
+
+
+u16 optical_mouse_sensor_set_cpi(u16 dst_cpi)
+{
+    u16 cpi = 0;
+
+    if (OMSensor_hdl->OMSensor_set_cpi) {
+        cpi = OMSensor_hdl->OMSensor_set_cpi(dst_cpi);
+    }
+
+    return cpi;
+}
+
+
+u8 get_optical_mouse_sensor_status(void)
+{
+    u8 ret = 0;
+
+    if (OMSensor_hdl->OMSensor_status_dump) {
+        ret =  OMSensor_hdl->OMSensor_status_dump();
+    }
+
+    return ret;
+}
+
+void optical_mouse_sensor_force_wakeup(void)
+{
+    if (OMSensor_hdl->OMSensor_wakeup) {
+        OMSensor_hdl->OMSensor_wakeup();
+    }
+}
+
+void optical_mouse_sensor_led_switch(u8 led_status)
+{
+    if (OMSensor_hdl->OMSensor_led_switch) {
+        OMSensor_hdl->OMSensor_led_switch(led_status);
+    }
+}
+
+bool optical_mouse_sensor_init(OMSENSOR_PLATFORM_DATA *priv)
+{
+    int retval = false;
+
+    //查询驱动列表,匹配设备
+    list_for_each_omsensor(OMSensor_hdl) {
+        if (!memcmp(OMSensor_hdl->OMSensor_id, priv->OMSensor_id, strlen(priv->OMSensor_id))) {
+            retval = true;
+            break;
+        }
+    }
+
+    //匹配失败
+    if (retval == false) {
+        log_error("no match optical mouse sensor driver");
+        return retval;
+    }
+
+    //初始化设备驱动
+    retval = false;
+    if (OMSensor_hdl->OMSensor_init) {
+        retval = OMSensor_hdl->OMSensor_init(priv);
+    }
+
+    //设置optical mouse sensor的采样率
+    if (retval == true) {
+        sys_s_hi_timer_add(NULL, optical_mouse_sensor_read_motion_handler, OPTICAL_SENSOR_SAMPLE_PERIOD); //10ms
+
+        /* port_wkup_enable(priv->OMSensor_int_io, 1); */
+        /* request_irq(IRQ_PORT_IDX, 3, port_wkup_isr, 0); */
+    }
+
+
+    return retval;
+}
+
+#endif
+
+

+ 553 - 0
apps/common/device/optical_mouse_sensor/hal3205/hal3205.c

@@ -0,0 +1,553 @@
+#include "OMSensor_config.h"
+#include "OMSensor_manage.h"
+#include "asm/gpio.h"
+#include "app_config.h"
+#include "stdlib.h"
+
+#if TCFG_HAL3205_EN
+
+#define LOG_TAG         "[hal3205]"
+#define LOG_INFO_ENABLE
+#define LOG_DUMP_ENABLE
+#define LOG_ERROR_ENABLE
+#include "debug.h"
+
+#define CPI_600     600
+#define CPI_800     800
+#define CPI_1000    1000
+#define CPI_1200    1200
+#define CPI_1600    1600
+
+#define CONFIG_CPI		0b111
+
+static OMSENSOR_PLATFORM_DATA *pdata = NULL;
+static u8 time_count = 0;
+static const u8 timeout = 5;
+static u8 configvalue = 0 ;
+static void uSecDelay(u8 len);
+static void frameDelay();
+static bool hal_pixart_init(OMSENSOR_PLATFORM_DATA *priv);
+static bool  hal_pixart_readMotion(s16 *deltaX, s16 *deltaY);
+static u8 hal_pixart_readRegister(u8 regAddress);
+static void hal_pixart_writeRegister(u8 regAddress, u8 innData);
+static u8 hal_pixart_read(void);
+static void hal_pixart_write(u8 dataOut);
+static void resync(void);
+static u16 hal3205_set_cpi(u16 cpi);
+static bool hal_pixart_resync(void);
+static void hal_pixart_led_switch(u8 led_status);
+static void get_overflow_status(u8 motion);
+static void hal_pixart_info_dump(void);
+static void hal_pixart_set_cpi_init(u16 dst_cpi);
+
+
+static const u16 cpi_table[] = {
+    CPI_600, CPI_800, CPI_1000, CPI_1200, CPI_1600,
+};
+
+//static const u16 cpi_table[] = {
+//     CPI_800,  CPI_1200, CPI_1600,
+//};
+
+//功能:超时计数
+static void time_counter(void)
+{
+    time_count++;
+}
+
+//功能:毫秒级延时
+static void uSecDelay(u8 len)
+{
+    len += (len >> 1);
+    while (len--);
+}
+
+// Approximately 2 mSec delay
+static void frameDelay()
+{
+    u8 frameDel = 200;
+    while (frameDel--) {
+        uSecDelay(98);
+    }
+}
+
+static void hal_pixart_gpio_init(void)
+{
+    gpio_set_die(pdata->OMSensor_sclk_io, 1);          //CLK output
+    gpio_set_dieh(pdata->OMSensor_sclk_io, 1);
+    gpio_set_direction(pdata->OMSensor_sclk_io, 0);
+
+    gpio_set_die(pdata->OMSensor_data_io, 1);         //SDIO output
+    gpio_set_dieh(pdata->OMSensor_data_io, 1);
+    gpio_set_direction(pdata->OMSensor_data_io, 0);
+
+    gpio_set_die(pdata->OMSensor_int_io, 1);          //int_io input
+    gpio_set_dieh(pdata->OMSensor_int_io, 1);
+    gpio_set_direction(pdata->OMSensor_int_io, 1);
+    gpio_set_pull_up(pdata->OMSensor_int_io, 0);
+    gpio_set_pull_down(pdata->OMSensor_int_io, 0);
+
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 1);//SCLK is high
+
+}
+
+//功能:paw3205初始化
+static void paw3205_init(void)
+{
+    u8 reg = 0;
+
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x5a);	//Unlock WP
+
+    hal_pixart_writeRegister(0x28, 0xb4);
+    hal_pixart_writeRegister(0x29, 0x46);
+    hal_pixart_writeRegister(0x2a, 0x96);
+    hal_pixart_writeRegister(0x2b, 0x8c);
+    hal_pixart_writeRegister(0x2c, 0x6e);
+    hal_pixart_writeRegister(0x2d, 0x64);
+    hal_pixart_writeRegister(0x38, 0x5f);
+    hal_pixart_writeRegister(0x39, 0x0f);
+    hal_pixart_writeRegister(0x3a, 0x32);
+    hal_pixart_writeRegister(0x3b, 0x47);
+    hal_pixart_writeRegister(0x42, 0x10);
+    hal_pixart_writeRegister(0x54, 0x2e);
+    hal_pixart_writeRegister(0x55, 0xf2);
+    hal_pixart_writeRegister(0x61, 0xf4);
+    hal_pixart_writeRegister(0x63, 0x70);
+    hal_pixart_writeRegister(0x75, 0x52);
+    hal_pixart_writeRegister(0x76, 0x41);
+    hal_pixart_writeRegister(0x77, 0xed);
+    hal_pixart_writeRegister(0x78, 0x23);
+    hal_pixart_writeRegister(0x79, 0x46);
+    hal_pixart_writeRegister(0x7a, 0xe5);
+    hal_pixart_writeRegister(0x7c, 0x48);
+    hal_pixart_writeRegister(0x7d, 0x80);
+    hal_pixart_writeRegister(0x7e, 0x77);
+    hal_pixart_writeRegister(0x4b, 0x1B);
+    hal_pixart_writeRegister(0x06, 0x01);
+    hal_pixart_write(0xff);		//bank1
+    hal_pixart_write(0x01);
+    hal_pixart_writeRegister(0x0b, 0x00);
+    hal_pixart_write(0xff);		//bank0
+    hal_pixart_write(0x00);
+
+    hal_pixart_set_cpi_init(CPI_1200);
+
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x00);	//Lock WP
+}
+
+static bool hal_pixart_init(OMSENSOR_PLATFORM_DATA *priv)
+{
+    pdata = priv;
+
+    //初始化GPIO
+    hal_pixart_gpio_init();
+
+    //初始化延时,确保初始化成功
+    frameDelay();
+
+    //初始化定时器,用以超时检查
+    sys_s_hi_timer_add(NULL, time_counter, 20);
+
+    //同步通信检查
+    if (!hal_pixart_resync()) {
+        goto _init_fail_;
+    }
+
+#ifdef EN_PAW3205
+    paw3205_init(); //paw3205初始化
+#endif
+    hal_pixart_info_dump();
+
+    return true;
+
+_init_fail_:
+    log_error("optical sensor init fail!!!");
+    return false;
+}
+
+
+//功能:检测传感器数据是否可读
+static u8 hal_pixart_data_ready(void)
+{
+    return (!gpio_read(pdata->OMSensor_int_io));
+}
+
+
+//功能:光学感应器寄存器信息打印
+static void hal_pixart_info_dump(void)
+{
+    log_info("Motion_Status    = 0x%x.\n", hal_pixart_readRegister(pixart_MOTION_ADDR));
+    log_info("Opreation_Mode   = 0x%x.\n", hal_pixart_readRegister(pixart_OPMODE_ADDR));
+    log_info("configuration    = 0x%x.\n", hal_pixart_readRegister(pixart_CONFIG_ADDR));
+    log_info("Image_Quality    = 0x%x.\n", hal_pixart_readRegister(pixart_IMGQA_ADDR));
+    log_info("Operation_State  = 0x%x.\n", hal_pixart_readRegister(pixart_OPSTATE_ADDR));
+    log_info("Sleep1_Setting   = 0x%x.\n", hal_pixart_readRegister(pixart_SLP1_ADDR));
+    log_info("Enter_Time       = 0x%x.\n", hal_pixart_readRegister(pixart_SLPETN_ADDR));
+    log_info("Sleep2_Setting   = 0x%x.\n", hal_pixart_readRegister(pixart_SLP2_ADDR));
+    log_info("Image_Threshold  = 0x%x.\n", hal_pixart_readRegister(pixart_IMGQATH_ADDR));
+    log_info("Image_Recognition= 0x%x.\n", hal_pixart_readRegister(pixart_IMGRECOG_ADDR));
+    log_info("POWER_DOWN_CONFIG= 0x%x.\n", hal_pixart_readRegister(pixart_POWER_DOWN_ADDR));
+    log_info("\n");
+}
+
+
+//功能:查看传感器的睡眠状态
+static u8 hal_pixart_status_dump(void)
+{
+    u8 reg = 0;
+    u8 sleep = 0;
+    reg = hal_pixart_readRegister(pixart_OPSTATE_ADDR);
+
+    if ((reg  & 0x07) == 0x06) {
+        if (reg & BIT(3)) {
+            sleep = 2;
+        } else {
+            sleep = 1;
+        }
+    }
+
+    else {
+        sleep = 0;
+    }
+
+    return sleep;
+}
+
+//功能:强制唤醒传感器
+static void hal_pixart_force_wakeup(void)
+{
+    u8 reg = 0;
+
+    reg = hal_pixart_readRegister(pixart_OPMODE_ADDR);
+    reg |= BIT(0);
+
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x5a);	//Lock WP
+    hal_pixart_writeRegister(pixart_OPMODE_ADDR, reg);
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x00);	//Lock WP
+}
+
+static void hal_pixart_led_switch(u8 led_status)
+{
+    u8 reg = 0;
+    u8 ret = 0;
+
+    reg = hal_pixart_readRegister(pixart_POWER_DOWN_ADDR);
+    ret = hal_pixart_readRegister(pixart_CONFIG_ADDR);
+
+    log_info("  before config reg value : 0x%x ", ret);
+
+
+    if (led_status) {
+        ret &= ~BIT(3);
+        reg = 0x1b;
+
+    } else {
+        ret |= BIT(3);
+        reg = 0x13;
+    }
+
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x5a);	//Lock WP
+    hal_pixart_writeRegister(pixart_CONFIG_ADDR, ret);
+    //hal_pixart_writeRegister(pixart_OPMODE_ADDR, reg);
+    hal_pixart_writeRegister(pixart_POWER_DOWN_ADDR, reg);
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x00);	//Lock WP
+    log_info("config reg value :0x%x", hal_pixart_readRegister(pixart_CONFIG_ADDR));
+
+}
+
+
+//功能:读数据
+static bool hal_pixart_readMotion(s16 *deltaX, s16 *deltaY)
+{
+    u8 pid = 0, motion = 0, i = 0, tmp_X = 0, tmp_Y = 0;
+    s16 deltaX_l = 0, deltaY_l = 0, deltaX_h = 0, deltaY_h = 0;
+
+    /* if (!gpio_read(pdata->OMSensor_int_io)) */
+    /* { */
+
+    //同步通信检查
+    if (!hal_pixart_resync()) {
+        goto _resync_fail_;
+    }
+
+    for (i = 0; i < 2; i++) {
+        motion = hal_pixart_readRegister(pixart_MOTION_ADDR);
+        uSecDelay(1);
+
+        get_overflow_status(motion);
+
+        if (motion & 0x80) {
+            tmp_X = hal_pixart_readRegister(pixart_DELTAX_ADDR);
+            uSecDelay(1);
+
+            tmp_Y = hal_pixart_readRegister(pixart_DELTAY_ADDR);
+            uSecDelay(1);
+
+            if (tmp_X & 0x80) {
+                deltaX_h -= (int8_t)(~tmp_X + 1);
+            } else {
+                deltaX_h += tmp_X;
+            }
+
+            if (tmp_Y & 0x80) {
+                deltaY_h -= (int8_t)(~tmp_Y + 1);
+            } else {
+                deltaY_h += tmp_Y;
+            }
+        }
+    }
+    *deltaX = deltaX_h;
+    *deltaY = deltaY_h;
+
+    return true;
+
+_resync_fail_:
+    log_error("optical sensor resync fail!!!");
+    return false;
+}
+
+
+static u8 hal_pixart_readRegister(u8 regAddress)
+{
+    u8 returnVal = 0;
+
+    hal_pixart_write(regAddress);			//Read address
+    returnVal = hal_pixart_read();		//Read data
+
+    return (returnVal);
+}
+
+
+static void hal_pixart_writeRegister(u8 regAddress, u8 innData)
+{
+    u8 time = 0;
+
+    time = time_count;
+
+    do {	//Ensure write setting correct
+        hal_pixart_write(pixart_WRITE | regAddress);  //Write address
+        hal_pixart_write(innData);
+
+        if (abs(time - time_count) >= timeout) { //写操作超时
+            log_error("optical sensor writting timeout!!!");
+            break;
+        }
+    } while (hal_pixart_readRegister(regAddress) != innData);
+}
+/* static void hal_pixart_writeRegister(u8 regAddress, u8 innData) */
+/* { */
+/*   do	//Ensure write setting correct */
+/*   { */
+/*   	hal_pixart_write(pixart_WRITE | regAddress);  //Write address */
+/*   	hal_pixart_write(innData); */
+/*   }while( hal_pixart_readRegister(regAddress)!= innData ); */
+/* } */
+
+
+static bool  hal_pixart_resync(void)
+{
+    u8 time = 0;
+
+    time = time_count;
+
+
+    while (hal_pixart_readRegister(pixart_PID0_ADDR) != 0x30 && hal_pixart_readRegister(pixart_PID0_ADDR) != 0x31) {	//Make sure SPI is sync
+        log_debug("snesor Id :%x", hal_pixart_readRegister(pixart_PID0_ADDR));
+        uSecDelay(10);
+        resync();
+
+        if (abs(time - time_count) >= timeout) { //信号同步超时
+            log_error("optical sensor resync fail!!!");
+            return false;
+        }
+    }
+    return true;
+}
+
+
+static u8 hal_pixart_read(void)
+{
+    u8 returnVal = 0;
+    u8 bitCnt = 0;
+
+    /*SDIO在SCLK处于下降沿时被sensor修改,在SCLK处于上升沿时被controller读取*/
+    OS_ENTER_CRITICAL();
+
+    gpio_set_direction(pdata->OMSensor_data_io, 1);  //SDIO, as input
+    gpio_set_pull_up(pdata->OMSensor_data_io, 1);
+    gpio_set_pull_down(pdata->OMSensor_data_io, 0);
+
+    for (bitCnt = 8; bitCnt != 0; bitCnt--) { /* Read 8 bits MSB...LSB */
+        //new spi ~760khz(21 cycles)
+        gpio_set_output_value(pdata->OMSensor_sclk_io, 0);    //SCLK is low, 3 cycles
+        /* gpio_set_output_value(pdata->OMSensor_sclk_io, 0); //3 cycles */
+
+        returnVal <<= 1;	                                  //Shift read data, 5 cycles
+
+        delay(1);                                             //3 cycles
+
+        gpio_set_output_value(pdata->OMSensor_sclk_io, 1);    //SCLK is high, 3 cycles
+
+        if (gpio_read(pdata->OMSensor_data_io)) {             //JNB 4 cycles
+            returnVal |= 0x01;	                              //DJNZ 3 cycles; if SDIO, plus 4 cycles
+        }
+        delay(1);
+    }
+
+    OS_EXIT_CRITICAL();
+    return (returnVal);
+}
+
+
+static void hal_pixart_write(u8 dataOut)
+{
+    u8 bitCnt = 0;
+
+    OS_ENTER_CRITICAL();
+    /*SDIO在SCLK处于下降沿时被controller修改,在SCLK处于上升沿时被sensor读取*/
+    gpio_set_direction(pdata->OMSensor_data_io, 0);              //SDIO, as output
+
+    for (bitCnt = 8; bitCnt != 0; bitCnt--) {               /* Read 8 bits MSB...LSB */
+        //new spi ~730khz(22 cycles)
+        gpio_set_output_value(pdata->OMSensor_sclk_io, 0);		//SCLK is low, 3 cycles
+        delay(1);
+
+        if (dataOut & 0x80) {	//JNB 4 cycles
+            gpio_set_output_value(pdata->OMSensor_data_io, 1);    //SDIO is high, 3 cycles; plus SJMP 4 cycles
+        } else {
+            gpio_set_output_value(pdata->OMSensor_data_io, 0);    //SDIO is low, 3 cycles
+        }
+
+        gpio_set_output_value(pdata->OMSensor_sclk_io, 1);		//SCLK is high, 3 cycles
+
+        delay(1);
+
+        dataOut <<= 1;		                                    //Shift write data, 5 cycles; plus DJNZ 3 cycles
+    }
+
+    gpio_set_direction(pdata->OMSensor_data_io, 1);		        //SDIO, as input
+
+    OS_EXIT_CRITICAL();
+
+}
+
+static void resync(void)
+{
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 0);    //SCLK is low
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 0);
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 0);
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 0);
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 0);
+
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 1);    //SCLK is high
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 1);
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 1);
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 1);
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 1);
+}
+
+
+static void hal_pixart_set_cpi_init(u16 dst_cpi)
+{
+    u8 reg, i;
+
+    for (i = 0; i < ARRAY_SIZE(cpi_table); i++) {
+        if (dst_cpi == cpi_table[i]) {
+            break;
+        }
+    }
+
+    reg = hal_pixart_readRegister(pixart_CONFIG_ADDR);
+    reg &= ~(CONFIG_CPI);
+    reg |= i;
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x5a);
+    hal_pixart_writeRegister(pixart_CONFIG_ADDR, reg);
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x00);
+    log_info("config  regs : 0x%x ", hal_pixart_readRegister(pixart_CONFIG_ADDR));
+    log_info("cpi init default = %d", cpi_table[i]);
+
+}
+
+//功能:设置CPI
+static u16 hal_pixart_set_cpi(u16 dst_cpi)
+{
+    u8 reg = 0;
+    u8 cpi_idx = -1;
+    u8 i;
+
+    for (i = 0; i < ARRAY_SIZE(cpi_table); i++) {
+        if (dst_cpi == cpi_table[i]) {
+            cpi_idx = i;
+            break;
+        }
+    }
+
+    if (cpi_idx > ARRAY_SIZE(cpi_table)) {
+        log_debug("cpi set fail");
+        return 0;
+    }
+
+    reg = hal_pixart_readRegister(pixart_CONFIG_ADDR);
+    reg &= ~(CONFIG_CPI);
+    reg |= cpi_idx;
+    log_info("get inddex of config  value :0x%x,cpi_idx=%d", reg, cpi_idx);
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x5a);     //Unlock WP
+    hal_pixart_writeRegister(pixart_CONFIG_ADDR, reg);  //set cpi
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x00);	   //Lock WP
+
+    reg = hal_pixart_readRegister(pixart_CONFIG_ADDR) & 7;
+    log_debug("CONFIGURATION:CPI[2:0] = %d. idx = %d\n", reg, cpi_idx);
+    log_info("config value :0x%x", hal_pixart_readRegister(pixart_CONFIG_ADDR));
+    cpi_idx = (cpi_idx + 1) % ARRAY_SIZE(cpi_table);
+
+    return cpi_table[reg & CONFIG_CPI];
+}
+
+
+REGISTER_OMSENSOR(optical_mouse_sensor) = {
+    .OMSensor_id          = "hal3205",
+    .OMSensor_init        = hal_pixart_init,
+    .OMSensor_read_motion = hal_pixart_readMotion,
+    .OMSensor_data_ready  = hal_pixart_data_ready,
+    .OMSensor_status_dump = hal_pixart_status_dump,
+    .OMSensor_wakeup = hal_pixart_force_wakeup,
+    .OMSensor_led_switch  = hal_pixart_led_switch,
+    .OMSensor_set_cpi     = hal_pixart_set_cpi,
+};
+
+static u8 hal3205_idle_query(void)
+{
+    if (pdata) {
+        return (gpio_read(pdata->OMSensor_int_io));
+    }
+    return 1;
+}
+
+REGISTER_LP_TARGET(hal3205_lp_target) = {
+    .name = "hal3205",
+    .is_idle = hal3205_idle_query,
+};
+
+
+static void get_overflow_status(u8 motion)
+{
+    u8 reg = 0, dxovf = 0, dyovf = 0;
+
+    dxovf = (motion & BIT(3)) >> 3;
+    dyovf = (motion & BIT(4)) >> 4;
+
+    if (dxovf) {
+        printf(">>>>>>>>>>>>>>>>>>>DXOVF>>>>>>>>>>>>>>>>>>>>>>>>\n");
+    }
+
+    if (dyovf) {
+        printf(">>>>>>>>>>>>>>>>>>>DYOVF>>>>>>>>>>>>>>>>>>>>>>>>\n");
+    }
+}
+
+
+
+
+#endif  /*  hal3205 enable */
+
+

+ 540 - 0
apps/common/device/optical_mouse_sensor/hal3212/hal3212.c

@@ -0,0 +1,540 @@
+#include "OMSensor_config.h"
+#include "OMSensor_manage.h"
+#include "asm/gpio.h"
+#include "app_config.h"
+#include "stdlib.h"
+#if TCFG_HAL3212_EN
+#define LOG_TAG         "[hal3212]"
+#define LOG_INFO_ENABLE
+#define LOG_DUMP_ENABLE
+#define LOG_ERROR_ENABLE
+#include "debug.h"
+
+#define CPI_800     0x15   /* 0x15 * 38 =800    38 per len            */
+#define CPI_1200    0x1b   /*27 * 38 = 1026*/
+#define CPI_1600    0x2a   /*0x2a * 38 =1600 */
+
+
+
+#define CONFIG_CPI		0b111
+
+static OMSENSOR_PLATFORM_DATA *pdata = NULL;
+static u8 time_count = 0;
+static const u8 timeout = 5;
+static u8 configvalue = 0 ;
+static void uSecDelay(u8 len);
+static void frameDelay();
+static bool hal_pixart_init(OMSENSOR_PLATFORM_DATA *priv);
+static bool  hal_pixart_readMotion(s16 *deltaX, s16 *deltaY);
+static u8 hal_pixart_readRegister(u8 regAddress);
+static void hal_pixart_writeRegister(u8 regAddress, u8 innData);
+static u8 hal_pixart_read(void);
+static void hal_pixart_write(u8 dataOut);
+static void resync(void);
+/* static u16 hal3205_set_cpi(u16 cpi); */
+static bool hal_pixart_resync(void);
+static void hal_pixart_led_switch(u8 led_status);
+static void get_overflow_status(u8 motion);
+static void hal_pixart_info_dump(void);
+static void hal_pixart_set_cpi_init(u16 dst_cpi);
+
+
+const u16 cpi_table[] = {
+    CPI_800, CPI_1200, CPI_1600,
+};
+
+
+
+//功能:超时计数
+static void time_counter(void)
+{
+    time_count++;
+}
+
+//功能:毫秒级延时
+static void uSecDelay(u8 len)
+{
+    len += (len >> 1);
+    while (len--);
+}
+
+// Approximately 2 mSec delay
+static void frameDelay()
+{
+    u8 frameDel = 200;
+    while (frameDel--) {
+        uSecDelay(98);
+    }
+}
+
+static void hal_pixart_gpio_init(void)
+{
+    gpio_set_die(pdata->OMSensor_sclk_io, 1);          //CLK output
+    gpio_set_dieh(pdata->OMSensor_sclk_io, 1);
+    gpio_set_direction(pdata->OMSensor_sclk_io, 0);
+
+    gpio_set_die(pdata->OMSensor_data_io, 1);         //SDIO output
+    gpio_set_dieh(pdata->OMSensor_data_io, 1);
+    gpio_set_direction(pdata->OMSensor_data_io, 0);
+
+    gpio_set_die(pdata->OMSensor_int_io, 1);          //int_io input
+    gpio_set_dieh(pdata->OMSensor_int_io, 1);
+    gpio_set_direction(pdata->OMSensor_int_io, 1);
+    gpio_set_pull_up(pdata->OMSensor_int_io, 0);
+    gpio_set_pull_down(pdata->OMSensor_int_io, 0);
+
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 1);//SCLK is high
+
+}
+
+//功能:paw3205初始化
+static void paw3212_init(void)
+{
+    u8 reg = 0;
+
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x5a);	//Unlock WP
+
+
+    //hal_pixart_writeRegister(0x02, 0x81);
+
+    hal_pixart_writeRegister(0x19, 0x00);   //8bit表示一个数据 还有一种配置12bit
+    hal_pixart_writeRegister(0x07, 0x08);   // X Y only
+    hal_pixart_writeRegister(0x26, 0x34);  //2_wired mode SPI
+    hal_pixart_writeRegister(0x4b, 0x04);   //turn off internal current low power1.7-2.1v
+    hal_pixart_writeRegister(0x06, 0x11);
+    /* hal_pixart_writeRegister(0x05, 0xb8); */
+    /* hal_pixart_writeRegister(0x5b, 0x63);  //LED continue mode */
+
+
+
+
+    hal_pixart_set_cpi_init(CPI_1200);
+
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x00);	//Lock WP
+}
+
+static bool hal_pixart_init(OMSENSOR_PLATFORM_DATA *priv)
+{
+    pdata = priv;
+
+    //初始化GPIO
+    hal_pixart_gpio_init();
+
+    //初始化延时,确保初始化成功
+    frameDelay();
+
+    //初始化定时器,用以超时检查
+    sys_s_hi_timer_add(NULL, time_counter, 20);
+
+    //同步通信检查
+    if (!hal_pixart_resync()) {
+        goto _init_fail_;
+    }
+
+#ifdef EN_PAW3212
+    paw3212_init(); //paw3212初始化
+#endif
+    hal_pixart_info_dump();
+
+    return true;
+
+_init_fail_:
+    log_error("optical sensor init fail!!!");
+    return false;
+}
+
+
+//功能:检测传感器数据是否可读
+static u8 hal_pixart_data_ready(void)
+{
+
+    return (!gpio_read(pdata->OMSensor_int_io));
+}
+
+
+//功能:光学感应器寄存器信息打印
+static void hal_pixart_info_dump(void)
+{
+
+
+    log_info("product  ID_00   = 0x%x.\n", hal_pixart_readRegister(pixart_PID0_ADDR));
+    log_info("product  ID_01   = 0x%x.\n", hal_pixart_readRegister(pixart_PID1_ADDR));
+    log_info("Motion_Status    = 0x%x.\n", hal_pixart_readRegister(pixart_MOTION_ADDR));
+    log_info("Opreation_Mode   = 0x%x.\n", hal_pixart_readRegister(pixart_OPMODE_ADDR));
+    log_info("configuration    = 0x%x.\n", hal_pixart_readRegister(pixart_CONFIG_ADDR));
+    log_info("Sleep_mode1      = 0x%x.\n", hal_pixart_readRegister(pixart_SLP1_ADDR));
+    log_info("IQC              = 0x%x.\n", hal_pixart_readRegister(pixart_IQC_ADDR));
+    log_info("Sleep_mode2      = 0x%x.\n", hal_pixart_readRegister(pixart_SLP2_ADDR));
+    log_info("Shutter          = 0x%x.\n", hal_pixart_readRegister(pixart_Shutter_ADDR));
+    log_info("Sleep_mode3      = 0x%x.\n", hal_pixart_readRegister(pixart_SLP3_ADDR));
+    log_info("Frame_Avg        = 0x%x.\n", hal_pixart_readRegister(pixart_Frame_Avg_ADDR));
+    log_info("Mouse_Option     = 0x%x.\n", hal_pixart_readRegister(pixart_Mouse_Option_ADDR));
+    log_info("POWER_DOWN_CONFIG= 0x%x.\n", hal_pixart_readRegister(pixart_POWER_DOWN_ADDR));
+
+
+    log_info("\n");
+}
+
+
+//功能:查看传感器的睡眠状态
+static u8 hal_pixart_status_dump(void)
+{
+    u8 reg = 0;
+    u8 sleep = 0;
+
+
+    if ((reg  & 0x07) == 0x06) {
+        if (reg & BIT(3)) {
+            sleep = 2;
+        } else {
+            sleep = 1;
+        }
+    }
+
+    else {
+        sleep = 0;
+    }
+
+    return sleep;
+}
+
+//功能:强制唤醒传感器
+static void hal_pixart_force_wakeup(void)
+{
+    u8 reg = 0;
+
+    reg = hal_pixart_readRegister(pixart_OPMODE_ADDR);
+    reg |= BIT(0);
+
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x5a);	//Lock WP
+    hal_pixart_writeRegister(pixart_OPMODE_ADDR, reg);
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x00);	//Lock WP
+}
+
+static void hal_pixart_led_switch(u8 led_status)
+{
+    u8 reg = 0;
+    u8 ret = 0;
+
+    reg = hal_pixart_readRegister(pixart_POWER_DOWN_ADDR);
+    ret = hal_pixart_readRegister(pixart_CONFIG_ADDR);
+
+
+    if (led_status) {
+        ret &= ~BIT(3);
+        ret |= BIT(5);
+        reg = 0x1b;
+
+    } else {
+        ret |= BIT(3);
+        reg = 0x13;
+    }
+
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x5a);	//Lock WP
+    hal_pixart_writeRegister(pixart_CONFIG_ADDR, ret);
+    hal_pixart_writeRegister(pixart_POWER_DOWN_ADDR, reg);
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x00);	//Lock WP
+    hal_pixart_readRegister(pixart_CONFIG_ADDR);
+
+}
+
+
+//功能:读数据
+static bool hal_pixart_readMotion(s16 *deltaX, s16 *deltaY)
+{
+    u8 pid = 0, motion = 0, i = 0, tmp_X = 0, tmp_Y = 0;
+    s16 deltaX_l = 0, deltaY_l = 0, deltaX_h = 0, deltaY_h = 0;
+
+    /* if (!gpio_read(pdata->OMSensor_int_io)) */
+    /* { */
+
+    //同步通信检查
+    if (!hal_pixart_resync()) {
+        goto _resync_fail_;
+    }
+
+    for (i = 0; i < 2; i++) {
+        motion = hal_pixart_readRegister(pixart_MOTION_ADDR);
+
+        uSecDelay(1);
+
+        get_overflow_status(motion);
+
+        if (motion & 0x80) {
+
+            tmp_X = hal_pixart_readRegister(pixart_DELTAX_ADDR);
+            uSecDelay(1);
+
+            tmp_Y = hal_pixart_readRegister(pixart_DELTAY_ADDR);
+            uSecDelay(1);
+
+            if (tmp_X & 0x80) {
+                deltaX_h -= (int8_t)(~tmp_X + 1);
+            } else {
+                deltaX_h += tmp_X;
+            }
+
+            if (tmp_Y & 0x80) {
+                deltaY_h -= (int8_t)(~tmp_Y + 1);
+            } else {
+                deltaY_h += tmp_Y;
+            }
+        }
+    }
+
+
+    *deltaX = deltaX_h;
+    *deltaY = deltaY_h;
+
+
+    return true;
+
+_resync_fail_:
+    log_error("optical sensor resync fail!!!");
+    return false;
+}
+
+
+static u8 hal_pixart_readRegister(u8 regAddress)
+{
+    u8 returnVal = 0;
+
+    hal_pixart_write(regAddress);			//Read address
+    returnVal = hal_pixart_read();		//Read data
+
+    return (returnVal);
+}
+
+
+static void hal_pixart_writeRegister(u8 regAddress, u8 innData)
+{
+    u8 time = 0;
+
+    time = time_count;
+
+
+    do {	//Ensure write setting correct
+        hal_pixart_write(pixart_WRITE | regAddress);  //Write address
+        hal_pixart_write(innData);
+
+        if (abs(time - time_count) >= timeout) { //写操作超时
+            log_error("optical sensor writting timeout!!!");
+            break;
+        }
+    } while (hal_pixart_readRegister(regAddress) != innData);
+
+}
+/* static void hal_pixart_writeRegister(u8 regAddress, u8 innData) */
+/* { */
+/*   do	//Ensure write setting correct */
+/*   { */
+/*   	hal_pixart_write(pixart_WRITE | regAddress);  //Write address */
+/*   	hal_pixart_write(innData); */
+/*   }while( hal_pixart_readRegister(regAddress)!= innData ); */
+/* } */
+
+
+static bool  hal_pixart_resync(void)
+{
+    u8 time = 0;
+
+    time = time_count;
+
+    while (hal_pixart_readRegister(pixart_PID0_ADDR) != 0x30 && hal_pixart_readRegister(pixart_PID0_ADDR) != 0x31) {	//Make sure SPI is sync
+        log_debug("sensor Id :%x", hal_pixart_readRegister(pixart_PID0_ADDR));
+        uSecDelay(10);
+        resync();
+
+        if (abs(time - time_count) >= timeout) { //信号同步超时
+            log_error("optical sensor resync fail!!!");
+            return false;
+        }
+    }
+    return true;
+}
+
+
+static u8 hal_pixart_read(void)
+{
+    u8 returnVal = 0;
+    u8 bitCnt = 0;
+
+    /*SDIO在SCLK处于下降沿时被sensor修改,在SCLK处于上升沿时被controller读取*/
+    OS_ENTER_CRITICAL();
+
+    gpio_set_direction(pdata->OMSensor_data_io, 1);  //SDIO, as input
+    gpio_set_pull_up(pdata->OMSensor_data_io, 1);
+    gpio_set_pull_down(pdata->OMSensor_data_io, 0);
+
+    for (bitCnt = 8; bitCnt != 0; bitCnt--) { /* Read 8 bits MSB...LSB */
+        //new spi ~760khz(21 cycles)
+        gpio_set_output_value(pdata->OMSensor_sclk_io, 0);    //SCLK is low, 3 cycles
+        /* gpio_set_output_value(pdata->OMSensor_sclk_io, 0); //3 cycles */
+
+        returnVal <<= 1;	                                  //Shift read data, 5 cycles
+
+        delay(1);                                             //3 cycles
+
+        gpio_set_output_value(pdata->OMSensor_sclk_io, 1);    //SCLK is high, 3 cycles
+
+        if (gpio_read(pdata->OMSensor_data_io)) {             //JNB 4 cycles
+            returnVal |= 0x01;	                              //DJNZ 3 cycles; if SDIO, plus 4 cycles
+        }
+        delay(1);
+    }
+
+    OS_EXIT_CRITICAL();
+    return (returnVal);
+}
+
+
+static void hal_pixart_write(u8 dataOut)
+{
+    u8 bitCnt = 0;
+
+    OS_ENTER_CRITICAL();
+    /*SDIO在SCLK处于下降沿时被controller修改,在SCLK处于上升沿时被sensor读取*/
+    gpio_set_direction(pdata->OMSensor_data_io, 0);              //SDIO, as output
+
+    for (bitCnt = 8; bitCnt != 0; bitCnt--) {               /* Read 8 bits MSB...LSB */
+        //new spi ~730khz(22 cycles)
+        gpio_set_output_value(pdata->OMSensor_sclk_io, 0);		//SCLK is low, 3 cycles
+        delay(1);
+
+        if (dataOut & 0x80) {	//JNB 4 cycles
+            gpio_set_output_value(pdata->OMSensor_data_io, 1);    //SDIO is high, 3 cycles; plus SJMP 4 cycles
+        } else {
+            gpio_set_output_value(pdata->OMSensor_data_io, 0);    //SDIO is low, 3 cycles
+        }
+
+        gpio_set_output_value(pdata->OMSensor_sclk_io, 1);		//SCLK is high, 3 cycles
+
+        delay(1);
+
+        dataOut <<= 1;		                                    //Shift write data, 5 cycles; plus DJNZ 3 cycles
+    }
+
+    gpio_set_direction(pdata->OMSensor_data_io, 1);		        //SDIO, as input
+
+    OS_EXIT_CRITICAL();
+
+}
+
+static void resync(void)
+{
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 0);    //SCLK is low
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 0);
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 0);
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 0);
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 0);
+
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 1);    //SCLK is high
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 1);
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 1);
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 1);
+    gpio_set_output_value(pdata->OMSensor_sclk_io, 1);
+}
+
+static const u16 cpi_value[3] = {800, 1200, 1600};
+static void hal_pixart_set_cpi_init(u16 dst_cpi)
+{
+    u8 reg, i;
+
+    for (i = 0; i < ARRAY_SIZE(cpi_table); i++) {
+        if (dst_cpi == cpi_value[i]) {
+            reg = cpi_table[i];
+            break;
+        }
+    }
+
+    reg = hal_pixart_readRegister(pixart_CPI_X_ADDR);
+    reg = hal_pixart_readRegister(pixart_CPI_Y_ADDR);
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x5a);
+    hal_pixart_writeRegister(pixart_CPI_X_ADDR, reg);
+    hal_pixart_writeRegister(pixart_CPI_Y_ADDR, reg);
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x00);
+    log_info("cpi init default = %d", cpi_table[i]);
+
+}
+
+//功能:设置CPI
+static u16 hal_pixart_set_cpi(u16 dst_cpi)
+{
+    u8 reg = 0;
+    u8 cpi_idx = -1;
+    u8 i;
+
+    for (i = 0; i < ARRAY_SIZE(cpi_table); i++) {
+        if (dst_cpi == cpi_value[i]) {
+            cpi_idx = i;
+            break;
+        }
+    }
+
+    if (cpi_idx > ARRAY_SIZE(cpi_table)) {
+        log_debug("cpi set fail");
+        return 0;
+    }
+
+    reg = hal_pixart_readRegister(pixart_CPI_X_ADDR);
+    reg = hal_pixart_readRegister(pixart_CPI_Y_ADDR);
+    reg = cpi_table[i];
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x5a);     //Unlock WP
+    hal_pixart_writeRegister(pixart_CPI_X_ADDR, reg);  //set cpi
+    hal_pixart_writeRegister(pixart_CPI_Y_ADDR, reg);  //set cpi
+    hal_pixart_writeRegister(pixart_WP_ADDR, 0x00);	   //Lock WP
+    log_debug("CONFIGURATION:CPI[2:0] = %d. idx = %d\n", reg, cpi_idx);
+    reg = hal_pixart_readRegister(pixart_CONFIG_ADDR) & 7;
+    cpi_idx = (cpi_idx + 1) % ARRAY_SIZE(cpi_table);
+    return cpi_table[reg & CONFIG_CPI];
+}
+
+
+REGISTER_OMSENSOR(optical_mouse_sensor) = {
+    .OMSensor_id          = "hal3212",
+    .OMSensor_init        = hal_pixart_init,
+    .OMSensor_read_motion = hal_pixart_readMotion,
+    .OMSensor_data_ready  = hal_pixart_data_ready,
+    .OMSensor_status_dump = hal_pixart_status_dump,
+    .OMSensor_wakeup = hal_pixart_force_wakeup,
+    .OMSensor_led_switch  = hal_pixart_led_switch,
+    .OMSensor_set_cpi     = hal_pixart_set_cpi,
+};
+
+static u8 hal3212_idle_query(void)
+{
+    if (pdata) {
+        return (gpio_read(pdata->OMSensor_int_io));
+    }
+    return 1;
+}
+
+REGISTER_LP_TARGET(hal3205_lp_target) = {
+    .name = "hal3212",
+    .is_idle = hal3212_idle_query,
+};
+
+
+static void get_overflow_status(u8 motion)
+{
+    u8 reg = 0, dxovf = 0, dyovf = 0;
+
+    dxovf = (motion & BIT(3)) >> 3;
+    dyovf = (motion & BIT(4)) >> 4;
+
+    if (dxovf) {
+        printf(">>>>>>>>>>>>>>>>>>>DXOVF>>>>>>>>>>>>>>>>>>>>>>>>\n");
+    }
+
+    if (dyovf) {
+        printf(">>>>>>>>>>>>>>>>>>>DYOVF>>>>>>>>>>>>>>>>>>>>>>>>\n");
+    }
+}
+
+
+
+
+#endif  /*  hal3212 enable */
+
+
+

+ 17 - 0
apps/common/device/optical_mouse_sensor/include/OMSensor_config.h

@@ -0,0 +1,17 @@
+#ifndef OMSENSOR_CONFIG_H
+#define OMSENSOR_CONFIG_H
+
+#define OMSensor_HAL3205_ENABLE TCFG_HAL3205_ENABLE
+// #define OMSensor_HAL3212_ENABLE TCFG_HAL3212_ENABLE
+
+
+#include "hal3205/hal3205.h"
+#include "hal3212/hal3212.h"
+
+
+
+
+#endif
+
+
+

+ 50 - 0
apps/common/device/optical_mouse_sensor/include/OMSensor_manage.h

@@ -0,0 +1,50 @@
+#ifndef _OMSM_H_
+#define _OMSM_H_
+
+#include "system/includes.h"
+
+#define VECTOR_REVERS(vec)	vec = ~vec; vec++
+
+typedef struct {
+    u8 OMSensor_id[20];
+    u8 OMSensor_sclk_io;
+    u8 OMSensor_data_io;
+    u8 OMSensor_int_io;
+} OMSENSOR_PLATFORM_DATA;
+
+typedef struct {
+    u8 OMSensor_id[20];
+    bool(*OMSensor_init)(OMSENSOR_PLATFORM_DATA *);
+    bool (*OMSensor_read_motion)(s16 *, s16 *);
+    u8(*OMSensor_data_ready)(void);
+    u8(*OMSensor_status_dump)(void);
+    void (*OMSensor_wakeup)(void);
+    void (*OMSensor_led_switch)(u8);
+    u16(*OMSensor_set_cpi)(u16 dst_cpi);
+} OMSENSOR_INTERFACE;
+
+
+extern OMSENSOR_INTERFACE OMSensor_dev_begin[];
+extern OMSENSOR_INTERFACE OMSensor_dev_end[];
+
+#define REGISTER_OMSENSOR(OMSensor) \
+	static OMSENSOR_INTERFACE OMSensor SEC_USED(.omsensor_dev)
+
+#define list_for_each_omsensor(c) \
+	for (c=OMSensor_dev_begin; c<OMSensor_dev_end; c++)
+
+#define OMSENSOR_PLATFORM_DATA_BEGIN(data) \
+		OMSENSOR_PLATFORM_DATA data = {
+
+#define OMSENSOR_PLATFORM_DATA_END() \
+};
+
+bool optical_mouse_sensor_init(OMSENSOR_PLATFORM_DATA *priv);
+void optical_mouse_sensor_read_motion_handler(void);
+u16 optical_mouse_sensor_set_cpi(u16 dst_cpi);
+u8 get_optical_mouse_sensor_status(void);
+void optical_mouse_sensor_force_wakeup(void);
+void optical_mouse_sensor_led_switch(u8 led_status);
+
+#endif // _OMSM_H_
+

+ 37 - 0
apps/common/device/optical_mouse_sensor/include/hal3205/hal3205.h

@@ -0,0 +1,37 @@
+//===========================================================================
+//	For PixArt Mouse Sensor		//Hill, 2009.12.11
+//===========================================================================
+#ifndef _PAW3205_H_
+#define _PAW3205_H_
+#include "asm/cpu.h"
+#include <stdint.h>
+#include <stdbool.h>
+#ifdef OMSensor_HAL3205_ENABLE
+
+#define EN_PAW3205
+// PixArt Register Addresses
+#define pixart_PID0_ADDR         	0x00
+#define pixart_PID1_ADDR        	0x01
+#define pixart_MOTION_ADDR       	0x02
+#define pixart_DELTAX_ADDR     		0x03
+#define pixart_DELTAY_ADDR   		0x04
+#define pixart_OPMODE_ADDR    		0x05
+#define pixart_CONFIG_ADDR      	0x06
+#define pixart_IMGQA_ADDR     		0x07
+#define pixart_OPSTATE_ADDR     	0x08
+#define pixart_WP_ADDR     			0x09
+#define pixart_SLP1_ADDR         	0x0A
+#define pixart_SLPETN_ADDR     		0x0B
+#define pixart_SLP2_ADDR    		0x0C
+#define pixart_IMGQATH_ADDR  		0x0D
+#define pixart_IMGRECOG_ADDR   		0x0E
+#define pixart_POWER_DOWN_ADDR          0x4B
+
+// PixArt Read/Write configuration settings
+#define pixart_WRITE      0x80
+#define pixart_READ       0x00
+
+#endif //_HAL3205_H_
+#endif //_HAL3205_H_
+
+

+ 46 - 0
apps/common/device/optical_mouse_sensor/include/hal3212/hal3212.h

@@ -0,0 +1,46 @@
+
+//===========================================================================
+//	For PixArt Mouse Sensor
+//===========================================================================
+#ifndef _PAW3212_H_
+#define _PAW3212_H_
+#include "asm/cpu.h"
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef OMSensor_HAL3212_ENABLE
+
+
+#define EN_PAW3212
+// PixArt Register Addresses
+#define pixart_PID0_ADDR         	0x00
+#define pixart_PID1_ADDR        	0x01
+#define pixart_MOTION_ADDR       	0x02
+#define pixart_DELTAX_ADDR     		0x03
+#define pixart_DELTAY_ADDR   		0x04
+#define pixart_OPMODE_ADDR    		0x05
+#define pixart_CONFIG_ADDR      	0x06
+
+#define pixart_WP_ADDR     			0x09
+#define pixart_SLP1_ADDR         	0x0A
+#define pixart_SLP2_ADDR     		0x0B
+#define pixart_SLP3_ADDR    		0x0C
+#define pixart_CPI_X_ADDR    		0x0D
+#define pixart_CPI_Y_ADDR   		0x0E
+
+#define pixart_Delta_XY_HI_ADDR     0x12
+#define pixart_IQC_ADDR     		0x13
+#define pixart_Shutter_ADDR    		0x14
+#define pixart_Frame_Avg_ADDR    	0x17
+#define pixart_Mouse_Option_ADDR   	0x19
+
+#define pixart_POWER_DOWN_ADDR      0x4B
+
+
+// PixArt Read/Write configuration settings
+#define pixart_WRITE      0x80
+#define pixart_READ       0x00
+
+#endif //_HAL3212_H_
+#endif //_HAL3212_H_
+

+ 115 - 0
apps/common/device/touch_pad/SYD9557M.c

@@ -0,0 +1,115 @@
+#include "app_config.h"
+#include "SYD9557M.h"
+#include "asm/gpio.h"
+#include "timer.h"
+#include "event.h"
+#include "asm/power_interface.h"
+
+#if TCFG_TOUCHPAD_ENABLE
+#if 0
+#define iic_init(iic)                       hw_iic_init(iic)
+#define iic_uninit(iic)                     hw_iic_uninit(iic)
+#define iic_start(iic)                      hw_iic_start(iic)
+#define iic_stop(iic)                       hw_iic_stop(iic)
+#define iic_tx_byte(iic, byte)              hw_iic_tx_byte(iic, byte)
+#define iic_rx_byte(iic, ack)               hw_iic_rx_byte(iic, ack)
+#define iic_read_buf(iic, buf, len)         hw_iic_read_buf(iic, buf, len)
+#define iic_write_buf(iic, buf, len)        hw_iic_write_buf(iic, buf, len)
+#define iic_suspend(iic)                    hw_iic_suspend(iic)
+#define iic_resume(iic)                     hw_iic_resume(iic)
+#else
+#define iic_init(iic)                       soft_iic_init(iic)
+#define iic_uninit(iic)                     soft_iic_uninit(iic)
+#define iic_start(iic)                      soft_iic_start(iic)
+#define iic_stop(iic)                       soft_iic_stop(iic)
+#define iic_tx_byte(iic, byte)              soft_iic_tx_byte(iic, byte)
+#define iic_rx_byte(iic, ack)               soft_iic_rx_byte(iic, ack)
+#define iic_read_buf(iic, buf, len)         soft_iic_read_buf(iic, buf, len)
+#define iic_write_buf(iic, buf, len)        soft_iic_write_buf(iic, buf, len)
+#define iic_suspend(iic)                    soft_iic_suspend(iic)
+#define iic_resume(iic)                     soft_iic_resume(iic)
+#endif
+
+#define INT_IO          IO_PORTB_04
+#define SYD9557M_READ_ADDR    0x49
+#define SYD9557M_WRITE_ADDR   0x48
+
+static u8 iic_hdl = 0;
+
+u8 syd9557m_get_ndata(u8 r_chip_id, u8 *buf, u8 data_len)
+{
+    u8 read_len = 0;
+
+    iic_start(iic_hdl);
+    if (0 == iic_tx_byte(iic_hdl, SYD9557M_WRITE_ADDR)) {
+        log_e("\n gsen iic rd err 0\n");
+        read_len = 0;
+        goto __gdend;
+    }
+
+
+    delay(50);
+
+
+    if (0 == iic_tx_byte(iic_hdl, 0x01)) {
+        log_e("\n gsen iic rd err 2\n");
+        read_len = 0;
+        goto __gdend;
+    }
+    delay(50);
+
+    iic_start(iic_hdl);
+    if (0 == iic_tx_byte(iic_hdl, SYD9557M_READ_ADDR)) {
+        log_e("\n gsen iic rd err 3\n");
+        read_len = 0;
+        goto __gdend;
+    }
+
+    for (; data_len > 1; data_len--) {
+        *buf++ = iic_rx_byte(iic_hdl, 1);
+        read_len ++;
+    }
+
+    *buf = iic_rx_byte(iic_hdl, 0);
+    read_len ++;
+
+__gdend:
+
+    iic_stop(iic_hdl);
+    delay(50);
+
+    return read_len;
+}
+
+void syd9557_timer_hdl(void *arg)
+{
+    u8 i = 0;
+    u8 data[5] = {0};
+    struct sys_event e;
+    if (gpio_read(INT_IO) == 0) {
+        syd9557m_get_ndata(SYD9557M_READ_ADDR, data, 5);
+        //put_buf(data, 5);
+        memset(&e, 0x0, sizeof(e));
+        e.type = SYS_TOUCHPAD_EVENT;
+        if (data[0] != TOUCHPAD_NO_GESTURE && data[0] < TOUCHPAD_MAX_GESTURE) {     //手势事件优先
+            e.u.touchpad.gesture_event = data[0];
+        }
+        e.u.touchpad.x = data[2];
+        e.u.touchpad.y = data[3];
+        sys_event_notify(&e);
+    }
+}
+
+void syd9557m_init(u8 iic)
+{
+    int i = 0;
+    iic_hdl = iic;
+    iic_init(iic);
+    gpio_set_direction(INT_IO, 1);
+    gpio_set_die(INT_IO, 1);
+    gpio_set_pull_up(INT_IO, 1);
+    gpio_set_pull_down(INT_IO, 0);
+    sys_s_hi_timer_add(NULL, syd9557_timer_hdl, 2);
+    lvd_extern_wakeup_enable();             //要根据封装来选择是否可以使用LVD唤醒, 6531C这个封装LVD是PB4
+}
+#endif

+ 24 - 0
apps/common/device/touch_pad/SYD9557M.h

@@ -0,0 +1,24 @@
+#ifndef __SYD9557M_H__
+#define __SYD9557M_H__
+
+#include "asm/iic_hw.h"
+#include "asm/iic_soft.h"
+
+#define TOUCHPAD_NO_GESTURE                             0x00
+// #define TOUCHPAD_ZOOM_IN                             0x01
+// #define TOUCHPAD_ZOOM_OUT                            0x02
+// #define TOUCHPAD_LIFT_CLICK                          0x03
+// #define TOUCHPAD_RIGHT_CLICK                         0x04
+// #define TOUCHPAD_THREE_FINGER_CLICK                  0x05
+// #define TOUCHPAD_SWIPE_RIGHT_FROM_THE_LEFT_EDGE      0x06
+// #define TOUCHPAD_SWIPE_LEFT_FROM_THE_RIGHT_EDGE      0x07
+// #define TOUCHPAD_SWIPE_DOWN_FROM_THE_TOP_EDGE        0x08
+// #define TOUCHPAD_SLIDE_UP_THE_BOTTOM_EDGE            0x09
+// #define TOUCHPAD_THREE_FINGERS_TO_THE_RIGHT          0x10
+// #define TOUCHPAD_THREE_FINGERS_TO_THE_LEFT           0x11
+// #define TOUCHPAD_SWEEP_DOWN_WITH_THREE_FINGERS       0x12
+#define TOUCHPAD_MAX_GESTURE                            0X17
+
+void syd9557m_init(u8 iic);
+
+#endif

+ 483 - 0
apps/common/device/usb/device/cdc.c

@@ -0,0 +1,483 @@
+#include "usb/device/usb_stack.h"
+#include "usb/usb_config.h"
+#include "usb/device/cdc.h"
+#include "app_config.h"
+#include "os/os_api.h"
+#include "cdc_defs.h"  //need redefine __u8, __u16, __u32
+
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if TCFG_USB_SLAVE_CDC_ENABLE
+
+
+struct usb_cdc_gadget {
+    u8 *cdc_buffer;
+    u8 *bulk_ep_out_buffer;
+    u8 *bulk_ep_in_buffer;
+    void *priv;
+    int (*output)(void *priv, u8 *obuf, u32 olen);
+    void (*wakeup_handler)(struct usb_device_t *usb_device);
+    OS_MUTEX mutex_data;
+#if CDC_INTR_EP_ENABLE
+    OS_MUTEX mutex_intr;
+    u8 *intr_ep_in_buffer;
+#endif
+    u8 bmTransceiver;
+    u8 subtype_data[8];
+};
+
+static struct usb_cdc_gadget *cdc_hdl;
+
+#if USB_MALLOC_ENABLE
+
+#else
+static u8 _cdc_buffer[MAXP_SIZE_CDC_BULKOUT] SEC(.cdc_var) __attribute__((aligned(4)));
+static struct usb_cdc_gadget _cdc_hdl SEC(.cdc_var);
+#endif
+
+static const u8 cdc_virtual_comport_desc[] = {
+    //IAD Descriptor
+    0x08,                       //bLength
+    0x0b,                       //bDescriptorType
+    0x00,                       //bFirstInterface
+    0x02,                       //bInterfaceCount
+    0x02,                       //bFunctionClass, Comunication and CDC control
+    0x02,                       //bFunctionSubClass
+    0x01,                       //bFunctionProtocol
+    0x00,                       //iFunction
+    //Interface 0, Alt 0
+    0x09,                       //Length
+    0x04,                       //DescriptorType:Interface
+    0x00,                       //InterfaceNum
+    0x00,                       //AlternateSetting
+    0x01,                       //NumEndpoint
+    0x02,                       //InterfaceClass, Communation and CDC control
+    0x02,                       //InterfaceSubClass, Abstract Control Model
+    0x01,                       //InterfaceProtocol, AT commands defined by ITU-T V.250 etc
+    0x00,                       //Interface String
+    //CDC Interface Descriptor
+    0x05,                       //bLength
+    0x24,                       //bDescriptorType
+    0x00,                       //bDescriptorSubType, Header Functional Desc
+    0x10, 0x01,                 //bcdCDC, version 1.10
+    //CDC Interface Descriptor
+    0x05,                       //bLength
+    0x24,                       //bDescriptorType
+    0x01,                       //bDescriptorSubType, Call Management Functional Descriptor
+    0x03,                       //bmCapabilities, D7..D2 reversed
+    //  D7..D2 reversed
+    //  D1 sends/receives call management information only over a Data Class interface
+    //  D0 handle call management itself
+    0x01,                       //bDataInterface
+    //CDC Interface Descriptor
+    0x04,                       //bLength
+    0x24,                       //bDescriptorType
+    0x02,                       //bDescriptorSubType, Abstract Control Management Functional Descriptor
+    0x02,                       //bmCapabilities, D7..D2 reversed
+    //  D7..D4 reversed
+    //  D3 supports the notification Network_Connection
+    //  D2 not supports the request Send_Break
+    //  D1 supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State
+    //  D0 supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature
+    //CDC Interface Descriptor
+    0x05,                       //bLength
+    0x24,                       //bDescriptorType
+    0x06,                       //bDescriptorSubType, Union Functional Descriptor
+    0x00,                       //bControlInterface
+    0x01,                       //bSubordinateInterface[0]
+    //Endpoint In
+    0x07,                       //bLength
+    0x05,                       //bDescritorType
+    0x82,                       //bEndpointAddr
+    0x03,                       //bmAttributes, interrupt
+    0x08, 0x00,                 //wMaxPacketSize
+    0x01,                       //bInterval, 1ms
+    //Interface 1, Alt 0
+    0x09,                       //Length
+    0x04,                       //DescriptorType:Interface
+    0x01,                       //InterfaceNum
+    0x00,                       //AlternateSetting
+    0x02,                       //NumEndpoint
+    0x0a,                       //InterfaceClass, CDC Data
+    0x00,                       //InterfaceSubClass
+    0x00,                       //InterfaceProtocol
+    0x00,                       //Interface String
+    //Endpoint Out
+    0x07,                       //bLength
+    0x05,                       //bDescriptor
+    0x02,                       //bEndpointAddr
+    0x02,                       //bmAttributes, bulk
+    0x40, 0x00,                 //wMaxPacketSize
+    0x00,                       //bInterval
+    //Endpoint In
+    0x07,                       //bLength
+    0x05,                       //bDescritorType
+    0x83,                       //bEndpointAddr
+    0x02,                       //bmAttributes, bulk
+    0x40, 0x00,                 //wMaxPacketSize
+    0x00,                       //bInterval
+};
+
+static void cdc_endpoint_init(struct usb_device_t *usb_device, u32 itf);
+static u32 cdc_setup_rx(struct usb_device_t *usb_device, struct usb_ctrlrequest *ctrl_req);
+
+static void usb_cdc_line_coding_init(struct usb_cdc_line_coding *lc)
+{
+    lc->dwDTERate = 460800;
+    lc->bCharFormat = USB_CDC_1_STOP_BITS;
+    lc->bParityType = USB_CDC_NO_PARITY;
+    lc->bDataBits = 8;
+}
+
+static void dump_line_coding(struct usb_cdc_line_coding *lc)
+{
+    log_debug("dtw rate      : %d", lc->dwDTERate);
+    log_debug("stop bits     : %d", lc->bCharFormat);
+    log_debug("verify bits   : %d", lc->bParityType);
+    log_debug("data bits     : %d", lc->bDataBits);
+}
+
+static u32 cdc_setup(struct usb_device_t *usb_device, struct usb_ctrlrequest *ctrl_req)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    int recip_type;
+    u32 len;
+
+    recip_type = ctrl_req->bRequestType & USB_TYPE_MASK;
+
+    switch (recip_type) {
+    case USB_TYPE_CLASS:
+        switch (ctrl_req->bRequest) {
+        case USB_CDC_REQ_SET_LINE_CODING:
+            log_debug("set line coding");
+            usb_set_setup_recv(usb_device, cdc_setup_rx);
+            break;
+        case USB_CDC_REQ_GET_LINE_CODING:
+            log_debug("get line codling");
+            len = ctrl_req->wLength < sizeof(struct usb_cdc_line_coding) ?
+                  ctrl_req->wLength : sizeof(struct usb_cdc_line_coding);
+            if (cdc_hdl == NULL) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+                break;
+            }
+            usb_set_data_payload(usb_device, ctrl_req, cdc_hdl->subtype_data, len);
+            dump_line_coding((struct usb_cdc_line_coding *)cdc_hdl->subtype_data);
+            break;
+        case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
+            log_debug("set control line state - %d", ctrl_req->wValue);
+            if (cdc_hdl) {
+                /* if (ctrl_req->wValue & BIT(0)) { //DTR */
+                cdc_hdl->bmTransceiver |= BIT(0);
+                /* } else { */
+                /* usb_slave->cdc->bmTransceiver &= ~BIT(0); */
+                /* } */
+                /* if (ctrl_req->wValue & BIT(1)) { //RTS */
+                cdc_hdl->bmTransceiver |= BIT(1);
+                /* } else { */
+                /* usb_slave->cdc->bmTransceiver &= ~BIT(1); */
+                /* } */
+                cdc_hdl->bmTransceiver |= BIT(4);  //cfg done
+            }
+            usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+            cdc_endpoint_init(usb_device, (ctrl_req->wIndex & USB_RECIP_MASK));
+            break;
+        default:
+            log_error("unsupported class req");
+            usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            break;
+        }
+        break;
+    default:
+        log_error("unsupported req type");
+        usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+        break;
+    }
+    return 0;
+}
+
+static u32 cdc_setup_rx(struct usb_device_t *usb_device, struct usb_ctrlrequest *ctrl_req)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    int recip_type;
+    struct usb_cdc_line_coding *lc = 0;
+    u32 len;
+    u8 read_ep[8];
+
+    len = ctrl_req->wLength;
+    usb_read_ep0(usb_id, read_ep, len);
+    recip_type = ctrl_req->bRequestType & USB_TYPE_MASK;
+    switch (recip_type) {
+    case USB_TYPE_CLASS:
+        switch (ctrl_req->bRequest) {
+        case USB_CDC_REQ_SET_LINE_CODING:
+            log_debug("USB_CDC_REQ_SET_LINE_CODING");
+            if (cdc_hdl == NULL) {
+                break;
+            }
+            if (len > sizeof(struct usb_cdc_line_coding)) {
+                len = sizeof(struct usb_cdc_line_coding);
+            }
+            memcpy(cdc_hdl->subtype_data, read_ep, len);
+            lc = (struct usb_cdc_line_coding *)cdc_hdl->subtype_data;
+            dump_line_coding(lc);
+            break;
+        }
+        break;
+    }
+    return USB_EP0_STAGE_SETUP;
+}
+
+static void cdc_reset(struct usb_device_t *usb_device, u32 itf)
+{
+    log_error("%s()", __func__);
+    const usb_dev usb_id = usb_device2id(usb_device);
+#if USB_ROOT2
+    usb_disable_ep(usb_id, CDC_DATA_EP_IN);
+#if CDC_INTR_EP_ENABLE
+    usb_disable_ep(usb_id, CDC_INTR_EP_IN);
+#endif
+#else
+    cdc_endpoint_init(usb_device, itf);
+#endif
+}
+
+u32 cdc_desc_config(const usb_dev usb_id, u8 *ptr, u32 *itf)
+{
+    u8 *tptr;
+
+    tptr = ptr;
+    memcpy(tptr, cdc_virtual_comport_desc, sizeof(cdc_virtual_comport_desc));
+    //iad interface number
+    tptr[2] = *itf;
+    //control interface number
+    tptr[8 + 2] = *itf;
+    tptr[8 + 9 + 5 + 4] = *itf + 1;
+    tptr[8 + 9 + 5 + 5 + 4 + 3] = *itf;
+    tptr[8 + 9 + 5 + 5 + 4 + 4] = *itf + 1;
+    //interrupt in ep
+    tptr[8 + 9 + 5 + 5 + 4 + 5 + 2] = USB_DIR_IN | CDC_INTR_EP_IN;
+    tptr[8 + 9 + 5 + 5 + 4 + 5 + 4] = MAXP_SIZE_CDC_INTRIN & 0xff;
+    tptr[8 + 9 + 5 + 5 + 4 + 5 + 5] = (MAXP_SIZE_CDC_INTRIN >> 8) & 0xff;
+    //data interface number
+    tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 2] = *itf + 1;
+    //bulk out ep
+    tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 2] = CDC_DATA_EP_OUT;
+    tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 4] = MAXP_SIZE_CDC_BULKOUT & 0xff;
+    tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 5] = (MAXP_SIZE_CDC_BULKOUT >> 8) & 0xff;
+    //bulk in ep
+    tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 2] = USB_DIR_IN | CDC_DATA_EP_IN;
+    tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 4] = MAXP_SIZE_CDC_BULKIN & 0xff;
+    tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 5] = (MAXP_SIZE_CDC_BULKIN >> 8) & 0xff;
+    tptr += sizeof(cdc_virtual_comport_desc);
+
+    if (usb_set_interface_hander(usb_id, *itf, cdc_setup) != *itf) {
+        ASSERT(0, "cdc set interface_hander fail");
+    }
+    if (usb_set_reset_hander(usb_id, *itf, cdc_reset) != *itf) {
+
+    }
+    *itf += 2;
+    return (u32)(tptr - ptr);
+}
+
+void cdc_set_wakeup_handler(void (*handle)(struct usb_device_t *usb_device))
+{
+    if (cdc_hdl) {
+        cdc_hdl->wakeup_handler = handle;
+    }
+}
+
+static void cdc_wakeup_handler(struct usb_device_t *usb_device, u32 ep)
+{
+    if (cdc_hdl && cdc_hdl->wakeup_handler) {
+        cdc_hdl->wakeup_handler(usb_device);
+    }
+}
+
+void cdc_set_output_handle(void *priv, int (*output_handler)(void *priv, u8 *buf, u32 len))
+{
+    if (cdc_hdl) {
+        cdc_hdl->output = output_handler;
+        cdc_hdl->priv = priv;
+    }
+}
+
+static void cdc_intrrx(struct usb_device_t *usb_device, u32 ep)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    if (cdc_hdl == NULL) {
+        return;
+    }
+    u8 *cdc_rx_buf = cdc_hdl->cdc_buffer;
+    //由于bulk传输使用双缓冲,无法用usb_get_ep_buffer()知道是哪一个buffer,需要外部buffer接收数据
+    u32 len = usb_g_bulk_read(usb_id, CDC_DATA_EP_OUT, cdc_rx_buf, MAXP_SIZE_CDC_BULKOUT, 0);
+    if (cdc_hdl->output) {
+        cdc_hdl->output(cdc_hdl->priv, cdc_rx_buf, len);
+    }
+}
+
+static void cdc_endpoint_init(struct usb_device_t *usb_device, u32 itf)
+{
+    ASSERT(cdc_hdl, "cdc not register");
+
+    const usb_dev usb_id = usb_device2id(usb_device);
+
+    usb_g_ep_config(usb_id, CDC_DATA_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_BULK,
+                    0, cdc_hdl->bulk_ep_in_buffer, MAXP_SIZE_CDC_BULKIN);
+
+    usb_g_ep_config(usb_id, CDC_DATA_EP_OUT | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK,
+                    1, cdc_hdl->bulk_ep_out_buffer, MAXP_SIZE_CDC_BULKOUT);
+    /* usb_g_set_intr_hander(usb_id, CDC_DATA_EP_OUT | USB_DIR_OUT, cdc_intrrx); */
+    usb_g_set_intr_hander(usb_id, CDC_DATA_EP_OUT | USB_DIR_OUT, cdc_wakeup_handler);
+    usb_enable_ep(usb_id, CDC_DATA_EP_IN);
+
+#if CDC_INTR_EP_ENABLE
+    usb_g_ep_config(usb_id, CDC_INTR_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_INT,
+                    0, cdc_hdl->intr_ep_in_buffer, MAXP_SIZE_CDC_INTRIN);
+    usb_enable_ep(usb_id, CDC_INTR_EP_IN);
+#endif
+}
+
+u32 cdc_read_data(const usb_dev usb_id, u8 *buf, u32 len)
+{
+    u32 rxlen;
+    if (cdc_hdl == NULL) {
+        return 0;
+    }
+    u8 *cdc_rx_buf = cdc_hdl->cdc_buffer;
+    os_mutex_pend(&cdc_hdl->mutex_data, 0);
+    //由于bulk传输使用双缓冲,无法用usb_get_ep_buffer()知道是哪一个buffer,需要外部buffer接收数据
+    rxlen = usb_g_bulk_read(usb_id, CDC_DATA_EP_OUT, cdc_rx_buf, MAXP_SIZE_CDC_BULKOUT, 0);
+    rxlen = rxlen > len ? len : rxlen;
+    if (rxlen > 0) {
+        memcpy(buf, cdc_rx_buf, rxlen);
+    }
+    os_mutex_post(&cdc_hdl->mutex_data);
+    return rxlen;
+}
+
+u32 cdc_write_data(const usb_dev usb_id, u8 *buf, u32 len)
+{
+    u32 txlen, offset;
+    if (cdc_hdl == NULL) {
+        return 0;
+    }
+    if ((cdc_hdl->bmTransceiver & (BIT(1) | BIT(4))) != (BIT(1) | BIT(4))) {
+        return 0;
+    }
+    offset = 0;
+    os_mutex_pend(&cdc_hdl->mutex_data, 0);
+    while (offset < len) {
+        txlen = len - offset > MAXP_SIZE_CDC_BULKIN ?
+                MAXP_SIZE_CDC_BULKIN : len - offset;
+        txlen = usb_g_bulk_write(usb_id, CDC_DATA_EP_IN, buf + offset, txlen);
+        if (txlen == 0) {
+            break;
+        }
+        if ((cdc_hdl->bmTransceiver & (BIT(1) | BIT(4))) != (BIT(1) | BIT(4))) {
+            break;
+        }
+        offset += txlen;
+    }
+    os_mutex_post(&cdc_hdl->mutex_data);
+    return offset;
+}
+
+u32 cdc_write_inir(const usb_dev usb_id, u8 *buf, u32 len)
+{
+#if CDC_INTR_EP_ENABLE
+    u32 txlen, offset;
+    if (cdc_hdl == NULL) {
+        return 0;
+    }
+    if ((cdc_hdl->bmTransceiver & BIT(4)) == 0) {
+        return 0;
+    }
+    offset = 0;
+    os_mutex_pend(&cdc_hdl->mutex_intr, 0);
+    while (offset < len) {
+        txlen = len - offset > MAXP_SIZE_CDC_INTRIN ?
+                MAXP_SIZE_CDC_INTRIN : len - offset;
+        txlen = usb_g_intr_write(usb_id, CDC_INTR_EP_IN, buf + offset, txlen);
+        if (txlen == 0) {
+            break;
+        }
+        if ((cdc_hdl->bmTransceiver & BIT(4)) == 0) {
+            break;
+        }
+        offset += txlen;
+    }
+    os_mutex_post(&cdc_hdl->mutex_intr);
+    return offset;
+#else
+    return 0;
+#endif
+}
+
+void cdc_register(const usb_dev usb_id)
+{
+    struct usb_cdc_line_coding *lc;
+    /* log_info("%s() %d", __func__, __LINE__); */
+    if (!cdc_hdl) {
+#if USB_MALLOC_ENABLE
+        cdc_hdl = zalloc(sizeof(struct usb_cdc_gadget));
+        if (!cdc_hdl) {
+            log_error("cdc_register err 1");
+            return;
+        }
+        cdc_hdl->cdc_buffer = malloc(MAXP_SIZE_CDC_BULKOUT);
+        if (!cdc_hdl->cdc_buf) {
+            log_error("cdc_register err 2");
+            goto __exit_err;
+        }
+#else
+        memset(&_cdc_hdl, 0, sizeof(struct usb_cdc_gadget));
+        cdc_hdl = &_cdc_hdl;
+        cdc_hdl->cdc_buffer = _cdc_buffer;
+#endif
+        lc = (struct usb_cdc_line_coding *)cdc_hdl->subtype_data;
+        usb_cdc_line_coding_init(lc);
+        os_mutex_create(&cdc_hdl->mutex_data);
+
+        cdc_hdl->bulk_ep_in_buffer = usb_alloc_ep_dmabuffer(usb_id, CDC_DATA_EP_IN | USB_DIR_IN, MAXP_SIZE_CDC_BULKIN + MAXP_SIZE_CDC_BULKOUT);
+        cdc_hdl->bulk_ep_out_buffer = cdc_hdl->bulk_ep_in_buffer + MAXP_SIZE_CDC_BULKIN;
+
+#if CDC_INTR_EP_ENABLE
+        os_mutex_create(&cdc_hdl->mutex_intr);
+        cdc_hdl->intr_ep_in_buffer = usb_alloc_ep_dmabuffer(usb_id, CDC_INTR_EP_IN | USB_DIR_IN, MAXP_SIZE_CDC_INTRIN);
+#endif
+
+    }
+    return;
+__exit_err:
+#if USB_MALLOC_ENABLE
+    if (cdc_hdl->cdc_buffer) {
+        free(cdc_hdl->cdc_buffer);
+    }
+    if (cdc_hdl) {
+        free(cdc_hdl);
+    }
+#endif
+    cdc_hdl = NULL;
+}
+
+void cdc_release(const usb_dev usb_id)
+{
+    /* log_info("%s() %d", __func__, __LINE__); */
+    if (cdc_hdl) {
+#if USB_MALLOC_ENABLE
+        free(cdc_hdl->cdc_buffer);
+        free(cdc_hdl);
+#endif
+        cdc_hdl = NULL;
+    }
+}
+
+#endif

+ 23 - 0
apps/common/device/usb/device/cdc.h

@@ -0,0 +1,23 @@
+#ifndef __CDC_H__
+#define __CDC_H__
+
+#include "usb/device/usb_stack.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+u32 cdc_desc_config(const usb_dev usb_id, u8 *ptr, u32 *itf);
+void cdc_set_wakeup_handler(void (*handle)(struct usb_device_t *usb_device));
+void cdc_set_output_handle(void *priv, int (*output_handler)(void *priv, u8 *buf, u32 len));
+u32 cdc_read_data(const usb_dev usb_id, u8 *buf, u32 len);
+u32 cdc_write_data(const usb_dev usb_id, u8 *buf, u32 len);
+u32 cdc_write_inir(const usb_dev usb_id, u8 *buf, u32 len);
+void cdc_register(const usb_dev usb_id);
+void cdc_release(const usb_dev usb_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 457 - 0
apps/common/device/usb/device/cdc_defs.h

@@ -0,0 +1,457 @@
+
+/*
+ * USB Communications Device Class (CDC) definitions
+ *
+ * CDC says how to talk to lots of different types of network adapters,
+ * notably ethernet adapters and various modems.  It's used mostly with
+ * firmware based USB peripherals.
+ */
+
+#ifndef __LINUX_USB_CDC_H
+#define __LINUX_USB_CDC_H
+
+#include "typedef.h"    /* __u8 etc */
+
+#ifdef __le16
+#undef __le16
+#endif
+typedef unsigned short      __le16;
+#ifdef __le32
+#undef __le32
+#endif
+typedef unsigned int       __le32;
+#ifdef __u8
+#undef __u8
+#endif
+typedef unsigned char       __u8;
+#ifdef __u16
+#undef __u16
+#endif
+typedef unsigned short      __u16;
+#ifdef __u32
+#undef __u32
+#endif
+typedef unsigned int       __u32;
+
+#define USB_CDC_SUBCLASS_ACM			0x02
+#define USB_CDC_SUBCLASS_ETHERNET		0x06
+#define USB_CDC_SUBCLASS_WHCM			0x08
+#define USB_CDC_SUBCLASS_DMM			0x09
+#define USB_CDC_SUBCLASS_MDLM			0x0a
+#define USB_CDC_SUBCLASS_OBEX			0x0b
+#define USB_CDC_SUBCLASS_EEM			0x0c
+#define USB_CDC_SUBCLASS_NCM			0x0d
+#define USB_CDC_SUBCLASS_MBIM			0x0e
+
+#define USB_CDC_PROTO_NONE			0
+
+#define USB_CDC_ACM_PROTO_AT_V25TER		1
+#define USB_CDC_ACM_PROTO_AT_PCCA101		2
+#define USB_CDC_ACM_PROTO_AT_PCCA101_WAKE	3
+#define USB_CDC_ACM_PROTO_AT_GSM		4
+#define USB_CDC_ACM_PROTO_AT_3G			5
+#define USB_CDC_ACM_PROTO_AT_CDMA		6
+#define USB_CDC_ACM_PROTO_VENDOR		0xff
+
+#define USB_CDC_PROTO_EEM			7
+
+#define USB_CDC_NCM_PROTO_NTB			1
+#define USB_CDC_MBIM_PROTO_NTB			2
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Class-Specific descriptors ... there are a couple dozen of them
+ */
+
+#define USB_CDC_HEADER_TYPE		0x00	/* header_desc */
+#define USB_CDC_CALL_MANAGEMENT_TYPE	0x01	/* call_mgmt_descriptor */
+#define USB_CDC_ACM_TYPE		0x02	/* acm_descriptor */
+#define USB_CDC_UNION_TYPE		0x06	/* union_desc */
+#define USB_CDC_COUNTRY_TYPE		0x07
+#define USB_CDC_NETWORK_TERMINAL_TYPE	0x0a	/* network_terminal_desc */
+#define USB_CDC_ETHERNET_TYPE		0x0f	/* ether_desc */
+#define USB_CDC_WHCM_TYPE		0x11
+#define USB_CDC_MDLM_TYPE		0x12	/* mdlm_desc */
+#define USB_CDC_MDLM_DETAIL_TYPE	0x13	/* mdlm_detail_desc */
+#define USB_CDC_DMM_TYPE		0x14
+#define USB_CDC_OBEX_TYPE		0x15
+#define USB_CDC_NCM_TYPE		0x1a
+#define USB_CDC_MBIM_TYPE		0x1b
+
+/* "Header Functional Descriptor" from CDC spec  5.2.3.1 */
+struct usb_cdc_header_desc {
+    __u8	bLength;
+    __u8	bDescriptorType;
+    __u8	bDescriptorSubType;
+
+    __le16	bcdCDC;
+} __attribute__((packed));
+
+/* "Call Management Descriptor" from CDC spec  5.2.3.2 */
+struct usb_cdc_call_mgmt_descriptor {
+    __u8	bLength;
+    __u8	bDescriptorType;
+    __u8	bDescriptorSubType;
+
+    __u8	bmCapabilities;
+#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT		0x01
+#define USB_CDC_CALL_MGMT_CAP_DATA_INTF		0x02
+
+    __u8	bDataInterface;
+} __attribute__((packed));
+
+/* "Abstract Control Management Descriptor" from CDC spec  5.2.3.3 */
+struct usb_cdc_acm_descriptor {
+    __u8	bLength;
+    __u8	bDescriptorType;
+    __u8	bDescriptorSubType;
+
+    __u8	bmCapabilities;
+} __attribute__((packed));
+
+/* capabilities from 5.2.3.3 */
+
+#define USB_CDC_COMM_FEATURE	0x01
+#define USB_CDC_CAP_LINE	0x02
+#define USB_CDC_CAP_BRK		0x04
+#define USB_CDC_CAP_NOTIFY	0x08
+
+/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */
+struct usb_cdc_union_desc {
+    __u8	bLength;
+    __u8	bDescriptorType;
+    __u8	bDescriptorSubType;
+
+    __u8	bMasterInterface0;
+    __u8	bSlaveInterface0;
+    /* ... and there could be other slave interfaces */
+} __attribute__((packed));
+
+/* "Country Selection Functional Descriptor" from CDC spec 5.2.3.9 */
+struct usb_cdc_country_functional_desc {
+    __u8	bLength;
+    __u8	bDescriptorType;
+    __u8	bDescriptorSubType;
+
+    __u8	iCountryCodeRelDate;
+    __le16	wCountyCode0;
+    /* ... and there can be a lot of country codes */
+} __attribute__((packed));
+
+/* "Network Channel Terminal Functional Descriptor" from CDC spec 5.2.3.11 */
+struct usb_cdc_network_terminal_desc {
+    __u8	bLength;
+    __u8	bDescriptorType;
+    __u8	bDescriptorSubType;
+
+    __u8	bEntityId;
+    __u8	iName;
+    __u8	bChannelIndex;
+    __u8	bPhysicalInterface;
+} __attribute__((packed));
+
+/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
+struct usb_cdc_ether_desc {
+    __u8	bLength;
+    __u8	bDescriptorType;
+    __u8	bDescriptorSubType;
+
+    __u8	iMACAddress;
+    __le32	bmEthernetStatistics;
+    __le16	wMaxSegmentSize;
+    __le16	wNumberMCFilters;
+    __u8	bNumberPowerFilters;
+} __attribute__((packed));
+
+/* "Telephone Control Model Functional Descriptor" from CDC WMC spec 6.3..3 */
+struct usb_cdc_dmm_desc {
+    __u8	bFunctionLength;
+    __u8	bDescriptorType;
+    __u8	bDescriptorSubtype;
+    __u16	bcdVersion;
+    __le16	wMaxCommand;
+} __attribute__((packed));
+
+/* "MDLM Functional Descriptor" from CDC WMC spec 6.7.2.3 */
+struct usb_cdc_mdlm_desc {
+    __u8	bLength;
+    __u8	bDescriptorType;
+    __u8	bDescriptorSubType;
+
+    __le16	bcdVersion;
+    __u8	bGUID[16];
+} __attribute__((packed));
+
+/* "MDLM Detail Functional Descriptor" from CDC WMC spec 6.7.2.4 */
+struct usb_cdc_mdlm_detail_desc {
+    __u8	bLength;
+    __u8	bDescriptorType;
+    __u8	bDescriptorSubType;
+
+    /* type is associated with mdlm_desc.bGUID */
+    __u8	bGuidDescriptorType;
+    __u8	bDetailData[0];
+} __attribute__((packed));
+
+/* "OBEX Control Model Functional Descriptor" */
+struct usb_cdc_obex_desc {
+    __u8	bLength;
+    __u8	bDescriptorType;
+    __u8	bDescriptorSubType;
+
+    __le16	bcdVersion;
+} __attribute__((packed));
+
+/* "NCM Control Model Functional Descriptor" */
+struct usb_cdc_ncm_desc {
+    __u8	bLength;
+    __u8	bDescriptorType;
+    __u8	bDescriptorSubType;
+
+    __le16	bcdNcmVersion;
+    __u8	bmNetworkCapabilities;
+} __attribute__((packed));
+
+/* "MBIM Control Model Functional Descriptor" */
+struct usb_cdc_mbim_desc {
+    __u8	bLength;
+    __u8	bDescriptorType;
+    __u8	bDescriptorSubType;
+
+    __le16	bcdMBIMVersion;
+    __le16  wMaxControlMessage;
+    __u8    bNumberFilters;
+    __u8    bMaxFilterSize;
+    __le16  wMaxSegmentSize;
+    __u8    bmNetworkCapabilities;
+} __attribute__((packed));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Class-Specific Control Requests (6.2)
+ *
+ * section 3.6.2.1 table 4 has the ACM profile, for modems.
+ * section 3.8.2 table 10 has the ethernet profile.
+ *
+ * Microsoft's RNDIS stack for Ethernet is a vendor-specific CDC ACM variant,
+ * heavily dependent on the encapsulated (proprietary) command mechanism.
+ */
+
+#define USB_CDC_SEND_ENCAPSULATED_COMMAND	0x00
+#define USB_CDC_GET_ENCAPSULATED_RESPONSE	0x01
+#define USB_CDC_REQ_SET_LINE_CODING		0x20
+#define USB_CDC_REQ_GET_LINE_CODING		0x21
+#define USB_CDC_REQ_SET_CONTROL_LINE_STATE	0x22
+#define USB_CDC_REQ_SEND_BREAK			0x23
+#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS	0x40
+#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER	0x41
+#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER	0x42
+#define USB_CDC_SET_ETHERNET_PACKET_FILTER	0x43
+#define USB_CDC_GET_ETHERNET_STATISTIC		0x44
+#define USB_CDC_GET_NTB_PARAMETERS		0x80
+#define USB_CDC_GET_NET_ADDRESS			0x81
+#define USB_CDC_SET_NET_ADDRESS			0x82
+#define USB_CDC_GET_NTB_FORMAT			0x83
+#define USB_CDC_SET_NTB_FORMAT			0x84
+#define USB_CDC_GET_NTB_INPUT_SIZE		0x85
+#define USB_CDC_SET_NTB_INPUT_SIZE		0x86
+#define USB_CDC_GET_MAX_DATAGRAM_SIZE		0x87
+#define USB_CDC_SET_MAX_DATAGRAM_SIZE		0x88
+#define USB_CDC_GET_CRC_MODE			0x89
+#define USB_CDC_SET_CRC_MODE			0x8a
+
+/* Line Coding Structure from CDC spec 6.2.13 */
+struct usb_cdc_line_coding {
+    __le32	dwDTERate;
+    __u8	bCharFormat;
+#define USB_CDC_1_STOP_BITS			0
+#define USB_CDC_1_5_STOP_BITS			1
+#define USB_CDC_2_STOP_BITS			2
+
+    __u8	bParityType;
+#define USB_CDC_NO_PARITY			0
+#define USB_CDC_ODD_PARITY			1
+#define USB_CDC_EVEN_PARITY			2
+#define USB_CDC_MARK_PARITY			3
+#define USB_CDC_SPACE_PARITY			4
+
+    __u8	bDataBits;
+} __attribute__((packed));
+
+/* table 62; bits in multicast filter */
+#define	USB_CDC_PACKET_TYPE_PROMISCUOUS		(1 << 0)
+#define	USB_CDC_PACKET_TYPE_ALL_MULTICAST	(1 << 1) /* no filter */
+#define	USB_CDC_PACKET_TYPE_DIRECTED		(1 << 2)
+#define	USB_CDC_PACKET_TYPE_BROADCAST		(1 << 3)
+#define	USB_CDC_PACKET_TYPE_MULTICAST		(1 << 4) /* filtered */
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Class-Specific Notifications (6.3) sent by interrupt transfers
+ *
+ * section 3.8.2 table 11 of the CDC spec lists Ethernet notifications
+ * section 3.6.2.1 table 5 specifies ACM notifications, accepted by RNDIS
+ * RNDIS also defines its own bit-incompatible notifications
+ */
+
+#define USB_CDC_NOTIFY_NETWORK_CONNECTION	0x00
+#define USB_CDC_NOTIFY_RESPONSE_AVAILABLE	0x01
+#define USB_CDC_NOTIFY_SERIAL_STATE		0x20
+#define USB_CDC_NOTIFY_SPEED_CHANGE		0x2a
+
+struct usb_cdc_notification {
+    __u8	bmRequestType;
+    __u8	bNotificationType;
+    __le16	wValue;
+    __le16	wIndex;
+    __le16	wLength;
+} __attribute__((packed));
+
+struct usb_cdc_speed_change {
+    __le32	DLBitRRate;	/* contains the downlink bit rate (IN pipe) */
+    __le32	ULBitRate;	/* contains the uplink bit rate (OUT pipe) */
+} __attribute__((packed));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Class Specific structures and constants
+ *
+ * CDC NCM NTB parameters structure, CDC NCM subclass 6.2.1
+ *
+ */
+
+struct usb_cdc_ncm_ntb_parameters {
+    __le16	wLength;
+    __le16	bmNtbFormatsSupported;
+    __le32	dwNtbInMaxSize;
+    __le16	wNdpInDivisor;
+    __le16	wNdpInPayloadRemainder;
+    __le16	wNdpInAlignment;
+    __le16	wPadding1;
+    __le32	dwNtbOutMaxSize;
+    __le16	wNdpOutDivisor;
+    __le16	wNdpOutPayloadRemainder;
+    __le16	wNdpOutAlignment;
+    __le16	wNtbOutMaxDatagrams;
+} __attribute__((packed));
+
+/*
+ * CDC NCM transfer headers, CDC NCM subclass 3.2
+ */
+
+#define USB_CDC_NCM_NTH16_SIGN		0x484D434E /* NCMH */
+#define USB_CDC_NCM_NTH32_SIGN		0x686D636E /* ncmh */
+
+struct usb_cdc_ncm_nth16 {
+    __le32	dwSignature;
+    __le16	wHeaderLength;
+    __le16	wSequence;
+    __le16	wBlockLength;
+    __le16	wNdpIndex;
+} __attribute__((packed));
+
+struct usb_cdc_ncm_nth32 {
+    __le32	dwSignature;
+    __le16	wHeaderLength;
+    __le16	wSequence;
+    __le32	dwBlockLength;
+    __le32	dwNdpIndex;
+} __attribute__((packed));
+
+/*
+ * CDC NCM datagram pointers, CDC NCM subclass 3.3
+ */
+
+#define USB_CDC_NCM_NDP16_CRC_SIGN	0x314D434E /* NCM1 */
+#define USB_CDC_NCM_NDP16_NOCRC_SIGN	0x304D434E /* NCM0 */
+#define USB_CDC_NCM_NDP32_CRC_SIGN	0x316D636E /* ncm1 */
+#define USB_CDC_NCM_NDP32_NOCRC_SIGN	0x306D636E /* ncm0 */
+
+#define USB_CDC_MBIM_NDP16_IPS_SIGN     0x00535049 /* IPS<sessionID> : IPS0 for now */
+#define USB_CDC_MBIM_NDP32_IPS_SIGN     0x00737069 /* ips<sessionID> : ips0 for now */
+#define USB_CDC_MBIM_NDP16_DSS_SIGN     0x00535344 /* DSS<sessionID> */
+#define USB_CDC_MBIM_NDP32_DSS_SIGN     0x00737364 /* dss<sessionID> */
+
+/* 16-bit NCM Datagram Pointer Entry */
+struct usb_cdc_ncm_dpe16 {
+    __le16	wDatagramIndex;
+    __le16	wDatagramLength;
+} __attribute__((__packed__));
+
+/* 16-bit NCM Datagram Pointer Table */
+struct usb_cdc_ncm_ndp16 {
+    __le32	dwSignature;
+    __le16	wLength;
+    __le16	wNextNdpIndex;
+    struct	usb_cdc_ncm_dpe16 dpe16[0];
+} __attribute__((packed));
+
+/* 32-bit NCM Datagram Pointer Entry */
+struct usb_cdc_ncm_dpe32 {
+    __le32	dwDatagramIndex;
+    __le32	dwDatagramLength;
+} __attribute__((__packed__));
+
+/* 32-bit NCM Datagram Pointer Table */
+struct usb_cdc_ncm_ndp32 {
+    __le32	dwSignature;
+    __le16	wLength;
+    __le16	wReserved6;
+    __le32	dwNextNdpIndex;
+    __le32	dwReserved12;
+    struct	usb_cdc_ncm_dpe32 dpe32[0];
+} __attribute__((packed));
+
+/* CDC NCM subclass 3.2.1 and 3.2.2 */
+#define USB_CDC_NCM_NDP16_INDEX_MIN			0x000C
+#define USB_CDC_NCM_NDP32_INDEX_MIN			0x0010
+
+/* CDC NCM subclass 3.3.3 Datagram Formatting */
+#define USB_CDC_NCM_DATAGRAM_FORMAT_CRC			0x30
+#define USB_CDC_NCM_DATAGRAM_FORMAT_NOCRC		0X31
+
+/* CDC NCM subclass 4.2 NCM Communications Interface Protocol Code */
+#define USB_CDC_NCM_PROTO_CODE_NO_ENCAP_COMMANDS	0x00
+#define USB_CDC_NCM_PROTO_CODE_EXTERN_PROTO		0xFE
+
+/* CDC NCM subclass 5.2.1 NCM Functional Descriptor, bmNetworkCapabilities */
+#define USB_CDC_NCM_NCAP_ETH_FILTER			(1 << 0)
+#define USB_CDC_NCM_NCAP_NET_ADDRESS			(1 << 1)
+#define USB_CDC_NCM_NCAP_ENCAP_COMMAND			(1 << 2)
+#define USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE		(1 << 3)
+#define USB_CDC_NCM_NCAP_CRC_MODE			(1 << 4)
+#define	USB_CDC_NCM_NCAP_NTB_INPUT_SIZE			(1 << 5)
+
+/* CDC NCM subclass Table 6-3: NTB Parameter Structure */
+#define USB_CDC_NCM_NTB16_SUPPORTED			(1 << 0)
+#define USB_CDC_NCM_NTB32_SUPPORTED			(1 << 1)
+
+/* CDC NCM subclass Table 6-3: NTB Parameter Structure */
+#define USB_CDC_NCM_NDP_ALIGN_MIN_SIZE			0x04
+#define USB_CDC_NCM_NTB_MAX_LENGTH			0x1C
+
+/* CDC NCM subclass 6.2.5 SetNtbFormat */
+#define USB_CDC_NCM_NTB16_FORMAT			0x00
+#define USB_CDC_NCM_NTB32_FORMAT			0x01
+
+/* CDC NCM subclass 6.2.7 SetNtbInputSize */
+#define USB_CDC_NCM_NTB_MIN_IN_SIZE			2048
+#define USB_CDC_NCM_NTB_MIN_OUT_SIZE			2048
+
+/* NTB Input Size Structure */
+struct usb_cdc_ncm_ndp_input_size {
+    __le32	dwNtbInMaxSize;
+    __le16	wNtbInMaxDatagrams;
+    __le16	wReserved;
+} __attribute__((packed));
+
+/* CDC NCM subclass 6.2.11 SetCrcMode */
+#define USB_CDC_NCM_CRC_NOT_APPENDED			0x00
+#define USB_CDC_NCM_CRC_APPENDED			0x01
+
+#endif /* __LINUX_USB_CDC_H */

+ 307 - 0
apps/common/device/usb/device/custom_hid.c

@@ -0,0 +1,307 @@
+#include "os/os_api.h"
+#include "usb/device/usb_stack.h"
+#include "usb/device/hid.h"
+#include "usb_config.h"
+
+#include "app_config.h"
+
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+#if TCFG_USB_CUSTOM_HID_ENABLE
+typedef void (*hid_rx_handle_t)(void *hdl, u8 *buffer, u32 len);
+struct custom_hid_hdl {
+    u8 cfg_done;
+    void *priv_hdl;
+    hid_rx_handle_t hid_rx_hook;
+};
+static struct custom_hid_hdl *custom_hid_info;
+#if USB_MALLOC_ENABLE
+#else
+static struct custom_hid_hdl _custom_hid_info;
+#endif
+
+static const u8 sHIDDescriptor[] = {
+//HID
+    //InterfaceDeszcriptor:
+    USB_DT_INTERFACE_SIZE,     // Length
+    USB_DT_INTERFACE,          // DescriptorType
+    0x00,                       // bInterface number
+    0x00,                      // AlternateSetting
+    0x02,                      // NumEndpoint
+    USB_CLASS_HID,             // Class = Human Interface Device
+    0x00,                      // Subclass, 0 No subclass, 1 Boot Interface subclass
+    0x00,                      // Procotol, 0 None, 1 Keyboard, 2 Mouse
+    0x00,                      // Interface Name
+
+    //HIDDescriptor:
+    0x09,                      // bLength
+    USB_HID_DT_HID,            // bDescriptorType, HID Descriptor
+    0x01, 0x02,                // bcdHID, HID Class Specification release NO.
+    0x00,                      // bCuntryCode, Country localization (=none)
+    0x01,                       // bNumDescriptors, Number of descriptors to follow
+    0x22,                       // bDescriptorType, Report Desc. 0x22, Physical Desc. 0x23
+    0, 0,                       // wDescriptorLength
+
+    //EndpointDescriptor:
+    USB_DT_ENDPOINT_SIZE,       // bLength
+    USB_DT_ENDPOINT,            // bDescriptorType, Type
+    USB_DIR_IN | CUSTOM_HID_EP_IN,     // bEndpointAddress
+    USB_ENDPOINT_XFER_INT,      // Interrupt
+    LOBYTE(MAXP_SIZE_CUSTOM_HIDIN), HIBYTE(MAXP_SIZE_CUSTOM_HIDIN),// Maximum packet size
+    0x01,                       // bInterval, for high speed 2^(n-1) * 125us, for full/low speed n * 1ms
+
+    //Endpoint Descriptor:
+    USB_DT_ENDPOINT_SIZE,       // bLength
+    USB_DT_ENDPOINT,            // bDescriptorType, Type
+    CUSTOM_HID_EP_OUT,   // bEndpointAddress
+    USB_ENDPOINT_XFER_INT,      // Interrupt
+    LOBYTE(MAXP_SIZE_CUSTOM_HIDOUT), HIBYTE(MAXP_SIZE_CUSTOM_HIDOUT),// Maximum packet size
+    0x01,                       // bInterval, for high speed 2^(n-1) * 125us, for full/low speed n * 1ms
+};
+
+
+static const u8 sHIDReportDesc[] = {
+    USAGE_PAGE(2, 0x02, 0xff),
+    USAGE(1, 0x02),
+    COLLECTION(1, APPLICATION),
+    USAGE(1, 0x03),
+    LOGICAL_MIN(1, 0x00),
+    LOGICAL_MAX(2, 0xff, 0x00),
+    REPORT_SIZE(1, 8),
+    REPORT_COUNT(1, 0x40),
+    INPUT(1, 0x00),
+    USAGE(1, 0x04),
+    LOGICAL_MIN(1, 0x00),
+    LOGICAL_MAX(2, 0xff, 0x00),
+    REPORT_SIZE(1, 0x08),
+    REPORT_COUNT(1, 0X40),
+    OUTPUT(1, 0x00),
+    END_COLLECTION,
+};
+
+static u32 get_hid_report_desc_len(u32 index)
+{
+    u32 len = 0;
+    len = sizeof(sHIDReportDesc);
+    return len;
+}
+static void *get_hid_report_desc(u32 index)
+{
+    u8 *ptr  = NULL;
+    ptr = (u8 *)sHIDReportDesc;
+    return ptr;
+}
+
+u32 custom_hid_tx_data(const usb_dev usb_id, const u8 *buffer, u32 len)
+{
+    if (len > MAXP_SIZE_CUSTOM_HIDIN) {
+        len = MAXP_SIZE_CUSTOM_HIDIN;
+    }
+    if (custom_hid_info == NULL || custom_hid_info->cfg_done == 0) {
+        return 0;
+    }
+    return usb_g_intr_write(usb_id, CUSTOM_HID_EP_IN, buffer, len);
+}
+
+static void custom_hid_rx_data(struct usb_device_t *usb_device, u32 ep)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    u8 rx_buffer[64] = {0};
+    u32 rx_len = usb_g_intr_read(usb_id, CUSTOM_HID_EP_OUT, rx_buffer, 64, 0);
+    if (custom_hid_info && custom_hid_info->hid_rx_hook) {
+        custom_hid_info->hid_rx_hook(custom_hid_info->priv_hdl, rx_buffer, rx_len);
+    }
+}
+
+int custom_hid_get_ready(const usb_dev usb_id)
+{
+    if (custom_hid_info && custom_hid_info->cfg_done) {
+        return 1;
+    }
+    return 0;
+}
+
+void custom_hid_set_rx_hook(void *priv, void (*rx_hook)(void *priv, u8 *buf, u32 len))
+{
+    if (custom_hid_info) {
+        custom_hid_info->priv_hdl = priv;
+        custom_hid_info->hid_rx_hook = rx_hook;
+    }
+}
+
+static u8 *custom_hid_ep_in_dma;
+static u8 *custom_hid_ep_out_dma;
+static void custom_hid_endpoint_init(struct usb_device_t *usb_device, u32 itf)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    //u8 *ep_buffer = usb_alloc_ep_dmabuffer(usb_id, CUSTOM_HID_EP_IN | USB_DIR_IN, MAXP_SIZE_CUSTOM_HIDIN);
+    usb_g_ep_config(usb_id, CUSTOM_HID_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_INT, 0, custom_hid_ep_in_dma, MAXP_SIZE_CUSTOM_HIDIN);
+
+    //ep_buffer = usb_alloc_ep_dmabuffer(usb_id, CUSTOM_HID_EP_OUT, MAXP_SIZE_CUSTOM_HIDOUT);
+    usb_g_set_intr_hander(usb_id, CUSTOM_HID_EP_OUT, custom_hid_rx_data);
+    usb_g_ep_config(usb_id, CUSTOM_HID_EP_OUT, USB_ENDPOINT_XFER_INT, 1, custom_hid_ep_out_dma, MAXP_SIZE_CUSTOM_HIDOUT);
+    usb_enable_ep(usb_id, CUSTOM_HID_EP_OUT);
+}
+
+static void custom_hid_reset(struct usb_device_t *usb_device, u32 itf)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    log_debug("%s", __func__);
+#if USB_ROOT2
+    usb_disable_ep(usb_id, HID_EP_OUT);
+#else
+    custom_hid_endpoint_init(usb_device, itf);
+#endif
+}
+
+static u32 custom_hid_itf_hander(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    u32 tx_len;
+    u8 *tx_payload = usb_get_setup_buffer(usb_device);
+    u32 bRequestType = req->bRequestType & USB_TYPE_MASK;
+    switch (bRequestType) {
+    case USB_TYPE_STANDARD:
+        switch (req->bRequest) {
+        case USB_REQ_GET_DESCRIPTOR:
+            switch (HIBYTE(req->wValue)) {
+            case USB_HID_DT_HID:
+                tx_payload = (u8 *)sHIDDescriptor + USB_DT_INTERFACE_SIZE;
+                tx_len = 9;
+                tx_payload = usb_set_data_payload(usb_device, req, tx_payload, tx_len);
+                tx_payload[7] = LOBYTE(get_hid_report_desc_len(req->wIndex));
+                tx_payload[8] = HIBYTE(get_hid_report_desc_len(req->wIndex));
+                break;
+            case USB_HID_DT_REPORT:
+                tx_len = get_hid_report_desc_len(req->wIndex);
+                tx_payload = get_hid_report_desc(req->wIndex);
+                usb_set_data_payload(usb_device, req, tx_payload, tx_len);
+                break;
+            default:
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            }// USB_REQ_GET_DESCRIPTOR
+            break;
+        case USB_REQ_SET_DESCRIPTOR:
+            usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            break;
+        case USB_REQ_SET_INTERFACE:
+            if (usb_device->bDeviceStates == USB_DEFAULT) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            } else if (usb_device->bDeviceStates == USB_CONFIGURED) {
+                //只有一个interface 没有Alternate
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            }
+            break;
+        case USB_REQ_GET_INTERFACE:
+            if (req->wLength) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            } else if (usb_device->bDeviceStates == USB_DEFAULT) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            } else if (usb_device->bDeviceStates == USB_CONFIGURED) {
+                tx_len = 1;
+                tx_payload[0] = 0x00;
+                usb_set_data_payload(usb_device, req, tx_payload, tx_len);
+            }
+            break;
+        case USB_REQ_GET_STATUS:
+            if (usb_device->bDeviceStates == USB_DEFAULT) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            } else {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            }
+            break;
+        default:
+            usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+        }//bRequest @ USB_TYPE_STANDARD
+        break;
+
+    case USB_TYPE_CLASS:
+        switch (req->bRequest) {
+        case USB_REQ_SET_IDLE:
+            custom_hid_endpoint_init(usb_device, LOBYTE(req->wIndex));
+            usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+            custom_hid_info->cfg_done = 1;
+            break;
+        case USB_REQ_GET_IDLE:
+            tx_len = 1;
+            tx_payload[0] = 0;
+            usb_set_data_payload(usb_device, req, tx_payload, tx_len);
+            break;
+        default:
+            usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+        }//bRequest @ USB_TYPE_CLASS
+        break;
+
+    default:
+        usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+    }
+    return 0;
+}
+
+u32 custom_hid_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num)
+{
+    log_debug("custom hid interface num:%d\n", *cur_itf_num);
+    memcpy(ptr, sHIDDescriptor, sizeof(sHIDDescriptor));
+    ptr[2] = *cur_itf_num;
+    ptr[USB_DT_INTERFACE_SIZE + 7] = LOBYTE(get_hid_report_desc_len(0));
+    ptr[USB_DT_INTERFACE_SIZE + 8] = HIBYTE(get_hid_report_desc_len(0));
+
+    if (usb_set_interface_hander(usb_id, *cur_itf_num, custom_hid_itf_hander) != *cur_itf_num) {
+        ASSERT(0, "custom hid set interface_hander fail");
+    }
+    if (usb_set_reset_hander(usb_id, *cur_itf_num, custom_hid_reset) != *cur_itf_num) {
+        ASSERT(0, "custom hid set interface_reset_hander fail");
+    }
+
+    *cur_itf_num = *cur_itf_num + 1;
+    return sizeof(sHIDDescriptor);
+}
+
+u32 custom_hid_register(usb_dev usb_id)
+{
+    if (custom_hid_info) {
+        return 0;
+    }
+#if USB_MALLOC_ENABLE
+    custom_hid_info = malloc(sizeof(struct custom_hid_hdl));
+    if (!custom_hid_info) {
+        log_error("custom hid allocates memory fail 1\n");
+        return -1;
+    }
+#else
+    custom_hid_info = &_custom_hid_info;
+#endif
+    memset(custom_hid_info, 0, sizeof(struct custom_hid_hdl));
+    custom_hid_ep_in_dma = usb_alloc_ep_dmabuffer(usb_id, CUSTOM_HID_EP_IN | USB_DIR_IN, MAXP_SIZE_CUSTOM_HIDIN);
+    custom_hid_ep_out_dma = usb_alloc_ep_dmabuffer(usb_id, CUSTOM_HID_EP_OUT, MAXP_SIZE_CUSTOM_HIDOUT);
+    return 0;
+}
+
+void custom_hid_release()
+{
+    if (custom_hid_info == NULL) {
+        return;
+    }
+#if USB_MALLOC_ENABLE
+    free(custom_hid_info);
+#else
+    memset(custom_hid_info, 0, sizeof(struct custom_hid_hdl));
+#endif
+    custom_hid_info = NULL;
+}
+
+
+
+#endif

+ 215 - 0
apps/common/device/usb/device/descriptor.c

@@ -0,0 +1,215 @@
+/**
+ * @file descriptor.c
+ * @brief overwrite usb device descriptor
+ * @version 1.00
+ * @date 2019-05-06
+ */
+
+#include "usb/device/usb_stack.h"
+#include "usb/device/descriptor.h"
+#include "usb/device/uac_audio.h"
+
+#include "app_config.h"
+
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if TCFG_USB_SLAVE_ENABLE
+
+static const u8 sDeviceDescriptor[] = { //<Device Descriptor
+    USB_DT_DEVICE_SIZE,      // bLength: Size of descriptor
+    USB_DT_DEVICE,       // bDescriptorType: Device
+#if defined(FUSB_MODE) && FUSB_MODE
+    0x10, 0x01,     // bcdUSB: USB 1.1
+#elif defined(FUSB_MODE) && (FUSB_MODE ==0 )
+    0x00, 0x02,     // bcdUSB: USB 2.0
+#else
+#error "USB_SPEED_MODE not defined"
+#endif
+    0x00,       // bDeviceClass: none
+    0x00,       // bDeviceSubClass: none
+    0x00,       // bDeviceProtocol: none
+    EP0_SETUP_LEN,//EP0_LEN,      // bMaxPacketSize0: 8/64 bytes
+    'J', 'L',     // idVendor: 0x4a4c - JL
+    'U', 'A',     // idProduct: chip id
+    0x00, 0x01,     // bcdDevice: version 1.0
+    0x01,       // iManufacturer: Index to string descriptor that contains the string <Your Name> in Unicode
+    0x02,       // iProduct: Index to string descriptor that contains the string <Your Product Name> in Unicode
+    0x03,       // iSerialNumber: none
+    0x01        // bNumConfigurations: 1
+};
+
+static const u8 LANGUAGE_STR[] = {
+    0x04, 0x03, 0x09, 0x04
+};
+
+
+static const u8 product_string[] = {
+    42,
+    0x03,
+    'U', 0x00,
+    'S', 0x00,
+    'B', 0x00,
+    ' ', 0x00,
+    'C', 0x00,
+    'o', 0x00,
+    'm', 0x00,
+    'p', 0x00,
+    'o', 0x00,
+    's', 0x00,
+    'i', 0x00,
+    't', 0x00,
+    'e', 0x00,
+    ' ', 0x00,
+    'D', 0x00,
+    'e', 0x00,
+    'v', 0x00,
+    'i', 0x00,
+    'c', 0x00,
+    'e', 0x00,
+};
+
+static const u8 MANUFACTURE_STR[] = {
+    34,         //该描述符的长度为34字节
+    0x03,       //字符串描述符的类型编码为0x03
+    0x4a, 0x00, //J
+    0x69, 0x00, //i
+    0x65, 0x00, //e
+    0x6c, 0x00, //l
+    0x69, 0x00, //i
+    0x20, 0x00, //
+    0x54, 0x00, //T
+    0x65, 0x00, //e
+    0x63, 0x00, //c
+    0x68, 0x00, //h
+    0x6e, 0x00, //n
+    0x6f, 0x00, //o
+    0x6c, 0x00, //l
+    0x6f, 0x00, //o
+    0x67, 0x00, //g
+    0x79, 0x00, //y
+};
+
+static const u8 sConfigDescriptor[] = {	//<Config Descriptor
+//ConfiguraTIon
+    USB_DT_CONFIG_SIZE,    //bLength
+    USB_DT_CONFIG,    //DescriptorType : ConfigDescriptor
+    0, 0, //TotalLength
+    0,//bNumInterfaces: 在set_descriptor函数里面计算
+    0x01,    //bConfigurationValue - ID of this configuration
+    0x00,    //Unused
+#if USB_ROOT2 || USB_SUSPEND_RESUME || USB_SUSPEND_RESUME_SYSTEM_NO_SLEEP
+    0xA0,    //Attributes:Bus Power remotewakeup
+#else
+    0x80,    //Attributes:Bus Power
+#endif
+    50,     //MaxPower * 2ma
+};
+
+static const u8 serial_string[] = {
+    0x22, 0x03, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x36, 0x00, 0x46, 0x00, 0x36, 0x00,
+    0x34, 0x00, 0x30, 0x00, 0x39, 0x00, 0x36, 0x00, 0x42, 0x00, 0x32, 0x00, 0x32, 0x00, 0x45, 0x00,
+    0x37, 0x00
+};
+
+void get_device_descriptor(u8 *ptr)
+{
+    memcpy(ptr, sDeviceDescriptor, USB_DT_DEVICE_SIZE);
+}
+
+void get_language_str(u8 *ptr)
+{
+    memcpy(ptr, LANGUAGE_STR, LANGUAGE_STR[0]);
+}
+
+void get_manufacture_str(u8 *ptr)
+{
+    memcpy(ptr, MANUFACTURE_STR, MANUFACTURE_STR[0]);
+}
+
+void get_iserialnumber_str(u8 *ptr)
+{
+#if USB_ROOT2
+    memcpy(ptr, serial_string, serial_string[0]);
+#else
+    extern __attribute__((weak)) u8 *get_norflash_uuid(void);
+    u8 flash_id[16] = {0};
+    int i;
+    u8 bcd;
+    if (get_norflash_uuid && get_norflash_uuid()) {
+        ptr[0] = 0x22;
+        ptr[1] = 0x03;
+        memset(&ptr[2], 0, 0x20);
+        memcpy(flash_id, get_norflash_uuid(), 16);
+        //take 8 bytes from flash uuid
+        for (i = 0; i < 8; i++) {
+            bcd = flash_id[i] >> 4;
+            if (bcd > 9) {
+                bcd = bcd - 0xa + 'A';
+            } else {
+                bcd = bcd + '0';
+            }
+            ptr[2 + i * 4] = bcd;
+            bcd = flash_id[i] & 0xf;
+            if (bcd > 9) {
+                bcd = bcd - 0xa + 'A';
+            } else {
+                bcd = bcd + '0';
+            }
+            ptr[2 + i * 4 + 2] = bcd;
+        }
+    } else {
+        memcpy(ptr, serial_string, serial_string[0]);
+    }
+#endif
+}
+
+#if USB_ROOT2
+static const u8 ee_string[] = {0x12, 0x03, 0x4D, 0x00, 0x53, 0x00, 0x46, 0x00, 0x54,
+                               0x00, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00, 0x90, 0x00
+                              };
+void get_string_ee(u8 *ptr)
+{
+    memcpy(ptr, ee_string, ee_string[0]);
+}
+#endif
+
+void get_product_str(u8 *ptr)
+{
+    memcpy(ptr, product_string, product_string[0]);
+}
+
+const u8 *usb_get_config_desc()
+{
+    return sConfigDescriptor;
+}
+
+const u8 *usb_get_string_desc(u32 id)
+{
+    const u8 *pstr = uac_get_string(id);
+    if (pstr != NULL) {
+        return pstr;
+    }
+    return NULL;
+}
+
+void get_device_info_to_ota(void *parm_priv)
+{
+    u8 *tmp = parm_priv;
+    memcpy(tmp, &(sDeviceDescriptor[8]), 4);
+    tmp[8]++;
+    if (product_string[0] > 28) {
+        log_error("The product_string length is more than 28 Byte");
+        memcpy(&(parm_priv[4]), product_string, 28);
+    } else {
+        memcpy(&(parm_priv[4]), product_string, product_string[0]);
+    }
+}
+
+#endif

+ 335 - 0
apps/common/device/usb/device/hid.c

@@ -0,0 +1,335 @@
+#include "os/os_api.h"
+#include "usb/device/usb_stack.h"
+#include "usb/device/hid.h"
+#include "usb_config.h"
+
+#include "app_config.h"
+
+#if TCFG_USB_SLAVE_USER_HID
+#undef TCFG_USB_SLAVE_HID_ENABLE
+#define TCFG_USB_SLAVE_HID_ENABLE           0
+#endif
+
+#if TCFG_USB_SLAVE_HID_ENABLE
+
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+static const u8 sHIDDescriptor[] = {
+//HID
+    //InterfaceDeszcriptor:
+    USB_DT_INTERFACE_SIZE,     // Length
+    USB_DT_INTERFACE,          // DescriptorType
+    /* 0x04,                      // bInterface number */
+    0x00,                       // bInterface number
+    0x00,                      // AlternateSetting
+    0x01,                      // NumEndpoint
+    /* 0x02,                        // NumEndpoint */
+    USB_CLASS_HID,             // Class = Human Interface Device
+    0x00,                      // Subclass, 0 No subclass, 1 Boot Interface subclass
+    0x00,                      // Procotol, 0 None, 1 Keyboard, 2 Mouse
+    0x00,                      // Interface Name
+
+    //HIDDescriptor:
+    0x09,                      // bLength
+    USB_HID_DT_HID,            // bDescriptorType, HID Descriptor
+    0x00, 0x01,                // bcdHID, HID Class Specification release NO.
+    0x00,                      // bCuntryCode, Country localization (=none)
+    0x01,                       // bNumDescriptors, Number of descriptors to follow
+    0x22,                       // bDescriptorType, Report Desc. 0x22, Physical Desc. 0x23
+    0,//LOW(ReportLength)
+    0, //HIGH(ReportLength)
+
+    //EndpointDescriptor:
+    USB_DT_ENDPOINT_SIZE,       // bLength
+    USB_DT_ENDPOINT,            // bDescriptorType, Type
+    USB_DIR_IN | HID_EP_IN,     // bEndpointAddress
+    USB_ENDPOINT_XFER_INT,      // Interrupt
+    LOBYTE(MAXP_SIZE_HIDIN), HIBYTE(MAXP_SIZE_HIDIN),// Maximum packet size
+    1,     // Poll every 10msec seconds
+
+//@Endpoint Descriptor:
+    /* USB_DT_ENDPOINT_SIZE,       // bLength
+    USB_DT_ENDPOINT,            // bDescriptorType, Type
+    USB_DIR_OUT | HID_EP_OUT,   // bEndpointAddress
+    USB_ENDPOINT_XFER_INT,      // Interrupt
+    LOBYTE(MAXP_SIZE_HIDOUT), HIBYTE(MAXP_SIZE_HIDOUT),// Maximum packet size
+    0x01,                       // bInterval, for high speed 2^(n-1) * 125us, for full/low speed n * 1ms */
+};
+
+static const u8 sHIDReportDesc[] = {
+    USAGE_PAGE(1, CONSUMER_PAGE),
+    USAGE(1, CONSUMER_CONTROL),
+    COLLECTION(1, APPLICATION),
+
+    LOGICAL_MIN(1, 0x00),
+    LOGICAL_MAX(1, 0x01),
+
+    USAGE(1, VOLUME_INC),
+    USAGE(1, VOLUME_DEC),
+    USAGE(1, MUTE),
+    USAGE(1, PLAY_PAUSE),
+    USAGE(1, SCAN_NEXT_TRACK),
+    USAGE(1, SCAN_PREV_TRACK),
+    USAGE(1, FAST_FORWARD),
+    USAGE(1, STOP),
+
+    USAGE(1, TRACKING_INC),
+    USAGE(1, TRACKING_DEC),
+    USAGE(1, STOP_EJECT),
+    USAGE(1, VOLUME),
+    USAGE(2, BALANCE_LEFT),
+    USAGE(2, BALANCE_RIGHT),
+    USAGE(1, PLAY),
+    USAGE(1, PAUSE),
+
+    REPORT_SIZE(1, 0x01),
+    REPORT_COUNT(1, 0x10),
+    INPUT(1, 0x42),
+    END_COLLECTION,
+
+};
+
+static u32 get_hid_report_desc_len(u32 index)
+{
+    u32 len = 0;
+    len = sizeof(sHIDReportDesc);
+    return len;
+}
+static void *get_hid_report_desc(u32 index)
+{
+    u8 *ptr  = NULL;
+    ptr = (u8 *)sHIDReportDesc;
+    return ptr;
+}
+
+
+static u8 *hid_ep_in_dma;
+/* static u8 *hid_ep_out_dma; */
+
+static u32 hid_tx_data(struct usb_device_t *usb_device, const u8 *buffer, u32 len)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    return usb_g_intr_write(usb_id, HID_EP_IN, buffer, len);
+}
+static void hid_rx_data(struct usb_device_t *usb_device, u32 ep)
+{
+    /* const usb_dev usb_id = usb_device2id(usb_device); */
+    /* u32 rx_len = usb_g_intr_read(usb_id, ep, NULL, 64, 0); */
+    /* hid_tx_data(usb_device, hid_ep_out_dma, rx_len); */
+}
+
+static void hid_endpoint_init(struct usb_device_t *usb_device, u32 itf)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    usb_g_ep_config(usb_id, HID_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_INT, 0, hid_ep_in_dma, MAXP_SIZE_HIDIN);
+    usb_enable_ep(usb_id, HID_EP_IN);
+
+    /* usb_g_set_intr_hander(usb_id, HID_EP_OUT, hid_rx_data); */
+    /* usb_g_ep_config(usb_id, HID_EP_OUT, USB_ENDPOINT_XFER_INT, 1, ep_buffer, MAXP_SIZE_HIDOUT); */
+}
+u32 hid_register(const usb_dev usb_id)
+{
+    hid_ep_in_dma = usb_alloc_ep_dmabuffer(usb_id, HID_EP_IN | USB_DIR_IN, MAXP_SIZE_HIDIN);
+
+    /* hid_ep_out_dma = hid_ep_in_dma + MAXP_SIZE_HIDIN; */
+    return 0;
+}
+
+void hid_release(const usb_dev usb_id)
+{
+    return ;
+}
+
+static void hid_reset(struct usb_device_t *usb_device, u32 itf)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    log_debug("%s", __func__);
+#if USB_ROOT2
+    usb_disable_ep(usb_id, HID_EP_IN);
+#else
+    hid_endpoint_init(usb_device, itf);
+#endif
+}
+static u32 hid_recv_output_report(struct usb_device_t *usb_device, struct usb_ctrlrequest *setup)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    u32 ret = 0;
+    u8 read_ep[8];
+    u8 mute;
+    u16 volume = 0;
+    usb_read_ep0(usb_id, read_ep, MIN(sizeof(read_ep), setup->wLength));
+    ret = USB_EP0_STAGE_SETUP;
+    put_buf(read_ep, 8);
+
+
+    return ret;
+}
+
+static u32 hid_itf_hander(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
+{
+    if (req == -1) {
+        return 0;
+    }
+    const usb_dev usb_id = usb_device2id(usb_device);
+    u32 tx_len;
+    u8 *tx_payload = usb_get_setup_buffer(usb_device);
+    u32 bRequestType = req->bRequestType & USB_TYPE_MASK;
+    switch (bRequestType) {
+    case USB_TYPE_STANDARD:
+        switch (req->bRequest) {
+        case USB_REQ_GET_DESCRIPTOR:
+            switch (HIBYTE(req->wValue)) {
+            case USB_HID_DT_HID:
+                tx_payload = (u8 *)sHIDDescriptor + USB_DT_INTERFACE_SIZE;
+                tx_len = 9;
+                tx_payload = usb_set_data_payload(usb_device, req, tx_payload, tx_len);
+                tx_payload[7] = LOBYTE(get_hid_report_desc_len(req->wIndex));
+                tx_payload[8] = HIBYTE(get_hid_report_desc_len(req->wIndex));
+                break;
+            case USB_HID_DT_REPORT:
+                hid_endpoint_init(usb_device, req->wIndex);
+                tx_len = get_hid_report_desc_len(req->wIndex);
+                tx_payload = get_hid_report_desc(req->wIndex);
+                usb_set_data_payload(usb_device, req, tx_payload, tx_len);
+                break;
+            }// USB_REQ_GET_DESCRIPTOR
+            break;
+        case USB_REQ_SET_DESCRIPTOR:
+            usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+            break;
+        case USB_REQ_SET_INTERFACE:
+            if (usb_device->bDeviceStates == USB_DEFAULT) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            } else if (usb_device->bDeviceStates == USB_CONFIGURED) {
+                //只有一个interface 没有Alternate
+                if (req->wValue == 0) { //alt 0
+                    usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+                } else {
+                    usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+                }
+            }
+            break;
+        case USB_REQ_GET_INTERFACE:
+            if (req->wValue || (req->wLength != 1)) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            } else if (usb_device->bDeviceStates == USB_DEFAULT) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            } else if (usb_device->bDeviceStates == USB_CONFIGURED) {
+                tx_len = 1;
+                tx_payload[0] = 0x00;
+                usb_set_data_payload(usb_device, req, tx_payload, tx_len);
+            }
+            break;
+        case USB_REQ_GET_STATUS:
+            if (usb_device->bDeviceStates == USB_DEFAULT) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            } else if (usb_device->bDeviceStates == USB_ADDRESS) {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            } else {
+                usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+            }
+            break;
+        }//bRequest @ USB_TYPE_STANDARD
+        break;
+
+    case USB_TYPE_CLASS: {
+        switch (req->bRequest) {
+        case USB_REQ_SET_IDLE:
+            usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
+            break;
+        case USB_REQ_GET_IDLE:
+            tx_len = 1;
+            tx_payload[0] = 0;
+            usb_set_data_payload(usb_device, req, tx_payload, tx_len);
+            break;
+        case USB_REQ_SET_REPORT:
+            usb_set_setup_recv(usb_device, hid_recv_output_report);
+            break;
+        }//bRequest @ USB_TYPE_CLASS
+    }
+    break;
+    }
+    return 0;
+}
+
+u32 hid_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num)
+{
+    log_debug("hid interface num:%d\n", *cur_itf_num);
+    u8 *_ptr = ptr;
+    memcpy(ptr, sHIDDescriptor, sizeof(sHIDDescriptor));
+    ptr[2] = *cur_itf_num;
+    if (usb_set_interface_hander(usb_id, *cur_itf_num, hid_itf_hander) != *cur_itf_num) {
+        ASSERT(0, "hid set interface_hander fail");
+    }
+    if (usb_set_reset_hander(usb_id, *cur_itf_num, hid_reset) != *cur_itf_num) {
+        ASSERT(0, "hid set interface_reset_hander fail");
+    }
+
+    ptr[USB_DT_INTERFACE_SIZE + 7] = LOBYTE(get_hid_report_desc_len(0));
+    ptr[USB_DT_INTERFACE_SIZE + 8] = HIBYTE(get_hid_report_desc_len(0));
+    *cur_itf_num = *cur_itf_num + 1;
+    return sizeof(sHIDDescriptor) ;
+}
+
+void hid_key_handler(struct usb_device_t *usb_device, u32 hid_key)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    if (usb_get_ep_status(usb_id, HID_EP_IN)) {
+        return;
+    }
+
+    u16 key_buf = hid_key;
+    hid_tx_data(usb_device, (const u8 *)&key_buf, 2);
+    os_time_dly(2);
+    key_buf = 0;
+    hid_tx_data(usb_device, (const u8 *)&key_buf, 2);
+}
+
+void hid_key_handler_send_one_packet(struct usb_device_t *usb_device, u32 hid_key)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    u16 key_buf = hid_key;
+    hid_tx_data(usb_device, (const u8 *)&key_buf, 2);
+}
+
+struct hid_button {
+    u8 report_id;
+    u8 button1: 1;
+    u8 button2: 1;
+    u8 button3: 1;
+    u8 no_button: 5;
+    u8 X_axis;
+    u8 Y_axis;
+};
+struct hid_button hid_key;
+void hid_test(struct usb_device_t *usb_device)
+{
+    static u32 tx_count = 0;
+
+    hid_key_handler(usb_device, BIT(tx_count));
+    tx_count ++;
+    if (BIT(tx_count) > USB_AUDIO_PAUSE) {
+        tx_count = 0;
+    }
+}
+#else
+void hid_key_handler(struct usb_device_t *usb_device, u32 hid_key)
+{
+
+}
+
+void hid_key_handler_for_one_packet(struct usb_device_t *usb_device, u32 hid_key)
+{
+
+}
+#endif

File diff suppressed because it is too large
+ 1117 - 0
apps/common/device/usb/device/msd.c


+ 75 - 0
apps/common/device/usb/device/msd_upgrade.c

@@ -0,0 +1,75 @@
+#include "system/includes.h"
+#include "usb/device/msd.h"
+#include "usb/scsi.h"
+#include "usb_config.h"
+#include "app_config.h"
+#include "cpu.h"
+#include "asm/debug.h"
+
+#define WRITE_FLASH                     0xFB
+#define READ_FLASH                      0xFD
+#define OTHER_CMD                       0xFC
+typedef enum {
+    UPGRADE_NULL = 0,
+    UPGRADE_USB_HARD_KEY,
+    UPGRADE_USB_SOFT_KEY,
+    UPGRADE_UART_KEY,
+} UPGRADE_STATE;
+
+extern void nvram_set_boot_state(u32 state);
+extern void hw_mmu_disable(void);
+extern void ram_protect_close(void);
+
+AT(.volatile_ram_code)
+void go_mask_usb_updata()
+{
+#ifdef CONFIG_CPU_BR18
+    gpio_set_die(IO_PORTD_02, 0);
+    gpio_set_die(IO_PORTB_04, 0);
+    cpu_reset();
+
+#else
+    local_irq_disable();
+    ram_protect_close();
+    hw_mmu_disable();
+    nvram_set_boot_state(UPGRADE_USB_SOFT_KEY);
+    JL_CLOCK->PWR_CON |= (1 << 4);
+#endif
+
+    /* chip_reset(); */
+    /* cpu_reset(); */
+    while (1);
+}
+#if TCFG_PC_UPDATE
+
+u32 _usb_bulk_rw_test(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw);
+
+u32 private_scsi_cmd(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw)
+{
+    /* if (_usb_bulk_rw_test(usb_device, cbw)) { */
+    /*     return TRUE;                          */
+    /* }                                         */
+
+    switch (cbw->operationCode) {
+//////////////////////Boot Loader Custom CMD
+    case WRITE_FLASH:
+    case READ_FLASH:
+    case OTHER_CMD:
+        log_d("goto mask pc mode\n");
+        go_mask_usb_updata();
+        break;
+
+    default:
+
+        return FALSE;
+    }
+
+    return TRUE;
+}
+#else
+u32 private_scsi_cmd(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw)
+{
+    return FALSE;
+}
+#endif
+

+ 352 - 0
apps/common/device/usb/device/task_pc.c

@@ -0,0 +1,352 @@
+/**
+ * @file task_pc.c
+ * @brief 从机模式
+ * @author chenrixin@zh-jieli.com
+ * @version 1.0.0
+ * @date 2020-02-29
+ */
+
+#include "system/app_core.h"
+#include "system/includes.h"
+#include "server/server_core.h"
+#include "app_config.h"
+#include "app_action.h"
+#include "os/os_api.h"
+#include "device/sdmmc.h"
+
+#include "app_charge.h"
+#include "asm/charge.h"
+
+#if TCFG_USB_SLAVE_ENABLE
+#ifndef  USB_PC_NO_APP_MODE
+#include "app_task.h"
+#endif
+#include "usb/usb_config.h"
+#include "usb/device/usb_stack.h"
+
+#if TCFG_USB_SLAVE_HID_ENABLE
+#include "usb/device/hid.h"
+#endif
+
+#if TCFG_USB_SLAVE_MSD_ENABLE
+#include "usb/device/msd.h"
+#endif
+
+#if TCFG_USB_SLAVE_CDC_ENABLE
+#include "usb/device/cdc.h"
+#endif
+
+#if (TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0)
+#include "dev_multiplex_api.h"
+#endif
+
+#if TCFG_USB_APPLE_DOCK_EN
+#include "apple_dock/iAP.h"
+#endif
+
+#if (TCFG_SOUNDBOX_TOOL_ENABLE || TCFG_EFFECT_TOOL_ENABLE)
+#include "app_sound_box_tool.h"
+#endif
+
+#if TCFG_USB_CUSTOM_HID_ENABLE
+#include "usb/device/custom_hid.h"
+#endif
+
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[USB_TASK]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define     USB_TASK_NAME   "usb_msd"
+
+#define USBSTACK_EVENT		    0x80
+#define USBSTACK_MSD_RUN		0x81
+#define USBSTACK_MSD_RELASE		0x82
+#define USBSTACK_HID		    0x83
+#define USBSTACK_MSD_RESET      0x84
+
+extern int usb_audio_demo_init(void);
+extern void usb_audio_demo_exit(void);
+
+static usb_dev usbfd = 0;//SEC(.usb_g_bss);
+static OS_MUTEX msd_mutex ;//SEC(.usb_g_bss);
+static u8 msd_in_task;
+static u8 msd_run_reset;
+
+
+static void usb_task(void *p)
+{
+    int ret = 0;
+    int msg[16];
+    while (1) {
+        ret = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
+        if (ret != OS_TASKQ) {
+            continue;
+        }
+        if (msg[0] != Q_MSG) {
+            continue;
+        }
+        switch (msg[1]) {
+#if TCFG_USB_SLAVE_MSD_ENABLE
+        case USBSTACK_MSD_RUN:
+            os_mutex_pend(&msd_mutex, 0);
+            msd_in_task = 1;
+#if TCFG_USB_APPLE_DOCK_EN
+            apple_mfi_link((void *)msg[2]);
+#else
+            USB_MassStorage((void *)msg[2]);
+#endif
+            if (msd_run_reset) {
+                msd_reset((struct usb_device_t *)msg[2], 0);
+                msd_run_reset = 0;
+            }
+            msd_in_task = 0;
+            os_mutex_post(&msd_mutex);
+            break;
+        case USBSTACK_MSD_RELASE:
+            os_sem_post((OS_SEM *)msg[2]);
+            while (1) {
+                os_time_dly(10000);
+            }
+            break;
+//        case USBSTACK_MSD_RESET:
+//            os_mutex_pend(&msd_mutex, 0);
+//            msd_reset((struct usb_device_t *)msg[2], (u32)msg[3]);
+//            os_mutex_post(&msd_mutex);
+//            break;
+#endif
+        default:
+            break;
+        }
+    }
+}
+
+static void usb_msd_wakeup(struct usb_device_t *usb_device)
+{
+    os_taskq_post_msg(USB_TASK_NAME, 2, USBSTACK_MSD_RUN, usb_device);
+}
+static void usb_msd_reset_wakeup(struct usb_device_t *usb_device, u32 itf_num)
+{
+    /* os_taskq_post_msg(USB_TASK_NAME, 3, USBSTACK_MSD_RESET, usb_device, itf_num); */
+    if (msd_in_task) {
+        msd_run_reset = 1;
+    } else {
+#if TCFG_USB_SLAVE_MSD_ENABLE
+        msd_reset(usb_device, 0);
+#endif
+    }
+}
+static void usb_msd_init()
+{
+    r_printf("%s()", __func__);
+    int err;
+    os_mutex_create(&msd_mutex);
+    err = task_create(usb_task, NULL, USB_TASK_NAME);
+    if (err != OS_NO_ERR) {
+        r_printf("usb_msd task creat fail %x\n", err);
+    }
+}
+static void usb_msd_free()
+{
+    r_printf("%s()", __func__);
+
+    os_mutex_del(&msd_mutex, 0);
+
+    int err;
+    OS_SEM sem;
+    os_sem_create(&sem, 0);
+    os_taskq_post_msg(USB_TASK_NAME, 2, USBSTACK_MSD_RELASE, (int)&sem);
+    os_sem_pend(&sem, 0);
+
+
+    err = task_kill(USB_TASK_NAME);
+    if (!err) {
+        r_printf("usb_msd_uninit succ!!\n");
+    } else {
+        r_printf("usb_msd_uninit fail!!\n");
+    }
+}
+
+#if TCFG_USB_SLAVE_CDC_ENABLE
+static void usb_cdc_wakeup(struct usb_device_t *usb_device)
+{
+    //回调函数在中断里,正式使用不要在这里加太多东西阻塞中断,
+    //或者先post到任务,由任务调用cdc_read_data()读取再执行后续工作
+    const usb_dev usb_id = usb_device2id(usb_device);
+    u8 buf[64] = {0};
+    u32 rlen;
+
+    log_debug("cdc rx hook");
+    rlen = cdc_read_data(usb_id, buf, 64);
+    put_buf(buf, rlen);
+    cdc_write_data(usb_id, buf, rlen);
+}
+#endif
+
+#if TCFG_USB_CUSTOM_HID_ENABLE
+static void custom_hid_rx_handler(void *priv, u8 *buf, u32 len)
+{
+    printf("%s,%d,\n", __func__, __LINE__);
+    put_buf(buf, len);
+    custom_hid_tx_data(0, buf, len);
+}
+#endif
+
+void usb_start()
+{
+
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+    usb_audio_demo_init();
+#endif
+
+#ifdef USB_DEVICE_CLASS_CONFIG
+    g_printf("USB_DEVICE_CLASS_CONFIG:%x", USB_DEVICE_CLASS_CONFIG);
+    usb_device_mode(usbfd, USB_DEVICE_CLASS_CONFIG);
+#endif
+
+
+#if TCFG_USB_SLAVE_MSD_ENABLE
+    //没有复用时候判断 sd开关
+    //复用时候判断是否参与复用
+#if (!TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_SD0_ENABLE)\
+     ||(TCFG_SD0_ENABLE && TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_DM_MULTIPLEX_WITH_SD_PORT != 0)
+    msd_register_disk("sd0", NULL);
+#endif
+
+#if (!TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_SD1_ENABLE)\
+     ||(TCFG_SD1_ENABLE && TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_DM_MULTIPLEX_WITH_SD_PORT != 1)
+    msd_register_disk("sd1", NULL);
+#endif
+
+#if TCFG_NOR_FAT
+    msd_register_disk("fat_nor", NULL);
+#endif
+
+#if TCFG_VIR_UDISK_ENABLE
+    msd_register_disk("vir_udisk0", NULL);
+#endif
+
+    msd_set_wakeup_handle(usb_msd_wakeup);
+    msd_set_reset_wakeup_handle(usb_msd_reset_wakeup);
+    usb_msd_init();
+#endif
+
+#if TCFG_USB_SLAVE_CDC_ENABLE
+    cdc_set_wakeup_handler(usb_cdc_wakeup);
+#endif
+
+#if TCFG_USB_CUSTOM_HID_ENABLE
+    custom_hid_set_rx_hook(NULL, custom_hid_rx_handler);
+    printf("custom_hid rx_hook\n");
+#endif
+}
+static void usb_remove_disk()
+{
+#if TCFG_USB_SLAVE_MSD_ENABLE
+    os_mutex_pend(&msd_mutex, 0);
+    msd_unregister_all();
+    os_mutex_post(&msd_mutex);
+#endif
+}
+void usb_pause()
+{
+    log_info("usb pause");
+
+    usb_sie_disable(usbfd);
+
+#if TCFG_USB_SLAVE_MSD_ENABLE
+    if (msd_set_wakeup_handle(NULL)) {
+        usb_remove_disk();
+        usb_msd_free();
+    }
+#endif
+
+
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+    usb_audio_demo_exit();
+#endif
+
+    usb_device_mode(usbfd, 0);
+}
+
+void usb_stop()
+{
+    log_info("App Stop - usb");
+
+    usb_pause();
+
+    usb_sie_close(usbfd);
+}
+
+
+int pc_device_event_handler(struct sys_event *event)
+{
+    if ((int)event->arg != DEVICE_EVENT_FROM_OTG) {
+        return false;
+    }
+
+    int switch_app_case = false;
+    const char *usb_msg = (const char *)event->u.dev.value;
+    log_debug("usb event : %d DEVICE_EVENT_FROM_OTG %s", event->u.dev.event, usb_msg);
+
+    if (usb_msg[0] == 's') {
+        if (event->u.dev.event == DEVICE_EVENT_IN) {
+            log_info("usb %c online", usb_msg[2]);
+            usbfd = usb_msg[2] - '0';
+#if   USB_PC_NO_APP_MODE
+            usb_start();
+#elif TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
+            usb_otg_suspend(0, OTG_KEEP_STATE);
+            mult_sdio_suspend();
+            usb_pause();
+            mult_sdio_resume();
+#else
+            usb_pause();
+#endif
+            switch_app_case = 1;
+        } else if (event->u.dev.event == DEVICE_EVENT_OUT) {
+            log_info("usb %c offline", usb_msg[2]);
+            switch_app_case = 2;
+#ifdef  USB_PC_NO_APP_MODE
+            usb_stop();
+#else
+
+#ifdef CONFIG_SOUNDBOX
+            if (!app_check_curr_task(APP_PC_TASK)) {
+#else
+            if (!app_cur_task_check(APP_NAME_PC)) {
+#endif
+#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
+                mult_sdio_suspend();
+#endif
+                usb_stop();
+#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
+                mult_sdio_resume();
+#endif
+            }
+
+#endif
+        }
+    }
+
+    return switch_app_case;
+}
+
+#ifdef  USB_PC_NO_APP_MODE
+void usbstack_init()
+{
+    register_sys_event_handler(SYS_DEVICE_EVENT, DEVICE_EVENT_FROM_OTG, 2,
+                               pc_device_event_handler);
+}
+
+void usbstack_exit()
+{
+    unregister_sys_event_handler(pc_device_event_handler);
+}
+#endif
+
+#endif

File diff suppressed because it is too large
+ 1396 - 0
apps/common/device/usb/device/uac1.c


+ 507 - 0
apps/common/device/usb/device/uac_stream.c

@@ -0,0 +1,507 @@
+#include "app_config.h"
+#include "system/includes.h"
+#include "printf.h"
+#include "usb/usb_config.h"
+#include "usb/device/usb_stack.h"
+
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+#include "usb/device/uac_audio.h"
+#include "uac_stream.h"
+#include "audio_config.h"
+
+/* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
+#include "audio_track.h"
+/* #endif */
+
+
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[UAC]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#define     UAC_DEBUG_ECHO_MODE 0
+
+static volatile u8 speaker_stream_is_open = 0;
+struct uac_speaker_handle {
+    cbuffer_t cbuf;
+    volatile u8 need_resume;
+    u8 channel;
+    u8 alive;
+    void *buffer;
+    void *audio_track;
+    //void (*rx_handler)(int, void *, int);
+};
+
+static void (*uac_rx_handler)(int, void *, int) = NULL;
+
+#if (SOUNDCARD_ENABLE)
+#define UAC_BUFFER_SIZE     (4 * 1024)
+#else
+#define UAC_BUFFER_SIZE     (1 * 1024)
+#endif
+
+#define UAC_BUFFER_MAX		(UAC_BUFFER_SIZE * 50 / 100)
+
+static struct uac_speaker_handle *uac_speaker = NULL;
+
+#if USB_MALLOC_ENABLE
+#else
+static struct uac_speaker_handle uac_speaker_handle SEC(.uac_var);
+static u8 uac_rx_buffer[UAC_BUFFER_SIZE] ALIGNED(4) SEC(.uac_rx);
+#endif
+u32 uac_speaker_stream_length()
+{
+    return UAC_BUFFER_SIZE;
+}
+u32 uac_speaker_stream_size()
+{
+    if (!speaker_stream_is_open) {
+        return 0;
+    }
+
+    if (uac_speaker) {
+        return cbuf_get_data_size(&uac_speaker->cbuf);
+    }
+
+    return 0;
+}
+
+u32 uac_speaker_get_alive()
+{
+    if (uac_speaker) {
+        return uac_speaker->alive;
+    }
+    return 0;
+}
+void uac_speaker_set_alive(u8 alive)
+{
+    local_irq_disable();
+    if (uac_speaker) {
+        uac_speaker->alive = alive;
+    }
+    local_irq_enable();
+}
+
+void uac_speaker_stream_buf_clear(void)
+{
+    if (speaker_stream_is_open) {
+        cbuf_clear(&uac_speaker->cbuf);
+    }
+}
+
+void set_uac_speaker_rx_handler(void *priv, void (*rx_handler)(int, void *, int))
+{
+    uac_rx_handler = rx_handler;
+    /* if (uac_speaker) { */
+    /* uac_speaker->rx_handler = rx_handler; */
+    /* } */
+}
+
+int uac_speaker_stream_sample_rate(void)
+{
+    /* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
+    if (uac_speaker && uac_speaker->audio_track) {
+        int sr = audio_local_sample_track_rate(uac_speaker->audio_track);
+        if ((sr < (SPK_AUDIO_RATE + 500)) && (sr > (SPK_AUDIO_RATE - 500))) {
+            return sr;
+        }
+        /* printf("uac audio_track reset \n"); */
+        local_irq_disable();
+        audio_local_sample_track_close(uac_speaker->audio_track);
+        uac_speaker->audio_track = audio_local_sample_track_open(SPK_CHANNEL, SPK_AUDIO_RATE, 1000);
+        local_irq_enable();
+    }
+    /* #endif */
+    return SPK_AUDIO_RATE;
+}
+
+void uac_speaker_stream_write(const u8 *obuf, u32 len)
+{
+    if (speaker_stream_is_open) {
+        //write dac
+        /* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
+        if (uac_speaker->audio_track) {
+            audio_local_sample_track_in_period(uac_speaker->audio_track, (len >> 1) / uac_speaker->channel);
+        }
+        /* #endif */
+        int wlen = cbuf_write(&uac_speaker->cbuf, (void *)obuf, len);
+        if (wlen != len) {
+            //putchar('W');
+        }
+        //if (uac_speaker->rx_handler) {
+        if (uac_rx_handler) {
+            /* if (uac_speaker->cbuf.data_len >= UAC_BUFFER_MAX) { */
+            // 马上就要满了,赶紧取走
+            uac_speaker->need_resume = 1; //2020-12-22注:无需唤醒
+            /* } */
+            if (uac_speaker->need_resume) {
+                uac_speaker->need_resume = 0;
+                uac_rx_handler(0, (void *)obuf, len);
+                //uac_speaker->rx_handler(0, (void *)obuf, len);
+            }
+        }
+        uac_speaker->alive = 0;
+    }
+}
+
+int uac_speaker_read(void *priv, void *data, u32 len)
+{
+    int r_len;
+    int err = 0;
+
+    local_irq_disable();
+    if (!speaker_stream_is_open) {
+        local_irq_enable();
+        return 0;
+    }
+
+    r_len = cbuf_get_data_size(&uac_speaker->cbuf);
+    if (r_len) {
+        r_len = r_len > len ? len : r_len;
+        r_len = cbuf_read(&uac_speaker->cbuf, data, r_len);
+        if (!r_len) {
+            putchar('U');
+        }
+    }
+
+    if (r_len == 0) {
+        uac_speaker->need_resume = 1;
+    }
+    local_irq_enable();
+    return r_len;
+}
+
+void uac_speaker_stream_open(u32 samplerate, u32 ch)
+{
+    if (speaker_stream_is_open) {
+        return;
+    }
+    log_info("%s", __func__);
+
+    if (!uac_speaker) {
+#if USB_MALLOC_ENABLE
+
+        uac_speaker = zalloc(sizeof(struct uac_speaker_handle));
+        if (!uac_speaker) {
+            return;
+        }
+
+        uac_speaker->buffer = malloc(UAC_BUFFER_SIZE);
+        if (!uac_speaker->buffer) {
+            free(uac_speaker);
+            uac_speaker = NULL;
+            goto __err;
+        }
+
+
+#else
+
+        uac_speaker = &uac_speaker_handle;
+
+        memset(uac_speaker, 0, sizeof(struct uac_speaker_handle));
+
+        uac_speaker->buffer = uac_rx_buffer;
+#endif
+        uac_speaker->channel = ch;
+        /* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
+        uac_speaker->audio_track = audio_local_sample_track_open(ch, samplerate, 1000);
+        /* #endif */
+    }
+
+
+    //uac_speaker->rx_handler = NULL;
+
+    cbuf_init(&uac_speaker->cbuf, uac_speaker->buffer, UAC_BUFFER_SIZE);
+    speaker_stream_is_open = 1;
+    struct sys_event event;
+    event.type = SYS_DEVICE_EVENT;
+    event.arg = (void *)DEVICE_EVENT_FROM_UAC;
+    event.u.dev.event = USB_AUDIO_PLAY_OPEN;
+    event.u.dev.value = (int)((ch << 24) | samplerate);
+
+#if !UAC_DEBUG_ECHO_MODE
+    sys_event_notify(&event);
+#endif
+
+    return;
+
+__err:
+    return;
+}
+
+void uac_speaker_stream_close()
+{
+    if (speaker_stream_is_open == 0) {
+        return;
+    }
+
+    log_info("%s", __func__);
+    speaker_stream_is_open = 0;
+
+    if (uac_speaker) {
+        /* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
+        audio_local_sample_track_close(uac_speaker->audio_track);
+        /* #endif */
+        uac_speaker->audio_track = NULL;
+#if USB_MALLOC_ENABLE
+        if (uac_speaker->buffer) {
+            free(uac_speaker->buffer);
+        }
+        free(uac_speaker);
+#endif
+        uac_speaker = NULL;
+    }
+    struct sys_event event;
+    event.type = SYS_DEVICE_EVENT;
+    event.arg = (void *)DEVICE_EVENT_FROM_UAC;
+    event.u.dev.event = USB_AUDIO_PLAY_CLOSE;
+    event.u.dev.value = (int)0;
+
+    sys_event_notify(&event);
+}
+
+int uac_get_spk_vol()
+{
+    int max_vol = get_max_sys_vol();
+    int vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
+    if (vol * 100 / max_vol < 100) {
+        return vol * 100 / max_vol;
+    } else {
+        return 99;
+    }
+    return 0;
+}
+static u8 flag_uac_event_enable = 1;
+void set_uac_event_flag(u8 en)
+{
+    flag_uac_event_enable = en;
+}
+u8 get_uac_event_flag(void)
+{
+    return flag_uac_event_enable;
+}
+static volatile u32 mic_stream_is_open;
+
+u8 uac_get_mic_stream_status(void)
+{
+    return mic_stream_is_open;
+}
+
+void uac_mute_volume(u32 type, u32 l_vol, u32 r_vol)
+{
+    struct sys_event event;
+    event.type = SYS_DEVICE_EVENT;
+    event.arg = (void *)DEVICE_EVENT_FROM_UAC;
+
+    static u32 last_spk_l_vol = (u32) - 1, last_spk_r_vol = (u32) - 1;
+    static u32 last_mic_vol = (u32) - 1;
+
+    if (!get_uac_event_flag()) {
+        return;
+    }
+    switch (type) {
+    case MIC_FEATURE_UNIT_ID: //MIC
+        if (mic_stream_is_open == 0) {
+            return ;
+        }
+        if (l_vol == last_mic_vol) {
+            return;
+        }
+        last_mic_vol = l_vol;
+        event.u.dev.event = USB_AUDIO_SET_MIC_VOL;
+        break;
+    case SPK_FEATURE_UNIT_ID: //SPK
+        if (speaker_stream_is_open == 0) {
+            return;
+        }
+        if (l_vol == last_spk_l_vol && r_vol == last_spk_r_vol) {
+            return;
+        }
+        last_spk_l_vol = l_vol;
+        last_spk_r_vol = r_vol;
+        event.u.dev.event = USB_AUDIO_SET_PLAY_VOL;
+        break;
+    default:
+        break;
+    }
+
+    event.u.dev.value = (int)(r_vol << 16 | l_vol);
+    sys_event_notify(&event);
+}
+
+
+static int (*mic_tx_handler)(int, void *, int) = NULL;
+int uac_mic_stream_read(u8 *buf, u32 len)
+{
+    if (mic_stream_is_open == 0) {
+        return 0;
+    }
+#if 0//48K 1ksin
+    const s16 sin_48k[] = {
+        0, 2139, 4240, 6270, 8192, 9974, 11585, 12998,
+        14189, 15137, 15826, 16244, 16384, 16244, 15826, 15137,
+        14189, 12998, 11585, 9974, 8192, 6270, 4240, 2139,
+        0, -2139, -4240, -6270, -8192, -9974, -11585, -12998,
+        -14189, -15137, -15826, -16244, -16384, -16244, -15826, -15137,
+        -14189, -12998, -11585, -9974, -8192, -6270, -4240, -2139
+    };
+    u16 *l_ch = (u16 *)buf;
+    u16 *r_ch = (u16 *)buf;
+    r_ch++;
+    for (int i = 0; i < len / 2; i++) {
+        *l_ch = sin_48k[i];
+        *r_ch = sin_48k[i];
+        l_ch += 1;
+        r_ch += 1;
+    }
+    return len;
+#elif   UAC_DEBUG_ECHO_MODE
+#if MIC_CHANNEL == 2
+    uac_speaker_read(NULL, buf, len);
+    const s16 sin_48k[] = {
+        0, 2139, 4240, 6270, 8192, 9974, 11585, 12998,
+        14189, 15137, 15826, 16244, 16384, 16244, 15826, 15137,
+        14189, 12998, 11585, 9974, 8192, 6270, 4240, 2139,
+        0, -2139, -4240, -6270, -8192, -9974, -11585, -12998,
+        -14189, -15137, -15826, -16244, -16384, -16244, -15826, -15137,
+        -14189, -12998, -11585, -9974, -8192, -6270, -4240, -2139
+    };
+    u16 *r_ch = (u16 *)buf;
+    r_ch++;
+    for (int i = 0; i < len / 4; i++) {
+        *r_ch = sin_48k[i];
+        r_ch += 2;
+    }
+#else
+    uac_speaker_read(NULL, buf, len * 2);
+    u16 *r_ch = (u16 *)buf;
+    for (int i = 0; i < len / 2; i++) {
+        r_ch[i] = r_ch[i * 2];
+    }
+
+#endif
+    return len;
+#else
+    if (mic_tx_handler) {
+#if 1
+        return mic_tx_handler(0, buf, len);
+#else
+        //16bit ---> 24bit
+        int rlen = mic_tx_handler(0, tmp_buf, len / 3 * 2);
+        rlen /= 2; //sampe point
+        for (int i = 0 ; i < rlen ; i++) {
+            buf[i * 3] = 0;
+            buf[i * 3 + 1] = tmp_buf[i * 2];
+            buf[i * 3 + 2] = tmp_buf[i * 2 + 1];
+        }
+#endif
+    } else {
+        //putchar('N');
+    }
+    return 0;
+#endif
+    return 0;
+}
+
+void set_uac_mic_tx_handler(void *priv, int (*tx_handler)(int, void *, int))
+{
+    mic_tx_handler = tx_handler;
+}
+static u32 mic_close_tid = 0;
+static u8 mic_sw;
+u32 uac_mic_stream_open(u32 samplerate, u32 frame_len, u32 ch)
+{
+    mic_sw = 1;
+    if (mic_stream_is_open) {
+        return 0;
+    }
+
+    /* mic_tx_handler = NULL; */
+    log_info("%s", __func__);
+
+    struct sys_event event;
+    event.type = SYS_DEVICE_EVENT;
+    event.arg = (void *)DEVICE_EVENT_FROM_UAC;
+    event.u.dev.event = USB_AUDIO_MIC_OPEN;
+    event.u.dev.value = (int)((ch << 24) | samplerate);
+    mic_stream_is_open = 1;
+
+#if !UAC_DEBUG_ECHO_MODE
+    sys_event_notify(&event);
+#endif
+    return 0;
+}
+
+static void uac_mic_stream_close_delay()
+{
+    mic_close_tid = 0;
+    if (!mic_sw) {
+
+    } else {
+        return ;
+    }
+    log_info("%s", __func__);
+    struct sys_event event;
+    event.type = SYS_DEVICE_EVENT;
+    event.arg = (void *)DEVICE_EVENT_FROM_UAC;
+    event.u.dev.event = USB_AUDIO_MIC_CLOSE;
+    event.u.dev.value = (int)0;
+    mic_stream_is_open = 0;
+    sys_event_notify(&event);
+}
+void uac_mic_stream_close()
+{
+    mic_sw = 0;
+    if (mic_stream_is_open == 0) {
+        return ;
+    }
+    //FIXME:
+    //未知原因出现频繁开关mic,导致出现audio或者蓝牙工作异常,
+    //收到mic关闭命令后延时1s再发消息通知audio模块执行关闭动作
+    //如果在1s之内继续收到usb下发的关闭命令,则继续推迟1s。
+    if (mic_close_tid == 0) {
+        mic_close_tid = sys_hi_timeout_add(NULL, uac_mic_stream_close_delay, 1000);
+    } else {
+        sys_hi_timeout_modify(mic_close_tid, 1000);
+    }
+}
+
+_WEAK_
+s8 app_audio_get_volume(u8 state)
+{
+    return 88;
+}
+_WEAK_
+void usb_audio_demo_exit(void)
+{
+
+}
+_WEAK_
+int usb_audio_demo_init(void)
+{
+    return 0;
+}
+_WEAK_
+u8 get_max_sys_vol(void)
+{
+    return 100;
+}
+_WEAK_
+void *audio_local_sample_track_open(u8 channel, int sample_rate, int period)
+{
+    return NULL;
+}
+_WEAK_
+int audio_local_sample_track_in_period(void *c, int samples)
+{
+    return 0;
+}
+_WEAK_
+void audio_local_sample_track_close(void *c)
+{
+}
+#endif

+ 31 - 0
apps/common/device/usb/device/uac_stream.h

@@ -0,0 +1,31 @@
+/*****************************************************************
+>file name : usb_audio.h
+>author : lichao
+>create time : Wed 22 May 2019 10:39:35 AM CST
+*****************************************************************/
+#ifndef _UAC_STREAM_H_
+#define _UAC_STREAM_H_
+#include "typedef.h"
+
+enum uac_event {
+    USB_AUDIO_PLAY_OPEN = 0x0,
+    USB_AUDIO_PLAY_CLOSE,
+    USB_AUDIO_MIC_OPEN,
+    USB_AUDIO_MIC_CLOSE,
+    // USB_AUDIO_MUTE,
+    USB_AUDIO_SET_PLAY_VOL,
+    USB_AUDIO_SET_MIC_VOL,
+};
+
+
+void uac_speaker_stream_buf_clear(void);
+u32 uac_speaker_stream_length();
+u32 uac_speaker_stream_size();
+void set_uac_speaker_rx_handler(void *priv, void (*rx_handler)(int, void *, int));
+void set_uac_mic_tx_handler(void *priv, int (*tx_handler)(int, void *, int));
+int uac_speaker_stream_sample_rate(void);
+
+int uac_speaker_read(void *priv, void *data, u32 len);
+u32 uac_speaker_get_alive();
+void uac_speaker_set_alive(u8 alive);
+#endif

+ 251 - 0
apps/common/device/usb/device/usb_device.c

@@ -0,0 +1,251 @@
+#include "usb/device/usb_stack.h"
+#include "usb_config.h"
+#include "usb/device/msd.h"
+#include "usb/scsi.h"
+#include "usb/device/hid.h"
+#include "usb/device/custom_hid.h"
+#include "usb/device/uac_audio.h"
+#include "usb/device/cdc.h"
+#include "irq.h"
+#include "init.h"
+#include "gpio.h"
+#include "app_config.h"
+
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+
+#include "debug.h"
+
+#if TCFG_USB_SLAVE_ENABLE
+
+static void usb_device_init(const usb_dev usb_id)
+{
+
+    usb_config(usb_id);
+    usb_g_sie_init(usb_id);
+    usb_slave_init(usb_id);
+    u8 *ep0_dma_buffer = usb_alloc_ep_dmabuffer(usb_id, 0, 64);
+
+    usb_set_dma_raddr(usb_id, 0, ep0_dma_buffer);
+    usb_set_dma_raddr(usb_id, 1, ep0_dma_buffer);
+    usb_set_dma_raddr(usb_id, 2, ep0_dma_buffer);
+    usb_set_dma_raddr(usb_id, 3, ep0_dma_buffer);
+    usb_set_dma_raddr(usb_id, 4, ep0_dma_buffer);
+
+    usb_write_intr_usbe(usb_id, INTRUSB_RESET_BABBLE | INTRUSB_SUSPEND);
+    usb_clr_intr_txe(usb_id, -1);
+    usb_clr_intr_rxe(usb_id, -1);
+    usb_set_intr_txe(usb_id, 0);
+    usb_set_intr_rxe(usb_id, 0);
+    usb_g_isr_reg(usb_id, 3, 0);
+    /* usb_sof_isr_reg(usb_id,3,0); */
+    /* usb_sofie_enable(usb_id); */
+    /* USB_DEBUG_PRINTF("ep0 addr %x %x\n", usb_get_dma_taddr(0), ep0_dma_buffer); */
+}
+static void usb_device_hold(const usb_dev usb_id)
+{
+
+    usb_g_hold(usb_id);
+    usb_release(usb_id);
+}
+
+
+static int usb_ep_conflict_check(const usb_dev usb_id);
+int usb_device_mode(const usb_dev usb_id, const u32 class)
+{
+
+    /* usb_device_set_class(CLASS_CONFIG); */
+    u8 class_index = 0;
+    if (class == 0) {
+        gpio_direction_input(IO_PORT_DM + 2 * usb_id);
+        gpio_set_pull_up(IO_PORT_DM + 2 * usb_id, 0);
+        gpio_set_pull_down(IO_PORT_DM + 2 * usb_id, 0);
+        gpio_set_die(IO_PORT_DM + 2 * usb_id, 0);
+
+        gpio_direction_input(IO_PORT_DP + 2 * usb_id);
+        gpio_set_pull_up(IO_PORT_DP + 2 * usb_id, 0);
+        gpio_set_pull_down(IO_PORT_DP + 2 * usb_id, 0);
+        gpio_set_die(IO_PORT_DP + 2 * usb_id, 0);
+
+        os_time_dly(15);
+
+        gpio_set_die(IO_PORT_DM + 2 * usb_id, 1);
+        gpio_set_die(IO_PORT_DP + 2 * usb_id, 1);
+
+#if TCFG_USB_SLAVE_MSD_ENABLE
+        msd_release(usb_id);
+#endif
+
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+        uac_release(usb_id);
+#endif
+
+#if TCFG_USB_SLAVE_CDC_ENABLE
+        cdc_release(usb_id);
+#endif
+#if TCFG_USB_SLAVE_HID_ENABLE
+        hid_release(usb_id);
+        //dongle 1t2设置两条usb通路
+#if CONFIG_APP_DONGLE && (CONFIG_BT_GATT_CLIENT_NUM == 2)
+        hid_release_second(usb_id);
+#endif
+#endif
+        usb_device_hold(usb_id);
+        return 0;
+    }
+
+    /* int ret = usb_ep_conflict_check(usb_id); */
+    /* if (ret) {                               */
+    /*     return ret;                          */
+    /* }                                        */
+
+    usb_memory_init();
+
+    usb_add_desc_config(usb_id, MAX_INTERFACE_NUM, NULL);
+
+#if TCFG_USB_SLAVE_MSD_ENABLE
+    if ((class & MASSSTORAGE_CLASS) == MASSSTORAGE_CLASS) {
+        log_info("add desc msd");
+        usb_add_desc_config(usb_id, class_index++, msd_desc_config);
+        msd_register(usb_id);
+    }
+#endif
+
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+    if ((class & AUDIO_CLASS) == AUDIO_CLASS) {
+        log_info("add audio desc");
+        usb_add_desc_config(usb_id, class_index++, uac_audio_desc_config);
+        uac_register(usb_id, AUDIO_CLASS);
+    } else if ((class & SPEAKER_CLASS) == SPEAKER_CLASS) {
+        log_info("add desc speaker");
+        usb_add_desc_config(usb_id, class_index++, uac_spk_desc_config);
+        uac_register(usb_id, SPEAKER_CLASS);
+    } else if ((class & MIC_CLASS) == MIC_CLASS) {
+        log_info("add desc mic");
+        usb_add_desc_config(usb_id, class_index++, uac_mic_desc_config);
+        uac_register(usb_id, MIC_CLASS);
+    }
+#endif
+
+#if TCFG_USB_CUSTOM_HID_ENABLE
+    if ((class & CUSTOM_HID_CLASS) == CUSTOM_HID_CLASS) {
+        log_info("add desc std custom_hid");
+        custom_hid_register(usb_id);
+        usb_add_desc_config(usb_id, class_index++, custom_hid_desc_config);
+    }
+#endif
+
+#if TCFG_USB_SLAVE_HID_ENABLE
+    if ((class & HID_CLASS) == HID_CLASS) {
+        log_info("add desc std hid");
+        hid_register(usb_id);
+        usb_add_desc_config(usb_id, class_index++, hid_desc_config);
+        //dongle 1t2设置两条usb通路
+#if CONFIG_APP_DONGLE && (CONFIG_BT_GATT_CLIENT_NUM == 2)
+        hid_register_second(usb_id);
+        usb_add_desc_config(usb_id, class_index++, hid_second_desc_config);
+
+#endif
+    }
+#endif
+
+
+#if TCFG_USB_SLAVE_CDC_ENABLE
+    if ((class & CDC_CLASS) == CDC_CLASS) {
+        log_info("add desc cdc");
+        usb_add_desc_config(usb_id, class_index++, cdc_desc_config);
+        cdc_register(usb_id);
+    }
+#endif
+
+    usb_device_init(usb_id);
+    user_setup_filter_install(usb_id2device(usb_id));
+    return 0;
+}
+/* module_initcall(usb_device_mode); */
+
+static int usb_ep_conflict_check(const usb_dev usb_id)
+{
+    u8 usb_ep_tx_list[] = {
+#if TCFG_USB_SLAVE_MSD_ENABLE
+        MSD_BULK_EP_IN,
+#endif
+#if TCFG_USB_SLAVE_HID_ENABLE
+        HID_EP_IN,
+#endif
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+        MIC_ISO_EP_IN,
+#endif
+#if TCFG_USB_SLAVE_CDC_ENABLE
+        CDC_DATA_EP_IN,
+#if CDC_INTR_EP_ENABLE
+        CDC_INTR_EP_IN,
+#endif
+#endif
+    };
+    u8 usb_ep_rx_list[] = {
+#if TCFG_USB_SLAVE_MSD_ENABLE
+        MSD_BULK_EP_OUT,
+#endif
+#if TCFG_USB_SLAVE_HID_ENABLE
+        HID_EP_OUT,
+#endif
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+        SPK_ISO_EP_OUT,
+#endif
+#if TCFG_USB_SLAVE_CDC_ENABLE
+        CDC_DATA_EP_OUT,
+#endif
+    };
+    int ret = 0;
+    int i, j;
+
+    for (i = 0; i < sizeof(usb_ep_tx_list) - 1; i++) {
+        for (j = i + 1; j < sizeof(usb_ep_tx_list); j++) {
+            if (usb_ep_tx_list[i] == usb_ep_tx_list[j]) {
+                ret = -1;
+                ASSERT(0, "ep%d conflict, dir in\n", usb_ep_tx_list[i]);
+                goto __exit;
+            }
+        }
+    }
+    for (i = 0; i < sizeof(usb_ep_rx_list) - 1; i++) {
+        for (j = i + 1; j < sizeof(usb_ep_rx_list); j++) {
+            if (usb_ep_rx_list[i] == usb_ep_rx_list[j]) {
+                ret = -1;
+                ASSERT(0, "ep%d conflict, dir out\n", usb_ep_rx_list[i]);
+                goto __exit;
+            }
+        }
+    }
+__exit:
+    return ret;
+}
+
+#endif
+
+/*
+ * @brief otg检测中sof初始化,不要放在TCFG_USB_SLAVE_ENABLE里
+ * @parm id usb设备号
+ * @return 0 ,忽略sof检查,1 等待sof信号
+ */
+u32 usb_otg_sof_check_init(const usb_dev id)
+{
+    /* return 0;// */
+    u8 *ep0_dma_buffer = usb_alloc_ep_dmabuffer(id, 0, 64);
+
+    usb_g_sie_init(id);
+
+    usb_set_dma_raddr(id, 0, ep0_dma_buffer);
+
+    for (int ep = 1; ep < USB_MAX_HW_EPNUM; ep++) {
+        usb_disable_ep(id, ep);
+    }
+    usb_sof_clr_pnd(id);
+    return 1;
+}

+ 223 - 0
apps/common/device/usb/device/user_setup.c

@@ -0,0 +1,223 @@
+#include "usb/device/usb_stack.h"
+#include "usb_config.h"
+#include "usb/device/msd.h"
+#include "usb/scsi.h"
+#include "usb/device/hid.h"
+#include "usb/device/uac_audio.h"
+#include "irq.h"
+#include "init.h"
+#include "gpio.h"
+#include "app_config.h"
+
+#if TCFG_USB_APPLE_DOCK_EN
+#include "apple_dock/iAP.h"
+#endif
+
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if TCFG_USB_SLAVE_ENABLE
+
+static const u8 user_stirng[] = {
+    24,
+    0x03,
+    'U', 0x00,
+    'S', 0x00,
+    'B', 0x00,
+    'A', 0x00,
+    'u', 0x00,
+    'd', 0x00,
+    'i', 0x00,
+    'o', 0x00,
+    '1', 0x00,
+    '.', 0x00,
+    '0', 0x00,
+};
+
+#if TCFG_USB_APPLE_DOCK_EN
+static const u8 IAP_interface_string[]  = {
+    0x1c, 0x03,
+    //iAP Interface
+    0x69, 0x00, 0x41, 0x00, 0x50, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x74, 0x00,
+    0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00, 0x65, 0x00
+};
+#endif
+
+static u8 root2_testing;
+u32 usb_root2_testing()
+{
+#if USB_ROOT2
+    return root2_testing;
+#else
+    return 0;
+#endif
+}
+u32 check_ep_vaild(u32 ep)
+{
+    u32 en = 0;
+    switch (ep) {
+    case 0:
+        en = 1;
+        break;
+#if TCFG_USB_SLAVE_MSD_ENABLE
+    case 1:
+        en = 1;
+        break;
+#endif
+#if TCFG_USB_SLAVE_HID_ENABLE
+    case 2:
+        en = 1;
+        break;
+#endif
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+    case 3:
+        en = 1;
+        break;
+#endif
+    case 4:
+        break;
+    }
+    return en;
+}
+static u32 setup_endpoint(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    u32 tx_len = 0;
+    u8 *tx_payload = usb_get_setup_buffer(usb_device);
+
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+    if (uac_setup_endpoint(usb_device, req)) {
+        return 1;
+    }
+#endif
+    u32 ep = LOBYTE(req->wIndex) & 0x0f;
+    if (check_ep_vaild(ep) == 0) {
+        usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
+        return 1;// not zero user handle this request
+    }
+
+
+    return 0;
+}
+static u32 setup_device(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
+{
+    const usb_dev usb_id = usb_device2id(usb_device);
+    u32 ret = 0;
+    switch (req->bRequest) {
+    case USB_REQ_GET_DESCRIPTOR:
+        switch (HIBYTE(req->wValue)) {
+        case USB_DT_STRING:
+            switch (LOBYTE(req->wValue)) {
+#if TCFG_USB_SLAVE_AUDIO_ENABLE
+            case SPEAKER_STR_INDEX:
+            case MIC_STR_INDEX:
+                if (usb_device->bDeviceStates == USB_DEFAULT) {
+                    ret = 0;
+                } else {
+                    usb_set_data_payload(usb_device, req, user_stirng, sizeof(user_stirng));
+                    ret = 1;
+                }
+                break;
+#endif
+#if TCFG_USB_APPLE_DOCK_EN
+            case MSD_STR_INDEX:
+                if (apple_mfi_chip_online_lib()) {
+                    y_printf("MSD_STR_INDEX \n");
+                    usb_set_data_payload(usb_device, req, IAP_interface_string, sizeof(IAP_interface_string));
+                    apple_mfi_pass_ready_set_api();
+                    extern void apple_usb_msd_wakeup(struct usb_device_t *usb_device);
+                    apple_usb_msd_wakeup(usb_device);
+                    ret = 1;
+                    break;
+                }
+#endif
+            default:
+                break;
+            }
+            break;
+        case USB_DT_DEVICE:
+#if USB_ROOT2
+            if (req->wLength == 0xffff) {
+                root2_testing = 1;
+            }
+#endif
+            break;
+        }
+        break;
+    case USB_REQ_SET_CONFIGURATION:
+        break;
+    case USB_REQ_SET_ADDRESS:
+        /* if(req->wLength || req->wIndex){                        */
+        /*     ret = 1;                                            */
+        /*     usb_set_setup_phase(usb_device, USB_EP0_SET_STALL); */
+        /*     dump_setup_request(req);                            */
+        /*     log_debug_hexdump((u8 *)req, 8);                    */
+        /* }                                                       */
+        break;
+    }
+    return ret;
+}
+
+static u32 setup_other(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
+{
+    u32 ret = 0;
+    u32 tx_len;
+    u8 *tx_payload = usb_get_setup_buffer(usb_device);
+    switch (req->bRequest) {
+    case USB_REQ_GET_STATUS:
+#if TCFG_TYPEC_EARPHONE_TEST_FILTER
+        tx_len = 1;
+        tx_payload[0] = 0xfe;
+        usb_set_data_payload(usb_device, req, tx_payload, tx_len);
+#endif
+        break;
+    default:
+        ret = 1 ;
+        break;
+    }
+    return ret;
+}
+static u32 user_setup_filter(struct usb_device_t *usb_device, struct usb_ctrlrequest *request)
+{
+    // dump_setup_request(request);
+    // log_debug_hexdump((u8 *)request, 8);
+    u32 ret = 0;
+    u32 recip = request->bRequestType & USB_RECIP_MASK;
+    switch (recip) {
+    case USB_RECIP_DEVICE:
+        ret = setup_device(usb_device, request);
+        break;
+    case USB_RECIP_INTERFACE:
+        break;
+    case USB_RECIP_ENDPOINT:
+        ret = setup_endpoint(usb_device, request);
+        break;
+    case USB_RECIP_OTHER:
+        ret = setup_other(usb_device, request);
+        break;
+    }
+#if 0
+    const char *statas[] = {"USB_ATTACHED", "USB_POWERED", "USB_DEFAULT",
+                            "USB_ADDRESS", "USB_CONFIGURED", "USB_SUSPENDED"
+                           };
+
+    const char *phases[] = {"SETUP", "IN", "OUT",
+                            "STALL",
+                           };
+
+    printf("state:%s phase: %s", statas[usb_device->bDeviceStates],
+           phases[usb_device->bsetup_phase]);
+#endif
+    return ret;// not zero user handle this request
+}
+void user_setup_filter_install(struct usb_device_t *usb_device)
+{
+    usb_set_setup_hook(usb_device, user_setup_filter);
+}
+#endif

+ 459 - 0
apps/common/device/usb/host/adb.c

@@ -0,0 +1,459 @@
+#include "includes.h"
+#include "asm/includes.h"
+#include "system/timer.h"
+#include "device/ioctl_cmds.h"
+#include "usb/host/usb_host.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_bulk_transfer.h"
+#include "device_drive.h"
+#include "adb.h"
+#include "usb_config.h"
+#include "app_config.h"
+#if TCFG_ADB_ENABLE
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[adb]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+
+#include "adb_rsa_key.c"
+
+struct adb_device_t adb;
+
+struct device adb_device;
+void aoa_switch(struct usb_host_device *host_dev);
+
+static int set_adb_power(struct usb_host_device *host_dev, u32 value)
+{
+    return DEV_ERR_NONE;
+}
+
+static int get_adb_power(struct usb_host_device *host_dev, u32 value)
+{
+    return DEV_ERR_NONE;
+}
+
+static const struct interface_ctrl adb_ops = {
+    .interface_class = USB_CLASS_ADB,
+    .set_power = set_adb_power,
+    .get_power = get_adb_power,
+    .ioctl = NULL,
+};
+
+static const struct usb_interface_info adb_inf = {
+    .ctrl = (struct interface_ctrl *) &adb_ops,
+    .dev.adb = &adb,
+};
+
+u32 usb_adb_interface_ptp_mtp_parse(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+    struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
+    pBuf += sizeof(struct usb_interface_descriptor);
+    int len = 0;
+    const usb_dev usb_id = host_device2id(host_dev);
+
+    for (int i = 0; i < interface->bNumEndpoints; i++) {
+        struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)pBuf;
+        if (endpoint->bDescriptorType == USB_DT_ENDPOINT) {
+            if (endpoint->bmAttributes == USB_ENDPOINT_XFER_BULK) {
+                if (endpoint->bEndpointAddress & USB_DIR_IN) {
+                    adb.extr_in = endpoint->bEndpointAddress & 0xf;
+                } else {
+                    adb.extr_out = endpoint->bEndpointAddress;
+                }
+            }
+            pBuf += USB_DT_ENDPOINT_SIZE;
+        } else {
+            return 0;
+        }
+    }
+    printf("%s() %x %x\n", __func__, adb.extr_in, adb.extr_out);
+    return pBuf - (u8 *)interface ;
+}
+
+int usb_adb_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+    struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
+    pBuf += sizeof(struct usb_interface_descriptor);
+    int len = 0;
+    const usb_dev usb_id = host_device2id(host_dev);
+
+    adb_device.private_data = host_dev;
+
+    host_dev->interface_info[interface_num] = &adb_inf;
+
+    for (int endnum = 0; endnum < interface->bNumEndpoints; endnum++) {
+        struct usb_endpoint_descriptor *end_desc = (struct usb_endpoint_descriptor *)pBuf;
+
+        if (end_desc->bDescriptorType != USB_DT_ENDPOINT ||
+            end_desc->bLength != USB_DT_ENDPOINT_SIZE) {
+            log_error("ep bDescriptorType = %d bLength = %d", end_desc->bDescriptorType, end_desc->bLength);
+            return -USB_DT_ENDPOINT;
+        }
+
+        len += USB_DT_ENDPOINT_SIZE;
+        pBuf += USB_DT_ENDPOINT_SIZE;
+
+        if ((end_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+            if (end_desc->bEndpointAddress & USB_DIR_IN) {
+                adb.host_epin = usb_get_ep_num(usb_id, USB_DIR_IN, USB_ENDPOINT_XFER_BULK);
+                adb.target_epin = end_desc->bEndpointAddress & 0x0f;
+#if HUSB_MODE
+                adb.rxmaxp = end_desc->wMaxPacketSize;
+#endif
+                log_debug("D(%d)->H(%d)", adb.target_epin, adb.host_epin);
+            } else {
+                adb.host_epout = usb_get_ep_num(usb_id, USB_DIR_OUT, USB_ENDPOINT_XFER_BULK);
+                adb.target_epout = end_desc->bEndpointAddress & 0x0f;
+#if HUSB_MODE
+                adb.txmaxp = end_desc->wMaxPacketSize;
+#endif
+                log_debug("H(%d)->D(%d)",  adb.host_epout, adb.target_epout);
+            }
+        }
+    }
+
+    u8 *ep_buffer = usb_h_get_ep_buffer(usb_id, adb.host_epin | USB_DIR_IN);
+    usb_h_ep_config(usb_id, adb.host_epin | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 0, 0, ep_buffer, 64);
+
+
+    ep_buffer = usb_h_get_ep_buffer(usb_id, adb.host_epout | USB_DIR_OUT);
+    usb_h_ep_config(usb_id, adb.host_epout | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, 0, 0, ep_buffer, 64);
+
+    return len;
+}
+
+static int adb_send_packet(struct amessage *msg, const u8 *data_ptr)
+{
+    if (msg == NULL) {
+        return usb_bulk_only_send(&adb_device, adb.host_epout, 64, adb.target_epout, NULL, 0);
+    }
+    u32 cnt;
+    u32 count = msg->data_length;
+
+    msg->magic = msg->command ^ 0xffffffff;
+    const u8 *_data_ptr = data_ptr;
+    msg->data_check = 0;
+    while (count--) {
+        msg->data_check += *_data_ptr++;
+    }
+    int ret = usb_bulk_only_send(&adb_device, adb.host_epout, 64, adb.target_epout, (u8 *)msg, sizeof(*msg));
+    if (ret < 0) {
+        return ret;
+    }
+    if (data_ptr != NULL) {
+        return usb_bulk_only_send(&adb_device, adb.host_epout, 64, adb.target_epout, data_ptr, msg->data_length);
+    } else {
+        return 0;
+    }
+}
+static int  adb_recv(u8 *buffer, u32 len, u32 timeout)
+{
+    return usb_bulk_only_receive(&adb_device, adb.host_epin, 64, adb.target_epin, buffer, len);
+}
+#define     check_usb_status(ret)   do{\
+                                        if(ret < 0){\
+                                            log_info("%s() @ %d %d\n", __func__, __LINE__, ret);\
+                                            return ret;\
+                                        }\
+                                    }while(0);
+
+static u8 adb_signatrue_data_index ;
+
+u32 adb_auth()
+{
+    log_info("%s() %d\n", __func__, __LINE__);
+    struct amessage msg;
+    int ret = 0;
+    u8 *cmd_string;
+    adb.local_id = 0x58525047;
+    adb.remote_id = 0;
+    msg.command = A_CNXN;
+    msg.arg0 = A_VERSION;
+    msg.arg1 = 0x00001000;
+    cmd_string = (u8 *)"host::";
+    msg.data_length = strlen((const char *)cmd_string) + 1;
+    ret = adb_send_packet(&msg, cmd_string);
+    check_usb_status(ret);
+    memset(&msg, 0, 24);
+    ret = adb_recv((u8 *)&msg, 24, 5);
+    check_usb_status(ret);
+
+    if (msg.command == A_CNXN) {
+        if (adb_recv(adb.buffer, msg.data_length, 1 * 100)) {
+            log_error("auth error 0\n");
+            return 0;
+        }
+        log_info("auth not send rsa pub key\n");
+        return 0;
+    } else if (msg.command == A_AUTH) {
+
+    } else {
+        log_error("auth error 1\n");
+        return 1;
+    }
+
+    ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);
+    check_usb_status(ret);
+    msg.command = A_AUTH;
+    msg.arg0 = ADB_AUTH_SIGNATURE;
+    msg.data_length = sizeof(adb_signatrue_data[0]);
+    if (adb_signatrue_data_index > 2) {
+        adb_signatrue_data_index = 0;
+    }
+
+    adb_signatrue_data_index ++;
+    cmd_string = (u8 *)&adb_signatrue_data[adb_signatrue_data_index][0];
+    ret = adb_send_packet(&msg, cmd_string);
+    check_usb_status(ret);
+
+    ret = adb_send_packet(NULL, NULL);//zero packet
+    check_usb_status(ret);
+
+    memset(&msg, 0, 24);
+    ret = adb_recv((u8 *)&msg, 24, 1 * 100);
+    check_usb_status(ret);
+    if (msg.command != A_AUTH) {
+        log_error("auth error 2\n");
+        return 1;
+    }
+    ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);
+    check_usb_status(ret);
+
+
+__RETRY:
+    msg.command = A_AUTH;
+    msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
+    msg.arg1 = 0;
+    msg.data_length = sizeof(adb_rsa_pub_key);
+    ret = adb_send_packet(&msg, (u8 *)adb_rsa_pub_key);
+    check_usb_status(ret);
+
+    ret = adb_recv((u8 *)&msg, 24, 30 * 100);
+
+    if (ret < 0) {
+        if (ret == -DEV_ERR_TIMEOUT) {
+            goto __RETRY;
+        }
+        check_usb_status(ret);
+    }
+
+    ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);//最长等待30s,等手机点击确认授权adb
+    if (ret < 0) {
+        if (ret == -DEV_ERR_TIMEOUT) {
+            goto __RETRY;
+        }
+        check_usb_status(ret);
+    }
+
+    if (msg.command == A_AUTH) {
+        goto __RETRY;
+    }
+    return 0;
+}
+
+u32 adb_shell_login()
+{
+    log_info("%s() %d\n", __func__, __LINE__);
+    struct amessage msg;
+    u8 *cmd_string;
+    /* __AUTH_SUCCESS: */
+
+    cmd_string = (u8 *)"shell:";
+    msg.command = A_OPEN;
+    msg.arg0 = adb.local_id;
+    msg.arg1 = 0;
+    msg.data_length = strlen((char const *)cmd_string) + 1;
+    int ret = adb_send_packet(&msg, cmd_string);
+    check_usb_status(ret);
+
+    memset(&msg, 0, 24);
+    ret = adb_recv((u8 *)&msg, 24, 1 * 100);
+    check_usb_status(ret);
+
+    if (msg.command != A_OKAY) {
+        log_error("A_OKAY error\n");
+        return 4;
+    }
+
+    ret = adb_recv((u8 *)&msg, 24, 1 * 100);
+    check_usb_status(ret);
+    if (msg.command != A_WRTE) {
+        log_error("A_WRTE error\n");
+        return 5;
+    }
+    adb.remote_id = msg.arg0;
+
+    ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);
+    check_usb_status(ret);
+
+    msg.command = A_OKAY;
+    msg.arg0 = adb.local_id;
+    msg.arg1 = adb.remote_id;
+    msg.data_length = 0;
+    ret = adb_send_packet(&msg, NULL);
+    check_usb_status(ret);
+    return 0;
+}
+
+static u32 adb_ex_cmd(const char *cmd_string, u8 *echo_buffer, u32 max_len)
+{
+    log_info("%s\n", cmd_string);
+    int ret;
+    struct amessage msg;
+    msg.command = A_WRTE;
+    msg.arg0 = adb.local_id;
+    msg.arg1 = adb.remote_id;
+    msg.data_length = strlen(cmd_string);
+    ret = adb_send_packet(&msg, (u8 *)cmd_string);
+    check_usb_status(ret);
+    memset(&msg, 0, 24);
+    memset(echo_buffer, 0, max_len);
+    ret = adb_recv((u8 *)&msg, sizeof(msg), 3 * 100);
+    check_usb_status(ret);
+
+    if (msg.command != A_OKAY) {
+        return true;
+    }
+    u32 offset = 0;
+    do {
+        ret = adb_recv((u8 *)&msg, sizeof(msg), 3 * 100);
+        check_usb_status(ret);
+        if (msg.command != A_WRTE) {
+            log_info("command %x\n", msg.command);
+            return true;
+        }
+        if ((offset + msg.data_length)  > max_len) {
+            log_info("%s", echo_buffer);
+            echo_buffer[offset] = 0;
+            offset = 0;
+        }
+
+        ret = adb_recv(&echo_buffer[offset], msg.data_length, 3 * 100);
+        check_usb_status(ret);
+        offset += msg.data_length;
+
+        if (msg.data_length == 0) {
+            log_info("no data_length\n");
+            break;
+        }
+
+        if (offset >= max_len) {
+
+        }
+        /* echo_buffer[offset] = '\n'; */
+        echo_buffer[offset] = 0;
+
+        if (echo_buffer[offset - 2] == 0x24 && echo_buffer[offset - 1] == 0x20) {
+            /* puts("end\n"); */
+            break;
+        } else if (echo_buffer[offset - 2] == 0x23 && echo_buffer[offset - 1] == 0x20) {
+            /* puts("end 1\n"); */
+            break;
+        }
+        msg.command = A_OKAY;
+        msg.arg0 = adb.local_id;
+        msg.arg1 = adb.remote_id;
+        msg.data_length = 0;
+        ret = adb_send_packet(&msg, NULL);
+        check_usb_status(ret);
+
+    } while (1);
+
+    msg.command = A_OKAY;
+    msg.arg0 = adb.local_id;
+    msg.arg1 = adb.remote_id;
+    msg.data_length = 0;
+    /* puts("exit\n"); */
+    return adb_send_packet(&msg, NULL);
+
+}
+#define     APP_ACTIVITY_PATH   "com.zh-jieli.gmaeCenter/com.zh-jieli.gameCenter.activity.guide.SplashActivity\n"
+#define     APP_WEBSITE         "http://www.zh-jieli.com\n"
+#define     APP_BASH_IN_PATH    "/sdcard/jilei/active.bash"
+#define     APP_BASH_OUT_PATH   "/data/local/tmp/active.bash"
+
+u32 adb_game_active()
+{
+    log_info("%s() %d\n", __func__, __LINE__);
+    u32 max_len = adb.max_len;;
+    u8 *adb_buffer = adb.buffer;
+    //1,启动app
+    adb_ex_cmd("am start -n " APP_ACTIVITY_PATH, adb_buffer, max_len);
+    puts((char *)adb_buffer);
+    //查找Error字符串,如果找到跳转网页下载app,否则执行adb指令
+    if (strstr((const char *)adb_buffer, "Error") != NULL) {
+        adb_ex_cmd("am start -a android.intent.action.VIEW -d " APP_WEBSITE, adb_buffer, max_len);
+        puts((char *)adb_buffer);
+    } else {
+        adb_ex_cmd("dd if=" APP_BASH_IN_PATH " of=" APP_BASH_OUT_PATH "\n", adb_buffer, max_len);
+        puts((char *)adb_buffer);
+        adb_ex_cmd("chown shell " APP_BASH_OUT_PATH";chmod 777 "APP_BASH_OUT_PATH "\n", adb_buffer, max_len);
+        puts((char *)adb_buffer);
+        adb_ex_cmd("trap \"\" HUP;sh "APP_BASH_OUT_PATH "&\n", adb_buffer, max_len);
+        puts((char *)adb_buffer);
+    }
+
+    return 0;
+}
+static void mtp_ptp_open_session(u32 is_mtp)
+{
+    /* usbh_bulk_send_blocking(ADB_HOST_EP, adb_device.extr_out, (u8 *)_open_session, 16);                        */
+    /* usbh_request_bulk_blocking(ADB_HOST_EP, adb_device.extr_in, get_data_buffer(), 12, 3);                     */
+
+    /* usbh_bulk_send_blocking(ADB_HOST_EP, adb_device.extr_out, (u8 *)get_device_info, sizeof(get_device_info)); */
+    /* usbh_request_bulk_blocking(ADB_HOST_EP, adb_device.extr_in, get_data_buffer(), 512, 3);                    */
+
+    /* usbh_request_bulk_blocking(ADB_HOST_EP, adb_device.extr_in, get_data_buffer(), 12, 3);                     */
+}
+
+static void adb_open_session()
+{
+    struct usb_host_device *host_dev = adb_device.private_data;
+    if (adb.extr_in && adb.extr_out) {
+        get_ms_extended_compat_id(host_dev, adb.buffer);
+        get_device_status(host_dev);
+        get_config_descriptor(host_dev, adb.buffer, 0xff);
+        /* mtp_ptp_open_session(ac6921_data_buffer[0x12] == 0x4d); */
+    }
+}
+u32 adb_process()
+{
+    adb.max_len = 1024;
+    adb.buffer = malloc(adb.max_len);
+    os_time_dly(20);
+    do {
+
+        adb_open_session();
+
+        if (adb_auth()) {
+            break;
+        }
+
+        if (adb_shell_login()) {
+            break;
+        }
+
+        adb_game_active();
+        log_info("adb active succ");
+        return 0;
+
+    } while (0);
+
+    free(adb.buffer);
+
+
+    log_info("adb active error");
+    return 1;
+}
+void adb_switch_aoa(u32 id)
+{
+    struct usb_host_device *host_dev = adb_device.private_data;
+    aoa_switch(host_dev);
+    /* usb_host_remount(id, 3, 30, 50, 1); */
+}
+#endif //TCFG_ADB_ENABLE

+ 73 - 0
apps/common/device/usb/host/adb.h

@@ -0,0 +1,73 @@
+#ifndef  __ADB_H__
+#define  __ADB_H__
+
+#include "system/task.h"
+#include "device/device.h"
+#include "usb/scsi.h"
+#include "usb_bulk_transfer.h"
+#include "usb/host/usb_host.h"
+struct adb_device_t {
+    u32 local_id;
+    u32 remote_id;
+    void *buffer;
+    u32 max_len;
+
+    u8 target_epin;
+    u8 target_epout;
+    u8 host_epin;
+    u8 host_epout;
+
+    u8 extr_in;
+    u8 extr_out;
+};
+u32 usb_adb_interface_ptp_mtp_parse(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
+int usb_adb_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
+u32 adb_process();
+void adb_switch_aoa(u32 id);
+
+#if 1
+#define A_SYNC 0x434e5953
+#define A_CNXN 0x4e584e43
+#define A_OPEN 0x4e45504f
+#define A_OKAY 0x59414b4f
+#define A_CLSE 0x45534c43
+#define A_WRTE 0x45545257
+#define A_AUTH 0x48545541
+//#define S_ID_LOCAL  0x00003456
+/* AUTH packets first argument */
+/* Request */
+#define ADB_AUTH_TOKEN 1
+/* Response */
+#define ADB_AUTH_SIGNATURE 2
+#define ADB_AUTH_RSAPUBLICKEY 3
+
+#define A_VERSION 0x01000000 // ADB protocol version
+
+#define ADB_VERSION_MAJOR 1 // Used for help/version information
+#define ADB_VERSION_MINOR 0 // Used for help/version information
+
+#else
+#define A_SYNC 0x53594e43
+#define A_CNXN 0x434e584e
+#define A_OPEN 0x4f50454e
+#define A_OKAY 0x4f4b4159
+#define A_CLSE 0x434c5345
+#define A_WRTE 0x57525445
+
+#define A_VERSION 0x00000001 // ADB protocol version
+
+#define ADB_VERSION_MAJOR 1 // Used for help/version information
+#define ADB_VERSION_MINOR 0 // Used for help/version information
+
+#endif
+
+struct amessage {
+    unsigned long int command;     /* command identifier constant      */
+    unsigned long int arg0;        /* first argument                   */
+    unsigned long int arg1;        /* second argument                  */
+    unsigned long int data_length; /* length of payload (0 is allowed) */
+    unsigned long int data_check;  /* checksum of data payload         */
+    unsigned long int magic;       /* command ^ 0xffffffff             */
+};
+
+#endif  /*ADB_H*/

+ 115 - 0
apps/common/device/usb/host/adb_rsa_key.c

@@ -0,0 +1,115 @@
+#include "typedef.h"
+#include "app_config.h"
+#if TCFG_ADB_ENABLE
+static  const u8 _open_session[] = {
+    0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
+};
+static const u8 get_device_info[] = {
+    0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00,
+};
+
+
+static const u8 adb_signatrue_data[][256] = {
+    {
+        0xFA, 0xA6, 0xE3, 0x50, 0x3C, 0xC4, 0x95, 0xFE, 0xBB, 0x46, 0xE0, 0x9F, 0xD9, 0x9A, 0x18, 0xC1,
+        0x28, 0x67, 0xA9, 0x46, 0xF8, 0x20, 0xBF, 0xDB, 0xFE, 0x6B, 0xC8, 0xC4, 0x0A, 0x09, 0xFA, 0x9A,
+        0xCD, 0x51, 0xE3, 0x67, 0xD1, 0xDF, 0xD2, 0x92, 0xD3, 0x9E, 0xFA, 0x17, 0x76, 0x01, 0xF5, 0xE2,
+        0xBD, 0x64, 0x9C, 0x92, 0x82, 0x4B, 0xE4, 0x27, 0x21, 0x22, 0x1A, 0x70, 0x99, 0x8F, 0xC5, 0xD5,
+        0xE2, 0x02, 0x2C, 0xA4, 0x13, 0x08, 0x1E, 0x42, 0x83, 0x5C, 0x7E, 0x3C, 0x1F, 0x97, 0x1B, 0xAF,
+        0x6F, 0x7E, 0x4F, 0xAB, 0xDA, 0x6A, 0x61, 0x56, 0x03, 0x79, 0xB5, 0xF0, 0x97, 0xEE, 0xEC, 0x88,
+        0x6F, 0x9E, 0x8D, 0x41, 0xE2, 0x13, 0x9B, 0x21, 0xEE, 0x6F, 0x09, 0x81, 0x62, 0xC1, 0xB5, 0xE7,
+        0xC2, 0x5C, 0x4A, 0x8C, 0x39, 0xAA, 0x50, 0x08, 0x48, 0xB5, 0x1D, 0xF6, 0x7C, 0x67, 0xD6, 0x39,
+        0x63, 0x7E, 0x5E, 0x49, 0x3D, 0x9B, 0x49, 0x4B, 0x67, 0x8E, 0x06, 0x31, 0x07, 0x4E, 0x56, 0x8A,
+        0xC4, 0x9D, 0x84, 0xA9, 0xF4, 0xFC, 0xE3, 0x2D, 0x1D, 0x2A, 0x98, 0x52, 0x40, 0x49, 0x93, 0x71,
+        0xA7, 0x43, 0x0D, 0x78, 0xEB, 0xFA, 0x49, 0x7A, 0x39, 0xBF, 0xE4, 0x06, 0x08, 0x1B, 0x20, 0x84,
+        0xDC, 0x64, 0xBB, 0xDE, 0x1A, 0x5E, 0x4B, 0xF8, 0x57, 0xBF, 0x9C, 0x8C, 0xB9, 0x1D, 0xEE, 0xB3,
+        0x90, 0x17, 0x03, 0x8B, 0x3E, 0x9F, 0x8A, 0x23, 0xEC, 0x30, 0xA7, 0x24, 0x5E, 0x5B, 0x58, 0xAA,
+        0x5A, 0xAE, 0xE2, 0x14, 0xC1, 0xAE, 0xA3, 0xF9, 0xAF, 0x70, 0xE0, 0x14, 0x7D, 0x73, 0x3B, 0x6D,
+        0x9B, 0x06, 0x2F, 0xAA, 0xFF, 0x7A, 0x2A, 0x56, 0x6F, 0x91, 0x70, 0x6D, 0x4A, 0x18, 0x35, 0x51,
+        0xD5, 0x5D, 0xFB, 0xA1, 0x8B, 0x03, 0xF2, 0x0C, 0x56, 0xF0, 0x5A, 0x4A, 0x08, 0x89, 0xFE, 0x86
+    },
+    {
+        0x60, 0xE6, 0x4A, 0x3D, 0x12, 0xD1, 0x48, 0x25, 0x7D, 0x6E, 0x8E, 0x03, 0xE2, 0xC8, 0xE7, 0x66,
+        0x96, 0xD7, 0xD3, 0xBF, 0xE6, 0x97, 0x13, 0x3A, 0x2D, 0x2B, 0x85, 0xE7, 0xDA, 0x5C, 0x87, 0xD8,
+        0xDC, 0x88, 0xAC, 0xF7, 0xC3, 0xF0, 0x5A, 0xE8, 0x95, 0x66, 0x19, 0xA1, 0xA8, 0x2A, 0xE1, 0x70,
+        0x13, 0xF0, 0x05, 0x59, 0x3D, 0x89, 0x04, 0x65, 0x08, 0x03, 0x9C, 0xDC, 0x71, 0x24, 0xC5, 0x9E,
+        0x4D, 0x82, 0xD8, 0x72, 0x07, 0xFD, 0x8F, 0xD3, 0x37, 0x56, 0x8C, 0xB6, 0x01, 0xDB, 0x08, 0x5B,
+        0xA3, 0x42, 0x8F, 0xF0, 0xCA, 0xDC, 0x80, 0xEB, 0x32, 0xC4, 0x67, 0x1F, 0x73, 0xAF, 0xF0, 0x56,
+        0xBC, 0x89, 0x72, 0xB1, 0x7D, 0xDA, 0xA4, 0x79, 0x7D, 0x02, 0x35, 0x38, 0xBA, 0xA0, 0x36, 0xFE,
+        0x5A, 0x70, 0x93, 0xF5, 0x10, 0x7A, 0x92, 0xE9, 0xD4, 0xB0, 0xED, 0xF3, 0x00, 0xD0, 0x27, 0x79,
+        0x51, 0x54, 0x38, 0x2D, 0x4C, 0xAA, 0x27, 0xEF, 0xA7, 0x8A, 0x34, 0x4E, 0x4B, 0x29, 0x90, 0xC4,
+        0x3E, 0xA8, 0x8D, 0x3D, 0x00, 0xD6, 0x84, 0x11, 0x17, 0x32, 0xD6, 0xE9, 0x33, 0x02, 0xCD, 0x04,
+        0x35, 0x3F, 0x1A, 0xC3, 0x05, 0xCF, 0x6F, 0xF4, 0x39, 0x65, 0xE5, 0x6B, 0x88, 0x1E, 0x25, 0xA1,
+        0xD7, 0xC0, 0x30, 0xE4, 0x0B, 0x2A, 0x61, 0x6D, 0x61, 0xF1, 0x93, 0xAE, 0xC3, 0x42, 0xDC, 0x15,
+        0x1D, 0x87, 0x60, 0x09, 0x92, 0x64, 0xC1, 0x63, 0xAD, 0xCA, 0x36, 0x63, 0x0E, 0x69, 0x51, 0x45,
+        0xD0, 0x18, 0x5E, 0x10, 0x88, 0x7B, 0xD9, 0xDE, 0xA3, 0x12, 0x85, 0xF9, 0x30, 0x01, 0x0A, 0xE1,
+        0x82, 0xD1, 0x49, 0x44, 0xD9, 0x97, 0xE4, 0xF1, 0x55, 0x2D, 0xE2, 0xF3, 0x32, 0xC8, 0xA0, 0xC8,
+        0x81, 0xB9, 0x02, 0x87, 0x5C, 0x19, 0xB7, 0x21, 0x6A, 0xB9, 0xB0, 0x81, 0x61, 0x8C, 0x35, 0x78
+    },
+    {
+        0x0C, 0x7E, 0xDC, 0x78, 0x60, 0x1A, 0xC8, 0x9B, 0x3A, 0x23, 0x0B, 0x1D, 0x6F, 0xAE, 0x71, 0x6D,
+        0xD8, 0x3C, 0xE9, 0xA3, 0x51, 0x90, 0xAA, 0x7B, 0x7E, 0x2F, 0x2B, 0xBD, 0x34, 0xF4, 0x43, 0x3F,
+        0x77, 0xC4, 0x0E, 0x41, 0x04, 0xD9, 0xD4, 0x9C, 0xB3, 0xD2, 0x6B, 0xE1, 0xC6, 0xA8, 0xEF, 0x50,
+        0x00, 0x11, 0xE1, 0x08, 0x8B, 0xB4, 0xF1, 0xE3, 0x3D, 0x56, 0x83, 0x07, 0x7F, 0xB8, 0x47, 0xF2,
+        0x84, 0xD2, 0xA1, 0x50, 0x64, 0x5A, 0x08, 0x42, 0x36, 0x23, 0x09, 0x31, 0x9A, 0x6B, 0x61, 0x6F,
+        0x60, 0x2C, 0xF2, 0x75, 0x4E, 0x6B, 0xB9, 0x15, 0xEE, 0x3C, 0x5E, 0xA2, 0x7F, 0xA0, 0x41, 0xFE,
+        0x00, 0x6A, 0x30, 0x49, 0x2C, 0xEC, 0x17, 0x8B, 0x04, 0x32, 0xE9, 0x7A, 0x68, 0xA0, 0xF4, 0xDF,
+        0x34, 0xF7, 0x1E, 0x6F, 0x19, 0x09, 0x37, 0x87, 0x99, 0xAA, 0x81, 0x1A, 0xCD, 0xF3, 0x1F, 0x89,
+        0x50, 0xB2, 0x17, 0x52, 0x6D, 0x8E, 0xA6, 0x02, 0xC4, 0x2A, 0xAB, 0x3E, 0x5B, 0x38, 0x0C, 0x3F,
+        0x50, 0xAA, 0x5F, 0xFE, 0x47, 0x04, 0xED, 0xCD, 0xEE, 0x7C, 0xD5, 0xED, 0x5F, 0x0E, 0xC6, 0x9C,
+        0x79, 0x10, 0x11, 0x6F, 0x65, 0x58, 0x37, 0x95, 0x54, 0x50, 0x59, 0x68, 0x4C, 0x8E, 0xE7, 0x35,
+        0xF0, 0x96, 0x5A, 0x21, 0x48, 0xB4, 0x53, 0x52, 0xFC, 0xA4, 0x7C, 0x2B, 0xB1, 0xE1, 0x54, 0x2C,
+        0x42, 0x3B, 0x68, 0xBF, 0xBB, 0x68, 0x0D, 0x62, 0x16, 0x2F, 0xF5, 0xC8, 0x5F, 0x95, 0x11, 0xF2,
+        0xDF, 0x03, 0x1E, 0xCB, 0x7C, 0xD0, 0x9C, 0xE9, 0x89, 0x62, 0xEA, 0xC5, 0x4B, 0xA9, 0xD5, 0xCC,
+        0xD2, 0x42, 0x33, 0xA8, 0x7B, 0x2C, 0x56, 0xCF, 0xCE, 0x0D, 0x09, 0x64, 0x62, 0x3F, 0x58, 0x41,
+        0x71, 0x79, 0x5D, 0x1D, 0xDF, 0x08, 0x0B, 0x36, 0x97, 0x16, 0x24, 0x20, 0x76, 0x9C, 0x9E, 0xEA
+    }
+};
+static const u8 adb_rsa_pub_key[] = {
+    0x51, 0x41, 0x41, 0x41, 0x41, 0x46, 0x4F, 0x56, 0x4F, 0x6E, 0x49, 0x6C, 0x69, 0x51, 0x58, 0x44,
+    0x73, 0x42, 0x43, 0x42, 0x31, 0x75, 0x6F, 0x68, 0x70, 0x2B, 0x52, 0x71, 0x6E, 0x6E, 0x59, 0x48,
+    0x2F, 0x75, 0x45, 0x58, 0x34, 0x59, 0x6A, 0x50, 0x71, 0x52, 0x4D, 0x35, 0x4B, 0x75, 0x62, 0x56,
+    0x50, 0x71, 0x66, 0x57, 0x35, 0x64, 0x56, 0x46, 0x33, 0x2B, 0x76, 0x57, 0x6B, 0x53, 0x4B, 0x71,
+    0x35, 0x4C, 0x31, 0x42, 0x4F, 0x4E, 0x4D, 0x36, 0x4B, 0x4F, 0x31, 0x69, 0x31, 0x73, 0x69, 0x4F,
+    0x54, 0x69, 0x34, 0x6C, 0x45, 0x30, 0x6F, 0x54, 0x6F, 0x74, 0x30, 0x41, 0x4B, 0x6E, 0x4D, 0x67,
+    0x4E, 0x6A, 0x6F, 0x33, 0x45, 0x4D, 0x65, 0x72, 0x30, 0x6C, 0x57, 0x56, 0x54, 0x54, 0x43, 0x39,
+    0x68, 0x52, 0x66, 0x67, 0x46, 0x65, 0x56, 0x73, 0x43, 0x32, 0x44, 0x74, 0x71, 0x62, 0x61, 0x6D,
+    0x4A, 0x48, 0x63, 0x41, 0x66, 0x59, 0x77, 0x36, 0x54, 0x62, 0x4C, 0x44, 0x6C, 0x4B, 0x70, 0x6A,
+    0x38, 0x34, 0x33, 0x63, 0x31, 0x59, 0x5A, 0x65, 0x59, 0x6D, 0x52, 0x56, 0x4D, 0x7A, 0x4D, 0x34,
+    0x6E, 0x74, 0x49, 0x78, 0x64, 0x56, 0x33, 0x33, 0x76, 0x4B, 0x75, 0x39, 0x38, 0x34, 0x6A, 0x72,
+    0x43, 0x41, 0x47, 0x68, 0x77, 0x4A, 0x41, 0x67, 0x4A, 0x46, 0x53, 0x41, 0x4B, 0x56, 0x59, 0x51,
+    0x55, 0x33, 0x6A, 0x4C, 0x76, 0x41, 0x76, 0x57, 0x45, 0x6C, 0x59, 0x47, 0x37, 0x2F, 0x4B, 0x59,
+    0x6D, 0x55, 0x34, 0x54, 0x71, 0x73, 0x70, 0x64, 0x76, 0x4C, 0x42, 0x6F, 0x65, 0x36, 0x68, 0x64,
+    0x46, 0x44, 0x65, 0x76, 0x4D, 0x4D, 0x43, 0x63, 0x72, 0x6C, 0x44, 0x49, 0x66, 0x65, 0x45, 0x53,
+    0x57, 0x68, 0x42, 0x56, 0x35, 0x67, 0x78, 0x6A, 0x57, 0x41, 0x70, 0x4D, 0x47, 0x67, 0x53, 0x71,
+    0x53, 0x45, 0x6A, 0x70, 0x36, 0x79, 0x62, 0x6A, 0x33, 0x38, 0x50, 0x4C, 0x72, 0x76, 0x49, 0x51,
+    0x48, 0x77, 0x2B, 0x66, 0x70, 0x6F, 0x51, 0x74, 0x6F, 0x4F, 0x4E, 0x65, 0x37, 0x6F, 0x68, 0x66,
+    0x42, 0x77, 0x45, 0x66, 0x47, 0x46, 0x4E, 0x63, 0x33, 0x61, 0x70, 0x48, 0x50, 0x6E, 0x59, 0x53,
+    0x47, 0x4F, 0x67, 0x70, 0x54, 0x78, 0x70, 0x57, 0x57, 0x75, 0x49, 0x42, 0x79, 0x2F, 0x67, 0x38,
+    0x35, 0x2B, 0x65, 0x54, 0x30, 0x44, 0x61, 0x36, 0x53, 0x65, 0x71, 0x33, 0x67, 0x62, 0x4A, 0x59,
+    0x64, 0x75, 0x52, 0x44, 0x65, 0x36, 0x5A, 0x39, 0x63, 0x4A, 0x77, 0x48, 0x79, 0x38, 0x43, 0x34,
+    0x59, 0x79, 0x6B, 0x44, 0x56, 0x45, 0x4B, 0x6A, 0x39, 0x75, 0x52, 0x41, 0x41, 0x45, 0x59, 0x70,
+    0x52, 0x6B, 0x74, 0x39, 0x66, 0x34, 0x79, 0x51, 0x4A, 0x31, 0x73, 0x4D, 0x48, 0x31, 0x5A, 0x75,
+    0x4F, 0x55, 0x46, 0x4A, 0x46, 0x65, 0x74, 0x6B, 0x72, 0x67, 0x32, 0x44, 0x46, 0x61, 0x35, 0x30,
+    0x50, 0x39, 0x48, 0x61, 0x78, 0x6F, 0x4D, 0x59, 0x30, 0x41, 0x79, 0x78, 0x7A, 0x51, 0x72, 0x53,
+    0x77, 0x4D, 0x44, 0x79, 0x6E, 0x36, 0x64, 0x49, 0x65, 0x38, 0x65, 0x58, 0x46, 0x78, 0x51, 0x62,
+    0x56, 0x4D, 0x4F, 0x6C, 0x4B, 0x36, 0x79, 0x33, 0x70, 0x6F, 0x2B, 0x4A, 0x4D, 0x42, 0x34, 0x79,
+    0x4D, 0x42, 0x36, 0x51, 0x77, 0x30, 0x7A, 0x31, 0x35, 0x62, 0x6F, 0x58, 0x4C, 0x78, 0x4D, 0x4B,
+    0x76, 0x4E, 0x59, 0x6E, 0x4B, 0x4E, 0x70, 0x69, 0x6F, 0x33, 0x67, 0x45, 0x78, 0x5A, 0x2B, 0x48,
+    0x68, 0x57, 0x62, 0x43, 0x47, 0x69, 0x37, 0x64, 0x4A, 0x6C, 0x56, 0x47, 0x50, 0x6F, 0x74, 0x34,
+    0x4D, 0x42, 0x45, 0x4C, 0x7A, 0x43, 0x38, 0x66, 0x4C, 0x55, 0x44, 0x69, 0x41, 0x43, 0x49, 0x54,
+    0x37, 0x75, 0x31, 0x58, 0x31, 0x62, 0x68, 0x65, 0x71, 0x6C, 0x35, 0x59, 0x7A, 0x43, 0x30, 0x6C,
+    0x67, 0x2F, 0x4B, 0x48, 0x5A, 0x7A, 0x62, 0x36, 0x6D, 0x63, 0x74, 0x4E, 0x2B, 0x34, 0x62, 0x52,
+    0x74, 0x79, 0x4B, 0x35, 0x75, 0x52, 0x52, 0x4A, 0x70, 0x48, 0x45, 0x56, 0x63, 0x4B, 0x58, 0x57,
+    0x50, 0x34, 0x30, 0x73, 0x31, 0x79, 0x38, 0x37, 0x75, 0x30, 0x6D, 0x49, 0x50, 0x4A, 0x6E, 0x73,
+    0x39, 0x6D, 0x4F, 0x2F, 0x2F, 0x44, 0x41, 0x35, 0x4C, 0x32, 0x6D, 0x64, 0x77, 0x56, 0x79, 0x73,
+    0x72, 0x74, 0x4B, 0x51, 0x69, 0x51, 0x37, 0x36, 0x57, 0x6A, 0x74, 0x59, 0x51, 0x63, 0x41, 0x73,
+    0x46, 0x2B, 0x42, 0x54, 0x4E, 0x56, 0x48, 0x62, 0x41, 0x6E, 0x7A, 0x7A, 0x52, 0x75, 0x6C, 0x52,
+    0x61, 0x43, 0x45, 0x78, 0x2B, 0x6E, 0x30, 0x49, 0x6A, 0x35, 0x34, 0x49, 0x45, 0x41, 0x4F, 0x75,
+    0x55, 0x4B, 0x70, 0x6F, 0x61, 0x48, 0x71, 0x6F, 0x56, 0x4F, 0x33, 0x51, 0x42, 0x36, 0x52, 0x41,
+    0x51, 0x7A, 0x4D, 0x67, 0x70, 0x44, 0x73, 0x41, 0x30, 0x58, 0x34, 0x4C, 0x6A, 0x4F, 0x32, 0x52,
+    0x2B, 0x4D, 0x4B, 0x6F, 0x6D, 0x6F, 0x6C, 0x52, 0x5A, 0x6F, 0x32, 0x34, 0x57, 0x32, 0x41, 0x35,
+    0x57, 0x2B, 0x30, 0x56, 0x4A, 0x77, 0x45, 0x41, 0x41, 0x51, 0x41, 0x3D, 0x20, 0x75, 0x6E, 0x6B,
+    0x6E, 0x6F, 0x77, 0x6E, 0x40, 0x75, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x00
+};
+#endif

+ 232 - 0
apps/common/device/usb/host/aoa.c

@@ -0,0 +1,232 @@
+/**
+ * @file aoa.c
+ * @brief https://source.android.com/devices/accessories/aoa
+ *        http://www.hackermi.com/2015-04/aoa-analyse/
+ *        Android 开放配件协议 1.0
+ * @author chenrixin@zh-jieli.com
+ * @version 1
+ * @date 2020-03-25
+ */
+
+#include "includes.h"
+#include "app_config.h"
+
+#include "usb_config.h"
+#include "usb/host/usb_host.h"
+#include "usb/usb_phy.h"
+#include "device_drive.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_bulk_transfer.h"
+#include "usb_storage.h"
+#include "adb.h"
+#include "aoa.h"
+#include "usb_hid_keys.h"
+#if TCFG_AOA_ENABLE
+#include "gamebox.h"
+
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[AOA]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+//0x2D00 有一个接口,该接口有两个批量端点,用于输入和输出通信。
+//0x2D01 有两个接口,每个接口有两个批量端点,用于输入和输出通信。
+//第一个接口处理标准通信,
+//第二个接口则处理 ADB 通信。
+//要使用接口,请找到第一个批量输入和输出端点,
+//使用 SET_CONFIGURATION (0x09) 设备请求将设备配置的值设为 1,然后使用端点进行通信
+//
+
+
+static void aoa_timer_handler(void *priv);
+static u32 aoa_timer_id;
+static struct aoa_device_t aoa;
+static struct device aoa_device;
+
+static int set_power(struct usb_host_device *host_dev, u32 value)
+{
+    if (aoa_timer_id) {
+        usr_timer_del(aoa_timer_id);
+        aoa_timer_id = 0;
+    }
+    return DEV_ERR_NONE;
+}
+
+static int get_power(struct usb_host_device *host_dev, u32 value)
+{
+    return DEV_ERR_NONE;
+}
+static const struct interface_ctrl aoa_ctrl = {
+    .interface_class = USB_CLASS_AOA,
+    .set_power = set_power,
+    .get_power = get_power,
+    .ioctl = NULL,
+};
+
+static const struct usb_interface_info aoa_inf = {
+    .ctrl = (struct interface_ctrl *) &aoa_ctrl,
+    .dev.aoa = &aoa,
+};
+
+static const char *credetials[] = {"JieLiTec",
+                                   "GameBox",
+                                   "Android accessories devcie !",
+                                   "1.0.0",
+                                   "http://www.zh-jieli.com",
+                                   "1234567890ABCDEF",
+                                  };
+
+void aoa_switch(struct usb_host_device *host_dev)
+{
+    u16 version;
+    log_info("aoa_switch");
+    usb_get_aoa_version(host_dev, &version);
+    log_info("AOA version: %x", version);
+    for (int i = 0; i < 5; i++) {
+        log_info("send string [%d] %s", i, credetials[i]);
+        int r = usb_set_credentials(host_dev, credetials[i], i);
+        if (r < 0) {
+            break;
+        }
+    }
+    usb_switch2aoa(host_dev);
+}
+
+int usb_aoa_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+    struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
+    pBuf += sizeof(struct usb_interface_descriptor);
+    int len = 0;
+    const usb_dev usb_id = host_device2id(host_dev);
+    aoa_device.private_data = host_dev;
+    host_dev->interface_info[interface_num] = &aoa_inf;
+
+    for (int endnum = 0; endnum < interface->bNumEndpoints; endnum++) {
+        struct usb_endpoint_descriptor *end_desc = (struct usb_endpoint_descriptor *)pBuf;
+
+        if (end_desc->bDescriptorType != USB_DT_ENDPOINT ||
+            end_desc->bLength != USB_DT_ENDPOINT_SIZE) {
+            log_error("ep bDescriptorType = %d bLength = %d", end_desc->bDescriptorType, end_desc->bLength);
+            return -USB_DT_ENDPOINT;
+        }
+
+        len += USB_DT_ENDPOINT_SIZE;
+        pBuf += USB_DT_ENDPOINT_SIZE;
+
+        if ((end_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+            if (end_desc->bEndpointAddress & USB_DIR_IN) {
+                aoa.target_epin = end_desc->bEndpointAddress & 0x0f;
+#if HUSB_MODE
+                aoa.rxmaxp = end_desc->wMaxPacketSize;
+#endif
+            } else {
+                aoa.target_epout = end_desc->bEndpointAddress & 0x0f;
+#if HUSB_MODE
+                aoa.txmaxp = end_desc->wMaxPacketSize;
+#endif
+            }
+        }
+    }
+
+
+    return len;
+}
+
+static int aoa_tx_data(const u8 *pbuf, u32 len)
+{
+    struct usb_host_device *host_dev = aoa_device.private_data;
+    usb_dev usb_id = host_device2id(host_dev);
+    g_printf("TX:");
+    printf_buf(pbuf, len);
+    return usb_h_ep_write_async(usb_id, aoa.host_epout, 64, aoa.target_epout, pbuf, len, USB_ENDPOINT_XFER_BULK, 1);
+}
+static void aoa_epin_isr(struct usb_host_device *host_dev, u32 ep)
+{
+    u8 buffer[64] = {0};
+    usb_dev usb_id = host_device2id(host_dev);
+    u32 rx_len = usb_h_ep_read_async(usb_id, ep, aoa.target_epin, buffer, sizeof(buffer), USB_ENDPOINT_XFER_BULK, 0);
+    g_printf("RX:");
+    printf_buf(buffer, rx_len);
+
+    usb_h_ep_read_async(usb_id, ep, aoa.target_epin, NULL, 0, USB_ENDPOINT_XFER_BULK, 1);
+}
+
+#define     Accessory_assigned_ID   0x0001
+
+u32 aoa_process(u32 mode, u32 id)
+{
+    struct usb_host_device *host_dev = aoa_device.private_data;
+    struct usb_device_descriptor device_desc;
+    usb_get_device_descriptor(host_dev, &device_desc);
+
+    if ((device_desc.idVendor == 0x18d1) &&
+        ((device_desc.idProduct & 0x2d00) == 0x2d00)) {
+        log_info("aoa mode ready idVendor:%x idProduct: %x",
+                 device_desc.idVendor, device_desc.idProduct);
+    } else {
+        log_info("aoa switch idVendor:%x idProduct: %x",
+                 device_desc.idVendor, device_desc.idProduct);
+
+        aoa_switch(host_dev);
+
+        usb_host_remount(id, 3, 30, 50, 1);
+        return 0;
+    }
+
+
+    usb_aoa_register_hid(host_dev, Accessory_assigned_ID, sizeof(hid_report_desc));
+
+    u32 offset = 0;
+    while (offset < sizeof(hid_report_desc)) {
+        u32 cnt = min(sizeof(hid_report_desc) - offset, 63);
+        usb_aoa_set_hid_report_desc(host_dev, Accessory_assigned_ID, offset, &hid_report_desc[offset], cnt);
+        offset += cnt;
+    }
+
+    aoa.host_epout = usb_get_ep_num(id, USB_DIR_OUT, USB_ENDPOINT_XFER_BULK);
+    aoa.host_epin = usb_get_ep_num(id, USB_DIR_IN, USB_ENDPOINT_XFER_BULK);
+    log_debug("D(%d)->H(%d)", aoa.target_epin, aoa.host_epin);
+    log_debug("H(%d)->D(%d)",  aoa.host_epout, aoa.target_epout);
+
+    usb_h_set_ep_isr(host_dev, aoa.host_epin | USB_DIR_IN, aoa_epin_isr, host_dev);
+    u8 *ep_buffer = usb_h_get_ep_buffer(id, aoa.host_epin | USB_DIR_IN);
+    usb_h_ep_config(id, aoa.host_epin | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 1, 0, ep_buffer, 64);
+    int r = usb_h_ep_read_async(id, aoa.host_epin, aoa.target_epin, NULL, 0, USB_ENDPOINT_XFER_BULK, 1);
+
+    ep_buffer = usb_h_get_ep_buffer(id, aoa.host_epout | USB_DIR_OUT);
+    usb_h_ep_config(id, aoa.host_epout | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, 0, 0, ep_buffer, 64);
+
+    aoa_timer_id = usr_timer_add((void *)0, aoa_timer_handler, 4, 0);
+    g_printf("aoa succ");
+
+    return 1;
+}
+
+
+static void aoa_timer_handler(void *priv)
+{
+    struct usb_host_device *host_dev = aoa_device.private_data;
+
+    u8 tx_buffer[32];
+    if (mouse_data_send == 1) {
+        tx_buffer[0] = MOUSE_POINT_ID;
+        memcpy(&tx_buffer[1], &mouse_data, sizeof(mouse_data));
+        usb_aoa_send_hid_event(host_dev, Accessory_assigned_ID, tx_buffer, sizeof(mouse_data) + 1);
+        memset(&mouse_data, 0, sizeof(mouse_data)) ;
+        mouse_data_send = 0;
+    }
+
+    tx_buffer[0] = TOUCH_SCREEN_ID;
+    struct touch_screen_t t;
+    memset(&t, 0, sizeof(t));
+    if (point_list_pop(&t)) {
+        memcpy(&tx_buffer[1], &t, sizeof(t));
+        usb_aoa_send_hid_event(host_dev, Accessory_assigned_ID, tx_buffer, sizeof(t) + 1);
+    }
+
+}
+#endif

+ 20 - 0
apps/common/device/usb/host/aoa.h

@@ -0,0 +1,20 @@
+#ifndef  __AOA_H__
+#define  __AOA_H__
+
+struct aoa_device_t {
+    u16 version;
+
+    u8 target_epin;
+    u8 target_epout;
+
+    u8 host_epin;
+    u8 host_epout;
+
+    struct adb_device_t *adb;
+};
+u32 aoa_process(u32 mode, u32 id);
+int usb_aoa_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
+
+
+
+#endif  /*AOA_H*/

+ 8 - 0
apps/common/device/usb/host/apple_mfi.h

@@ -0,0 +1,8 @@
+#ifndef _APPLE_MFI_H_
+#define _APPLE_MFI_H_
+
+int usb_apple_mfi_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
+
+
+
+#endif

+ 820 - 0
apps/common/device/usb/host/audio.c

@@ -0,0 +1,820 @@
+#include "includes.h"
+#include "asm/includes.h"
+#include "app_config.h"
+#include "system/timer.h"
+#include "device/ioctl_cmds.h"
+#include "device_drive.h"
+#if TCFG_HOST_AUDIO_ENABLE
+#include "usb/host/usb_host.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_bulk_transfer.h"
+#include "audio.h"
+#include "usb_config.h"
+
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[AUDIO]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+
+/* #define USB_AUDIO_PLAY_TEST */
+
+struct usb_audio_play {
+    u32 sample_rate;
+    u8 Cur_AlternateSetting;
+    u8 src_channel;
+    u8 play_state;
+    u8 mute;
+    u8 *send_buf;
+    u8 *usb_audio_play_buf;
+    u8 *usb_audio_play_buf2;
+    cbuffer_t usb_audio_play_cbuf;
+    u32 usb_audio_remain_len;
+    OS_SEM		sem;
+    int (*put_buf)(void *ptr, u32 len);
+};
+struct usb_audio_mic {
+    u8 Cur_AlternateSetting;
+    u32 sample_rate;
+    u8 record_state;
+    u8 *usb_audio_record_buf;
+    u8 *usb_audio_record_buf2;
+    cbuffer_t usb_audio_record_cbuf;
+    int *(*get_buf)(void *ptr, u32 len);
+};
+struct usb_audio_info {
+    usb_dev usb_id;
+    struct usb_audio_play player;
+    struct usb_audio_mic  microphone;
+};
+
+enum {
+    AUDIO_PLAY_IDLE = 0,
+    AUDIO_PLAY_START,
+    AUDIO_PLAY_STOP,
+    AUDIO_PLAY_PAUSE,
+};
+enum {
+    AUDIO_RECORD_IDLE = 0,
+    AUDIO_RECORD_START,
+    AUDIO_RECORD_STOP,
+    AUDIO_RECORD_PAUSE,
+};
+
+#define EP_MAX_PACKET_SIZE  (192)
+
+struct usb_audio_info _usb_audio_info = {0};
+#define __this   (&_usb_audio_info)
+
+struct audio_device_t audio_device[USB_MAX_HW_NUM][MAX_HOST_INTERFACE];
+
+static u8 ep_in_dma_buf[256]  __attribute__((aligned(4)));
+static u8 ep_out_dma_buf[256]  __attribute__((aligned(4)));
+
+static int set_power(struct usb_host_device *host_dev, u32 value)
+{
+    const usb_dev usb_id = host_device2id(host_dev);
+    return DEV_ERR_NONE;
+}
+
+static int get_power(struct usb_host_device *host_dev, u32 value)
+{
+    return DEV_ERR_NONE;
+}
+
+static const struct interface_ctrl uac_ctrl = {
+    .interface_class = USB_CLASS_AUDIO,
+    .set_power = set_power,
+    .get_power = get_power,
+    .ioctl = NULL,
+};
+
+static const struct usb_interface_info _uac_if[USB_MAX_HW_NUM][MAX_HOST_INTERFACE] = {
+    {
+        {
+            .ctrl = (struct interface_ctrl *) &uac_ctrl,
+            .dev.audio = &audio_device[0][0],
+        },
+        {
+            .ctrl = (struct interface_ctrl *) &uac_ctrl,
+            .dev.audio = &audio_device[0][1],
+        },
+        {
+            .ctrl = (struct interface_ctrl *) &uac_ctrl,
+            .dev.audio = &audio_device[0][2],
+        },
+        {
+            .ctrl = (struct interface_ctrl *) &uac_ctrl,
+            .dev.audio = &audio_device[0][3],
+        },
+    },
+};
+
+int usb_audio_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+    struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
+    const usb_dev usb_id = host_device2id(host_dev);
+
+    const struct usb_interface_info *usb_if = &_uac_if[usb_id][interface_num];
+    struct audio_streaming_t *as_t = NULL;
+    memset(usb_if->dev.p, 0, sizeof(struct audio_device_t));
+    host_dev->interface_info[interface_num] = usb_if;
+    usb_if->dev.audio->parent = host_dev;
+
+    if (interface->bInterfaceSubClass == USB_SUBCLASS_AUDIOCONTROL) {
+        log_info("audio control interface : %d\n", interface_num);
+        pBuf += sizeof(struct usb_interface_descriptor);
+        usb_if->dev.audio->subclass = interface->bInterfaceSubClass;
+        usb_if->dev.audio->interface_num = interface_num;
+
+        return sizeof(struct usb_interface_descriptor);
+    }
+
+    if (interface->bInterfaceSubClass == USB_SUBCLASS_AUDIOSTREAMING) {
+        usb_if->dev.audio->subclass = interface->bInterfaceSubClass;
+        usb_if->dev.audio->interface_num = interface_num;
+        if (interface->bNumEndpoints == 0) {
+            pBuf += sizeof(struct usb_interface_descriptor);
+            do {
+                struct usb_interface_descriptor *as_interface = (struct usb_interface_descriptor *)pBuf;
+                if (as_interface->bNumEndpoints == 0 || as_interface->bInterfaceClass != USB_CLASS_AUDIO) {
+                    break;
+                }
+                log_info("audio streaming interface : %d  ep_num:%d Altersetting:%d", interface_num, as_interface->bNumEndpoints, as_interface->bAlternateSetting);
+                as_t = &usb_if->dev.audio->as[as_interface->bAlternateSetting - 1];
+                as_t->bNumEndpoints = as_interface->bNumEndpoints;
+                pBuf += (USB_DT_INTERFACE_SIZE + UAC_DT_AS_HEADER_SIZE);
+                //解析format
+                struct uac_format_type_i_discrete_descriptor *uac_format_desc = (struct uac_format_type_i_discrete_descriptor *)pBuf;
+                if (uac_format_desc->bDescriptorSubtype == UAC_FORMAT_TYPE) {
+                    as_t->bFormatType = uac_format_desc->bFormatType;
+                    as_t->bNrChannels = uac_format_desc->bNrChannels;
+                    as_t->bSubframeSize = uac_format_desc->bSubframeSize;
+                    as_t->bBitResolution = uac_format_desc->bBitResolution;
+                    as_t->bSamFreqType = uac_format_desc->bSamFreqType;
+                    for (u8 i = 0; i < as_t->bSamFreqType; i++) {
+                        memcpy(&as_t->tSamFreq[i], &uac_format_desc->tSamFreq[i], 3);
+                        log_info("as bNrChannels:%d bBitResolution:%d  tSamFreq : %d", as_t->bNrChannels, as_t->bBitResolution, as_t->tSamFreq[i]);
+                    }
+                    //Endpointdescriptor
+                    pBuf += uac_format_desc->bLength;
+                    /* for (int i = 0; i < as_t->bNumEndpoints; i++) { */
+                    struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)pBuf;
+                    if (endpoint->bDescriptorType == USB_DT_ENDPOINT) {
+                        as_t->ep_Interval = endpoint->bInterval;
+                        as_t->ep_max_packet_size = endpoint->wMaxPacketSize;
+                        if (endpoint->bEndpointAddress & USB_DIR_IN) {
+                            as_t->ep = endpoint->bEndpointAddress & 0xf;
+                            log_info("ep in : %x\n", as_t->ep);
+                            usb_if->dev.audio->support = MICROPHONE_SUPPORTED;
+                        } else {
+                            as_t->ep = endpoint->bEndpointAddress;
+                            log_info("ep out : %x\n", as_t->ep);
+                            usb_if->dev.audio->support = HEADPHONE_SUPPORTED;
+                        }
+                        pBuf += (USB_DT_ENDPOINT_AUDIO_SIZE + UAC_ISO_ENDPOINT_DESC_SIZE);
+                    }
+                    /* } */
+                } else {
+                    log_error("uac_format_desc->bDescriptorSubtype err!!\n");
+                    goto __exit;
+                }
+
+            } while (1);
+            /* log_info("lennnn:%d\n",pBuf - (u8 *)interface); */
+            return pBuf - (u8 *)interface ;
+        } else {
+            log_info("audio streaming interface : %d  ep_num:%d Altersetting:%d\n", interface_num, interface->bNumEndpoints, interface->bAlternateSetting);
+        }
+
+    }
+
+__exit:
+    return USB_DT_INTERFACE_SIZE;
+
+}
+
+static struct audio_device_t *__find_microphone_interface(const struct usb_host_device *host_dev)
+{
+    struct audio_device_t *audio = NULL;
+    for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
+        const struct usb_interface_info *usb_if = host_dev->interface_info[i];
+        if (usb_if &&
+            (usb_if->ctrl->interface_class == USB_CLASS_AUDIO)) {
+            audio = usb_if->dev.audio;
+            if (audio->subclass == USB_SUBCLASS_AUDIOSTREAMING &&
+                audio->support == MICROPHONE_SUPPORTED) {
+                // find microphone
+                return audio;
+            }
+        }
+    }
+
+    return NULL;
+}
+static struct audio_device_t *__find_headphone_interface(const struct usb_host_device *host_dev)
+{
+    struct audio_device_t *audio = NULL;
+    for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
+        const struct usb_interface_info *usb_if = host_dev->interface_info[i];
+        if (usb_if &&
+            (usb_if->ctrl->interface_class == USB_CLASS_AUDIO)) {
+            audio = usb_if->dev.audio;
+            if (audio->subclass == USB_SUBCLASS_AUDIOSTREAMING &&
+                audio->support == HEADPHONE_SUPPORTED) {
+                // find headphone
+                return audio;
+            }
+        }
+    }
+
+    return NULL;
+}
+static u32 play_vol_convert(u16 v)
+{
+    //固定音量表,更换声卡需要修改音量表
+    const u16 vol_table[] = {
+        //0-100
+        0xd300, //0
+        0xd58f, 0xd7bf, 0xd9a8, 0xdb5b, 0xdce1, 0xde45, 0xdf8a, 0xe0b6, 0xe1cd, 0xe2d1,
+        0xe3c5, 0xe4ab, 0xe583, 0xe651, 0xe714, 0xe7cd, 0xe87f, 0xe928, 0xe9ca, 0xea66,
+        0xeafc, 0xeb8d, 0xec18, 0xec9e, 0xed20, 0xed9e, 0xee18, 0xee8e, 0xef00, 0xef6f,
+        0xefdc, 0xf045, 0xf0ab, 0xf10f, 0xf171, 0xf1d0, 0xf22c, 0xf287, 0xf2e0, 0xf336,
+        0xf38b, 0xf3de, 0xf42f, 0xf47e, 0xf4cc, 0xf518, 0xf563, 0xf5ad, 0xf5f5, 0xf63c,
+        0xf681, 0xf6c6, 0xf709, 0xf74b, 0xf78c, 0xf7cb, 0xf80a, 0xf848, 0xf885, 0xf8c1,
+        0xf8fc, 0xf936, 0xf96f, 0xf9a8, 0xf9df, 0xfa16, 0xfa4c, 0xfa81, 0xfab6, 0xfaea,
+        0xfb1d, 0xfb50, 0xfb82, 0xfbb3, 0xfbe4, 0xfc14, 0xfc43, 0xfc72, 0xfca0, 0xfcce,
+        0xfcfc, 0xfd28, 0xfd55, 0xfd80, 0xfdab, 0xfdd6, 0xfe01, 0xfe2a, 0xfe54, 0xfe7d,
+        0xfea5, 0xfece, 0xfef5, 0xff1d, 0xff43, 0xff6a, 0xff90, 0xffb6, 0xffdb, 0x0000,
+    };
+
+    if (v <= 100) {
+        return vol_table[v];
+    }
+
+    for (int i = 0; i < sizeof(vol_table) / 2; i++) {
+        if (v <= vol_table[i]) {
+            return i;
+        }
+    }
+
+    return 0;
+}
+
+void set_usb_audio_play_volume(u16 vol)
+{
+    const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
+    u8 featureUnitID = 6;
+    usb_audio_volume_control(host_dev, featureUnitID, 1, play_vol_convert(vol));
+    usb_audio_volume_control(host_dev, featureUnitID, 2, play_vol_convert(vol));
+    if (vol == 0) {
+        __this->player.mute = 1;
+        usb_audio_mute_control(host_dev, featureUnitID, __this->player.mute); //mute
+    } else {
+        if (__this->player.mute == 1) {
+            __this->player.mute = 0;
+            usb_audio_mute_control(host_dev, featureUnitID, __this->player.mute);
+        }
+    }
+}
+
+#ifdef USB_AUDIO_PLAY_TEST
+static const s16 sin_48k[] = {
+    0, 2139, 4240, 6270, 8192, 9974, 11585, 12998,
+    14189, 15137, 15826, 16244, 16384, 16244, 15826, 15137,
+    14189, 12998, 11585, 9974, 8192, 6270, 4240, 2139,
+    0, -2139, -4240, -6270, -8192, -9974, -11585, -12998,
+    -14189, -15137, -15826, -16244, -16384, -16244, -15826, -15137,
+    -14189, -12998, -11585, -9974, -8192, -6270, -4240, -2139
+};
+#endif
+static void usb_audio_tx_isr(struct usb_host_device *host_dev, u32 ep)
+{
+    const usb_dev usb_id = host_device2id(host_dev);
+    struct audio_device_t *audio = NULL;
+    struct audio_streaming_t *as_t = NULL;
+    u16 ep_max_packet_size = 0;
+    u8 channel = 0;
+    u32 rlen = 0;
+    static u32 usb_audio_tx_len = 0;
+
+    if (__this->player.play_state != AUDIO_PLAY_START) {
+        return;
+    }
+
+    audio = __find_headphone_interface(host_dev);
+    if (!audio) {
+        log_error("no find headphone interface!");
+        return;
+    }
+
+    as_t = &audio->as[__this->player.Cur_AlternateSetting - 1];
+    /* ep_max_packet_size = as_t->ep_max_packet_size; */
+    ep_max_packet_size = EP_MAX_PACKET_SIZE;
+    channel = as_t->bNrChannels;
+
+    //iso send
+#ifdef USB_AUDIO_PLAY_TEST
+    //For Test
+    int tx_len = 0;
+#if 1 // 单声道双声道输出
+    s16 buf[240 / 2];
+    for (u8 i = 0, j = 0; i < 240 / 2; i += 2) {
+        buf[i] = sin_48k[j];
+        buf[i + 1] = sin_48k[j];
+        j++;
+        if (j >= sizeof(sin_48k) / sizeof(sin_48k[0])) {
+            j = 0;
+        }
+    }
+#else
+    //单声道直接输出
+    u8 buf[248];
+    do {
+        memcpy(&buf[tx_len], sin_48k, sizeof(sin_48k));
+        tx_len += sizeof(sin_48k);
+    } while (tx_len < ep_max_packet_size);
+#endif
+    usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, buf, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 0);
+#else
+    if (__this->player.usb_audio_remain_len == 0) {
+        cbuf_read_alloc(&__this->player.usb_audio_play_cbuf, &__this->player.usb_audio_remain_len);
+        usb_audio_tx_len = 0;
+    }
+    if (__this->player.usb_audio_remain_len) {
+        if (usb_audio_tx_len == 0) {
+            rlen = cbuf_read(&__this->player.usb_audio_play_cbuf, __this->player.usb_audio_play_buf2, __this->player.usb_audio_remain_len);
+            if (!rlen) {
+                __this->player.usb_audio_remain_len = 0;
+                usb_audio_tx_len = 0;
+                putchar('C');
+                usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, NULL, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1);
+                os_sem_post(&__this->player.sem);
+                return;
+            }
+            os_sem_post(&__this->player.sem);
+
+        }
+        u8 *send_buf = __this->player.send_buf;
+        u8 *play_buf = __this->player.usb_audio_play_buf2;
+        if (channel == 2) {
+            if (__this->player.src_channel == 1) {
+                //源数据是单声道数据,转双声道输出
+                int j = 0;
+                for (u8 i = 0; i < ep_max_packet_size; i += 4) {
+                    //left
+                    *(send_buf + i) = *(play_buf + (usb_audio_tx_len + j));
+                    *(send_buf + i + 1) = *(play_buf + (usb_audio_tx_len + j + 1));
+                    //right
+
+                    *(send_buf + i + 2) = *(play_buf + (usb_audio_tx_len + j));
+                    *(send_buf + i + 3) = *(play_buf + (usb_audio_tx_len + j + 1));
+                    j += 2;
+                }
+                usb_audio_tx_len += j;
+                usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, send_buf, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 0);
+            } else if (__this->player.src_channel == 2) {
+                //源数据是双声道数据,直接双声道输出
+                usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, play_buf + usb_audio_tx_len, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 0);
+                usb_audio_tx_len += ep_max_packet_size;
+            }
+        } else if (channel == 1) {
+        }
+        if (usb_audio_tx_len >= __this->player.usb_audio_remain_len) {
+            __this->player.usb_audio_remain_len = 0;
+            usb_audio_tx_len = 0;
+        }
+    } else {
+        //audio buf null ,send null packet
+        putchar('E');
+        usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, NULL, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1);
+    }
+
+#endif
+}
+void set_vol_test(void *p)
+{
+    struct usb_host_device *host_dev = (struct usb_host_device *)p;
+    static u16 vol = 100;
+    set_usb_audio_play_volume(vol);
+    /* static u8 f = 0; */
+    /* void usb_audio_pause_play(void); */
+    /* void usb_audio_resume_play(void); */
+    /* if (!f) { */
+    /* usb_audio_pause_play(); */
+    /* } else { */
+    /* usb_audio_resume_play(); */
+    /* } */
+    /* f = !f; */
+    vol -= 10;
+}
+void audio_play_task(void *p)
+{
+    log_info(">>> Enter usb audio play task");
+    struct usb_host_device *host_dev = (struct usb_host_device *)p;
+    const usb_dev usb_id = host_device2id(host_dev);
+    u8 *ptr = NULL;
+    u32 wlen = 0;
+    u32 ret = 0;
+    struct audio_device_t *audio = NULL;
+    audio = __find_headphone_interface(host_dev);
+    struct audio_streaming_t *as_t = &audio->as[__this->player.Cur_AlternateSetting - 1];
+    /* u32 ep_max_packet_size = as_t->ep_max_packet_size; */
+    u32 ep_max_packet_size = EP_MAX_PACKET_SIZE;
+    log_info("ep max packet : %d\n", ep_max_packet_size);
+    if (__this->player.send_buf) {
+        free(__this->player.send_buf);
+        __this->player.send_buf = NULL;
+    }
+    __this->player.send_buf = zalloc(ep_max_packet_size);
+    u32 usb_audio_buf_size = ep_max_packet_size * 5; //预留5个包的缓存
+
+    /* sys_timer_add(host_dev,set_vol_test,5000); */
+    os_sem_create(&__this->player.sem, 0);
+    u32 host_ep = as_t->host_ep;
+    __this->player.play_state = AUDIO_PLAY_START;
+    //分配双缓存
+    // 一个缓存保存读卡的数据,一个用于usb发送
+    if (!__this->player.usb_audio_play_buf) {
+        __this->player.usb_audio_play_buf = zalloc(usb_audio_buf_size);
+        cbuf_init(&__this->player.usb_audio_play_cbuf, __this->player.usb_audio_play_buf, usb_audio_buf_size);
+        usb_h_ep_write_async(usb_id, host_ep, ep_max_packet_size, as_t->ep, NULL, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1); //启动iso传输
+    }
+    if (!__this->player.usb_audio_play_buf2) {
+        __this->player.usb_audio_play_buf2 = zalloc(usb_audio_buf_size);
+    }
+    while (1) {
+        if (__this->player.Cur_AlternateSetting == 0 || __this->player.play_state != AUDIO_PLAY_START) {
+            putchar('C');
+            os_time_dly(50);
+            continue;
+        }
+        ptr = cbuf_write_alloc(&__this->player.usb_audio_play_cbuf, &wlen);
+        if (wlen) {
+            putchar('R');
+            ret = __this->player.put_buf(ptr, wlen);
+            if (ret != wlen) {
+                __this->player.play_state = AUDIO_PLAY_STOP;
+                goto __task_exit;
+
+            }
+            cbuf_write_updata(&__this->player.usb_audio_play_cbuf, wlen);
+        } else {
+            log_w("usb audio play buf not enough!\n");
+        }
+__task_exit:
+        os_sem_pend(&__this->player.sem, 0);
+    }
+}
+
+void usb_audio_start_play(const usb_dev usb_id, u8 channel, u8 bit_reso, u32 sample_rate)
+{
+    log_info(" usb audio play\n");
+    const struct usb_host_device *host_dev = host_id2device(usb_id);
+    struct audio_device_t *audio = NULL;
+    struct audio_streaming_t *as_t = NULL;
+    u8 *ep_buffer = ep_out_dma_buf;
+    u8 find_alternatesetting = 0;
+    audio = __find_headphone_interface(host_dev);
+    if (!audio) {
+        log_error("no find headphone interface!");
+        return;
+    }
+    for (u8 i = 0; i < ARRAY_SIZE(audio->as); i++) {
+        as_t = &audio->as[i];
+        if (as_t->bBitResolution == bit_reso) {
+            for (u8 j = 0; j < as_t->bSamFreqType; j++) {
+                if (as_t->tSamFreq[j] == sample_rate) {
+                    find_alternatesetting = i + 1;
+                    break;
+                }
+            }
+        }
+    }
+    if (!find_alternatesetting) {
+        log_e("can not find Alternatesetting,please check bit_reso and sample_rate\n");
+        return;
+    }
+
+    __this->usb_id = usb_id;
+    //端点分配
+    u32 host_ep = usb_get_ep_num(usb_id, USB_DIR_OUT, USB_ENDPOINT_XFER_ISOC);
+    ASSERT(host_ep != -1, "ep not enough");
+
+    __this->player.Cur_AlternateSetting = find_alternatesetting; //选择Alternatesetting
+    __this->player.sample_rate = sample_rate;   //选择采样率
+    __this->player.src_channel = channel;
+    as_t = &audio->as[find_alternatesetting - 1];
+    u8 target_ep = as_t->ep;
+    u8 ep_interval = as_t->ep_Interval;
+    as_t->host_ep = host_ep;
+
+    usb_set_interface(host_dev, audio->interface_num, find_alternatesetting); //interface   Alternatesetting
+    usb_audio_sampling_frequency_control(host_dev, target_ep, sample_rate);//设置采样率
+    //设置音量
+    /* usb_audio_volume_control(host_dev, 6, 1, vol_convert(5)); */
+    /* usb_audio_volume_control(host_dev, 6, 2, vol_convert(5)); */
+
+    log_info("H2D ep: %x --> %x  interval: %d", host_ep, target_ep, ep_interval);
+    usb_h_set_ep_isr(host_dev, host_ep, usb_audio_tx_isr, host_dev);
+    usb_h_ep_config(usb_id,  host_ep, USB_ENDPOINT_XFER_ISOC, 1, ep_interval, ep_buffer, sizeof(ep_out_dma_buf));
+    task_create(audio_play_task, host_dev, "uac_play");
+}
+
+void usb_audio_stop_play(const usb_dev usb_id)
+{
+    const struct usb_host_device *host_dev = host_id2device(usb_id);
+    usb_h_set_ep_isr(NULL, 0, NULL, NULL);
+    __this->player.put_buf(NULL, 0);
+    __this->player.Cur_AlternateSetting = 0;
+    __this->player.sample_rate = 0;
+    __this->player.src_channel = 0;
+    if (__this->player.usb_audio_play_buf) {
+        free(__this->player.usb_audio_play_buf);
+        __this->player.usb_audio_play_buf = NULL;
+    }
+    if (__this->player.usb_audio_play_buf2) {
+        free(__this->player.usb_audio_play_buf2);
+        __this->player.usb_audio_play_buf2 = NULL;
+    }
+    if (__this->player.send_buf) {
+        free(__this->player.send_buf);
+        __this->player.send_buf = NULL;
+    }
+    printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
+    task_kill("uac_play");
+    printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
+}
+void usb_audio_pause_play(void)
+{
+    __this->player.play_state = AUDIO_PLAY_PAUSE;
+}
+void usb_audio_resume_play(void)
+{
+    const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
+    struct audio_device_t *audio = __find_headphone_interface(host_dev);
+    struct audio_streaming_t *as_t = &audio->as[__this->player.Cur_AlternateSetting - 1];
+    __this->player.play_state = AUDIO_PLAY_START;
+    usb_h_ep_write_async(__this->usb_id, as_t->host_ep, as_t->ep_max_packet_size, as_t->ep, NULL, as_t->ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1); //重新启动传输
+}
+
+
+static u32 record_vol_convert(u16 v)
+{
+    //固定音量表,更换声卡需要修改音量表
+    const u16 vol_table[] = {
+        //0-100
+        0xf400,
+        0xf479, 0xf4ee, 0xf560, 0xf5cf, 0xf63a, 0xf6a3, 0xf709, 0xf76c, 0xf7cd, 0xf82b,
+        0xf887, 0xf8e1, 0xf939, 0xf98f, 0xf9e4, 0xfa36, 0xfa87, 0xfad6, 0xfb23, 0xfb6f,
+        0xfbba, 0xfc03, 0xfc4b, 0xfc91, 0xfcd6, 0xfd1a, 0xfd5d, 0xfd9f, 0xfde0, 0xfe1f,
+        0xfe5e, 0xfe9b, 0xfed8, 0xff14, 0xff4e, 0xff88, 0xffc1, 0xfff9, 0x0003, 0x0069,
+        0x00a3, 0x00de, 0x0119, 0x0155, 0x0193, 0x01d1, 0x0210, 0x0251, 0x0292, 0x02d5,
+        0x0318, 0x035d, 0x03a3, 0x03eb, 0x0434, 0x047e, 0x04c9, 0x0517, 0x0565, 0x05b5,
+        0x0607, 0x065b, 0x06b1, 0x0708, 0x0762, 0x07bd, 0x081b, 0x087c, 0x08de, 0x0943,
+        0x09ab, 0x0a16, 0x0a84, 0x0af4, 0x0b69, 0x0be1, 0x0c5c, 0x0cdc, 0x0d60, 0x0de9,
+        0x0e77, 0x0f0a, 0x0fa2, 0x1041, 0x10e7, 0x1195, 0x124a, 0x1308, 0x13d0, 0x14a3,
+        0x1582, 0x166e, 0x176a, 0x1877, 0x1998, 0x1ad0, 0x1c24, 0x1d98, 0x1f33, 0x2100,
+    };
+
+    if (v <= 100) {
+        return vol_table[v];
+    }
+
+    for (int i = 0; i < sizeof(vol_table) / 2; i++) {
+        if (v <= vol_table[i]) {
+            return i;
+        }
+    }
+
+    return 0;
+}
+
+void set_usb_audio_record_volume(u16 vol)
+{
+    const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
+    u8 featureUnitID = 5;
+    usb_audio_volume_control(host_dev, featureUnitID, 0, record_vol_convert(vol));
+}
+
+static u32 write_file_len = 0;
+static void usb_audio_rx_isr(struct usb_host_device *host_dev, u32 ep)
+{
+    u8 buffer[192] = {0};
+    u8 *ptr = NULL;
+    int rlen, wlen = 0;
+    usb_dev usb_id = host_device2id(host_dev);
+    struct audio_device_t *audio = NULL;
+    struct audio_streaming_t *as_t = NULL;
+    audio = __find_microphone_interface(host_dev);
+    if (!audio) {
+        log_error("no find microphone interface!");
+        return;
+    }
+    if (__this->microphone.record_state != AUDIO_RECORD_START) {
+        return;
+    }
+    as_t = &audio->as[__this->microphone.Cur_AlternateSetting - 1];
+    u8 channel = as_t->bNrChannels;
+
+    u32 rx_len = usb_h_ep_read_async(usb_id, ep, as_t->ep, buffer, sizeof(buffer), USB_ENDPOINT_XFER_ISOC, 0);
+    /* g_printf("RX:%d\n",rx_len); */
+    /* printf_buf(buffer, rx_len); */
+    cbuf_write(&__this->microphone.usb_audio_record_cbuf, buffer, rx_len);
+    cbuf_write_alloc(&__this->microphone.usb_audio_record_cbuf, &wlen);
+    if (wlen == 0) {
+        putchar('O');
+        if (write_file_len) {
+            log_w("write againnnnn\n");
+        }
+        /* [> printf("R:%d  W:%d\n", rx_len,wlen); <] */
+        cbuf_read_alloc(&__this->microphone.usb_audio_record_cbuf, &rlen);
+        cbuf_read(&__this->microphone.usb_audio_record_cbuf, __this->microphone.usb_audio_record_buf2, rlen);
+        write_file_len = rlen;
+        os_taskq_post_msg("uac_record", 2, 0x01, rlen);
+        /* return; */
+    }
+
+    usb_h_ep_read_async(usb_id, ep, as_t->ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1); //触发下一个接收中断
+}
+void audio_record_task(void *p)
+{
+    log_info(">>> Enter usb audio record task");
+    struct usb_host_device *host_dev = (struct usb_host_device *)p;
+    const usb_dev usb_id = host_device2id(host_dev);
+    u8 *ptr = NULL;
+    u32 rlen = 0;
+    u32 ret = 0;
+    int msg[16];
+    struct audio_device_t *audio = NULL;
+    audio = __find_microphone_interface(host_dev);
+    struct audio_streaming_t *as_t = &audio->as[__this->microphone.Cur_AlternateSetting - 1];
+    /* u32 ep_max_packet_size = as_t->ep_max_packet_size; */
+    u32 ep_max_packet_size = EP_MAX_PACKET_SIZE;
+    log_info("ep max packet : %d\n", ep_max_packet_size);
+    u32 usb_audio_buf_size = ep_max_packet_size * 50;
+
+    u32 host_ep = as_t->host_ep;
+    u8 target_ep = as_t->ep;
+    //分配双缓存
+    // 一个缓存写卡的数据,一个用于usb接收
+    if (!__this->microphone.usb_audio_record_buf) {
+        __this->microphone.usb_audio_record_buf = zalloc(usb_audio_buf_size);
+        cbuf_init(&__this->microphone.usb_audio_record_cbuf, __this->microphone.usb_audio_record_buf, usb_audio_buf_size);
+
+    }
+    if (!__this->microphone.usb_audio_record_buf2) {
+        __this->microphone.usb_audio_record_buf2 = zalloc(usb_audio_buf_size);
+    }
+
+    usb_h_ep_read_async(usb_id, host_ep, target_ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1); //启动iso
+    while (1) {
+        ret = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
+        if (ret == OS_TASKQ) {
+            switch (msg[1]) {
+            case 0x01:
+                ptr = __this->microphone.usb_audio_record_buf2;
+                rlen = msg[2];
+                putchar('W');
+                __this->microphone.get_buf(ptr, rlen);
+                write_file_len = 0;
+                break;
+            }
+        }
+    }
+}
+void usb_audio_start_record(const usb_dev usb_id, u8 bit_reso, u32 sample_rate)
+{
+    log_info(" usb audio record\n");
+    const struct usb_host_device *host_dev = host_id2device(usb_id);
+    struct audio_device_t *audio = NULL;
+    struct audio_streaming_t *as_t = NULL;
+    u8 *ep_buffer = ep_in_dma_buf;
+    u8 find_alternatesetting = 0;
+    audio = __find_microphone_interface(host_dev);
+    if (!audio) {
+        log_error("no find microphone interface!");
+        return;
+    }
+    for (u8 i = 0; i < ARRAY_SIZE(audio->as); i++) {
+        as_t = &audio->as[i];
+        if (as_t->bBitResolution == bit_reso) {
+            for (u8 j = 0; j < as_t->bSamFreqType; j++) {
+                if (as_t->tSamFreq[j] == sample_rate) {
+                    find_alternatesetting = i + 1;
+                    break;
+                }
+            }
+        }
+    }
+    if (!find_alternatesetting) {
+        log_e("can not find Alternatesetting,please check bit_reso and sample_rate\n");
+        return;
+    }
+    //端点分配
+    u32 host_ep = usb_get_ep_num(usb_id, USB_DIR_IN, USB_ENDPOINT_XFER_ISOC);
+    ASSERT(host_ep != -1, "ep not enough");
+    __this->usb_id = usb_id;
+    host_ep = host_ep | USB_DIR_IN;
+
+    __this->microphone.Cur_AlternateSetting = find_alternatesetting; //选择Alternatesetting
+    __this->microphone.sample_rate = sample_rate;   //选择采样率
+    as_t = &audio->as[find_alternatesetting - 1];
+    u8 target_ep = as_t->ep;
+    u8 ep_interval = as_t->ep_Interval;
+    as_t->host_ep = host_ep;
+
+    usb_set_interface(host_dev, audio->interface_num, find_alternatesetting); //interface 1  Alternatesetting 1
+    usb_audio_sampling_frequency_control(host_dev, target_ep, sample_rate);//设置采样率
+    //设置音量
+    /* usb_audio_volume_control(host_dev, 6, 1, vol_convert(5)); */
+    /* usb_audio_volume_control(host_dev, 6, 2, vol_convert(5)); */
+    log_info("D2H ep: %x --> %x", target_ep, host_ep);
+    usb_h_set_ep_isr(host_dev, host_ep, usb_audio_rx_isr, host_dev);
+    usb_h_ep_config(usb_id,  host_ep, USB_ENDPOINT_XFER_ISOC, 1, ep_interval, ep_buffer, sizeof(ep_in_dma_buf));
+    task_create(audio_record_task, host_dev, "uac_record");
+    __this->microphone.record_state = AUDIO_RECORD_START;
+}
+void usb_audio_stop_record(const usb_dev usb_id)
+{
+    const struct usb_host_device *host_dev = host_id2device(usb_id);
+    usb_h_set_ep_isr(NULL, 0, NULL, NULL);
+    __this->microphone.get_buf(NULL, 0);
+    __this->microphone.Cur_AlternateSetting = 0;
+    __this->microphone.sample_rate = 0;
+    if (__this->microphone.usb_audio_record_buf) {
+        free(__this->microphone.usb_audio_record_buf);
+        __this->microphone.usb_audio_record_buf = NULL;
+    }
+    if (__this->microphone.usb_audio_record_buf2) {
+        free(__this->microphone.usb_audio_record_buf2);
+        __this->microphone.usb_audio_record_buf2 = NULL;
+    }
+    printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
+    task_kill("uac_record");
+    printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
+}
+void usb_audio_pause_record(void)
+{
+    __this->microphone.record_state = AUDIO_RECORD_PAUSE;
+}
+void usb_audio_resume_record(void)
+{
+    const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
+    struct audio_device_t *audio = __find_microphone_interface(host_dev);
+    struct audio_streaming_t *as_t = &audio->as[__this->microphone.Cur_AlternateSetting - 1];
+    __this->microphone.record_state = AUDIO_RECORD_START;
+    usb_h_ep_read_async(__this->usb_id, as_t->host_ep, as_t->ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1); //重新启动接收
+}
+
+void usb_audio_start_process(u32 id)
+{
+    usb_audio_start_play(id, 1, 16, 48000); //开启headphone
+    usb_audio_start_record(id, 16, 48000); //开启microphone
+}
+void usb_audio_stop_process(u32 id)
+{
+    usb_audio_stop_play(id);
+    usb_audio_stop_record(id);
+}
+
+
+static void usb_audio_event_handler(struct sys_event *event, void *priv)
+{
+    const char *audio = NULL;
+    switch (event->type) {
+    case SYS_DEVICE_EVENT:
+        if ((u32)event->arg == DEVICE_EVENT_FROM_USB_HOST) {
+            if ((event->u.dev.event == DEVICE_EVENT_IN) ||
+                (event->u.dev.event == DEVICE_EVENT_CHANGE)) {
+                audio = (const char *)event->u.dev.value;
+                usb_audio_start_process(audio[5] - '0');
+
+            } else if (event->u.dev.event == DEVICE_EVENT_OUT) {
+                log_error("device out %x", event->u.dev.value);
+                usb_audio_stop_process(audio[5] - '0');
+            }
+            break;
+        }
+    }
+}
+void usb_host_audio_init(int (*put_buf)(void *ptr, u32 len), int *(*get_buf)(void *ptr, u32 len))
+{
+    memset(__this, 0, sizeof(struct usb_audio_info));
+    __this->player.put_buf = put_buf;
+    __this->microphone.get_buf = get_buf;
+    register_sys_event_handler(SYS_DEVICE_EVENT, DEVICE_EVENT_FROM_USB_HOST, 2,
+                               usb_audio_event_handler);
+}
+void usb_host_audio_exit()
+{
+    unregister_sys_event_handler(usb_audio_event_handler);
+    __this->player.put_buf = NULL;
+    __this->microphone.get_buf = NULL;
+}
+
+#endif

+ 56 - 0
apps/common/device/usb/host/audio.h

@@ -0,0 +1,56 @@
+#ifndef  __AUDIO_H__
+#define  __AUDIO_H__
+
+#include "system/task.h"
+#include "device/device.h"
+#include "usb_bulk_transfer.h"
+#include "usb/host/usb_host.h"
+#include "usb/device/uac_audio.h"
+
+
+#define HEADPHONE_SUPPORTED                0x01
+#define MICROPHONE_SUPPORTED               0x02
+#define HEADSET_SUPPORTED                  0x03
+
+struct audio_streaming_t {
+    u8  bNumEndpoints;
+    u8  bFormatType;		/** FORMAT_TYPE_1 */
+    u8  bNrChannels;		/** physical channels in the stream */
+    u8  bSubframeSize;
+    u8  bBitResolution;
+    u8  bSamFreqType;
+    u32 tSamFreq[8];
+    u8  host_ep; //主机传输端点
+    u8  ep; //从机端点(由描述符中指定)
+    u8  ep_Interval;
+    u16 ep_max_packet_size;
+};
+
+struct audio_device_t {
+    u8 interface_num; //接口号
+    u8 subclass;
+    u8 support;
+    void *parent;
+    struct audio_streaming_t as[8];
+};
+
+int usb_audio_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
+
+// API
+int usb_audio_play_put_buf(void *ptr, u32 len);
+int usb_audio_record_get_buf(void *ptr, u32 len);
+
+//headphone api
+void set_usb_audio_play_volume(u16 vol);
+void usb_audio_start_play(const usb_dev usb_id, u8 channel, u8 bit_reso, u32 sample_rate); //指定播放数据的声道数,位数,采样率
+void usb_audio_stop_play(const usb_dev usb_id);
+void usb_audio_pause_play(void);
+void usb_audio_resume_play(void);
+
+//microphone api
+void set_usb_audio_record_volume(u16 vol);
+void usb_audio_start_record(const usb_dev usb_id, u8 bit_reso, u32 sample_rate); //指定录制数据的位数,采样率
+void usb_audio_stop_record(const usb_dev usb_id);
+void usb_audio_pause_record(void);
+void usb_audio_resume_record(void);
+#endif

+ 111 - 0
apps/common/device/usb/host/audio_demo.c

@@ -0,0 +1,111 @@
+#include "includes.h"
+#include "asm/includes.h"
+#include "app_config.h"
+#include "system/timer.h"
+#include "device/ioctl_cmds.h"
+#include "device_drive.h"
+#if TCFG_HOST_AUDIO_ENABLE
+#include "usb/host/usb_host.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_bulk_transfer.h"
+#include "audio.h"
+#include "usb_config.h"
+
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[AUDIO]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+
+#define TEST_FILE_ENABLE   (0)  //从sd卡读数据; 录制数据至sd卡
+#if (TEST_FILE_ENABLE)
+static FILE *play_file = NULL;
+int usb_audio_play_put_buf(void *ptr, u32 len)
+{
+    int ret = 0;
+    if (ptr == NULL && len == 0) {
+        //err
+        if (play_file) {
+            fclose(play_file);
+            play_file = NULL;
+            return 0;
+        }
+    }
+    if (!play_file) {
+        play_file = fopen("storage/sd0/C/raw.pcm", "r"); //单声道
+        /* play_file = fopen("storage/sd0/C/raw2.pcm", "r"); //双声道 */
+        if (!play_file) {
+            log_e("fopen play file faild!\n");
+            return -1;
+        }
+    }
+    //读sd卡数据到播放缓存中
+    ret = fread(play_file, ptr, len);
+    if (ret != len) {
+        log_e(" file read buf err %d\n", ret);
+        fclose(play_file);
+        play_file = NULL;
+        return -1;
+    }
+
+    return len;
+}
+static FILE *record_file = NULL;
+int usb_audio_record_get_buf(void *ptr, u32 len)
+{
+#if (TEST_FILE_ENABLE)
+    int ret = 0;
+    static u32 cnt = 0;
+    if (!record_file) {
+        record_file = fopen("storage/sd0/C/record01.pcm", "w+");
+        cnt = 0;
+        if (!record_file) {
+            log_e("fopen play file faild!\n");
+            return -1;
+        }
+    }
+    putchar('W');
+    ret = fwrite(record_file, ptr, len);
+    if (ret != len) {
+        log_e(" file write buf err %d\n", ret);
+        fclose(record_file);
+        record_file = NULL;
+        return -1;
+    }
+    //test
+    if (cnt++ >= 800) {
+        cnt = 0;
+        log_info("stop record....\n");
+        fclose(record_file);
+        record_file = NULL;
+    }
+#endif
+
+    return len;
+}
+#else
+
+//将数据传入usb
+//ptr:usb数据指针
+//len:需要传入的数据长度
+int usb_audio_play_put_buf(void *ptr, u32 len)
+{
+    return len;
+}
+
+//从usb读取数据
+//ptr:usb数据指针
+//len:读取的数据长度
+int usb_audio_record_get_buf(void *ptr, u32 len)
+{
+    return len;
+}
+
+
+#endif
+
+#endif

+ 657 - 0
apps/common/device/usb/host/hid.c

@@ -0,0 +1,657 @@
+#include "includes.h"
+#include "asm/includes.h"
+#include "app_config.h"
+#include "system/timer.h"
+#include "device/ioctl_cmds.h"
+#include "device_drive.h"
+#if TCFG_HID_HOST_ENABLE
+#include "usb/host/usb_host.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_bulk_transfer.h"
+#include "hid.h"
+#include "usb_config.h"
+#include "usb_hid_keys.h"
+
+#define MAIN_ITEM    0
+#define GLOBAL_ITEM  1
+#define LOCAL_ITEM   2
+
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[HID]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+
+struct hid_device_t hid_device[USB_MAX_HW_NUM][MAX_HOST_INTERFACE];
+
+static int set_power(struct usb_host_device *host_dev, u32 value)
+{
+    const usb_dev usb_id = host_device2id(host_dev);
+    memset(hid_device[usb_id], 0, sizeof(hid_device[usb_id]));
+    return DEV_ERR_NONE;
+}
+
+static int get_power(struct usb_host_device *host_dev, u32 value)
+{
+    return DEV_ERR_NONE;
+}
+
+static const struct interface_ctrl hid_ctrl = {
+    .interface_class = USB_CLASS_HID,
+    .set_power = set_power,
+    .get_power = get_power,
+    .ioctl = NULL,
+};
+
+static const struct usb_interface_info _usb_if[USB_MAX_HW_NUM][MAX_HOST_INTERFACE] = {
+    {
+        {
+            .ctrl = (struct interface_ctrl *) &hid_ctrl,
+            .dev.hid = &hid_device[0][0],
+        },
+        {
+            .ctrl = (struct interface_ctrl *) &hid_ctrl,
+            .dev.hid = &hid_device[0][1],
+        },
+        {
+            .ctrl = (struct interface_ctrl *) &hid_ctrl,
+            .dev.hid = &hid_device[0][2],
+        },
+        {
+            .ctrl = (struct interface_ctrl *) &hid_ctrl,
+            .dev.hid = &hid_device[0][3],
+        },
+    },
+#if USB_MAX_HW_NUM > 1
+    {
+        {
+            .ctrl = (struct interface_ctrl *) &hid_ctrl,
+            .dev.hid = &hid_device[1][0],
+        },
+        {
+            .ctrl = (struct interface_ctrl *) &hid_ctrl,
+            .dev.hid = &hid_device[1][1],
+        },
+        {
+            .ctrl = (struct interface_ctrl *) &hid_ctrl,
+            .dev.hid = &hid_device[1][2],
+        },
+        {
+            .ctrl = (struct interface_ctrl *) &hid_ctrl,
+            .dev.hid = &hid_device[1][3],
+        },
+    },
+#endif
+};
+
+static u8 interval[USB_MAX_HW_NUM][16];
+
+int usb_hid_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+    struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
+    pBuf += sizeof(struct usb_interface_descriptor);
+    int len = 0;
+    const usb_dev usb_id = host_device2id(host_dev);
+
+    struct usb_endpoint_descriptor *endpoint;
+
+    pBuf += 9;//hid desc;
+
+    const struct usb_interface_info *usb_if = &_usb_if[usb_id][interface_num];
+
+    memset(usb_if->dev.p, 0, sizeof(struct hid_device_t));
+
+    host_dev->interface_info[interface_num] = usb_if;
+    usb_if->dev.hid->parent = host_dev;
+
+    log_info("hid eps %d  %d %x %x", interface->bNumEndpoints, interface_num, usb_if, usb_if->dev.p);
+
+    log_info("parent %x hid @ interface %d usb_if %x hid %x",
+             host_dev, interface_num, usb_if, usb_if->dev.hid);
+
+    if ((interface->bInterfaceProtocol == 0x02) ||
+        (interface->bInterfaceProtocol == 0x01)) { //mouse & keyboard
+
+        usb_if->dev.hid->bNumEndpoints = interface->bNumEndpoints;
+        usb_if->dev.hid->report_list[0].usage = interface->bInterfaceProtocol;
+        for (int i = 0 ; i < interface->bNumEndpoints; i++) {
+            endpoint = (struct usb_endpoint_descriptor *)pBuf;
+            if (USB_DIR_IN & endpoint->bEndpointAddress) {
+                const u8 ep = endpoint->bEndpointAddress & 0x0f;
+                usb_if->dev.hid->ep_pair[i] = ep;
+                interval[usb_id][ep] = endpoint->bInterval;
+                log_info("interfacenum = %d,endpoint = %x interval = %x",
+                         interface->bInterfaceNumber, endpoint->bEndpointAddress, endpoint->bInterval);
+            }
+            pBuf += endpoint->bLength;
+        }
+    } else {
+        log_info("vendor");
+        host_dev->interface_info[interface_num] = NULL; //???
+        for (int i = 0 ; i < interface->bNumEndpoints; i++) {
+            endpoint = (struct usb_endpoint_descriptor *)pBuf;
+            if (USB_DIR_IN & endpoint->bEndpointAddress) {
+                /* interface_endpoint[interface->bInterfaceNumber] = endpoint->bEndpointAddress & 0x0f; */
+                log_info("interfacenum = %d,endpoint = %x interval = %x",
+                         interface->bInterfaceNumber, endpoint->bEndpointAddress, endpoint->bInterval);
+            }
+            pBuf += endpoint->bLength;
+        }
+        return sizeof(struct usb_interface_descriptor);
+    }
+
+    return pBuf - (u8 *)interface;
+}
+
+static u32 _hid_report_parse(struct hid_device_t *hid, const u8 *report, u32 len)
+{
+    hid->report_count = 0;
+    struct report_info_t null_rpt;
+    struct report_info_t *const rpt = &null_rpt;
+
+    memset(rpt, 0, sizeof(*rpt));
+
+    unsigned char ops;
+    int index = 0;
+    u8 report_size = 0;
+    u8 report_count = 0;
+    u8 cur_ops_is_report_size_count = 0;
+    u8 old_ops_is_report_size_count = 0;
+    s8 cur_section_bit = 0;
+    u8 input_bit_index = 0;
+    u8 total_bits = 0;
+    u8 output_bit_index = 0;
+    u8 cur_usage = 0;
+    u32 undef_type = 0;
+    u8 undef_usage = 0;
+    u8 collection_deep = 0;
+
+    while (index < len) {
+        ops = (char)report[index++];
+        char bSize = ops & 0x03;
+        bSize = bSize == 3 ? 4 : bSize; // size is 4 when bSize is 3
+        char bType = (ops >> 2) & 0x03;
+        char bTag = (ops >> 4) & 0x0F;
+
+        cur_ops_is_report_size_count = 0;
+        char bSizeActual = 0;
+        int itemVal = 0;
+        for (int j = 0; j < bSize; j++) {
+            if (index + j < len) {
+                itemVal += report[index + j] << (8 * j);
+                bSizeActual++;
+            }
+        }
+        if (undef_type) {
+            undef_type ++;
+            if (bTag == 0x0A) {
+                undef_usage ++;
+            } else if (bTag == 0x0C) {
+                undef_usage --;
+            }
+            if (undef_usage == 0 && undef_type > 2) {
+                undef_type = 0;
+            }
+            index += bSize;
+            continue;
+        }
+        if (undef_type) {
+            index += bSize;
+            continue;
+        }
+        if (itemVal == 0xffb5) {
+            undef_type = 1;
+            index += bSize;
+            continue;
+        } else {
+            undef_type = 0;
+        }
+        if (bType == MAIN_ITEM) {
+            if (old_ops_is_report_size_count) {
+                cur_section_bit += report_size * report_count;
+            }
+            if (bTag == 0x08) {
+                /* log_info("input %X", itemVal);                       */
+                /* log_info("\tusage %x", cur_usage);                   */
+                /* log_info("\t\tcur_section_bit %d", cur_section_bit); */
+                if (rpt->usage == 0x02) { //mouse
+                    if (cur_usage == 1) {
+                        if (rpt->btn_start_bit == 0) {
+                            rpt->btn_start_bit = total_bits ;
+                        }
+                        rpt->btn_width += cur_section_bit ;
+                        /* log_info("btn_width %d-%d", rpt->btn_start_bit, rpt->btn_width); */
+                    } else if ((cur_usage == 0x30) || (cur_usage == 0x31)) {
+
+                        if (rpt->xy_start_bit == 0) {
+                            rpt->xy_start_bit = total_bits;
+                        }
+                        rpt->xy_width = cur_section_bit;
+                        /* log_info("xy_width %d-%d", rpt->xy_start_bit, rpt->xy_width); */
+                    } else if (cur_usage == 0x38) {
+                        if (rpt->wheel_start_bit == 0) {
+                            rpt->wheel_start_bit = total_bits;
+                        }
+                        if (rpt->xy_width || cur_section_bit < 24) {
+                            rpt->wheel_width = cur_section_bit;
+                            /* log_info("wheel_width %d-%d", rpt->wheel_start_bit, rpt->wheel_width); */
+                        } else {
+                            rpt->wheel_width = rpt->xy_width = cur_section_bit / 3;
+
+                            rpt->xy_start_bit = total_bits;
+                            rpt->wheel_start_bit = rpt->xy_start_bit + rpt->xy_width * 2;
+                            /* log_info("wheel_width %d-%d", rpt->wheel_start_bit, rpt->wheel_width); */
+                            /* log_info("xy_width %d-%d", rpt->xy_start_bit, rpt->xy_width);          */
+                        }
+                    } else if (cur_usage == 0xb8) {
+                        rpt->wheel_width = rpt->xy_width = cur_section_bit / 4;
+                        rpt->xy_start_bit = total_bits;
+                        rpt->wheel_start_bit = rpt->xy_start_bit + rpt->xy_width * 2;
+                    }
+                }
+                total_bits += cur_section_bit;
+                /* input_bit[input_bit_index++] = cur_section_bit; */
+                cur_section_bit = -1;
+            } else if (bTag == 0x09) {
+                /* log_info("OUTPUT %X", itemVal);                      */
+                /* log_info("\tusage %x", cur_usage);                   */
+                /* log_info("\t\tcur_section_bit %d", cur_section_bit); */
+                /* output_bit[output_bit_index++] = cur_section_bit; */
+                cur_section_bit = -1;
+            } else if (bTag == 0x0B) {
+                /* log_info("Feature %X", itemVal);                     */
+                /* log_info("\tusage %x", cur_usage);                   */
+                /* log_info("\t\tcur_section_bit %d", cur_section_bit); */
+                /* output_bit[output_bit_index++] = cur_section_bit; */
+                cur_section_bit = -1;
+            } else if (bTag == 0x0A) {
+                collection_deep ++ ;
+                log_info("Collection %d %x", collection_deep, rpt->usage);
+            } else if (bTag == 0x0C) {
+                collection_deep --;
+                log_info("End Collection %d %x", collection_deep, rpt->usage);
+                if (collection_deep == 0) {
+                    if (rpt->usage == 0x02 ||
+                        rpt->usage == 0x06 ||
+                        rpt->usage == 0x07) {
+
+                        memcpy(&hid->report_list[hid->report_count], rpt, sizeof(*rpt));
+                        memset(rpt, 0, sizeof(*rpt));
+
+                        hid->report_count ++;
+                    }
+                }
+                if (index < len) {
+                    continue;
+                }
+            } else {
+                log_info("MAIN_ITEM Unknown btag :%x", bTag);
+                return 1;
+            }
+        } else if (bType == GLOBAL_ITEM) {
+            /* log_info("GLOBAL_ITEM"); */
+            if (bTag == 0x00) {
+                /* log_info("Usage Page %x", itemVal); */
+
+                if (rpt->usage == 0x06) {
+                    if (itemVal == 0x07) {
+                        rpt->usage = 0x07;
+                        log_info("re set type %x", 0x07);
+                    }
+                }
+                if (itemVal == 0x02) {
+                    rpt->usage = 0x02;
+                    log_info("re set type %x", 0x02);
+                }
+
+            } else if (bTag == 0x01) {
+                //log_info("Logical Minimum %x", itemVal);
+            } else if (bTag == 0x02) {
+                //log_info("Logical Maximum %x", itemVal);
+            } else if (bTag == 0x03) {
+                /* log_info("Physical Minimum %x", itemVal); */
+            } else if (bTag == 0x04) {
+                /* log_info("Physical Maximum %x", itemVal); */
+            } else if (bTag == 0x05) {
+                /* log_info("Unit Exponent %x", itemVal); */
+            } else if (bTag == 0x06) {
+                /* log_info("Unit %x", itemVal); */
+            } else if (bTag == 0x07) {
+                /* log_info("Report Size %x", itemVal); */
+                report_size = itemVal;
+                cur_ops_is_report_size_count = 1;
+            } else if (bTag == 0x08) {
+                log_info("Report ID %x", itemVal, rpt->usage);
+                rpt->report_id = itemVal;
+            } else if (bTag == 0x09) {
+                /* log_info("Report Count %x", itemVal); */
+                report_count = itemVal;
+                cur_ops_is_report_size_count = 1;
+            } else if (bTag == 0x0A) {
+                /* log_info("Push %x", bSizeActual); */
+            } else if (bTag == 0x0B) {
+                /* log_info("Pop %x", bSizeActual); */
+            } else {
+                log_info("GLOBAL_ITEM Unknown btag :%x", bTag);
+                return 2;
+            }
+        } else if (bType == LOCAL_ITEM) {
+            /* log_info("LOCAL_ITEM"); */
+            if (bTag == 0x00) {
+                if (rpt->usage == 0) {
+                    rpt->usage = itemVal;
+                    log_info("set type %x", rpt->usage);
+                }
+                if (itemVal == 0x30) { //X
+                } else if (itemVal == 0x31) { //y
+                } else if (itemVal == 0x38) { //wheel
+                } else {
+                }
+                /* log_info("\t change usage %x -> %x", cur_usage, itemVal); */
+                cur_usage = itemVal;
+                if (!collection_deep) {
+                    if (itemVal == 0x06 || itemVal == 0x07 || itemVal == 0x02) {
+                        //仅限键盘和鼠标
+                        rpt->usage = itemVal;
+                        log_info("set typee %x", rpt->usage);
+                    }
+                }
+                /* type = itemVal; */
+            } else if (bTag == 0x01) {
+                // log_info("Usage Minimum %x", itemVal);
+            } else if (bTag == 0x02) {
+                // log_info("Usage Maximum %x", itemVal);
+            } else if (bTag == 0x03) {
+                /* log_info("Designator Index %x", itemVal); */
+            } else if (bTag == 0x04) {
+                /* log_info("Designator Minimum %x", itemVal); */
+            } else if (bTag == 0x05) {
+                /* log_info("Designator Maximum %x", itemVal); */
+            } else if (bTag == 0x07) {
+                /* log_info("String Index %x", itemVal); */
+            } else if (bTag == 0x08) {
+                /* log_info("String Minimum %x", itemVal); */
+            } else if (bTag == 0x09) {
+                /* log_info("String Maximum %x", itemVal); */
+            } else if (bTag == 0x0A) {
+                /* log_info("Delimiter %x", itemVal); */
+            } else {
+                log_info("LOCAL_ITEM Unknown btag :%x", bTag);
+                return 3;
+            }
+        } else {
+            log_info("OTHER Unknown btag :%x", bTag);
+            return 4;
+        }
+        if (!cur_ops_is_report_size_count && old_ops_is_report_size_count) {
+            if (cur_section_bit != -1) {
+                cur_section_bit += report_size * report_count;
+            } else {
+                cur_section_bit = 0;
+            }
+        }
+        if (cur_section_bit == -1) {
+            cur_section_bit = 0;
+        }
+        old_ops_is_report_size_count = cur_ops_is_report_size_count;
+        index += bSize;
+
+    }
+    return 0;
+}
+static u32 hid_report_parse(struct hid_device_t *hid, const u8 *report, u32 len)
+{
+    u8 type = _hid_report_parse(hid, report, len);
+    for (int i = 0; i < hid->report_count; i++) {
+        struct report_info_t *rpt = &hid->report_list[i];
+        if (rpt->usage == 0x02) {
+            if (rpt->report_id == 0) {
+                rpt->report_id = 0xff;
+            }
+            rpt->btn_start_bit /= 8;
+            rpt->btn_width /= 8;
+            rpt->xy_start_bit /= 8;
+            rpt->xy_width /= 8;
+            rpt->wheel_start_bit /= 8;
+            rpt->wheel_width /= 8;
+
+            log_info("mouse report_id %d",
+                     rpt->report_id);
+
+            log_info("btn_width %d-%d",
+                     rpt->btn_start_bit, rpt->btn_width);
+            log_info("xy_width %d-%d",
+                     rpt->xy_start_bit, rpt->xy_width);
+            log_info("wheel_width %d-%d",
+                     rpt->wheel_start_bit, rpt->wheel_width);
+
+            if (rpt->btn_width != 2) {
+                rpt->btn_width = 1;
+            }
+
+            log_info("btn_width %d-%d",
+                     rpt->btn_start_bit, rpt->btn_width);
+
+        } else if (rpt->usage == 6 || rpt->usage == 7) {
+            if (rpt->report_id == 0) {
+                rpt->report_id = 0xff;
+            }
+            log_info("keyboard report_id %d", rpt->report_id);
+        } else {
+            log_info("unknown usage %d", rpt->usage);
+        }
+    }
+    return 0;
+}
+
+void mouse_route(const struct mouse_data_t *p);
+/* __attribute__((weak)) void mouse_route(const struct mouse_data_t *p) */
+/* {                                                                    */
+/*     log_info("btn: %x x-y %d %d wheel %d ac_pan %d",                 */
+/*              p->btn, p->x, p->y, p->wheel, p->ac_pan);               */
+/* }                                                                    */
+static void hid_convert_mouse(const struct report_info_t *mouse, const u8 *buffer)
+{
+    struct mouse_data_t mouse_data;
+    memset(&mouse_data, 0, sizeof(mouse_data));
+    if (mouse->report_id != 0xff) {
+        if (mouse->report_id != buffer[0]) {
+            log_error("report_id = %x buffer[0] = %x", mouse->report_id, buffer[0]);
+            return;
+        }
+        buffer++;
+    }
+    const u8 *ptr;
+    ptr = &buffer[mouse->btn_start_bit];
+    if (mouse->btn_width == 2) {
+        mouse_data.btn = ptr[0] | (ptr[1] << 8);
+    } else {
+        mouse_data.btn = ptr[0] ;
+    }
+    s16 tmp;
+    ptr = &buffer[mouse->xy_start_bit];
+    if (mouse->xy_width == 1 || mouse->xy_width == 2) {
+        mouse_data.x = (char)ptr[0];
+        mouse_data.y = (char)ptr[1];
+    } else if (mouse->xy_width == 4) {
+        mouse_data.x = ptr[0] | (ptr[1] << 8);
+        ptr += 2;
+        mouse_data.y = ptr[0] | (ptr[1] << 8);
+    } else if (mouse->xy_width == 3) {
+        tmp = (ptr[1] & 0xf) << 12 | ptr[0] << 4;
+        tmp = tmp >> 4;
+        mouse_data.x = tmp;
+
+        tmp = (ptr[2] << 8) | ((ptr[1] >> 4) << 4);
+        tmp = tmp >> 4;
+        mouse_data.y = tmp;
+    } else {
+        log_error("error mouse xy_width %d", mouse->xy_width);
+    }
+
+    ptr = &buffer[mouse->wheel_start_bit];
+
+    if (mouse->wheel_width == 1) {
+        mouse_data.wheel = (char)ptr[0];
+    } else {
+        mouse_data.wheel = ptr[0] | (ptr[1] << 8);
+    }
+
+    mouse_route(&mouse_data);
+}
+__attribute__((weak)) void keyboard_route(const u8  *p)
+{
+    log_info("keyboard_buffer:");
+    printf_buf(p, 12);
+}
+void hid_convert_krbd(const struct report_info_t *kbd, u8 *buffer)
+{
+#if 0
+    u8 keyboard_buffer[12];
+    memset(keyboard_buffer, 0, sizeof(keyboard_buffer));
+    if (kbd->report_id != 0xff) {
+        if (kbd->report_id != buffer[0]) {
+            log_error("report_id = %x buffer[0] = %x", kbd->report_id, buffer[0]);
+            return;
+        }
+        buffer++;
+    }
+
+    u8 idx = 0;
+    u8 index = 0;
+    int i = 0;
+    for (i = 0; i < 8; i++) {
+        if (buffer[0] & BIT(i)) {
+            keyboard_buffer[idx++] = 0xe0 + i;
+        }
+    }
+
+    if (buffer[1] == 0) {
+        buffer += 2;
+    }
+    index = idx;
+    for (; idx < 12; idx++) {
+        if (*buffer) {
+            keyboard_buffer[index] = *buffer;
+            index++;
+        }
+        buffer ++;
+    }
+    keyboard_route(keyboard_buffer);
+#else
+    if (kbd->report_id != 0xff) {
+        if (kbd->report_id != buffer[0]) {
+            log_error("report_id = %x buffer[0] = %x", kbd->report_id, buffer[0]);
+            return;
+        }
+        buffer++;
+    }
+    u8 keyboard_buffer[8];
+    memset(keyboard_buffer, 0, sizeof(keyboard_buffer));
+
+    keyboard_buffer[0] = *buffer;
+    buffer ++;
+
+    if (*buffer == 0) {
+        buffer ++;
+    }
+    keyboard_buffer[1] = 0;
+
+    /* memcpy(&keyboard_buffer[2], buffer, 6); */
+    u8 pos = 2;
+    for (int i = pos; i < 8; i++) {
+        if (*buffer) {
+            keyboard_buffer[pos] = *buffer;
+            pos++;
+        }
+        buffer++;
+    }
+    keyboard_route(keyboard_buffer);
+#endif
+}
+
+static void hid_route(const struct hid_device_t *hid, const u8 *buffer)
+{
+    for (int i = 0; i < hid->report_count; i++) {
+        if (hid->report_list[i].usage == 0x02) {
+            hid_convert_mouse(&hid->report_list[i], buffer);
+        } else if ((hid->report_list[i].usage == 0x06) ||
+                   (hid->report_list[i].usage == 0x07)) {
+            hid_convert_krbd(&hid->report_list[i], buffer);
+        } else {
+            r_printf("usage %x", hid->report_list[i].usage);
+        }
+    }
+}
+static void hid_isr(struct usb_interface_info *usb_if, u32 ep)
+{
+    u8 buffer[64] = {0};
+    struct usb_host_device *host_dev = usb_if->dev.hid->parent;
+    usb_dev usb_id = host_device2id(host_dev);
+    u32 target_ep = usb_if->dev.hid->ep_pair[ep];
+    u32 rx_len = usb_h_ep_read_async(usb_id, ep, target_ep, buffer, 64, USB_ENDPOINT_XFER_INT, 0);
+
+    if (rx_len) {
+        hid_route(usb_if->dev.hid, buffer);
+    }
+    /* printf_buf(buffer, rx_len);    */
+
+    usb_h_ep_read_async(usb_id, ep, target_ep, buffer, 8, USB_ENDPOINT_XFER_INT, 1);
+}
+void hid_process(u32 id)
+{
+    struct usb_host_device *host_dev = host_id2device(id);
+    u8 report[256 + 2];
+    u8 ep_pair[4];
+
+    for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
+        struct usb_interface_info  *usb_if = host_dev->interface_info[i];
+        log_info("parent %x hid @ interface %d usb_if %x hid %x",
+                 host_dev, i, usb_if, usb_if ? usb_if->dev.hid : 0);
+        if (usb_if &&
+            (usb_if->ctrl->interface_class == USB_CLASS_HID)) {
+            hid_set_idle(host_dev, i);
+            memset(report, 0, sizeof(report));
+            hid_get_report(host_dev, report, i, 0xff);
+            printf_buf(report, 256);
+            hid_report_parse(usb_if->dev.hid, report, 256);
+            memcpy(ep_pair, usb_if->dev.hid->ep_pair, 4);
+
+            if (usb_if->dev.hid->report_count == 0) {
+                continue;
+            }
+
+            for (int i = 0; i < usb_if->dev.hid->bNumEndpoints; i++) {
+
+                u32 host_ep = usb_get_ep_num(id, USB_DIR_IN, USB_ENDPOINT_XFER_INT);
+
+                ASSERT(host_ep != -1, "ep not enough");
+
+                u32 target_ep = ep_pair[i];
+
+                usb_if->dev.hid->ep_pair[host_ep] = target_ep;
+
+                log_info("D2H ep: %x --> %x interval %d",
+                         target_ep, host_ep, interval[id][target_ep]);
+
+                usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, hid_isr, usb_if);
+
+                u8 *ep_buffer = usb_h_get_ep_buffer(id, host_ep | USB_DIR_OUT);
+                usb_h_ep_config(id,  host_ep | USB_DIR_IN, USB_ENDPOINT_XFER_INT, 1,
+                                interval[id][target_ep], ep_buffer, 64);
+                int r = usb_h_ep_read_async(id, host_ep, target_ep, NULL, 0, USB_ENDPOINT_XFER_INT, 1);
+            }
+        } else {
+            if (usb_if) {
+                log_error("error hid class %x", usb_if->ctrl->interface_class);
+            }
+        }
+    }
+
+}
+
+#endif

+ 83 - 0
apps/common/device/usb/host/hid.h

@@ -0,0 +1,83 @@
+/**@file        hid.h
+  * @brief      hid驱动头文件(做主机)
+  * @details    结构体声明,功能函数声明
+  * @author     jieli
+  * @date       2021-9-1
+  * @version    V1.0
+  * @copyright  Copyright(c)2010-2021   珠海市杰理科技股份有限公司
+  *********************************************************
+  * @attention
+  * 硬件平台:AC632N
+  * SDK版本:AC632N_V1.0.0_SDK
+  * @修改日志:
+  * <table>
+  * <tr><th>Date        <th>Version     <th>Author      <th>Description
+  * <tr><td>2021-9-1    <td>1.0         <td>jieli       <td>创建初始版本
+  * </table>
+  *
+  *********************************************************
+  */
+#ifndef  __HID_H__
+#define  __HID_H__
+
+#include "system/task.h"
+#include "device/device.h"
+#include "usb/scsi.h"
+#include "usb_bulk_transfer.h"
+#include "usb/host/usb_host.h"
+
+/**@struct  report_info_t
+  * @brief  报告描述符包含的信息结构体\n
+  * 自定义一些私有数据信息存储在该结构体中
+  */
+struct report_info_t {
+    u8 report_id; ///<id号,不同hid设备对应不同id
+    u8 usage; ///<描述该数据信息的用途
+
+    u8 btn_start_bit; ///<鼠标按键数据起始位
+    u8 btn_width; ///<鼠标按键数据宽度
+
+    u8 xy_start_bit; ///<鼠标平移数据起始位
+    u8 xy_width; ///<鼠标平移数据宽度
+
+    u8 wheel_start_bit; ///<鼠标滚轮数据起始位
+    u8 wheel_width; ///<鼠标滚轮数据宽度
+};
+
+#define     MAX_REPORT_COUNT    4
+
+/**@struct  hid_device_t
+  * @brief  报告描述符包含的信息结构体\n
+  * 自定义一些私有数据信息存储在该结构体中
+  */
+struct hid_device_t {
+    void *parent; ///<定义的parent指针,指向该hid的所属设备
+    u8 ep_pair[4]; ///<端点对数组,数组下标存放主机端点,对应的元素存放目标端点
+    u8 report_count; ///<报告描述符中item计数器
+    u8 bNumEndpoints; ///<端点数量
+    struct report_info_t report_list[MAX_REPORT_COUNT]; ///<报告描述符结构体
+};
+
+/**@brief   USB hid设备解析
+  * @param[in]  host_dev usb_host_device定义的结构体指针
+  * @param[in]  interface_num 接口号
+  * @param[in]  *pBuf 数据指针,指向数据存放的地址
+  * @return     接口描述符长度
+  * @par    示例:
+  * @code
+  * usb_hid_parser(host_dev,interface_num,pBuf);
+  * @encode
+  */
+int usb_hid_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
+
+/**@brief   USB hid设备信息处理
+  * @param[in]  id usb设备id号
+  * @return 无
+  * @par    示例:
+  * @code
+  * hid_process(id);
+  * @encode
+  */
+void hid_process(u32 id);
+
+#endif  /*HID_H*/

+ 296 - 0
apps/common/device/usb/host/usb_bulk_transfer.c

@@ -0,0 +1,296 @@
+/**
+ * @file usb_bulk_transfer.c
+ * @brief bulk transfer driver
+ * @author chenrixin@zh-jieli.com
+ * @version 1.00
+ * @date 2017-02-09
+ */
+
+#include <string.h>
+#include "jiffies.h"
+#include "usb_config.h"
+#include "usb_bulk_transfer.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_storage.h"
+#include "usb/host/usb_host.h"
+#include "usb/usb_phy.h"
+#include "app_config.h"
+#include "device_drive.h"
+
+#if USB_HOST_ENABLE
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+struct usb_request_block {
+    void *ptr;
+    u32 len;
+    u32 target_ep;
+    u16 rxmap;
+    u16 txmap;
+    u32 msg;
+    u32 async_mode;
+};
+static struct usb_request_block urb;
+
+u8 get_async_mode(void)
+{
+    u8 mode = BULK_ASYNC_MODE_EXIT ;
+#if UDISK_READ_512_ASYNC_ENABLE
+    local_irq_disable();
+    mode = urb.async_mode;
+    local_irq_enable();
+#endif
+    return mode;
+
+}
+void set_async_mode(u8 mode)
+{
+#if UDISK_READ_512_ASYNC_ENABLE
+    local_irq_disable();
+    urb.async_mode = mode;
+    local_irq_enable();
+#endif
+}
+static void usb_bulk_rx_isr(struct usb_host_device *host_dev, u32 ep)
+{
+    usb_dev usb_id = host_device2id(host_dev);
+    int l  = min(urb.len, urb.rxmap);
+
+    l = usb_h_ep_read_async(usb_id, ep, urb.target_ep, urb.ptr, l, USB_ENDPOINT_XFER_BULK, 0);
+    /* g_printf("%s() %d %d", __func__, l, urb.len); */
+    if (l > 0) {
+        urb.len -= l;
+        if (urb.ptr) {
+            urb.ptr += l;
+        }
+        urb.msg = 0;
+    } else {
+        urb.msg = l;
+        urb.len = 0;
+    }
+
+
+    if (urb.len == 0) {
+        u32 async_mode = get_async_mode();
+
+        if (async_mode == BULK_ASYNC_MODE_EXIT) {
+            usb_sem_post(host_dev);
+        } else if (async_mode == BULK_ASYNC_MODE_SEM_PEND) {
+            if (urb.msg == 0) {
+                usb_sem_post(host_dev);
+            } else {
+                r_printf("usb async error");
+            }
+        }
+    } else {
+        usb_h_ep_read_async(usb_id, ep, urb.target_ep, urb.ptr, urb.len, USB_ENDPOINT_XFER_BULK, 1);
+    }
+}
+s32 usb_bulk_only_receive_async(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
+{
+    struct usb_host_device *host_dev = device_to_usbdev(device);
+    const usb_dev usb_id = host_device2id(host_dev);
+
+    urb.ptr = pBuf;
+    urb.len = len;
+    urb.target_ep = target_ep;
+
+#ifdef CONFIG_USB_SUPPORT_MRX_TX
+    urb.rxmap = 1 * 1024;
+#else
+    urb.rxmap = 0x40;
+#endif
+
+    urb.msg = -DEV_ERR_OFFLINE;
+
+    usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, usb_bulk_rx_isr, host_dev);
+    usb_set_intr_rxe(usb_id, host_ep);
+
+    int ret = usb_h_ep_read_async(usb_id, host_ep, target_ep, urb.ptr, len, USB_ENDPOINT_XFER_BULK, 1);
+    if (ret < 0) {
+        return ret;
+    }
+    ret = usb_sem_pend(host_dev, 300);
+
+    usb_clr_intr_rxe(usb_id, host_ep);
+    usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, NULL, host_dev);
+    if (ret) {
+        return -DEV_ERR_TIMEOUT;
+    }
+    return urb.msg ? urb.msg : len;
+}
+
+/**
+ * @brief usb_bulk_receive_async_no_wait 启动USB Bulk 异步预读
+ *        不用等信号量,启动传输后返回
+ * @param device 设备句柄
+ * @param pBuf 读buffer缓冲区,芯片所有memory都可以
+ * @param len 需要预读的长度
+ *
+ * @return 负数表示失败
+ */
+s32 usb_bulk_receive_async_no_wait(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
+{
+    struct usb_host_device *host_dev = device_to_usbdev(device);
+    const usb_dev usb_id = host_device2id(host_dev);
+
+    set_async_mode(BULK_ASYNC_MODE_SEM_PEND);
+    urb.ptr = pBuf;
+    urb.len = len;
+    urb.target_ep = target_ep;
+
+#ifdef CONFIG_USB_SUPPORT_MRX_TX
+    urb.rxmap = 1 * 1024;
+#else
+    urb.rxmap = 0x40;
+#endif
+
+    urb.msg = -DEV_ERR_OFFLINE;
+
+    usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, usb_bulk_rx_isr, host_dev);
+    usb_set_intr_rxe(usb_id, host_ep);
+
+    int ret = usb_h_ep_read_async(usb_id, host_ep, target_ep, urb.ptr, len, USB_ENDPOINT_XFER_BULK, 1);
+    if (ret < 0) {
+        if (ret == -DEV_ERR_RXSTALL) {
+            ret = usb_clear_feature(host_dev, target_ep | USB_DIR_IN);
+            if (ret == 0) {
+                return -DEV_ERR_RXSTALL;
+            }
+        }
+        return ret;
+    }
+    return len;
+}
+static s32 _usb_bulk_only_receive(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
+{
+#if 0
+    struct usb_host_device *host_dev = device_to_usbdev(device);
+    const usb_dev usb_id = host_device2id(host_dev);
+    return usb_h_bulk_read(usb_id, host_ep, rxmaxp, target_ep, pBuf, len);
+#else
+    return usb_bulk_only_receive_async(device, host_ep, rxmaxp, target_ep, pBuf, len);
+#endif
+}
+s32 usb_bulk_only_receive(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
+{
+
+    struct usb_host_device *host_dev = device_to_usbdev(device);
+    int ret = _usb_bulk_only_receive(device, host_ep, rxmaxp, target_ep, pBuf, len);
+    if (ret == -DEV_ERR_RXSTALL) {
+        ret = usb_clear_feature(host_dev, target_ep | USB_DIR_IN);
+        if (ret == 0) {
+            return -DEV_ERR_RXSTALL;
+        }
+    }
+    return ret;
+}
+static void usb_bulk_tx_isr(struct usb_host_device *host_dev, u32 ep)
+{
+    usb_dev usb_id = host_device2id(host_dev);
+    int l  = min(urb.len, urb.txmap);
+    l = usb_h_ep_write_async(usb_id, ep, urb.txmap, urb.target_ep, urb.ptr, l, USB_ENDPOINT_XFER_BULK, 0);
+
+    if (l > 0) {
+        urb.len -= l;
+        urb.ptr += l;
+        urb.msg = 0;
+    } else {
+        urb.msg = l;
+        urb.len = 0;
+    }
+
+    if (urb.len == 0) {
+        if (urb.msg || l == 0) {
+            usb_sem_post(host_dev);
+        }
+    }
+}
+s32 usb_bulk_only_send_async(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len)
+{
+    struct usb_host_device *host_dev = device_to_usbdev(device);
+    const usb_dev usb_id = host_device2id(host_dev);
+
+    urb.target_ep = target_ep;
+#ifdef CONFIG_USB_SUPPORT_MRX_TX
+    urb.txmap = 8 * 1024;
+#else
+    urb.txmap = 0x40;
+#endif
+
+
+    urb.msg = -DEV_ERR_OFFLINE;
+    urb.len = len - min(len, urb.txmap);
+    urb.ptr = (u8 *)pBuf + min(len, urb.txmap);
+
+
+    usb_h_set_ep_isr(host_dev, host_ep, usb_bulk_tx_isr, host_dev);
+    usb_set_intr_txe(usb_id, host_ep);
+
+    int ret = usb_h_ep_write_async(usb_id, host_ep, txmaxp, target_ep, pBuf, min(len, urb.txmap), USB_ENDPOINT_XFER_BULK, 1);
+    if (ret < 0) {
+        return ret;
+    }
+    ret = usb_sem_pend(host_dev, 250);
+
+    usb_clr_intr_txe(usb_id, host_ep);
+    usb_h_set_ep_isr(host_dev, host_ep, NULL, host_dev);
+
+    if (ret) {
+        r_printf("ret %d", ret);
+        return -DEV_ERR_TIMEOUT;
+    }
+    /* g_printf("%s() %d %d", __func__, urb.len, urb.msg); */
+    return urb.msg ? urb.msg : len;
+}
+/**
+ * @brief usb_bulk_only_send
+ *
+ * @param device
+ * @param host_ep   主机的端点号
+ * @param target_ep 目标设备的端点号
+ * @param pBuf
+ * @param len
+ *
+ * @return 负数失败
+ * 		正数发送的字节数
+ */
+static s32 _usb_bulk_only_send(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len)
+{
+#if 0
+    struct usb_host_device *host_dev = device_to_usbdev(device);
+    const usb_dev usb_id = host_device2id(host_dev);
+    return usb_h_bulk_write(usb_id, host_ep, txmaxp, target_ep, pBuf, len);
+#elif 0
+    if (len < 512) {
+        struct usb_host_device *host_dev = device_to_usbdev(device);
+        const usb_dev usb_id = host_device2id(host_dev);
+        return usb_h_bulk_write(usb_id, host_ep, txmaxp, target_ep, pBuf, len);
+    } else {
+        return usb_bulk_only_send_async(device, host_ep, txmaxp, target_ep, pBuf, len);
+    }
+#else
+    return usb_bulk_only_send_async(device, host_ep, txmaxp, target_ep, pBuf, len);
+#endif
+}
+s32 usb_bulk_only_send(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len)
+{
+    struct usb_host_device *host_dev = device_to_usbdev(device);
+    int ret = _usb_bulk_only_send(device, host_ep, txmaxp, target_ep, pBuf, len);
+
+    if (ret == -DEV_ERR_TXSTALL) {
+        ret = usb_clear_feature(host_dev, target_ep);
+        if (ret == 0) {
+            return -DEV_ERR_TXSTALL;
+        }
+    }
+    return ret;
+
+}
+#endif

+ 120 - 0
apps/common/device/usb/host/usb_bulk_transfer.h

@@ -0,0 +1,120 @@
+/**@file        usb_bulk_transfer.h
+  * @brief      usb_bulk_transfer批量传输头文件
+  * @details    功能函数声明
+  * @author     jieli
+  * @date       2021-8-1
+  * @version    V1.0
+  * @copyright  Copyright(c)2010-2021   珠海市杰理科技股份有限公司
+  *********************************************************
+  * @attention
+  * 硬件平台:AC695N
+  * SDK版本:AC695N_V1.0.0_SDK
+  * @修改日志:
+  * <table>
+  * <tr><th>Date        <th>Version     <th>Author      <th>Description
+  * <tr><td>2021-8-1    <td>1.0         <td>jieli       <td>创建初始版本
+  * </table>
+  *
+  *********************************************************
+  */
+#ifndef __USB_BULK_TRANSFER_H__
+#define __USB_BULK_TRANSFER_H__
+#include "typedef.h"
+#include "device/device.h"
+
+
+/**@brief   批量传输只读取(异步模式)
+  * @param[in] device定义的结构体指针
+  * @param[in] host_ep 主机端点号
+  * @param[in] rxmaxp 接收端点最大包长
+  * @param[in] target_ep 目标端点号
+  * @param[in] *pBuf BUFFER指针
+  * @param[in] len 数据长度
+  * @return
+  * @par    示例:
+  * @code
+  * usb_bulk_only_receive_async(device, host_ep, rxmaxp, target_ep, pBuf, len);
+  * @encode
+  */
+s32 usb_bulk_only_receive_async(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len);
+
+/**@brief   批量传输只读取(普通模式)
+  * @param[in] device定义的结构体指针
+  * @param[in] host_ep 主机端点号
+  * @param[in] rxmaxp 接收端点最大包长
+  * @param[in] ep 目标端点号
+  * @param[in] *pBuf BUFFER指针
+  * @param[in] len 数据长度
+  * @return
+  * @par    示例:
+  * @code
+  * usb_bulk_only_receive(device, host_ep, rxmaxp, ep, pBuf, len);
+  * @encode
+  */
+s32 usb_bulk_only_receive(struct device *device, u8 host_ep, u16 rxmaxp, u8 ep, u8 *pBuf, u32 len);
+
+/**@brief   批量传输只发送(异步模式)
+  * @param[in] device定义的结构体指针
+  * @param[in] host_ep 主机端点号
+  * @param[in] txmaxp 发送端点最大包长
+  * @param[in] target_ep 目标端点号
+  * @param[in] *pBuf BUFFER指针
+  * @param[in] len 数据长度
+  * @return
+  * @par    示例:
+  * @code
+  * usb_bulk_only_send_async(device, host_ep, txmaxp, target_ep, pBuf, len);
+  * @encode
+  */
+s32 usb_bulk_only_send_async(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len);
+
+/**@brief   批量传输只发送(普通模式)
+  * @param[in] device定义的结构体指针
+  * @param[in] ep 主机端点号
+  * @param[in] txmaxp 发送端点最大包长
+  * @param[in] ep 目标端点号
+  * @param[in] *pBuf BUFFER指针
+  * @param[in] len 数据长度
+  * @return
+  * @par    示例:
+  * @code
+  * usb_bulk_only_send(device, host_ep, txmaxp, ep, pBuf, len);
+  * @encode
+  */
+s32 usb_bulk_only_send(struct device *device, u8 host_ep, u16 txmaxp, u8 ep, const u8 *pBuf, u32 len);
+
+/**@brief   获取异步模式当前状态
+  * @param[in] 空
+  * @return    当前状态
+  * @par    示例:
+  * @code
+  * get_async_mode();
+  * @encode
+  */
+u8 get_async_mode(void);
+
+/**@brief   设置异步模式
+  * @param[in] mode 需要设置的模式
+  * @return    空
+  * @par    示例:
+  * @code
+  * set_async_mode(BULK_ASYNC_MODE_EXIT);退出异步模式
+  * @encode
+  */
+void set_async_mode(u8 mode);
+
+/**@brief   批量传输异步模式读取并且不等待
+  * @param[in] device定义的结构体指针
+  * @param[in] ep 主机端点号
+  * @param[in] rxmaxp 发送端点最大包长
+  * @param[in] target_ep 目标端点号
+  * @param[in] *pBuf BUFFER指针
+  * @param[in] len 数据长度
+  * @return
+  * @par    示例:
+  * @code
+  * usb_bulk_only_send(device, host_ep, rxmaxp, ep, pBuf, len);
+  * @encode
+  */
+s32 usb_bulk_receive_async_no_wait(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len);
+#endif

+ 622 - 0
apps/common/device/usb/host/usb_ctrl_transfer.c

@@ -0,0 +1,622 @@
+/**
+ * @file usb_ctrl_transfer.c
+ * @brief usb 控制传输接口
+ * @author chenrixin@zh-jieli.com
+ * @version 1.00
+ * @date 2017-02-09
+ */
+
+#include "usb/host/usb_host.h"
+#include "usb_ctrl_transfer.h"
+#include "app_config.h"
+#include "device_drive.h"
+#include "gpio.h"
+#include "usb/scsi.h"
+
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[USB]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+#if USB_HOST_ENABLE
+
+_WEAK_
+void usb_dis_ep0_txdly(const usb_dev id)
+{
+}
+static void ep0_h_isr(struct usb_host_device *host_dev, u32 ep)
+{
+    usb_dev usb_id = host_device2id(host_dev);
+    usb_sem_post(host_dev);
+}
+/**
+ * @brief usb_ctlXfer
+ *
+ * @param host_dev
+ * @param urb
+ *
+ * @return
+ */
+static int usb_ctlXfer(struct usb_host_device *host_dev, struct ctlXfer *urb)
+{
+    u32 ret = DEV_ERR_NONE;
+    u8 reg = 0;
+    u32 data_len;
+    usb_dev usb_id = host_device2id(host_dev);
+    u8 devnum = host_dev->private_data.devnum;
+    u32 max_packet_size = host_dev->private_data.ep0_max_packet_size;
+
+    usb_write_faddr(usb_id, devnum);
+
+    switch (urb->stage) {
+    case USB_PID_SETUP :
+        usb_write_ep0(usb_id, (u8 *)&urb->setup, 8);
+        reg = CSR0H_SetupPkt | CSR0H_TxPktRdy;
+        break;
+    case USB_PID_IN :
+        if (urb->setup.wLength) {
+            reg = CSR0H_ReqPkt;
+        } else {
+            reg = CSR0H_StatusPkt | CSR0H_ReqPkt;
+        }
+        break;
+    case USB_PID_OUT:
+        if (urb->setup.wLength) {
+            data_len = min(urb->setup.wLength, max_packet_size);
+            reg = CSR0H_TxPktRdy;
+            usb_write_ep0(usb_id, urb->buffer, data_len);
+            urb->setup.wLength -= data_len;
+            urb->buffer += data_len;
+        } else {
+            reg = CSR0H_StatusPkt | CSR0H_TxPktRdy;
+        }
+        break;
+    default :
+        break;
+    }
+
+#if USB_HOST_ASYNC
+    //config ep0 callback fun
+    usb_h_set_ep_isr(host_dev, 0, ep0_h_isr, host_dev);
+    usb_set_intr_txe(usb_id, 0);
+#endif
+
+    usb_write_csr0(usb_id, reg);
+
+    u32 st = 0;
+    u32 ot = get_jiffies() + 500;
+    while (1) {
+        if (usb_host_timeout(ot)) {
+            log_error("time out %x\n", reg);
+            ret = -DEV_ERR_TIMEOUT;
+            goto __exit;
+        }
+        if (usb_h_dev_status(usb_id)) {
+            st ++;
+        } else {
+            st = 0;
+        }
+        if (((usb_read_devctl(usb_id) & BIT(2)) == 0) || (st > 1000)) {
+            log_error("usb%d_offline\n", usb_id);
+            ret = -DEV_ERR_OFFLINE;
+            goto __exit;
+        }
+
+#if USB_HOST_ASYNC
+        ret = usb_sem_pend(host_dev, 250); //wait isr
+        if (ret) {
+            log_error("usb%d_offline\n", usb_id);
+            ret = -DEV_ERR_OFFLINE;
+            goto __exit;
+        }
+#endif
+
+        reg = usb_read_csr0(usb_id);
+        if (reg & CSR0H_RxStall) {
+            log_error(" rxStall CSR0:0x%x", reg);
+            ret = -DEV_ERR_CONTROL_STALL;
+            goto __exit;
+        }
+        if (reg & CSR0H_Error) {
+            log_error(" Error CSR0:0x%x", reg);
+            usb_write_csr0(usb_id, 0);
+            ret = -DEV_ERR_CONTROL;
+            goto __exit;
+        }
+        if (USB_PID_IN == urb->stage) {
+
+            if (reg & CSR0H_RxPktRdy) {
+                data_len = usb_read_count0(usb_id);
+                data_len = min(data_len, urb->setup.wLength);
+                usb_read_ep0(usb_id, urb->buffer, data_len);;
+                urb->buffer += data_len;
+                urb->setup.wLength -= data_len;
+                if (data_len < max_packet_size) {
+                    urb->setup.wLength = 0;
+                }
+                if (urb->setup.wLength) {
+                    usb_write_csr0(usb_id, CSR0H_ReqPkt);
+                } else {
+                    usb_write_csr0(usb_id, 0);
+                    break;
+                }
+            }
+        } else {
+            if (!(reg & CSR0H_TxPktRdy)) {
+                break;
+            }
+        }
+    }
+__exit:
+    usb_clr_intr_txe(usb_id, 0);
+    usb_dis_ep0_txdly(usb_id);
+    return ret;
+}
+/**
+ * @brief usb_control_transfers
+ *
+ * @param struct host_dev
+ * @param urb
+ *
+ * @return
+ */
+static int usb_control_transfers(struct usb_host_device *host_dev, struct ctlXfer *urb)
+{
+    usb_dev usb_id = host_device2id(host_dev);
+
+    int res;
+    /*SETUP*/
+
+    urb->stage = USB_PID_SETUP;		//SETUP transaction
+
+    res = usb_ctlXfer(host_dev, urb);
+
+    if (res) {
+        return res;
+    }
+
+    /*IN or OUT*/
+    urb->stage = USB_PID_IN;
+
+
+    while (urb->setup.wLength) {
+        if (urb->setup.bRequestType & USB_DIR_IN) {	//Request Direction
+            urb->stage = USB_PID_IN;	//IN transaction
+
+            res = usb_ctlXfer(host_dev, urb);
+
+            if (res) {
+                return res;
+            }
+
+            urb->stage = USB_PID_OUT;
+        } else {
+            urb->stage = USB_PID_OUT;	//OUT transaction
+
+            res = usb_ctlXfer(host_dev, urb);
+
+            if (res) {
+                return res;
+            }
+
+            urb->stage = USB_PID_IN;
+        }
+    }
+
+    res = usb_ctlXfer(host_dev, urb);
+
+    if (res) {
+        return res;
+    }
+
+    return DEV_ERR_NONE;
+}
+
+/**
+ * @brief usb_control_msg
+ *
+ * @param host_dev
+ * @param request
+ * @param requesttype
+ * @param value
+ * @param index
+ * @param data
+ * @param size
+ *
+ * @return
+ */
+static int usb_control_msg(struct usb_host_device *host_dev,
+                           u8 request, u8 requesttype,
+                           u16 value, u16 index,
+                           void *data, u16 size)
+{
+    struct ctlXfer urb;
+    urb.setup.bRequestType = requesttype;
+    urb.setup.bRequest = request;
+    urb.setup.wValue = cpu_to_le16(value);
+    urb.setup.wIndex = cpu_to_le16(index);
+    urb.setup.wLength = cpu_to_le16(size);
+    urb.buffer = data;
+
+    return usb_control_transfers(host_dev, &urb);
+
+}
+
+/**
+ * @brief usb_clear_feature
+ *
+ * @param host_dev
+ * @param ep
+ *
+ * @return
+ */
+int usb_clear_feature(struct usb_host_device *host_dev, u32 ep)
+{
+    return usb_control_msg(host_dev,  USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, ep, NULL, 0);
+}
+
+int set_address(struct usb_host_device *host_dev, u8 devnum)
+{
+    return usb_control_msg(host_dev, USB_REQ_SET_ADDRESS, 0,  devnum, 0, NULL, 0);
+}
+
+int usb_get_device_descriptor(struct usb_host_device *host_dev, struct usb_device_descriptor *desc)
+{
+    return usb_control_msg(host_dev,
+                           USB_REQ_GET_DESCRIPTOR,
+                           USB_DIR_IN,
+                           (USB_DT_DEVICE << 8),
+                           0,
+                           desc,
+                           USB_DT_DEVICE_SIZE
+                          );
+}
+
+int usb_get_string_descriptor(struct usb_host_device *host_dev, struct usb_device_descriptor *desc)
+{
+    int ret = DEV_ERR_NONE;
+#if 0
+    struct usb_private_data *private_data = host_dev->private_data ;
+    /**********get string language*********/
+    u8 buf[16];
+    memset(buf, 0x0, sizeof(buf));
+    ret = usb_control_msg(host_dev,
+                          USB_REQ_GET_DESCRIPTOR,
+                          USB_DIR_IN,
+                          (USB_DT_STRING << 8),
+                          0,
+                          desc,
+                          sizeof(buf)
+                         );
+    if (ret) {
+        return ret;
+    }
+    memcpy(&private_data->language, buf + 2, sizeof(private_data->language));
+
+    /**********get manufacturer string**********/
+    memset(private_data->manufacturer, 0x0, sizeof(private_data->manufacturer));
+    if (desc->iManufacturer) {
+        ret = usb_control_msg(host_dev,
+                              USB_REQ_GET_DESCRIPTOR,
+                              USB_DIR_IN,
+                              (USB_DT_STRING << 8) | desc->iManufacturer,
+                              0,
+                              private_data->manufacturer,
+                              sizeof(private_data->manufacturer)
+                             );
+        if (ret) {
+            return ret;
+        }
+    }
+    /**********get product string**********/
+    memset(private_data->product, 0x0, sizeof(private_data->product));
+    if (desc->iProduct) {
+        ret = usb_control_msg(host_dev,
+                              USB_REQ_GET_DESCRIPTOR,
+                              USB_DIR_IN,
+                              (USB_DT_STRING << 8) | desc->iProduct,
+                              0,
+                              private_data->product,
+                              sizeof(private_data->product)
+                             );
+        if (ret) {
+            return ret;
+        }
+    }
+#endif
+    return ret;
+}
+
+int set_configuration(struct usb_host_device *host_dev)
+{
+    return  usb_control_msg(host_dev, USB_REQ_SET_CONFIGURATION, 0, 1, 0, NULL, 0);
+}
+int set_configuration_add_value(struct usb_host_device *host_dev, u16 value)
+{
+    return  usb_control_msg(host_dev, USB_REQ_SET_CONFIGURATION, 0, value, 0, NULL, 0);
+}
+int get_config_descriptor(struct usb_host_device *host_dev, void *cfg_desc, u32 len)
+{
+    return usb_control_msg(host_dev,
+                           USB_REQ_GET_DESCRIPTOR,
+                           USB_DIR_IN,
+                           (USB_DT_CONFIG << 8),
+                           0,
+                           cfg_desc,
+                           len);
+}
+
+int get_config_descriptor_add_value_l(struct usb_host_device *host_dev, void *cfg_desc, u32 len, u8 value_l)
+{
+    return usb_control_msg(host_dev,
+                           USB_REQ_GET_DESCRIPTOR,
+                           USB_DIR_IN,
+                           (USB_DT_CONFIG << 8) | value_l,
+                           0,
+                           cfg_desc,
+                           len);
+}
+
+
+int get_msd_max_lun(struct usb_host_device *host_dev, void *lun)
+{
+    return usb_control_msg(host_dev,
+                           USB_MSD_MAX_LUN,
+                           USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                           0,
+                           0,
+                           lun,
+                           1);
+}
+int set_msd_reset(struct usb_host_device *host_dev)
+{
+    return usb_control_msg(host_dev,
+                           0xff,
+                           USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                           0,
+                           0,
+                           NULL,
+                           0);
+}
+
+int hid_set_idle(struct usb_host_device *host_dev, u32 id)
+{
+    return usb_control_msg(host_dev, 0x0a, 0x21, 0, id << 8, NULL, 0);
+}
+int hid_get_report(struct usb_host_device *host_dev, u8 *report, u8 report_id, u16 report_len)
+{
+    return usb_control_msg(host_dev,
+                           USB_REQ_GET_DESCRIPTOR,
+                           USB_DIR_IN | USB_RECIP_INTERFACE,
+                           0x2200,
+                           report_id,
+                           report,
+                           report_len);
+}
+int hid_set_output_report(struct usb_host_device *host_dev, u8 *report, u8 report_id, u8 report_len)
+{
+    return usb_control_msg(host_dev,
+                           0x09,
+                           USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                           0x0201,
+                           report_id,
+                           report,
+                           report_len);
+}
+int usb_set_remote_wakeup(struct usb_host_device *host_dev)
+{
+    return usb_control_msg(host_dev, USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
+                           USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0);
+}
+int get_device_status(struct usb_host_device *host_dev)
+{
+    u16 status;
+    return usb_control_msg(host_dev, USB_REQ_GET_STATUS, USB_DIR_IN, 0, 0, (u8 *)&status, 2);
+}
+int usb_get_device_qualifier(struct usb_host_device *host_dev, u8 *buffer)
+{
+    return usb_control_msg(host_dev,
+                           USB_REQ_GET_DESCRIPTOR,
+                           USB_DIR_IN,
+                           (USB_DT_DEVICE_QUALIFIER << 8),
+                           0,
+                           buffer,
+                           0x0a);
+
+}
+#define     AOA_CMD51   0x33
+#define     AOA_CMD52   0x34
+#define     AOA_CMD53   0x35
+
+
+
+
+int usb_get_aoa_version(struct usb_host_device *host_dev, u16 *version)
+{
+    return usb_control_msg(host_dev,
+                           AOA_CMD51,
+                           USB_DIR_IN | USB_TYPE_VENDOR,
+                           0,
+                           0,
+                           version,
+                           2);
+}
+int usb_set_credentials(struct usb_host_device *host_dev, const char *string, int index)
+{
+    return usb_control_msg(host_dev,
+                           AOA_CMD52,
+                           USB_DIR_OUT | USB_TYPE_VENDOR,
+                           0,
+                           index,
+                           (u8 *)string,
+                           strlen(string));
+}
+int usb_switch2aoa(struct usb_host_device *host_dev)
+{
+    return usb_control_msg(host_dev,
+                           AOA_CMD53,
+                           USB_DIR_OUT | USB_TYPE_VENDOR,
+                           0,
+                           0,
+                           NULL,
+                           0);
+}
+int usb_switch2slave(struct usb_host_device *host_dev)
+{
+    return usb_control_msg(host_dev,
+                           0x51,
+                           USB_DIR_OUT | USB_TYPE_VENDOR,
+                           0,
+                           0,
+                           NULL,
+                           0);
+}
+/* Control request for registering a HID device.
+ * Upon registering, a unique ID is sent by the accessory in the
+ * value parameter. This ID will be used for future commands for
+ * the device
+ *
+ *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+ *  request:        ACCESSORY_REGISTER_HID_DEVICE
+ *  value:          Accessory assigned ID for the HID device
+ *  index:          total length of the HID report descriptor
+ *  data            none
+ */
+#define ACCESSORY_REGISTER_HID         54
+int usb_aoa_register_hid(struct usb_host_device *host_dev, u16 value, u16 index)
+{
+    return usb_control_msg(host_dev,
+                           ACCESSORY_REGISTER_HID,
+                           USB_DIR_OUT | USB_TYPE_VENDOR,
+                           value,
+                           index,
+                           NULL,
+                           0);
+}
+/* Control request for unregistering a HID device.
+ *
+ *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+ *  request:        ACCESSORY_REGISTER_HID
+ *  value:          Accessory assigned ID for the HID device
+ *  index:          0
+ *  data            none
+ */
+#define ACCESSORY_UNREGISTER_HID         55
+int usb_aoa_unregister_hid(struct usb_host_device *host_dev, u16 value)
+{
+    return usb_control_msg(host_dev,
+                           ACCESSORY_UNREGISTER_HID,
+                           USB_DIR_OUT | USB_TYPE_VENDOR,
+                           value,
+                           0,
+                           NULL,
+                           0);
+}
+
+/* Control request for sending the HID report descriptor.
+ * If the HID descriptor is longer than the endpoint zero max packet size,
+ * the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
+ * commands. The data for the descriptor must be sent sequentially
+ * if multiple packets are needed.
+ *
+ *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+ *  request:        ACCESSORY_SET_HID_REPORT_DESC
+ *  value:          Accessory assigned ID for the HID device
+ *  index:          offset of data in descriptor
+ *                      (needed when HID descriptor is too big for one packet)
+ *  data            the HID report descriptor
+ */
+#define ACCESSORY_SET_HID_REPORT_DESC         56
+int usb_aoa_set_hid_report_desc(struct usb_host_device *host_dev, u16 value, u16 offset, const char *pbuf, u32 len)
+{
+    return usb_control_msg(host_dev,
+                           ACCESSORY_SET_HID_REPORT_DESC,
+                           USB_DIR_OUT | USB_TYPE_VENDOR,
+                           value,
+                           offset,
+                           (u8 *)pbuf,
+                           len);
+}
+
+/* Control request for sending HID events.
+ *
+ *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+ *  request:        ACCESSORY_SEND_HID_EVENT
+ *  value:          Accessory assigned ID for the HID device
+ *  index:          0
+ *  data            the HID report for the event
+ */
+#define ACCESSORY_SEND_HID_EVENT         57
+int usb_aoa_send_hid_event(struct usb_host_device *host_dev, u16 value, const u8 *pbuf, u32 len)
+{
+    return usb_control_msg(host_dev,
+                           ACCESSORY_SEND_HID_EVENT,
+                           USB_DIR_OUT | USB_TYPE_VENDOR,
+                           value,
+                           0,
+                           (u8 *)pbuf,
+                           len);
+}
+int get_ms_extended_compat_id(struct usb_host_device *host_dev,  u8 *buffer)
+{
+    return usb_control_msg(host_dev,
+                           0x01,
+                           USB_DIR_IN | USB_RECIP_DEVICE | USB_TYPE_VENDOR,
+                           0x0000,
+                           4,
+                           buffer,
+                           0x28);
+}
+
+
+int usb_set_interface(struct usb_host_device *host_dev, u8 interface, u8 alternateSetting)
+{
+    log_info("%s Set Interface:%d AlternateSetting:%d", __func__, interface, alternateSetting);
+    return usb_control_msg(host_dev,
+                           USB_REQ_SET_INTERFACE,
+                           USB_RECIP_INTERFACE,
+                           alternateSetting,
+                           interface,
+                           NULL,
+                           0);
+
+}
+
+int usb_audio_sampling_frequency_control(struct usb_host_device *host_dev, u32 ep, u32 sampe_rate)
+{
+    log_info("%s ep:%d sampe_rate:%d", __func__, ep, sampe_rate);
+    return usb_control_msg(host_dev,
+                           1,
+                           USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
+                           0x0100,
+                           ep,
+                           &sampe_rate,
+                           3);
+}
+int usb_audio_volume_control(struct usb_host_device *host_dev, u8 feature_id, u8 channel_num, u16 volume)
+{
+    log_info("%s featureID:%d vol:%x", __func__, feature_id, volume);
+    return usb_control_msg(host_dev,
+                           1,
+                           USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                           (0x02 << 8) | channel_num,
+                           feature_id << 8,
+                           &volume,
+                           2);
+}
+int usb_audio_mute_control(struct usb_host_device *host_dev, u8 feature_id, u8 mute)
+{
+    log_info("%s featureID:%d mute:%d", __func__, feature_id, mute);
+    return usb_control_msg(host_dev,
+                           1,
+                           USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                           0x0100,
+                           feature_id << 8,
+                           &mute,
+                           1);
+}
+#endif

+ 380 - 0
apps/common/device/usb/host/usb_ctrl_transfer.h

@@ -0,0 +1,380 @@
+/**@file        usb_ctrl_transfer.h
+  * @brief      usb_ctrl_transfer控制传输头文件
+  * @details    功能函数声明
+  * @author     jieli
+  * @date       2021-8-1
+  * @version    V1.0
+  * @copyright  Copyright(c)2010-2021   珠海市杰理科技股份有限公司
+  *********************************************************
+  * @attention
+  * 硬件平台:AC695N
+  * SDK版本:AC695N_V1.0.0_SDK
+  * @修改日志:
+  * <table>
+  * <tr><th>Date        <th>Version     <th>Author      <th>Description
+  * <tr><td>2021-8-1    <td>1.0         <td>jieli       <td>创建初始版本
+  * </table>
+  *
+  *********************************************************
+  */
+#ifndef __USB_CTRL_TRANSFER_H__
+#define __USB_CTRL_TRANSFER_H__
+
+#include "usb/ch9.h"
+#include "usb/usb_phy.h"
+#include "device/device.h"
+#include "usb_config.h"
+
+
+/*
+ * USB Packet IDs (PIDs)
+ */
+#define USB_PID_EXT			0xf0	/* USB 2.0 LPM ECN */
+#define USB_PID_OUT			0xe1
+#define USB_PID_ACK			0xd2
+#define USB_PID_DATA0			0xc3
+#define USB_PID_PING			0xb4	/* USB 2.0 */
+#define USB_PID_SOF			0xa5
+#define USB_PID_NYET			0x96	/* USB 2.0 */
+#define USB_PID_DATA2			0x87	/* USB 2.0 */
+#define USB_PID_SPLIT			0x78	/* USB 2.0 */
+#define USB_PID_IN			0x69
+#define USB_PID_NAK			0x5a
+#define USB_PID_DATA1			0x4b
+#define USB_PID_PREAMBLE		0x3c	/* Token mode */
+#define USB_PID_ERR			0x3c	/* USB 2.0: handshake mode */
+#define USB_PID_SETUP			0x2d
+#define USB_PID_STALL			0x1e
+#define USB_PID_MDATA			0x0f	/* USB 2.0 */
+
+
+
+struct ctlXfer {
+    struct usb_ctrlrequest setup; ///<控制请求
+    void *buffer; ///<控制请求的data
+    u8  stage; ///<当前状态
+};
+
+
+/**@brief   USB清除或禁用特定的特性
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  ep 端点号
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_clear_feature(host_dev , ep);
+  * @encode
+  */
+int usb_clear_feature(struct usb_host_device *usb_dev, u32 ep);
+
+/**@brief   USB设置地址
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  devnum 设备编号
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * set_address(host_dev , ep);
+  * @encode
+  */
+int set_address(struct usb_host_device *usb_dev, u8 devnum);
+
+/**@brief   USB获取设备描述符
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  usb_device_descriptor定义的结构体指针
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_get_device_descriptor(host_dev , device_desc);
+  * @encode
+  */
+int usb_get_device_descriptor(struct usb_host_device *usb_dev, struct usb_device_descriptor *desc);
+
+/**@brief   USB获取字符串描述符
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  usb_device_descriptor定义的结构体指针
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_get_string_descriptor(host_dev , device_desc);
+  * @encode
+  */
+int usb_get_string_descriptor(struct usb_host_device *usb_dev, struct usb_device_descriptor *desc);
+
+/**@brief   USB设置相关配置
+  * @param[in]  usb_host_device定义的结构体指针
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * set_configuration(host_dev);
+  * @encode
+  */
+int set_configuration(struct usb_host_device *usb_dev);
+
+/**@brief   USB设置相关配置,添加相关参数
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  value 当前请求的参数
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * set_configuration_add_value(host_dev , value);
+  * @encode
+  */
+int set_configuration_add_value(struct usb_host_device *host_dev, u16 value);
+
+/**@brief   USB获取配置描述符
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  cfg_desc 自定义的配置描述符指针
+  * @param[in]  len 长度
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * get_config_descriptor(host_dev , cfg_desc , len);
+  * @encode
+  */
+int get_config_descriptor(struct usb_host_device *usb_dev, void *cfg_desc, u32 len);
+
+/**@brief   USB获取配置描述符,添加相关参数
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  cfg_desc 自定义的配置描述符指针
+  * @param[in]  len 长度
+  * @param[in]  value_l 请求的参数
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * get_config_descriptor_add_value_l(host_dev , cfg_desc , len , value_l);
+  * @encode
+  */
+int get_config_descriptor_add_value_l(struct usb_host_device *host_dev, void *cfg_desc, u32 len, u8 value_l);
+
+/**@brief   USB获取大容量存储设备的最大逻辑单元号
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  lun 逻辑单元号
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * get_msd_max_lun(host_dev , lun);
+  * @encode
+  */
+int get_msd_max_lun(struct usb_host_device *usb_dev, void *lun);
+
+/**@brief   USB设置大容量存储设备复位
+  * @param[in]  usb_host_device定义的结构体指针
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * set_msd_reset(host_dev);
+  * @encode
+  */
+int set_msd_reset(struct usb_host_device *usb_dev);
+
+/**@brief   hid设置为空闲模式
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  id 指定接口或端点号
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * hid_set_idle(host_dev , id);
+  * @encode
+  */
+int hid_set_idle(struct usb_host_device *usb_dev, u32 id);
+
+/**@brief   hid获取报告描述符
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  report 自定义报告指针,指向报告内容
+  * @param[in]  report_id 报告描述符id号
+  * @param[in]  report_len 报告描述符长度
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * hid_get_report(host_dev , report , report_id , report_len);
+  * @encode
+  */
+int hid_get_report(struct usb_host_device *usb_dev, u8 *report, u8 report_id, u16 report_len);
+
+/**@brief   hid设置输出报告描述符
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  report 自定义报告指针,指向报告内容
+  * @param[in]  report_id
+  * @param[in]  report_len
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * hid_set_output_report(host_dev , report , report_id , report_len);
+  * @encode
+  */
+int hid_set_output_report(struct usb_host_device *usb_dev, u8 *report, u8 report_id, u8 report_len);
+
+/**@brief   USB设置远程唤醒
+  * @param[in]  usb_host_device定义的结构体指针
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_set_remote_wakeup(host_dev);
+  * @encode
+  */
+int usb_set_remote_wakeup(struct usb_host_device *usb_dev);
+
+/**@brief   USB获取设备状态
+  * @param[in]  usb_host_device定义的结构体指针
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * get_device_status(host_dev);
+  * @encode
+  */
+int get_device_status(struct usb_host_device *usb_dev);
+
+/**@brief   USB获取设备限定描述符
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  BUFFER 自定义的指针,指向限定描述符内容
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_get_device_qualifier(host_dev , buffer);
+  * @encode
+  */
+int usb_get_device_qualifier(struct usb_host_device *usb_dev, u8 *buffer);
+
+/**@brief   USB获取安卓aoa协议版本
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  version 自定义的指针,指向版本内容
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_get_aoa_version(host_dev , version);
+  * @encode
+  */
+int usb_get_aoa_version(struct usb_host_device *host_dev, u16 *version);
+
+/**@brief   USB设置证书信息
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  string 字符串指针,指向证书内容
+  * @param[in]  index 传递的参数
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_set_credentials(host_dev , string , index);
+  * @encode
+  */
+int usb_set_credentials(struct usb_host_device *host_dev, const char *string, int index);
+
+/**@brief   USB设置aoa开关
+  * @param[in]  usb_host_device定义的结构体指针
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_switch2aoa(host_dev);
+  * @encode
+  */
+int usb_switch2aoa(struct usb_host_device *host_dev);
+
+/**@brief   USB设置从机模式开关
+  * @param[in]  usb_host_device定义的结构体指针
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_switch2slave(host_dev);
+  * @encode
+  */
+int usb_switch2slave(struct usb_host_device *host_dev);
+
+/**@brief   USB hid设备注册
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  value 请求的参数
+  * @param[in]  index 传递的参数
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_aoa_register_hid(host_dev , value , index);
+  * @encode
+  */
+int usb_aoa_register_hid(struct usb_host_device *host_dev, u16 value, u16 index);
+
+/**@brief   USB设置hid报告描述符
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  value 请求的参数
+  * @param[in]  offset 偏移量参数
+  * @param[in]  pbuf 存放数据的BUFFER指针
+  * @param[in]  len 长度
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_aoa_set_hid_report_desc(host_dev , value , offset , *pbuf , len);
+  * @encode
+  */
+int usb_aoa_set_hid_report_desc(struct usb_host_device *host_dev, u16 value, u16 offset, const char *pbuf, u32 len);
+
+/**@brief   USB发送hid事件
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  value 请求的参数
+  * @param[in]  pbuf 存放数据的BUFFER指针
+  * @param[in]  len 长度
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_aoa_send_hid_event(host_dev , value , *pbuf , len);
+  * @encode
+  */
+int usb_aoa_send_hid_event(struct usb_host_device *host_dev, u16 value, const u8 *pbuf, u32 len);
+
+/**@brief   获取扩展的大容量存储设备(可兼容)id 号
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  BUFFER 存放数据的BUFFER
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * get_ms_extended_compat_id(host_dev , value , *pbuf , len);
+  * @encode
+  */
+int get_ms_extended_compat_id(struct usb_host_device *host_dev,  u8 *buffer);
+
+/**@brief   USB设置接口
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  interface 接口参数(请求的参数)
+  * @param[in]  alternateSetting 交替设置(传递的参数)
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_set_interface(host_dev , interface , alternateSetting);
+  * @encode
+  */
+int usb_set_interface(struct usb_host_device *host_dev, u8 interface, u8 alternateSetting);
+
+/**@brief   USB音频采样频率控制
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  ep 端点号
+  * @param[in]  samp_rate 采样率
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_audio_sampling_frequency_control(host_dev , ep , sampe_rate);
+  * @encode
+  */
+int usb_audio_sampling_frequency_control(struct usb_host_device *host_dev, u32 ep, u32 sampe_rate);
+
+/**@brief   USB音频音量控制
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  feature_id 特征值id号(端点或接口的id)(传递的参数)
+  * @param[in]  channel_num 通道编号(请求的参数)
+  * @paeam[in]  volume 音量
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_audio_volume_control(host_dev , feature_id , channel_num , volume);
+  * @encode
+  */
+int usb_audio_volume_control(struct usb_host_device *host_dev, u8 feature_id, u8 channel_num, u16 volume);
+
+/**@brief   USB音频静音控制
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  feature_id 特征值id号(端点或接口的id)(传递的参数)
+  * @param[in]  mute 静音信号(静音标志)
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * usb_audio_mute_control(host_dev , feature_id , channel_num , volume);
+  * @encode
+  */
+int usb_audio_mute_control(struct usb_host_device *host_dev, u8 feature_id, u8 mute);
+
+#endif

+ 363 - 0
apps/common/device/usb/host/usb_hid_keys.h

@@ -0,0 +1,363 @@
+/**
+ * USB HID Keyboard scan codes as per USB spec 1.11
+ * plus some additional codes
+ *
+ * Created by MightyPork, 2016
+ * Public domain
+ *
+ * Adapted from:
+ * https://source.android.com/devices/input/keyboard-devices.html
+ */
+
+#ifndef USB_HID_KEYS
+#define USB_HID_KEYS
+
+struct keyboard_data_t {
+    u8 fun_key;
+    u8 res;
+    u8 Keypad[6];
+} _GNU_PACKED_	;
+
+struct mouse_data_t {
+    u8 btn;
+    s16 x;
+    s16 y;
+    s8 wheel;
+    s8 ac_pan;
+} _GNU_PACKED_	;
+struct point_t {
+    u8 tip_switch: 2;
+    /* u8 in_range: 1; */
+    u8 res: 2;
+    u8 cid: 4;
+    s16 x;
+    s16 y;
+} _GNU_PACKED_ ;
+
+struct touch_screen_t {
+    struct point_t p[3];
+} _GNU_PACKED_;
+
+struct mouse_point_t {
+    u8 btn;
+    s8 x;
+    s8 y;
+    s8 wheel;
+} _GNU_PACKED_;
+/**
+ * Modifier masks - used for the first byte in the HID report.
+ * NOTE: The second byte in the report is reserved, 0x00
+ */
+#define _KEY_MOD_LCTRL  0x01
+#define _KEY_MOD_LSHIFT 0x02
+#define _KEY_MOD_LALT   0x04
+#define _KEY_MOD_LMETA  0x08
+#define _KEY_MOD_RCTRL  0x10
+#define _KEY_MOD_RSHIFT 0x20
+#define _KEY_MOD_RALT   0x40
+#define _KEY_MOD_RMETA  0x80
+
+/**
+ * Scan codes - last N slots in the HID report (usually 6).
+ * 0x00 if no key pressed.
+ *
+ * If more than N keys are pressed, the HID reports
+ * KEY_ERR_OVF in all slots to indicate this condition.
+ */
+
+#define _KEY_NONE 0x00 // No key pressed
+#define _KEY_ERR_OVF 0x01 //  Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key")
+// 0x02 //  Keyboard POST Fail
+// 0x03 //  Keyboard Error Undefined
+#define _KEY_A 0x04 // Keyboard a and A
+#define _KEY_B 0x05 // Keyboard b and B
+#define _KEY_C 0x06 // Keyboard c and C
+#define _KEY_D 0x07 // Keyboard d and D
+#define _KEY_E 0x08 // Keyboard e and E
+#define _KEY_F 0x09 // Keyboard f and F
+#define _KEY_G 0x0a // Keyboard g and G
+#define _KEY_H 0x0b // Keyboard h and H
+#define _KEY_I 0x0c // Keyboard i and I
+#define _KEY_J 0x0d // Keyboard j and J
+#define _KEY_K 0x0e // Keyboard k and K
+#define _KEY_L 0x0f // Keyboard l and L
+#define _KEY_M 0x10 // Keyboard m and M
+#define _KEY_N 0x11 // Keyboard n and N
+#define _KEY_O 0x12 // Keyboard o and O
+#define _KEY_P 0x13 // Keyboard p and P
+#define _KEY_Q 0x14 // Keyboard q and Q
+#define _KEY_R 0x15 // Keyboard r and R
+#define _KEY_S 0x16 // Keyboard s and S
+#define _KEY_T 0x17 // Keyboard t and T
+#define _KEY_U 0x18 // Keyboard u and U
+#define _KEY_V 0x19 // Keyboard v and V
+#define _KEY_W 0x1a // Keyboard w and W
+#define _KEY_X 0x1b // Keyboard x and X
+#define _KEY_Y 0x1c // Keyboard y and Y
+#define _KEY_Z 0x1d // Keyboard z and Z
+
+#define _KEY_1 0x1e // Keyboard 1 and !
+#define _KEY_2 0x1f // Keyboard 2 and @
+#define _KEY_3 0x20 // Keyboard 3 and #
+#define _KEY_4 0x21 // Keyboard 4 and $
+#define _KEY_5 0x22 // Keyboard 5 and %
+#define _KEY_6 0x23 // Keyboard 6 and ^
+#define _KEY_7 0x24 // Keyboard 7 and &
+#define _KEY_8 0x25 // Keyboard 8 and *
+#define _KEY_9 0x26 // Keyboard 9 and (
+#define _KEY_0 0x27 // Keyboard 0 and )
+
+#define _KEY_ENTER 0x28 // Keyboard Return (ENTER)
+#define _KEY_ESC 0x29 // Keyboard ESCAPE
+#define _KEY_BACKSPACE 0x2a // Keyboard DELETE (Backspace)
+#define _KEY_TAB 0x2b // Keyboard Tab
+#define _KEY_SPACE 0x2c // Keyboard Spacebar
+#define _KEY_MINUS 0x2d // Keyboard - and _
+#define _KEY_EQUAL 0x2e // Keyboard = and +
+#define _KEY_LEFTBRACE 0x2f // Keyboard [ and {
+#define _KEY_RIGHTBRACE 0x30 // Keyboard ] and }
+#define _KEY_BACKSLASH 0x31 // Keyboard \ and |
+#define _KEY_HASHTILDE 0x32 // Keyboard Non-US # and ~
+#define _KEY_SEMICOLON 0x33 // Keyboard ; and :
+#define _KEY_APOSTROPHE 0x34 // Keyboard ' and "
+#define _KEY_GRAVE 0x35 // Keyboard ` and ~
+#define _KEY_COMMA 0x36 // Keyboard , and <
+#define _KEY_DOT 0x37 // Keyboard . and >
+#define _KEY_SLASH 0x38 // Keyboard / and ?
+#define _KEY_CAPSLOCK 0x39 // Keyboard Caps Lock
+
+#define _KEY_F1 0x3a // Keyboard F1
+#define _KEY_F2 0x3b // Keyboard F2
+#define _KEY_F3 0x3c // Keyboard F3
+#define _KEY_F4 0x3d // Keyboard F4
+#define _KEY_F5 0x3e // Keyboard F5
+#define _KEY_F6 0x3f // Keyboard F6
+#define _KEY_F7 0x40 // Keyboard F7
+#define _KEY_F8 0x41 // Keyboard F8
+#define _KEY_F9 0x42 // Keyboard F9
+#define _KEY_F10 0x43 // Keyboard F10
+#define _KEY_F11 0x44 // Keyboard F11
+#define _KEY_F12 0x45 // Keyboard F12
+
+#define _KEY_SYSRQ 0x46 // Keyboard Print Screen
+#define _KEY_SCROLLLOCK 0x47 // Keyboard Scroll Lock
+#define _KEY_PAUSE 0x48 // Keyboard Pause
+#define _KEY_INSERT 0x49 // Keyboard Insert
+#define _KEY_HOME 0x4a // Keyboard Home
+#define _KEY_PAGEUP 0x4b // Keyboard Page Up
+#define _KEY_DELETE 0x4c // Keyboard Delete Forward
+#define _KEY_END 0x4d // Keyboard End
+#define _KEY_PAGEDOWN 0x4e // Keyboard Page Down
+#define _KEY_RIGHT 0x4f // Keyboard Right Arrow
+#define _KEY_LEFT 0x50 // Keyboard Left Arrow
+#define _KEY_DOWN 0x51 // Keyboard Down Arrow
+#define _KEY_UP 0x52 // Keyboard Up Arrow
+
+#define _KEY_NUMLOCK 0x53 // Keyboard Num Lock and Clear
+#define _KEY_KPSLASH 0x54 // Keypad /
+#define _KEY_KPASTERISK 0x55 // Keypad *
+#define _KEY_KPMINUS 0x56 // Keypad -
+#define _KEY_KPPLUS 0x57 // Keypad +
+#define _KEY_KPENTER 0x58 // Keypad ENTER
+#define _KEY_KP1 0x59 // Keypad 1 and End
+#define _KEY_KP2 0x5a // Keypad 2 and Down Arrow
+#define _KEY_KP3 0x5b // Keypad 3 and PageDn
+#define _KEY_KP4 0x5c // Keypad 4 and Left Arrow
+#define _KEY_KP5 0x5d // Keypad 5
+#define _KEY_KP6 0x5e // Keypad 6 and Right Arrow
+#define _KEY_KP7 0x5f // Keypad 7 and Home
+#define _KEY_KP8 0x60 // Keypad 8 and Up Arrow
+#define _KEY_KP9 0x61 // Keypad 9 and Page Up
+#define _KEY_KP0 0x62 // Keypad 0 and Insert
+#define _KEY_KPDOT 0x63 // Keypad . and Delete
+
+#define _KEY_102ND 0x64 // Keyboard Non-US \ and |
+#define _KEY_COMPOSE 0x65 // Keyboard Application
+#define _KEY_POWER 0x66 // Keyboard Power
+#define _KEY_KPEQUAL 0x67 // Keypad =
+
+#define _KEY_F13 0x68 // Keyboard F13
+#define _KEY_F14 0x69 // Keyboard F14
+#define _KEY_F15 0x6a // Keyboard F15
+#define _KEY_F16 0x6b // Keyboard F16
+#define _KEY_F17 0x6c // Keyboard F17
+#define _KEY_F18 0x6d // Keyboard F18
+#define _KEY_F19 0x6e // Keyboard F19
+#define _KEY_F20 0x6f // Keyboard F20
+#define _KEY_F21 0x70 // Keyboard F21
+#define _KEY_F22 0x71 // Keyboard F22
+#define _KEY_F23 0x72 // Keyboard F23
+#define _KEY_F24 0x73 // Keyboard F24
+
+#define _KEY_OPEN 0x74 // Keyboard Execute
+#define _KEY_HELP 0x75 // Keyboard Help
+#define _KEY_PROPS 0x76 // Keyboard Menu
+#define _KEY_FRONT 0x77 // Keyboard Select
+#define _KEY_STOP 0x78 // Keyboard Stop
+#define _KEY_AGAIN 0x79 // Keyboard Again
+#define _KEY_UNDO 0x7a // Keyboard Undo
+#define _KEY_CUT 0x7b // Keyboard Cut
+#define _KEY_COPY 0x7c // Keyboard Copy
+#define _KEY_PASTE 0x7d // Keyboard Paste
+#define _KEY_FIND 0x7e // Keyboard Find
+#define _KEY_MUTE 0x7f // Keyboard Mute
+#define _KEY_VOLUMEUP 0x80 // Keyboard Volume Up
+#define _KEY_VOLUMEDOWN 0x81 // Keyboard Volume Down
+// 0x82  Keyboard Locking Caps Lock
+// 0x83  Keyboard Locking Num Lock
+// 0x84  Keyboard Locking Scroll Lock
+#define _KEY_KPCOMMA 0x85 // Keypad Comma
+// 0x86  Keypad Equal Sign
+#define _KEY_RO 0x87 // Keyboard International1
+#define _KEY_KATAKANAHIRAGANA 0x88 // Keyboard International2
+#define _KEY_YEN 0x89 // Keyboard International3
+#define _KEY_HENKAN 0x8a // Keyboard International4
+#define _KEY_MUHENKAN 0x8b // Keyboard International5
+#define _KEY_KPJPCOMMA 0x8c // Keyboard International6
+// 0x8d  Keyboard International7
+// 0x8e  Keyboard International8
+// 0x8f  Keyboard International9
+#define _KEY_HANGEUL 0x90 // Keyboard LANG1
+#define _KEY_HANJA 0x91 // Keyboard LANG2
+#define _KEY_KATAKANA 0x92 // Keyboard LANG3
+#define _KEY_HIRAGANA 0x93 // Keyboard LANG4
+#define _KEY_ZENKAKUHANKAKU 0x94 // Keyboard LANG5
+// 0x95  Keyboard LANG6
+// 0x96  Keyboard LANG7
+// 0x97  Keyboard LANG8
+// 0x98  Keyboard LANG9
+// 0x99  Keyboard Alternate Erase
+// 0x9a  Keyboard SysReq/Attention
+// 0x9b  Keyboard Cancel
+// 0x9c  Keyboard Clear
+// 0x9d  Keyboard Prior
+// 0x9e  Keyboard Return
+// 0x9f  Keyboard Separator
+// 0xa0  Keyboard Out
+// 0xa1  Keyboard Oper
+// 0xa2  Keyboard Clear/Again
+// 0xa3  Keyboard CrSel/Props
+// 0xa4  Keyboard ExSel
+
+// 0xb0  Keypad 00
+// 0xb1  Keypad 000
+// 0xb2  Thousands Separator
+// 0xb3  Decimal Separator
+// 0xb4  Currency Unit
+// 0xb5  Currency Sub-unit
+#define _KEY_KPLEFTPAREN 0xb6 // Keypad (
+#define _KEY_KPRIGHTPAREN 0xb7 // Keypad )
+// 0xb8  Keypad {
+// 0xb9  Keypad }
+// 0xba  Keypad Tab
+// 0xbb  Keypad Backspace
+// 0xbc  Keypad A
+// 0xbd  Keypad B
+// 0xbe  Keypad C
+// 0xbf  Keypad D
+// 0xc0  Keypad E
+// 0xc1  Keypad F
+// 0xc2  Keypad XOR
+// 0xc3  Keypad ^
+// 0xc4  Keypad %
+// 0xc5  Keypad <
+// 0xc6  Keypad >
+// 0xc7  Keypad &
+// 0xc8  Keypad &&
+// 0xc9  Keypad |
+// 0xca  Keypad ||
+// 0xcb  Keypad :
+// 0xcc  Keypad #
+// 0xcd  Keypad Space
+// 0xce  Keypad @
+// 0xcf  Keypad !
+// 0xd0  Keypad Memory Store
+// 0xd1  Keypad Memory Recall
+// 0xd2  Keypad Memory Clear
+// 0xd3  Keypad Memory Add
+// 0xd4  Keypad Memory Subtract
+// 0xd5  Keypad Memory Multiply
+// 0xd6  Keypad Memory Divide
+// 0xd7  Keypad +/-
+// 0xd8  Keypad Clear
+// 0xd9  Keypad Clear Entry
+// 0xda  Keypad Binary
+// 0xdb  Keypad Octal
+// 0xdc  Keypad Decimal
+// 0xdd  Keypad Hexadecimal
+
+#define _KEY_LEFTCTRL 0xe0 // Keyboard Left Control
+#define _KEY_LEFTSHIFT 0xe1 // Keyboard Left Shift
+#define _KEY_LEFTALT 0xe2 // Keyboard Left Alt
+#define _KEY_LEFTMETA 0xe3 // Keyboard Left GUI
+#define _KEY_RIGHTCTRL 0xe4 // Keyboard Right Control
+#define _KEY_RIGHTSHIFT 0xe5 // Keyboard Right Shift
+#define _KEY_RIGHTALT 0xe6 // Keyboard Right Alt
+#define _KEY_RIGHTMETA 0xe7 // Keyboard Right GUI
+
+#define _KEY_MEDIA_PLAYPAUSE 0xe8
+#define _KEY_MEDIA_STOPCD 0xe9
+#define _KEY_MEDIA_PREVIOUSSONG 0xea
+#define _KEY_MEDIA_NEXTSONG 0xeb
+#define _KEY_MEDIA_EJECTCD 0xec
+#define _KEY_MEDIA_VOLUMEUP 0xed
+#define _KEY_MEDIA_VOLUMEDOWN 0xee
+#define _KEY_MEDIA_MUTE 0xef
+#define _KEY_MEDIA_WWW 0xf0
+#define _KEY_MEDIA_BACK 0xf1
+#define _KEY_MEDIA_FORWARD 0xf2
+#define _KEY_MEDIA_STOP 0xf3
+#define _KEY_MEDIA_FIND 0xf4
+#define _KEY_MEDIA_SCROLLUP 0xf5
+#define _KEY_MEDIA_SCROLLDOWN 0xf6
+#define _KEY_MEDIA_EDIT 0xf7
+#define _KEY_MEDIA_SLEEP 0xf8
+#define _KEY_MEDIA_COFFEE 0xf9
+#define _KEY_MEDIA_REFRESH 0xfa
+#define _KEY_MEDIA_CALC 0xfb
+
+#define _KEY_CUSTOM_CTRL_VOL_UP         0x00e9
+#define _KEY_CUSTOM_CTRL_VOL_DOWN       0x00ea
+#define _KEY_CUSTOM_CTRL_MUTE           0x00e2
+#define _KEY_CUSTOM_CTRL_FORWARD        0x00b5
+#define _KEY_CUSTOM_CTRL_STOP           0x00cd
+#define _KEY_CUSTOM_CTRL_BACK           0x00b6
+#define _KEY_CUSTOM_CTRL_MUSIC          0x0183
+#define _KEY_CUSTOM_CTRL_CALCULATOR     0x0192
+#define _KEY_CUSTOM_CTRL_SEARCH         0x0221
+#define _KEY_CUSTOM_CTRL_EMAIL          0x018A
+#define _KEY_CUSTOM_CTRL_HOME           0x0223
+#define _KEY_CUSTOM_CTRL_RETURN         0x0224
+#define _KEY_BRIGHTNESS_INCREASE        0x006F
+#define _KEY_BRIGHTNESS_REDUCTION       0x0070
+#define _KEY_ZOOM_IN                    0x022D
+#define _KEY_ZOOM_OUT                   0x022E
+#define _KEY_CUSTOM_COPY                0x021B
+#define _KEY_CUSTOM_CUT                 0x021C
+#define _KEY_CUSTOM_PASTE               0x021D
+#define _KEY_CUSTOM_SELECT_ALL          0x021E
+#define _KEY_CUSTOM_SPLIT_SCREEN        0x0196
+#define _KEY_CUSTOM_LOCK                0x0030
+#define _KEY_CUSTOM_ESC                 0x0223
+#define _KEY_CUSTOM_CALENDAR            0x018e
+#define _KEY_CUSTOM_MESSAGE             0X018d
+
+#define _KEY_CUSTOM_BROWER              0x0231
+#define _KEY_CUSTOM_PROCESS             0x023a
+
+#define _KEY_CUSTOM_SET                 0x029b
+
+#define _KEY_VIRTUAL_KEYBBOARD          0x0307
+
+#define _KEY_CUSTOM_SELECT_ALL_TEST     0x0004
+#define _KEY_CUSTOM_COPY_TEST           0x0006
+#define _KEY_CUSTOM_PASTE_TEST          0x0019
+#define _KEY_CUSTOM_CUT_TEST            0x001B
+#define _KEY_CHANGE_LANGUAGE_TEST       0x2C00
+
+
+#define LED_NUM_LOCK     0x01
+#define LED_CAPS_LOCK    0x02
+#define LED_SCROLL_CLOCK 0x04
+#endif
+

+ 744 - 0
apps/common/device/usb/host/usb_host.c

@@ -0,0 +1,744 @@
+#include "includes.h"
+#include "app_config.h"
+#include "device_drive.h"
+/* #include "os/os_compat.h" */
+#if USB_HOST_ENABLE
+#include "usb_config.h"
+#include "usb/host/usb_host.h"
+#include "usb/usb_phy.h"
+#include "usb_ctrl_transfer.h"
+#include "usb_storage.h"
+#include "adb.h"
+#include "aoa.h"
+#include "hid.h"
+#include "audio.h"
+
+#if TCFG_USB_APPLE_DOCK_EN
+#include "apple_dock/iAP.h"
+#include "apple_mfi.h"
+#endif
+
+#define LOG_TAG_CONST       USB
+#define LOG_TAG             "[mount]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+/* #define LOG_DUMP_ENABLE */
+#define LOG_CLI_ENABLE
+#include "debug.h"
+
+
+static struct usb_host_device host_devices[USB_MAX_HW_NUM];// SEC(.usb_h_bss);
+
+#define     device_to_usbdev(device)	((struct usb_host_device *)((device)->private_data))
+
+
+int host_dev_status(const struct usb_host_device *host_dev)
+{
+    return ((host_dev)->private_data.status);
+}
+
+u32 host_device2id(const struct usb_host_device *host_dev)
+{
+#if USB_MAX_HW_NUM > 1
+    return ((host_dev)->private_data.usb_id);
+#else
+    return 0;
+#endif
+}
+const struct usb_host_device *host_id2device(const usb_dev id)
+{
+#if USB_MAX_HW_NUM > 1
+    return &host_devices[id];
+#else
+    return &host_devices[0];
+#endif
+}
+int usb_sem_init(struct usb_host_device  *host_dev)
+{
+    usb_dev usb_id = host_device2id(host_dev);
+
+    usb_host_config(usb_id);
+
+    OS_SEM *sem = zalloc(sizeof(OS_SEM));
+    ASSERT(sem, "usb alloc sem error");
+    host_dev->sem = sem;
+    g_printf("%s %x %x ", __func__, host_dev, sem);
+    os_sem_create(host_dev->sem, 0);
+    return 0;
+}
+int usb_sem_pend(struct usb_host_device  *host_dev, u32 timeout)
+{
+    if (host_dev->sem == NULL) {
+        return 1;
+    }
+    int ret = os_sem_pend(host_dev->sem, timeout);
+    if (ret) {
+        r_printf("%s %d ", __func__, ret);
+    }
+    return ret;
+}
+int usb_sem_post(struct usb_host_device  *host_dev)
+{
+    if (host_dev->sem == NULL) {
+        return 1;
+    }
+    int ret = os_sem_post(host_dev->sem);
+    if (ret) {
+        r_printf("%s %d ", __func__, ret);
+    }
+    return 0;
+}
+int usb_sem_del(struct usb_host_device *host_dev)
+{
+    usb_dev usb_id = host_device2id(host_dev);
+
+    r_printf("1");
+    if (host_dev->sem == NULL) {
+        return 0;
+    }
+    r_printf("2");
+    r_printf("3");
+#if USB_HUB
+    if (host_dev && host_ep->sem && host_dev->father == NULL) {
+        os_sem_del(host_dev->sem);
+    }
+#else
+    if (host_dev && host_dev->sem) {
+        os_sem_del(host_dev->sem, 0);
+    }
+#endif
+    r_printf("4");
+    g_printf("%s %x %x ", __func__, host_dev, host_dev->sem);
+    free(host_dev->sem);
+    r_printf("5");
+    host_dev->sem = NULL;
+    r_printf("6");
+    usb_host_free(usb_id);
+    r_printf("7");
+    return 0;
+}
+
+/**
+ * @brief usb_descriptor_parser
+ *
+ * @param device
+ * @param pBuf
+ * @param total_len
+ *
+ * @return
+ */
+static int _usb_msd_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+    log_info("find udisk @ interface %d", interface_num);
+#if TCFG_UDISK_ENABLE
+    return   usb_msd_parser(host_dev, interface_num, pBuf);
+#else
+    return USB_DT_INTERFACE_SIZE;
+#endif
+}
+static int _usb_apple_mfi_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+    log_info("find udisk @ interface %d", interface_num);
+#if TCFG_USB_APPLE_DOCK_EN
+    return   usb_apple_mfi_parser(host_dev, interface_num, pBuf);
+#else
+    return USB_DT_INTERFACE_SIZE;
+#endif
+}
+static int _usb_adb_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+    log_info("find adb @ interface %d", interface_num);
+#if TCFG_ADB_ENABLE
+    return usb_adb_parser(host_dev, interface_num, pBuf);
+#else
+    return USB_DT_INTERFACE_SIZE;
+#endif
+}
+static int _usb_aoa_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+    log_info("find aoa @ interface %d", interface_num);
+#if TCFG_AOA_ENABLE
+    return usb_aoa_parser(host_dev, interface_num, pBuf);
+#else
+    return USB_DT_INTERFACE_SIZE;
+#endif
+
+}
+static int _usb_hid_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+    log_info("find hid @ interface %d", interface_num);
+#if TCFG_HID_HOST_ENABLE
+    return usb_hid_parser(host_dev, interface_num, pBuf);
+#else
+    return USB_DT_INTERFACE_SIZE;
+#endif
+}
+static int _usb_audio_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+    log_info("find audio @ interface %d", interface_num);
+#if TCFG_HOST_AUDIO_ENABLE
+    return usb_audio_parser(host_dev, interface_num, pBuf);
+#else
+    return USB_DT_INTERFACE_SIZE;
+#endif
+}
+static int _usb_adb_interface_ptp_mtp_parse(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
+{
+    log_info("find adbmtp @ interface %d", interface_num);
+#if TCFG_ADB_ENABLE
+    return usb_adb_interface_ptp_mtp_parse(host_dev, interface_num, pBuf);
+#else
+    return USB_DT_INTERFACE_SIZE;
+#endif
+}
+static int usb_descriptor_parser(struct usb_host_device *host_dev, const u8 *pBuf, u32 total_len, struct usb_device_descriptor *device_desc)
+{
+    int len = 0;
+    u8 interface_num = 0;
+    struct usb_private_data *private_data = &host_dev->private_data;
+
+    struct usb_config_descriptor *cfg_desc = (struct usb_config_descriptor *)pBuf;
+
+    if (cfg_desc->bDescriptorType != USB_DT_CONFIG ||
+        cfg_desc->bLength < USB_DT_CONFIG_SIZE) {
+        log_error("invalid descriptor for config bDescriptorType = %d bLength= %d",
+                  cfg_desc->bDescriptorType, cfg_desc->bLength);
+        return -USB_DT_CONFIG;
+    }
+
+    log_info("idVendor %x idProduct %x", device_desc->idVendor, device_desc->idProduct);
+
+    len += USB_DT_CONFIG_SIZE;
+    pBuf += USB_DT_CONFIG_SIZE;
+    int i = 0;
+    u32 have_find_valid_class = 0;
+    while (len < total_len) {
+        if (interface_num > 4) {
+            log_error("interface_num too much");
+            break;
+        }
+
+        struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
+        if (interface->bDescriptorType == USB_DT_INTERFACE) {
+
+            printf("inf class %x subclass %x ep %d",
+                   interface->bInterfaceClass, interface->bInterfaceSubClass, interface->bNumEndpoints);
+
+            if (interface->bInterfaceClass == USB_CLASS_MASS_STORAGE) {
+                i = _usb_msd_parser(host_dev, interface_num, pBuf);
+                if (i < 0) {
+                    log_error("---%s %d---", __func__, __LINE__);
+                    len = total_len;
+                } else {
+                    interface_num++;
+                    len += i;
+                    pBuf += i;
+                    have_find_valid_class = true;
+                }
+            } else if ((device_desc->idVendor == 0x05AC) &&
+                       ((device_desc->idProduct & 0xff00) == 0x1200)) {
+                i = _usb_apple_mfi_parser(host_dev, interface_num, pBuf);
+                if (i < 0) {
+                    log_error("---%s %d---", __func__, __LINE__);
+                    len = total_len;
+                } else {
+                    interface_num++;
+                    len += i;
+                    pBuf += i;
+                    have_find_valid_class = true;
+                }
+            } else if (interface->bInterfaceClass == USB_CLASS_AUDIO) {
+                i = _usb_audio_parser(host_dev, interface_num, pBuf);
+                if (i < 0) {
+                    log_error("---%s %d---", __func__, __LINE__);
+                    len = total_len;
+                } else {
+                    interface_num++;
+                    len += i;
+                    pBuf += i;
+                    have_find_valid_class = true;
+                }
+            } else if ((interface->bInterfaceClass == 0xff)  &&
+                       (interface->bInterfaceSubClass == USB_CLASS_ADB)) {
+                i = _usb_adb_parser(host_dev, interface_num, pBuf);
+                if (i < 0) {
+                    log_error("---%s %d---", __func__, __LINE__);
+                    len = total_len;
+                } else {
+                    interface_num++;
+                    len += i;
+                    pBuf += i;
+                    have_find_valid_class = true;
+                }
+            } else if ((device_desc->idVendor == 0x18d1) &&
+                       ((device_desc->idProduct & 0x2d00) == 0x2d00)) {
+                i = _usb_aoa_parser(host_dev, interface_num, pBuf);
+                if (i < 0) {
+                    log_error("---%s %d---", __func__, __LINE__);
+                    len = total_len;
+                } else {
+                    interface_num++;
+                    len += i;
+                    pBuf += i;
+                    have_find_valid_class = true;
+                }
+            } else if (interface->bInterfaceClass == USB_CLASS_HID) {
+                i = _usb_hid_parser(host_dev, interface_num, pBuf);
+                if (i < 0) {
+                    log_error("---%s %d---", __func__, __LINE__);
+                    len = total_len;
+                } else {
+                    interface_num++;
+                    len += i;
+                    pBuf += i;
+                    have_find_valid_class = true;
+                }
+            } else if ((interface->bNumEndpoints == 3) &&
+                       (interface->bInterfaceClass == 0xff || interface->bInterfaceClass == 0x06)) {
+                i = _usb_adb_interface_ptp_mtp_parse(host_dev, interface_num, pBuf);
+                if (i < 0) {
+                    log_error("---%s %d---", __func__, __LINE__);
+                    len = total_len;
+                } else {
+                    interface_num++;
+                    len += i;
+                    pBuf += i;
+                }
+                have_find_valid_class = true;
+            } else if ((interface->bInterfaceClass == 0xff) &&
+                       (interface->bInterfaceSubClass == 0xff)) {
+                i = _usb_aoa_parser(host_dev, interface_num, pBuf);
+                if (i < 0) {
+                    log_error("---%s %d---", __func__, __LINE__);
+                    len = total_len;
+                } else {
+                    interface_num++;
+                    len += i;
+                    pBuf += i;
+                }
+                have_find_valid_class = true;
+
+            } else {
+                log_info("find unsupport [class %x subClass %x] @ interface %d",
+                         interface->bInterfaceClass,
+                         interface->bInterfaceSubClass,
+                         interface_num);
+
+                len += USB_DT_INTERFACE_SIZE;
+                pBuf += USB_DT_INTERFACE_SIZE;
+            }
+        } else {
+            /* log_error("unknown section %d %d", len, pBuf[0]); */
+            if (pBuf[0]) {
+                len += pBuf[0];
+                pBuf += pBuf[0];
+            } else {
+                len = total_len;
+            }
+        }
+    }
+
+
+    log_debug("len %d total_len %d", len, total_len);
+    return !have_find_valid_class;
+}
+
+
+/* --------------------------------------------------------------------------*/
+/**
+ * @brief usb_host_suspend
+ *
+ * @param usb
+ *
+ * @return
+ */
+/* --------------------------------------------------------------------------*/
+void usb_host_suspend(const usb_dev usb_id)
+{
+    usb_h_entry_suspend(usb_id);
+}
+
+void usb_host_resume(const usb_dev usb_id)
+{
+    usb_h_resume(usb_id);
+}
+
+static u32 _usb_host_mount(const usb_dev usb_id, u32 retry, u32 reset_delay, u32 mount_timeout)
+{
+    u32 ret = DEV_ERR_NONE;
+    struct usb_host_device *host_dev = &host_devices[usb_id];
+    struct usb_private_data *private_data = &host_dev->private_data;
+
+
+    for (int i = 0; i < retry; i++) {
+        usb_h_sie_init(usb_id);
+        ret = usb_host_init(usb_id, reset_delay, mount_timeout);
+        if (ret) {
+            reset_delay += 10;
+            continue;
+        }
+
+        void *const ep0_dma = usb_h_get_ep_buffer(usb_id, 0);
+        usb_set_dma_taddr(usb_id, 0, ep0_dma);
+
+        usb_sie_enable(usb_id);//enable sie intr
+        usb_mdelay(reset_delay);
+
+        /**********get device descriptor*********/
+        struct usb_device_descriptor device_desc;
+        private_data->usb_id = usb_id;
+        private_data->status = 0;
+        private_data->devnum = 0;
+        private_data->ep0_max_packet_size = 8;
+        ret = usb_get_device_descriptor(host_dev, &device_desc);
+
+        /**********set address*********/
+        usb_mdelay(20);
+        u8 devnum = rand32() % 16 + 1;
+        ret = set_address(host_dev, devnum);
+        check_usb_mount(ret);
+        private_data->devnum = devnum ;
+
+        /**********get device descriptor*********/
+        usb_mdelay(20);
+        ret = usb_get_device_descriptor(host_dev, &device_desc);
+        check_usb_mount(ret);
+        private_data->ep0_max_packet_size = device_desc.bMaxPacketSize0;
+
+        /**********get config descriptor*********/
+        struct usb_config_descriptor cfg_desc;
+        ret = get_config_descriptor(host_dev, &cfg_desc, USB_DT_CONFIG_SIZE);
+        check_usb_mount(ret);
+
+#if USB_H_MALLOC_ENABLE
+        u8 *desc_buf = zalloc(cfg_desc.wTotalLength + 16);
+        ASSERT(desc_buf, "desc_buf");
+#else
+        u8 desc_buf[128] = {0};
+        cfg_desc.wTotalLength = min(sizeof(desc_buf), cfg_desc.wTotalLength);
+#endif
+
+        ret = get_config_descriptor(host_dev, desc_buf, cfg_desc.wTotalLength);
+        check_usb_mount(ret);
+
+        /**********set configuration*********/
+        ret = set_configuration(host_dev);
+        /* printf_buf(desc_buf, cfg_desc.wTotalLength); */
+        ret |= usb_descriptor_parser(host_dev, desc_buf, cfg_desc.wTotalLength, &device_desc);
+#if USB_H_MALLOC_ENABLE
+        log_info("free:desc_buf= %x\n", desc_buf);
+        free(desc_buf);
+#endif
+        check_usb_mount(ret);
+
+        break;//succ
+    }
+
+    if (ret) {
+        goto __exit_fail;
+    }
+    private_data->status = 1;
+    return DEV_ERR_NONE;
+
+__exit_fail:
+    printf("usb_probe fail");
+    private_data->status = 0;
+    usb_sie_close(usb_id);
+    return ret;
+}
+static int usb_event_notify(const struct usb_host_device *host_dev, u32 ev)
+{
+    const usb_dev id = host_device2id(host_dev);
+    struct sys_event event;
+    if (ev == 0) {
+        event.u.dev.event = DEVICE_EVENT_IN;
+    } else {
+        event.u.dev.event = DEVICE_EVENT_CHANGE;
+    }
+    u8 have_post_event = 0;
+    u8 no_send_event;
+    for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
+        no_send_event = 0;
+        event.u.dev.value = 0;
+        if (host_dev->interface_info[i]) {
+            switch (host_dev->interface_info[i]->ctrl->interface_class) {
+#if TCFG_UDISK_ENABLE
+            case USB_CLASS_MASS_STORAGE:
+                if (have_post_event & BIT(0)) {
+                    no_send_event = 1;
+                } else {
+                    have_post_event |= BIT(0);
+                }
+                if (id == 0) {
+                    event.u.dev.value = (int)"udisk0";
+                } else {
+                    event.u.dev.value = (int)"udisk1";
+                }
+                break;
+#endif
+
+#if TCFG_ADB_ENABLE
+            case USB_CLASS_ADB:
+                if (have_post_event & BIT(1)) {
+                    no_send_event = 1;
+                } else {
+                    have_post_event |= BIT(1);
+                }
+                if (id == 0) {
+                    event.u.dev.value = (int)"adb0";
+                } else {
+                    event.u.dev.value = (int)"adb1";
+                }
+                break;
+#endif
+#if TCFG_AOA_ENABLE
+            case USB_CLASS_AOA:
+                if (have_post_event & BIT(2)) {
+                    no_send_event = 1;
+                } else {
+                    have_post_event |= BIT(2);
+                }
+                if (id == 0) {
+                    event.u.dev.value = (int)"aoa0";
+                } else {
+                    event.u.dev.value = (int)"aoa1";
+                }
+                break;
+#endif
+#if TCFG_HID_HOST_ENABLE
+            case USB_CLASS_HID:
+                if (have_post_event & BIT(3)) {
+                    no_send_event = 1;
+                } else {
+                    have_post_event |= BIT(3);
+                }
+                if (id == 0) {
+                    event.u.dev.value = (int)"hid0";
+                } else {
+                    event.u.dev.value = (int)"hid1";
+                }
+                break;
+#endif
+#if TCFG_HOST_AUDIO_ENABLE
+            case USB_CLASS_AUDIO:
+                if (have_post_event & BIT(4)) {
+                    no_send_event = 1;
+                } else {
+                    have_post_event |= BIT(4);
+                }
+                if (id == 0) {
+                    event.u.dev.value = (int)"audio0";
+                } else {
+                    event.u.dev.value = (int)"audio1";
+                }
+                break;
+#endif
+            }
+
+            if (!no_send_event && event.u.dev.value) {
+                log_info("event %x interface %x class %x %s",
+                         event.u.dev.event, i,
+                         host_dev->interface_info[i]->ctrl->interface_class,
+                         (const char *)event.u.dev.value);
+
+                /* printf("usb_host_mount notify >>>>>>>>>>>\n"); */
+                event.arg = (void *)DEVICE_EVENT_FROM_USB_HOST;
+                event.type = SYS_DEVICE_EVENT;
+                sys_event_notify(&event);
+            }
+        }
+    }
+    if (have_post_event) {
+        return DEV_ERR_NONE;
+    } else {
+        return DEV_ERR_UNKNOW_CLASS;
+    }
+
+}
+
+const char *usb_host_valid_class_to_dev(const usb_dev id, u32 usbclass)
+{
+#if USB_MAX_HW_NUM > 1
+    const usb_dev usb_id = id;
+#else
+    const usb_dev usb_id = 0;
+#endif
+    struct usb_host_device *host_dev = &host_devices[usb_id];
+    u32 itf_class;
+
+    for (int i = 0; i < MAX_HOST_INTERFACE; i++) {
+        if (host_dev->interface_info[i] &&
+            host_dev->interface_info[i]->ctrl) {
+            itf_class = host_dev->interface_info[i]->ctrl->interface_class;
+            if (itf_class == usbclass) {
+                switch (itf_class) {
+                case USB_CLASS_MASS_STORAGE:
+                    if (usb_id == 0) {
+                        return "udisk0";
+                    } else if (usb_id == 1) {
+                        return "udisk1";
+                    }
+                    break;
+                case USB_CLASS_ADB:
+                    if (usb_id == 0) {
+                        return "adb0";
+                    } else if (usb_id == 1) {
+                        return "adb1";
+                    }
+                    break;
+                case USB_CLASS_AOA:
+                    if (usb_id == 0) {
+                        return "aoa0";
+                    } else if (usb_id == 1) {
+                        return "aoa1";
+                    }
+                    break;
+                case USB_CLASS_HID:
+                    if (usb_id == 0) {
+                        return "hid0";
+                    } else if (usb_id == 1) {
+                        return "hid1";
+                    }
+                    break;
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+/* --------------------------------------------------------------------------*/
+/**
+ * @brief usb_host_mount
+ *
+ * @param usb
+ *
+ * @return
+ */
+/* --------------------------------------------------------------------------*/
+u32 usb_host_mount(const usb_dev id, u32 retry, u32 reset_delay, u32 mount_timeout)
+{
+#if USB_MAX_HW_NUM > 1
+    const usb_dev usb_id = id;
+#else
+    const usb_dev usb_id = 0;
+#endif
+
+    u32 ret;
+    struct usb_host_device *host_dev = &host_devices[usb_id];
+    memset(host_dev, 0, sizeof(*host_dev));
+
+    host_dev->private_data.usb_id = id;
+    usb_otg_resume(usb_id);  //打开usb host之后恢复otg检测
+
+    usb_sem_init(host_dev);
+    usb_h_isr_reg(usb_id, 1, 0);
+
+
+    ret = _usb_host_mount(usb_id, retry, reset_delay, mount_timeout);
+    if (ret) {
+        goto __exit_fail;
+    }
+    return usb_event_notify(host_dev, 0);
+
+__exit_fail:
+    usb_sie_disable(usb_id);
+    usb_sem_del(host_dev);
+    return ret;
+}
+
+static u32 _usb_host_unmount(const usb_dev usb_id)
+{
+    struct usb_host_device *host_dev = &host_devices[usb_id];
+
+    struct usb_private_data *private_data = &host_dev->private_data;
+    private_data->status = 0;
+
+    usb_sem_post(host_dev);//拔掉设备时,让读写线程快速释放
+
+    for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
+        if (host_dev->interface_info[i]) {
+            host_dev->interface_info[i]->ctrl->set_power(host_dev, -1);
+            host_dev->interface_info[i] = NULL;
+        }
+    }
+
+    usb_sie_close(usb_id);
+    return DEV_ERR_NONE;
+}
+
+/* --------------------------------------------------------------------------*/
+/**
+ * @brief usb_host_unmount
+ *
+ * @param usb
+ *
+ * @return
+ */
+/* --------------------------------------------------------------------------*/
+/* u32 usb_host_unmount(const usb_dev usb_id, char *device_name) */
+u32 usb_host_unmount(const usb_dev id)
+{
+#if USB_MAX_HW_NUM > 1
+    const usb_dev usb_id = id;
+#else
+    const usb_dev usb_id = 0;
+#endif
+    u32 ret;
+    struct usb_host_device *host_dev = &host_devices[usb_id];
+    struct sys_event event;
+
+#if (TCFG_UDISK_ENABLE && UDISK_READ_512_ASYNC_ENABLE)
+    _usb_stor_async_wait_sem(host_dev);
+#endif
+    ret = _usb_host_unmount(usb_id);
+    if (ret) {
+        goto __exit_fail;
+    }
+    usb_sem_del(host_dev);
+
+    /* printf("usb_host_unmount notify >>>>>>>>>>>\n"); */
+    event.arg = (void *)DEVICE_EVENT_FROM_USB_HOST;
+    event.type = SYS_DEVICE_EVENT;
+    event.u.dev.event = DEVICE_EVENT_OUT;
+    sys_event_notify(&event);
+    return DEV_ERR_NONE;
+
+__exit_fail:
+    return ret;
+}
+
+u32 usb_host_remount(const usb_dev id, u32 retry, u32 delay, u32 ot, u8 notify)
+{
+#if USB_MAX_HW_NUM > 1
+    const usb_dev usb_id = id;
+#else
+    const usb_dev usb_id = 0;
+#endif
+    u32 ret;
+    struct sys_event event;
+
+    ret = _usb_host_unmount(usb_id);
+    if (ret) {
+        goto __exit_fail;
+    }
+
+    struct usb_host_device *host_dev = &host_devices[usb_id];
+    os_sem_set(host_dev->sem, 0);
+
+    ret = _usb_host_mount(usb_id, retry, delay, ot);
+    if (ret) {
+        goto __exit_fail;
+    }
+
+    if (notify) {
+        struct usb_host_device *host_dev = &host_devices[usb_id];
+        usb_event_notify(host_dev, 1);
+    }
+    return DEV_ERR_NONE;
+
+__exit_fail:
+    return ret;
+}
+#endif

File diff suppressed because it is too large
+ 2038 - 0
apps/common/device/usb/host/usb_storage.c


+ 131 - 0
apps/common/device/usb/host/usb_storage.h

@@ -0,0 +1,131 @@
+/**@file        usb_storage.h
+  * @brief      usb_storage驱动头文件(做主机)
+  * @details    结构体声明,功能函数声明
+  * @author     jieli
+  * @date       2021-8-1
+  * @version    V1.0
+  * @copyright  Copyright(c)2010-2021   珠海市杰理科技股份有限公司
+  *********************************************************
+  * @attention
+  * 硬件平台:AC695N
+  * SDK版本:AC695N_V1.0.0_SDK
+  * @修改日志:
+  * <table>
+  * <tr><th>Date        <th>Version     <th>Author      <th>Description
+  * <tr><td>2021-8-1    <td>1.0         <td>jieli       <td>创建初始版本
+  * </table>
+  *
+  *********************************************************
+  */
+#ifndef __USB_STORAGE_H__
+#define __USB_STORAGE_H__
+
+#include "system/task.h"
+#include "device/device.h"
+#include "usb/scsi.h"
+#include "usb_bulk_transfer.h"
+#include "usb/host/usb_host.h"
+
+/* u盘预读功能配置, 二选一
+ * 当两种方式都不使能,则表示不开启预读 */
+#define  UDISK_READ_BIGBLOCK_ASYNC_ENABLE    0   //使能大扇区预读方式(不需要额外buf,速度比512预读慢10%)
+#define  UDISK_READ_512_ASYNC_ENABLE         1   //使能512Byte预读方式(需要额外的512byte buffer,速度比大扇区预读快10%)
+/****************************/
+
+#define UDISK_READ_ASYNC_BLOCK_NUM  (16) //预读扇区数
+
+/**@enum    usb_sta
+  * @brief  USB设备当前状态
+  */
+typedef enum usb_sta {
+    DEV_IDLE = 0, ///<空闲状态
+    DEV_INIT, ///<初始化
+    DEV_OPEN, ///<开启
+    DEV_READ, ///<读操作
+    DEV_WRITE, ///<写操作
+    DEV_CLOSE, ///<关闭
+    DEV_SUSPEND, ///<挂起
+} USB_STA ;
+
+/**@struct  udisk_end_desc
+  * @brief  U盘端点描述结构体
+  *
+  */
+struct udisk_end_desc {
+    u8 host_epout; ///<主机端点输出
+    u8 target_epout; ///<目标端点输出
+    u8 host_epin; ///<主机端点输入
+    u8 target_epin; ///<目标端点输入
+#if HUSB_MODE
+    u16 rxmaxp; ///<接收最大端点号
+    u16 txmaxp; ///<发送最大端点号
+#endif
+};
+
+#define ENABLE_DISK_HOTPLUG  0
+
+/**@struct  mass_storage
+  * @brief  mass_storage协议所使用的相关变量
+  */
+struct mass_storage {
+    OS_MUTEX mutex; ///<互斥量
+
+    struct usb_scsi_cbw cbw; ///<CBW指令结构体
+    struct usb_scsi_csw csw; ///<CSW状态结构体
+    struct request_sense_data sense; ///<请求数据检查结构体
+
+    char *name; ///<设备名字
+    struct read_capacity_data capacity[2]; ///<读取数据的能力,包含数据块的编号、大小
+    u8 lun; ///<最大逻辑单元地址
+    u8 curlun; ///<当前逻辑单元地址
+
+    u8 dev_status; ///<设备状态
+    u8 suspend_cnt; ///<挂起状态计数器
+    u8 read_only; ///<只读标志位
+
+    u32 remain_len; ///<剩余的包长度
+    u32 prev_lba; ///<上一次扇区
+#if (UDISK_READ_BIGBLOCK_ASYNC_ENABLE || UDISK_READ_512_ASYNC_ENABLE)
+    u8 async_en; ///<异步模式使能
+    u8 need_send_csw; ///<需要发送csw标志位
+    u8 *udisk_512_buf; ///<U盘512K大小BUFFER指针
+    u32 async_prev_lba; ///<异步模式上一次地址
+#endif
+#if ENABLE_DISK_HOTPLUG
+    u8 media_sta_cur; ///<当前媒介状态                //for card reader, card removable
+    u8 media_sta_prev; ///<上次媒介状态
+
+    int test_unit_ready_tick; ///<测试准备标记
+#endif
+};
+
+enum usb_async_mode {
+    BULK_ASYNC_MODE_EXIT = 0, ///<退出异步模式
+    BULK_ASYNC_MODE_SEM_PEND, ///<异步预读等待信号量
+};
+
+#define MASS_LBA_INIT    (-2)
+
+/**@brief   使用mass_storage协议,对大容量存储设备进行解析,端点配置
+  * @param[in]  usb_host_device定义的结构体指针
+  * @param[in]  interface_num 接口号
+  * @param[in]  *pBuf 指向BUFFER的指针
+  * @return     len    BUFFER的长度
+  * @par    示例:
+  * @code
+  * usb_msd_parser(host_dev,interface_num,pBuf);
+  * @encode
+  */
+int usb_msd_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
+
+/**@brief   异步模式等待信号量
+  * @param[in]  usb_host_device定义的结构体指针
+  * @return     0:成功
+  * @par    示例:
+  * @code
+  * _usb_stor_async_wait_sem(host_dev);
+  * @encode
+  */
+int _usb_stor_async_wait_sem(struct usb_host_device *host_dev);
+
+#endif

+ 155 - 0
apps/common/device/usb/usb_common_def.h

@@ -0,0 +1,155 @@
+#ifndef __USB_COMMON_DEFINE_H__
+#define __USB_COMMON_DEFINE_H__
+
+///<<<注意此文件不要放函数声明, 只允许宏定义, 并且差异化定义可以根据需求在对应板卡中重新定义, 除非新增,否则不要直接修改这里
+///<<<注意此文件不要放函数声明, 只允许宏定义, 并且差异化定义可以根据需求在对应板卡中重新定义, 除非新增,否则不要直接修改这里
+///<<<注意此文件不要放函数声明, 只允许宏定义, 并且差异化定义可以根据需求在对应板卡中重新定义, 除非新增,否则不要直接修改这里
+//
+/**************************************************************************/
+/*
+               CLASS  BITMAP
+    7   |   6   |   5   |   4   |   3   |   2   |   1   |   0
+                                   HID    AUDIO  SPEAKER   Mass Storage
+*/
+/**************************************************************************/
+#define     MASSSTORAGE_CLASS   0x00000001
+#define     SPEAKER_CLASS       0x00000002
+#define     MIC_CLASS           0x00000004
+#define     HID_CLASS           0x00000008
+#define     CDC_CLASS           0x00000010
+#define     CUSTOM_HID_CLASS    0x00000020
+
+#define     AUDIO_CLASS         (SPEAKER_CLASS|MIC_CLASS)
+
+
+#define     USB_ROOT2   0
+
+/// board文件没有定义的宏,在这里定义,防止编译报warning
+#ifndef TCFG_PC_ENABLE
+#define TCFG_PC_ENABLE  0
+#endif
+#ifndef TCFG_UDISK_ENABLE
+#define TCFG_UDISK_ENABLE     0
+#endif
+#ifndef TCFG_HID_HOST_ENABLE
+#define TCFG_HID_HOST_ENABLE  0
+#endif
+#ifndef TCFG_AOA_ENABLE
+#define TCFG_AOA_ENABLE  0
+#endif
+#ifndef TCFG_ADB_ENABLE
+#define TCFG_ADB_ENABLE   0
+#endif
+#ifndef TCFG_USB_APPLE_DOCK_EN
+#define TCFG_USB_APPLE_DOCK_EN 0
+#endif
+#ifndef TCFG_HOST_AUDIO_ENABLE
+#define TCFG_HOST_AUDIO_ENABLE  0
+#endif
+#ifndef TCFG_CHARGE_ENABLE
+#define TCFG_CHARGE_ENABLE     0
+#endif
+#ifndef TCFG_USB_PORT_CHARGE
+#define TCFG_USB_PORT_CHARGE   0
+#endif
+#ifndef TCFG_USB_MIC_ECHO_ENABLE
+#define TCFG_USB_MIC_ECHO_ENABLE   0
+#endif
+#ifndef TCFG_USB_MIC_DATA_FROM_MICEFFECT
+#define TCFG_USB_MIC_DATA_FROM_MICEFFECT   0
+#endif
+#ifndef TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
+#define TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0   0
+#endif
+#ifndef TCFG_ONLY_PC_ENABLE     //只有pc模式
+#define TCFG_ONLY_PC_ENABLE 0
+#endif
+#ifndef TCFG_TYPE_C_ENABLE      //应用于type-c场景
+#define TCFG_TYPE_C_ENABLE  0
+#endif
+#ifndef TCFG_USB_CUSTOM_HID_ENABLE
+#define TCFG_USB_CUSTOM_HID_ENABLE  0
+#endif
+
+/********************************/
+
+#if TCFG_UDISK_ENABLE || TCFG_HID_HOST_ENABLE || TCFG_AOA_ENABLE || TCFG_ADB_ENABLE || TCFG_HOST_AUDIO_ENABLE
+#define MOUNT_RETRY                         3
+#define MOUNT_RESET                         40
+#define MOUNT_TIMEOUT                       50
+#define     USB_HOST_ENABLE                 1
+#else
+#define     USB_HOST_ENABLE                 0
+#endif
+
+#if TCFG_CHARGE_ENABLE && TCFG_USB_PORT_CHARGE
+#define TCFG_OTG_MODE_CHARGE                (OTG_CHARGE_MODE)
+#else
+#define TCFG_OTG_MODE_CHARGE                0
+#endif
+
+#if (TCFG_PC_ENABLE)
+#define TCFG_PC_UPDATE                      1
+#define TCFG_OTG_MODE_SLAVE                 (OTG_SLAVE_MODE)
+#else
+#define TCFG_PC_UPDATE                      0
+#define TCFG_OTG_MODE_SLAVE                 0
+#endif
+
+#if (USB_HOST_ENABLE)
+#define TCFG_OTG_MODE_HOST                  (OTG_HOST_MODE)
+#else
+#define TCFG_OTG_MODE_HOST                  0
+#endif
+
+#if TCFG_PC_ENABLE
+#define TCFG_USB_SLAVE_ENABLE               1
+#if (USB_DEVICE_CLASS_CONFIG & MASSSTORAGE_CLASS)
+#define TCFG_USB_SLAVE_MSD_ENABLE           1
+#else
+#define TCFG_USB_SLAVE_MSD_ENABLE           0
+#endif
+
+#if (USB_DEVICE_CLASS_CONFIG & AUDIO_CLASS)
+#define TCFG_USB_SLAVE_AUDIO_ENABLE         1
+#else
+#define TCFG_USB_SLAVE_AUDIO_ENABLE         0
+#endif
+
+#if (USB_DEVICE_CLASS_CONFIG & HID_CLASS)
+#define TCFG_USB_SLAVE_HID_ENABLE           1
+#else
+#define TCFG_USB_SLAVE_HID_ENABLE           0
+#endif
+
+#if (USB_DEVICE_CLASS_CONFIG & CDC_CLASS)
+#define TCFG_USB_SLAVE_CDC_ENABLE           1
+#else
+#define TCFG_USB_SLAVE_CDC_ENABLE           0
+#endif
+
+#else  /* TCFG_PC_ENABLE == 0*/
+#define TCFG_USB_SLAVE_ENABLE               0
+#define TCFG_USB_SLAVE_MSD_ENABLE           0
+#define TCFG_USB_SLAVE_AUDIO_ENABLE         0
+#define TCFG_USB_SLAVE_HID_ENABLE           0
+#define TCFG_USB_SLAVE_CDC_ENABLE           0
+#endif
+
+#define TCFG_OTG_SLAVE_ONLINE_CNT           2
+#define TCFG_OTG_SLAVE_OFFLINE_CNT          2
+
+#define TCFG_OTG_HOST_ONLINE_CNT            2
+#define TCFG_OTG_HOST_OFFLINE_CNT           3
+
+#ifndef TCFG_OTG_MODE
+#define TCFG_OTG_MODE                       (TCFG_OTG_MODE_HOST|TCFG_OTG_MODE_SLAVE|TCFG_OTG_MODE_CHARGE)
+#endif
+
+#define TCFG_OTG_DET_INTERVAL               50
+
+#ifndef TCFG_OTG1_ENABLE
+#define TCFG_OTG1_ENABLE                    0//1:使能两个otg独立配置   0:禁用otg独立配置
+#endif
+
+#endif

+ 0 - 0
apps/common/device/usb/usb_config.c


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