1.新增esp-idf设备端sdk
2
sdk/ESP-IDF/esp_fastbee_aliyun/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
build/
|
||||||
|
.idea
|
||||||
23
sdk/ESP-IDF/esp_fastbee_aliyun/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Win32",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**",
|
||||||
|
"D:/soft/esp-idf/Espressif/frameworks/esp-idf-v4.4.7/components/**",
|
||||||
|
"./esp-aliyun/**",
|
||||||
|
],
|
||||||
|
"defines": [
|
||||||
|
"_DEBUG",
|
||||||
|
"UNICODE",
|
||||||
|
"_UNICODE"
|
||||||
|
],
|
||||||
|
"windowsSdkVersion": "10.0.22621.0",
|
||||||
|
"compilerPath": "cl.exe",
|
||||||
|
"cStandard": "c17",
|
||||||
|
"cppStandard": "c++17",
|
||||||
|
"intelliSenseMode": "windows-msvc-x64"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
35
sdk/ESP-IDF/esp_fastbee_aliyun/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "ESP-IDF Debug: Launch",
|
||||||
|
"type": "espidf",
|
||||||
|
"request": "launch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "GDB",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"miDebuggerPath": "${command:espIdf.getXtensaGdb}",
|
||||||
|
"program": "${workspaceFolder}/build/${command:espIdf.getProjectName}.elf",
|
||||||
|
"windows": {
|
||||||
|
"program": "${workspaceFolder}\\build\\${command:espIdf.getProjectName}.elf"
|
||||||
|
},
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"environment": [{ "name": "PATH", "value": "${config:idf.customExtraPaths}" }],
|
||||||
|
"setupCommands": [
|
||||||
|
{ "text": "set remotetimeout 100" },
|
||||||
|
{ "text": "target extended-remote :3333" },
|
||||||
|
{ "text": "set remote hardware-watchpoint-limit 2"},
|
||||||
|
{ "text": "mon reset halt" },
|
||||||
|
{ "text": "thb app_main" },
|
||||||
|
{ "text": "flushregs" }
|
||||||
|
],
|
||||||
|
"externalConsole": false,
|
||||||
|
"logging": {
|
||||||
|
"engineLogging": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
19
sdk/ESP-IDF/esp_fastbee_aliyun/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"idf.portWin": "COM6",
|
||||||
|
"idf.adapterTargetName": "esp32s3",
|
||||||
|
"idf.openOcdConfigs": [
|
||||||
|
"board/esp32s3-builtin.cfg"
|
||||||
|
],
|
||||||
|
"idf.flashType": "UART",
|
||||||
|
"files.associations": {
|
||||||
|
"infra_config.h": "c",
|
||||||
|
"cjson.h": "c",
|
||||||
|
"dm_wrapper.h": "c",
|
||||||
|
"infra_defs.h": "c",
|
||||||
|
"freertos.h": "c",
|
||||||
|
"stddef.h": "c",
|
||||||
|
"string.h": "c",
|
||||||
|
"esp_log.h": "c",
|
||||||
|
"mqtt_client.h": "c"
|
||||||
|
}
|
||||||
|
}
|
||||||
12
sdk/ESP-IDF/esp_fastbee_aliyun/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
# (Automatically converted from project Makefile by convert_to_cmake.py.)
|
||||||
|
|
||||||
|
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||||
|
# in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
set (EXTRA_COMPONENT_DIRS "./esp-aliyun")
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
|
||||||
|
project(esp_fastbee_aliyun)
|
||||||
11
sdk/ESP-IDF/esp_fastbee_aliyun/Makefile
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#
|
||||||
|
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||||
|
# project subdirectory.
|
||||||
|
#
|
||||||
|
PROJECT_NAME := esp_fastbee_aliyun
|
||||||
|
|
||||||
|
EXTRA_COMPONENT_DIRS := $(realpath ./esp-aliyun)
|
||||||
|
|
||||||
|
SDKCONFIG_DEFAULTS := sdkconfig_$(chip).defaults
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
||||||
152
sdk/ESP-IDF/esp_fastbee_aliyun/README.md
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
# ESP 设备对接Fastbee物联网云平台指南
|
||||||
|
# 目录
|
||||||
|
|
||||||
|
- [1.目的](#aim)
|
||||||
|
- [2.硬件准备](#hardwareprepare)
|
||||||
|
- [3.云平台准备](#fastbeeprepare)
|
||||||
|
- [4.环境搭建](#compileprepare)
|
||||||
|
- [5.SDK 准备](#sdkprepare)
|
||||||
|
- [6.编译&烧写&运行](#makeflash)
|
||||||
|
|
||||||
|
|
||||||
|
# <span id = "aim">1.目的</span>
|
||||||
|
本项目基于esp-aliyun SDK进行修改,介绍 ESP 设备对接Fastbee物联网云平台,阿里云平台的具体流程。
|
||||||
|
主要实现的功能:
|
||||||
|
- 支持 <Fastbee物联网云平台> 配网&接入&控制
|
||||||
|
- 支持 <云智能> APP 一键配网
|
||||||
|
- 支持 <云智能> APP 控制设备
|
||||||
|
- 支持 <天猫精灵智能音箱> 控制设备
|
||||||
|
- 支持 <天猫精灵智能音箱> 配网并控制设备
|
||||||
|
- 支持 LED 控制(开关,颜色等)
|
||||||
|
- 支持 OTA 升级
|
||||||
|
|
||||||
|
# <span id = "hardwareprepare">2.硬件准备</span>
|
||||||
|
- **linux 环境**
|
||||||
|
用来编译 & 烧写 & 运行等操作的必须环境。
|
||||||
|
> windows 用户可安装虚拟机,在虚拟机中安装 linux。
|
||||||
|
|
||||||
|
- **ESP 设备**
|
||||||
|
ESP 设备包括 [ESP芯片](https://www.espressif.com/zh-hans/products/hardware/socs),[ESP模组](https://www.espressif.com/zh-hans/products/hardware/modules),[ESP开发板](https://www.espressif.com/zh-hans/products/hardware/development-boards)等。
|
||||||
|
|
||||||
|
- **USB 线**
|
||||||
|
连接 PC 和 ESP 设备,用来烧写/下载程序,查看 log 等。
|
||||||
|
|
||||||
|
# <span id = "compileprepare">3.云平台准备</span>
|
||||||
|
|
||||||
|
# <span id = "compileprepare">4.环境搭建</span>
|
||||||
|
**如果您熟悉 ESP 开发环境,可以很顺利理解下面步骤; 如果您不熟悉某个部分,比如编译,烧录,需要您结合官方的相关文档来理解。如您需阅读 [ESP-IDF 编程指南](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/index.html)文档等。**
|
||||||
|
|
||||||
|
## 4.1 编译器环境搭建
|
||||||
|
- ESP8266 平台: 根据[官方链接](https://github.com/espressif/ESP8266_RTOS_SDK)中 **Get toolchain**,获取 toolchain
|
||||||
|
- ESP32 & ESP32S2 平台:根据[官方链接](https://github.com/espressif/esp-idf/blob/master/docs/zh_CN/get-started/linux-setup.rst)中 **工具链的设置**,下载 toolchain
|
||||||
|
|
||||||
|
toolchain 设置参考 [ESP-IDF 编程指南](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/get-started/index.html#get-started-setup-toolchain)。
|
||||||
|
## 4.2 烧录工具/下载工具获取
|
||||||
|
- ESP8266 平台:烧录工具位于 [ESP8266_RTOS_SDK](https://github.com/espressif/ESP8266_RTOS_SDK) 下 `./components/esptool_py/esptool/esptool.py`
|
||||||
|
- ESP32 & ESP32S2 平台:烧录工具位于 [esp-idf](https://github.com/espressif/esp-idf) 下 `./components/esptool_py/esptool/esptool.py`
|
||||||
|
|
||||||
|
esptool 功能参考:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ ./components/esptool_py/esptool/esptool.py --help
|
||||||
|
```
|
||||||
|
|
||||||
|
# <span id = "sdkprepare">5.SDK 准备</span>
|
||||||
|
- [esp-aliyun SDK](https://github.com/espressif/esp-aliyun), 通过该 SDK 可实现使用 MQTT 协议,连接 ESP 设备到阿里云。
|
||||||
|
- Espressif SDK
|
||||||
|
- ESP32 & ESP32S2 平台: [ESP-IDF](https://github.com/espressif/esp-idf)
|
||||||
|
- ESP8266 平台: [ESP8266_RTOS_SDK](https://github.com/espressif/ESP8266_RTOS_SDK)
|
||||||
|
|
||||||
|
> Espressif SDK 下载好后:
|
||||||
|
> ESP-IDF: 请切换到 v4.2 分支: `git checkout v4.2`
|
||||||
|
如果需要使用 ESP32S2 模组,请切换到 v4.2 版本: `git checkout v4.2`
|
||||||
|
> ESP8266_RTOS_SDK: 请切换到 v3.3 分支: `git checkout v3.3`
|
||||||
|
|
||||||
|
# <span id = "makeflash">6.编译 & 烧写 & 运行</span>
|
||||||
|
## 6.1 编译
|
||||||
|
|
||||||
|
### 6.1.1 导出编译器
|
||||||
|
参考 [工具链的设置](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/get-started/linux-setup.html)
|
||||||
|
|
||||||
|
### 6.1.2 编译 demo 示例
|
||||||
|
**由于 esp32 和 esp8266 将会采用不同的 sdkconfig.defaults 和对应的 partitions.csv,在对应的 make 命令中加入了对应的芯片选项,如 chip=esp32 或 chip=esp8266。**
|
||||||
|
|
||||||
|
当 chip=esp32 时将默认使用 sdkconfig_esp32.defaults 以及 partitions_esp32.csv。
|
||||||
|
|
||||||
|
当 chip=esp8266 时将默认使用 sdkconfig_esp8266.defaults 以及 partitions_esp8266.csv。
|
||||||
|
|
||||||
|
当使用 esp32s2 时,将默认使用 sdkconfig.defaults ,sdkconfig.defaults.esp32s2 以及 partitions_esp32s2.csv,编译方式与 8266 & 32 都不一样,需要使用 cmake 进行编译。
|
||||||
|
|
||||||
|
以上需要特别注意。
|
||||||
|
|
||||||
|
在 esp-aliyun 目录下执行:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd fastbee\sdk\ESP-IDF\esp-aliyun
|
||||||
|
make chip=esp32 defconfig
|
||||||
|
make menuconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
如果需要编译esp32s2版本, 请按照如下步骤编译:
|
||||||
|
|
||||||
|
在 esp-aliyun 目录下执行:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd fastbee\sdk\ESP-IDF\esp-aliyun
|
||||||
|
idf.py set-target esp32s2
|
||||||
|
idf.py menuconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
- 配置烧写串口
|
||||||
|
- 配置 `WIFI_SSID`, `WIFI_PASSWORD`
|
||||||
|
|
||||||
|
如果需要编译esp32s3版本, 请按照如下步骤编译:
|
||||||
|
|
||||||
|
在 esp-aliyun 目录下执行:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd fastbee\sdk\ESP-IDF\esp-aliyun
|
||||||
|
idf.py set-target esp32s3
|
||||||
|
idf.py menuconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
2.生成最终 bin
|
||||||
|
|
||||||
|
```
|
||||||
|
make -j8
|
||||||
|
```
|
||||||
|
使用 esp32s2/esp32s3 生成 bin
|
||||||
|
|
||||||
|
```
|
||||||
|
idf.py build
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6.2 擦除 & 编译烧写 & 下载固件 & 查看 log
|
||||||
|
将 USB 线连接好 ESP 设备和 PC,确保烧写端口正确。
|
||||||
|
|
||||||
|
### 6.2.1[可选] 擦除 flash
|
||||||
|
```
|
||||||
|
make erase_flash
|
||||||
|
```
|
||||||
|
> 注:无需每次擦除,擦除后需要重做 6.2.3。
|
||||||
|
|
||||||
|
### 6.2.2 烧录程序
|
||||||
|
```
|
||||||
|
make flash
|
||||||
|
```
|
||||||
|
|
||||||
|
使用 esp32s2/esp32s3 擦除 flash
|
||||||
|
```
|
||||||
|
idf.py -p (PORT) erase_flash
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2.3 烧录三元组信息
|
||||||
|
参考 [量产说明](./aliyunsdk/config/mass_mfg/README.md) 文档烧录三元组 NVS 分区。
|
||||||
|
|
||||||
|
## 6.2.4 运行
|
||||||
|
|
||||||
|
```
|
||||||
|
make monitor
|
||||||
|
```
|
||||||
|
|
||||||
|
> 也可执行 `make flash monitor` 来编译烧写和查看 log。
|
||||||
127
sdk/ESP-IDF/esp_fastbee_aliyun/README_examples.md
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
# Smart Light 解决方案
|
||||||
|
|
||||||
|
### 解决方案部署
|
||||||
|
#### 1.参考 [README](./README.md) 文档进行硬件准备、环境搭建、SDK 准备
|
||||||
|
|
||||||
|
#### 2.阿里云平台部署
|
||||||
|
在阿里云 [生活物联网平台](https://living.aliyun.com/#/) 创建产品, 参考[创建产品文档](https://living.aliyun.com/doc#readygo.html).
|
||||||
|
> 配置较多, 如果不太懂, 也不用纠结, 后续都可以修改.
|
||||||
|
|
||||||
|
部署自己的产品, 可参考如下:
|
||||||
|
新增 RGB 调色功能:
|
||||||
|

|
||||||
|
|
||||||
|
新增测试设备, 此处即可以获得`三元组`, 后续需要烧录到 NVS 分区.
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
选择面板, 手机 APP 上会显示同样界面; `配网二维码`是贴在产品包装上, 终端客户给设备配网中需扫描此二维码.
|
||||||
|

|
||||||
|
|
||||||
|
选择面板时, 主题面板在手机上仅能显示标准界面, 没有 RGB 调色功能. 可以自定义面板, 增加 RGB 调色.
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
配网方案选择:
|
||||||
|

|
||||||
|
|
||||||
|
完成
|
||||||
|

|
||||||
|
|
||||||
|
#### 3.下载本工程
|
||||||
|
```
|
||||||
|
git clone https://github.com/espressif/esp-aliyun.git
|
||||||
|
cd esp-aliyun
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.烧录三元组信息
|
||||||
|
- 参考 [量产说明](../../../config/mass_mfg/README.md) 文档烧录三元组 NVS 分区.
|
||||||
|
|
||||||
|
> 如果执行了 `make erase_flash`, 需要重新烧录三元组.
|
||||||
|
|
||||||
|
#### 5.配置 `smart light example`
|
||||||
|
- RGB 灯分别接 ESP32/ESP8266 开发板上 `GPIO0`, `GPIO2`, `GPIO4` (可在 `lightbulb.c` 中修改)
|
||||||
|
|
||||||
|
#### 6.编译 `smart light` 并烧录运行
|
||||||
|
```
|
||||||
|
cd examples/solutions/smart_light
|
||||||
|
make chip=esp32 defconfig 或者 make chip=esp8266 defconfig
|
||||||
|
make -j8 flash monitor
|
||||||
|
```
|
||||||
|
使用 esp32s2 请参考根目录 README。
|
||||||
|
|
||||||
|
> 在测试配网中, 请先执行 `make erase_flash` .
|
||||||
|
|
||||||
|
#### 7.设备第一次运行时, 会进入配网
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 8.手机从[阿里云官网](https://living.aliyun.com/doc#muti-app.html) 下载 `云智能` 公版 APP, 国内用户版.
|
||||||
|
|
||||||
|
#### 9.注册好账号后,进入 APP, 右上角扫描, 扫描第二步的二维码配网.
|
||||||
|
设备端配网成功后会保存 `ssid` 和 `password` :
|
||||||
|

|
||||||
|
|
||||||
|
设备与手机绑定成功后, APP 上会弹出灯的配置页面. 返回主页显示灯 `在线`.
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
#### 10.控制智能灯
|
||||||
|
|
||||||
|
在 APP 上打开灯, 设备端收到消息:
|
||||||
|

|
||||||
|
|
||||||
|
在 APP 上设置 RGB 调色:
|
||||||
|

|
||||||
|
|
||||||
|
设备端即解析 RGB 颜色, 并设置到具体的灯产品上.
|
||||||
|

|
||||||
|
|
||||||
|
#### 11.重新配网
|
||||||
|
快速重启设备 5 次, 设备会擦除配置信息, 重新进入配网状态.
|
||||||
|
|
||||||
|
可以配置快速重启的次数和超时时间.
|
||||||
|
```
|
||||||
|
cd examples/solutions/smart_light
|
||||||
|
make menuconfig
|
||||||
|
```
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
#### 12.OTA 支持
|
||||||
|
参考 examples/ota/ota_example_mqtt 示例下的 [README](../../ota/ota_example_mqtt/README.md) , 向管理控制台上传固件, 验证固件后, 下发升级指令.
|
||||||
|
设备端收到升级指令后, 即开始 OTA:
|
||||||
|

|
||||||
|
|
||||||
|
升级完成后, 会检查固件的有效性, 下图说明固件有效.
|
||||||
|

|
||||||
|
|
||||||
|
iotkit-embedded 目前没有设置软重启操作, 可以手动按模组重启键运行新固件:
|
||||||
|

|
||||||
|
|
||||||
|
#### 13.天猫精灵
|
||||||
|
##### 13.1 天猫精灵控制设备
|
||||||
|
针对使用公版 APP 的产品,用户可以一键开通天猫精灵,实现天猫精灵音箱对设备的控制. 使用步骤参照[阿里云文档](https://living.aliyun.com/doc#TmallGenie.html).
|
||||||
|
- 在阿里云 [生活物联网平台](https://living.aliyun.com/#/)上一键开通天猫精灵, 查看功能映射.
|
||||||
|
- 在 `云智能` [公版 APP]((https://living.aliyun.com/doc#muti-app.html))上绑定天猫精灵账号(即淘宝账号).
|
||||||
|
|
||||||
|
注意最后步骤, 否则天猫精灵无法找到设备:
|
||||||
|
> 在天猫精灵 APP 找到 "阿里智能" 技能, 手动进行 "尝试" 或 "设备同步"(后期会进行自动同步)
|
||||||
|
> 即可在 "我家" 的设备列表中看到您的设备
|
||||||
|
|
||||||
|
完成以上步骤后,您可以通过天猫精灵音箱控制您的设备了. 您可以对天猫精灵说 "天猫精灵,开灯", "天猫精灵, 关灯", "天猫精灵, 把灯调成红色" 或者其他您希望设置的颜色, 设备即响应相应的命令.
|
||||||
|
|
||||||
|
##### 13.2 天猫精灵配网并控制设备
|
||||||
|
阿里云设备支持 `零配` 的配网方式.
|
||||||
|
使设备进入配网状态, 对天猫精灵说 "天猫精灵,发现设备"
|
||||||
|
天猫精灵回复 "正在为您扫描, 发现了智能灯, 现在连接吗"
|
||||||
|
对天猫精灵说 "连接" 或者 "是的"
|
||||||
|
天猫精灵回复 "好的, 设备连接中, 稍等一下下哦"
|
||||||
|
设备收到天猫精灵发送的管理帧配网信息, 进行联网:
|
||||||
|

|
||||||
|
|
||||||
|
等待联网成功, 天猫精灵说 "智能设备联网成功, 现在用语音控制它试试", 这时您可以通过天猫精灵音箱控制您的设备了.
|
||||||
|
|
||||||
|
如果您之前通过云智能 APP 配网, 天猫精灵配网成功后, 云智能 APP 将不再显示设备. 如果继续通过云智能 APP 配网, APP 会配网失败, 显示 "设备添加失败, 设备已被管理员绑定, 请联系管理员解绑或将设备分享给您".
|
||||||
|
> 在天猫精灵 APP 删除设备, 云智能 APP 再进行配网可以配置成功并显示设备.
|
||||||
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-redirect.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-se.png
Normal file
|
After Width: | Height: | Size: 175 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-sub.png
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-us.png
Normal file
|
After Width: | Height: | Size: 179 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p1.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p10.png
Normal file
|
After Width: | Height: | Size: 248 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p11.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p12.png
Normal file
|
After Width: | Height: | Size: 133 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p13.png
Normal file
|
After Width: | Height: | Size: 174 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p14.png
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p15.png
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p16.png
Normal file
|
After Width: | Height: | Size: 200 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p17.png
Normal file
|
After Width: | Height: | Size: 185 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p18.png
Normal file
|
After Width: | Height: | Size: 216 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p19.png
Normal file
|
After Width: | Height: | Size: 280 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p2.png
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p20.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p21.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p22.jpg
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p23.jpg
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p24.jpg
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p3.png
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p4.png
Normal file
|
After Width: | Height: | Size: 153 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p5.png
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p6.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p7.png
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p8.png
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
sdk/ESP-IDF/esp_fastbee_aliyun/_static/p9.png
Normal file
|
After Width: | Height: | Size: 297 KiB |
@@ -0,0 +1,7 @@
|
|||||||
|
set(COMPONENT_ADD_INCLUDEDIRS .)
|
||||||
|
|
||||||
|
set(COMPONENT_SRCS "factory_restore.c")
|
||||||
|
|
||||||
|
set(COMPONENT_REQUIRES "esp-aliyun")
|
||||||
|
|
||||||
|
register_component()
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
menu "[Aliyun]Factory restore"
|
||||||
|
|
||||||
|
config FACTORY_QUICK_REBOOT_TIMEOUT
|
||||||
|
int "Quick reboot timeout, unit second"
|
||||||
|
default 6
|
||||||
|
help
|
||||||
|
Timeout for exiting quick reboot timer, users should reboot device before this timeout.
|
||||||
|
|
||||||
|
config FACTORY_QUICK_REBOOT_MAX_TIMES
|
||||||
|
int "Quick reboot times max record"
|
||||||
|
default 5
|
||||||
|
help
|
||||||
|
If quick reboot times reach this max value, device will do factory restore.
|
||||||
|
|
||||||
|
endmenu
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
COMPONENT_ADD_INCLUDEDIRS := ./
|
||||||
|
COMPONENT_SRCDIRS := ./
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* ESPRESSIF MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
|
||||||
|
* it is 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
|
#include "freertos/timers.h"
|
||||||
|
#include "esp_sleep.h"
|
||||||
|
#include "dm_wrapper.h"
|
||||||
|
#include "conn_mgr.h"
|
||||||
|
|
||||||
|
#define FACTORY_QUICK_REBOOT_TIMEOUT (CONFIG_FACTORY_QUICK_REBOOT_TIMEOUT * 1000)
|
||||||
|
#define FACTORY_QUICK_REBOOT_MAX_TIMES CONFIG_FACTORY_QUICK_REBOOT_MAX_TIMES
|
||||||
|
#define FACTORY_QUICK_REBOOT_TIMES "q_rt"
|
||||||
|
|
||||||
|
#define AWSS_KV_RST "awss.rst"
|
||||||
|
|
||||||
|
static const char *TAG = "factory_rst";
|
||||||
|
|
||||||
|
static esp_err_t factory_restore_handle(void)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
int quick_reboot_times = 0;
|
||||||
|
|
||||||
|
/**< If the device restarts within the instruction time, the event_mdoe value will be incremented by one */
|
||||||
|
int length = sizeof(int);
|
||||||
|
ret = HAL_Kv_Get(FACTORY_QUICK_REBOOT_TIMES, &quick_reboot_times, &length);
|
||||||
|
|
||||||
|
quick_reboot_times++;
|
||||||
|
|
||||||
|
ret = HAL_Kv_Set(FACTORY_QUICK_REBOOT_TIMES, &quick_reboot_times, sizeof(int), 0);
|
||||||
|
|
||||||
|
if (quick_reboot_times >= FACTORY_QUICK_REBOOT_MAX_TIMES) {
|
||||||
|
char rst = 0x01;
|
||||||
|
|
||||||
|
/* since we cannot report reset status to cloud in this stage, just set the reset flag.
|
||||||
|
when connects to cloud, awss will do the reset report. */
|
||||||
|
ret = HAL_Kv_Set(AWSS_KV_RST, &rst, sizeof(rst), 0);
|
||||||
|
ret = HAL_Kv_Del(FACTORY_QUICK_REBOOT_TIMES);
|
||||||
|
|
||||||
|
ESP_LOGW(TAG, "factory restore");
|
||||||
|
conn_mgr_reset_wifi_config();
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "quick reboot times %d, don't need to restore", quick_reboot_times);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void factory_restore_timer_handler(void *timer)
|
||||||
|
{
|
||||||
|
if (!xTimerStop(timer, 0)) {
|
||||||
|
ESP_LOGE(TAG, "xTimerStop timer %p", timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!xTimerDelete(timer, 0)) {
|
||||||
|
ESP_LOGE(TAG, "xTimerDelete timer %p", timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* erase reboot times record */
|
||||||
|
HAL_Kv_Del(FACTORY_QUICK_REBOOT_TIMES);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Quick reboot timeout, clear reboot times");
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t factory_restore_init(void)
|
||||||
|
{
|
||||||
|
#ifndef CONFIG_IDF_TARGET_ESP8266
|
||||||
|
if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_UNDEFINED) {
|
||||||
|
HAL_Kv_Del(FACTORY_QUICK_REBOOT_TIMES);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TimerHandle_t timer = xTimerCreate("factory_clear", FACTORY_QUICK_REBOOT_TIMEOUT / portTICK_RATE_MS,
|
||||||
|
false, NULL, factory_restore_timer_handler);
|
||||||
|
|
||||||
|
xTimerStart(timer, portMAX_DELAY);
|
||||||
|
|
||||||
|
return factory_restore_handle();
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* ESPRESSIF MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||||
|
* it is 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esp_err.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize factory restore
|
||||||
|
*
|
||||||
|
* @note For some devices which don't have a physical restore key or button, such as light, we use
|
||||||
|
* a quick reboot method to record the reboot times, if users quickly reboot the device within
|
||||||
|
* a specific time, configured by FACTORY_QUICK_REBOOT_TIMEOUT, and reboot several times,
|
||||||
|
* configured by FACTORY_QUICK_REBOOT_MAX_TIMES, the device will do a factory restore, clear
|
||||||
|
* stored ssid and password.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK : OK
|
||||||
|
* - others : fail
|
||||||
|
*/
|
||||||
|
esp_err_t factory_restore_init(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
set(COMPONENT_ADD_INCLUDEDIRS "./include")
|
||||||
|
|
||||||
|
set(COMPONENT_SRCS "fastbee.c" "Config.c" "Mqtt.c")
|
||||||
|
|
||||||
|
set(COMPONENT_REQUIRES "esp-aliyun" "mqtt" "json")
|
||||||
|
|
||||||
|
register_component()
|
||||||
174
sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/Config.c
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* function: 设备交互
|
||||||
|
* board: esp8266,esp32,esp32s2,esp32s3 core for esp-idf v4.4.7
|
||||||
|
* source: https://gitee.com/zhuangpengli/IOTDeviceSDK
|
||||||
|
* copyright: zhuangpeng.li all rights reserved.
|
||||||
|
********************************************************************/
|
||||||
|
#include "Config.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
#include "nvs.h"
|
||||||
|
#include "dm_wrapper.h"
|
||||||
|
|
||||||
|
// 设备信息配置
|
||||||
|
char g_userId[USER_ID_LEN + 1] = {0};
|
||||||
|
char g_productId[PRODUCT_ID_LEN + 1] = {0};
|
||||||
|
char g_deviceSN[DEVICE_SN_LEN + 1] = {0};
|
||||||
|
|
||||||
|
// Mqtt配置
|
||||||
|
char g_mqtt_url[MQTT_URL_LEN + 1] = {0};
|
||||||
|
char g_mqtt_username[MQTT_USERNAME_LEN + 1] = {0};
|
||||||
|
char g_mqtt_password[MQTT_PASSWORD_LEN + 1] = {0};
|
||||||
|
char g_mqtt_clientid[MQTT_CLIENTID_LEN + 1] = {0};
|
||||||
|
char g_mqtt_prefix[MQTT_PREFIX_LEN + 1] = {0};
|
||||||
|
|
||||||
|
float rssi = 0;
|
||||||
|
char wumei_iv[17] = "wumei-smart-open";
|
||||||
|
int monitorCount = 0;
|
||||||
|
long monitorInterval = 1000;
|
||||||
|
bool isApMode = false;
|
||||||
|
/********************************** begin 可配置的项 **********************************/
|
||||||
|
// wifi信息
|
||||||
|
char *wifiSsid = "";
|
||||||
|
char *wifiPwd = "";
|
||||||
|
// 产品启用授权码,则授权码不能为空
|
||||||
|
char *authCode = "";
|
||||||
|
// 设备信息配置
|
||||||
|
float firmwareVersion = 1.0;
|
||||||
|
// 经度和纬度可选,如果产品使用设备定位,则必须传
|
||||||
|
float latitude = 0;
|
||||||
|
float longitude = 0;
|
||||||
|
// Mqtt配置
|
||||||
|
char mqttSecret[17] = "KV52PPZ813EFCQD8";
|
||||||
|
// NTP地址(用于获取时间,修改为自己部署项目的接口地址)
|
||||||
|
char *ntpServer = "http://fastbee.cn:8080/iot/tool/ntp?deviceSendTime=";
|
||||||
|
/********************************** end 可配置的项 **********************************/
|
||||||
|
|
||||||
|
static const char *TAG = "FASTBEE_CONFIG";
|
||||||
|
static bool s_part_init_flag;
|
||||||
|
|
||||||
|
static esp_err_t HAL_ProductParam_init(void)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (s_part_init_flag == false) {
|
||||||
|
if ((ret = nvs_flash_init_partition(MFG_FASTBEE_PARTITION_NAME)) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "NVS Flash init %s failed, Please check that you have flashed fctry partition!!!", MFG_FASTBEE_PARTITION_NAME);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_part_init_flag = true;
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int HAL_GetProductParam(char *param_name, const char *param_name_str)
|
||||||
|
{
|
||||||
|
esp_err_t ret;
|
||||||
|
size_t read_len = 0;
|
||||||
|
nvs_handle handle;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (HAL_ProductParam_init() != ESP_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param_name == NULL) {
|
||||||
|
ESP_LOGE(TAG, "%s param %s NULL", __func__, param_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nvs_open_from_partition(MFG_FASTBEE_PARTITION_NAME, NVS_FASTBEE_PRODUCT, NVS_READONLY, &handle);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s nvs_open failed with %x", __func__, ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nvs_get_str(handle, param_name_str, NULL, (size_t *)&read_len);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s nvs_get_str get %s failed with %x", __func__, param_name_str, ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nvs_get_str(handle, param_name_str, param_name, (size_t *)&read_len);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s nvs_get_str get %s failed with %x", __func__, param_name_str, ret);
|
||||||
|
} else {
|
||||||
|
ESP_LOGV(TAG, "%s %s %s", __func__, param_name_str, param_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
return read_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HAL_GetMqttUrl(char mqtt_url[MQTT_URL_LEN + 1])
|
||||||
|
{
|
||||||
|
return HAL_GetProductParam(mqtt_url, "MQTTUrl");
|
||||||
|
}
|
||||||
|
int HAL_GetMqttUsername(char mqtt_username[MQTT_USERNAME_LEN + 1])
|
||||||
|
{
|
||||||
|
return HAL_GetProductParam(mqtt_username, "MQTTUsername");
|
||||||
|
}
|
||||||
|
int HAL_GetMqttPassword(char mqtt_password[MQTT_PASSWORD_LEN + 1])
|
||||||
|
{
|
||||||
|
return HAL_GetProductParam(mqtt_password, "MQTTPassword");
|
||||||
|
}
|
||||||
|
int HAL_GetMqttClientId(char mqtt_clientid[MQTT_CLIENTID_LEN + 1])
|
||||||
|
{
|
||||||
|
return HAL_GetProductParam(mqtt_clientid, "MQTTClientId");
|
||||||
|
}
|
||||||
|
int HAL_GetUserId(char userid[USER_ID_LEN + 1])
|
||||||
|
{
|
||||||
|
return HAL_GetProductParam(userid, "UserId");
|
||||||
|
}
|
||||||
|
int HAL_GetDeviceSN(char deviceSN[DEVICE_SN_LEN + 1])
|
||||||
|
{
|
||||||
|
return HAL_GetProductParam(deviceSN, "DeviceSN");
|
||||||
|
}
|
||||||
|
int HAL_GetProductId(char productId[PRODUCT_ID_LEN + 1])
|
||||||
|
{
|
||||||
|
return HAL_GetProductParam(productId, "ProductId");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadConfig() {
|
||||||
|
HAL_GetMqttUrl(g_mqtt_url);
|
||||||
|
if (strlen(g_mqtt_url) == 0) {
|
||||||
|
//加载默认配置
|
||||||
|
memcpy(g_mqtt_url, CONFIG_ESP_MQTT_PLATFORM_FASTBEE_URL, strlen(CONFIG_ESP_MQTT_PLATFORM_FASTBEE_URL));
|
||||||
|
}
|
||||||
|
HAL_GetMqttUsername(g_mqtt_username);
|
||||||
|
if (strlen(g_mqtt_username) == 0) {
|
||||||
|
memcpy(g_mqtt_username, CONFIG_ESP_MQTT_PLATFORM_FASTBEE_USERNAME, strlen(CONFIG_ESP_MQTT_PLATFORM_FASTBEE_USERNAME));
|
||||||
|
}
|
||||||
|
HAL_GetMqttPassword(g_mqtt_password);
|
||||||
|
if (strlen(g_mqtt_password) == 0) {
|
||||||
|
memcpy(g_mqtt_password, CONFIG_ESP_MQTT_PLATFORM_FASTBEE_PASSWORD, strlen(CONFIG_ESP_MQTT_PLATFORM_FASTBEE_PASSWORD));
|
||||||
|
}
|
||||||
|
HAL_GetMqttClientId(g_mqtt_clientid);
|
||||||
|
if (strlen(g_mqtt_clientid) == 0) {
|
||||||
|
HAL_Snprintf(g_mqtt_clientid, sizeof(g_mqtt_clientid), "S&%s&%s&%s", CONFIG_ESP_MQTT_PLATFORM_FASTBEE_DEVICESN,CONFIG_ESP_MQTT_PLATFORM_FASTBEE_PRODICTID,CONFIG_ESP_MQTT_PLATFORM_FASTBEE_USERID);
|
||||||
|
}
|
||||||
|
HAL_GetUserId(g_userId);
|
||||||
|
if (strlen(g_userId) == 0) {
|
||||||
|
memcpy(g_userId, CONFIG_ESP_MQTT_PLATFORM_FASTBEE_USERID, strlen(CONFIG_ESP_MQTT_PLATFORM_FASTBEE_USERID));
|
||||||
|
}
|
||||||
|
HAL_GetDeviceSN(g_productId);
|
||||||
|
if (strlen(g_productId) == 0) {
|
||||||
|
memcpy(g_productId, CONFIG_ESP_MQTT_PLATFORM_FASTBEE_PRODICTID, strlen(CONFIG_ESP_MQTT_PLATFORM_FASTBEE_PRODICTID));
|
||||||
|
}
|
||||||
|
HAL_GetProductId(g_deviceSN);
|
||||||
|
if (strlen(g_deviceSN) == 0) {
|
||||||
|
memcpy(g_deviceSN, CONFIG_ESP_MQTT_PLATFORM_FASTBEE_DEVICESN, strlen(CONFIG_ESP_MQTT_PLATFORM_FASTBEE_DEVICESN));
|
||||||
|
}
|
||||||
|
HAL_Snprintf(g_mqtt_prefix, sizeof(g_mqtt_prefix), "/%s/%s", g_productId,g_deviceSN);
|
||||||
|
}
|
||||||
158
sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/Mqtt.c
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* function: 设备交互
|
||||||
|
* board: esp8266,esp32,esp32s2,esp32s3 core for esp-idf v4.4.7
|
||||||
|
* source: https://gitee.com/zhuangpengli/IOTDeviceSDK
|
||||||
|
* copyright: zhuangpeng.li all rights reserved.
|
||||||
|
********************************************************************/
|
||||||
|
#include "Mqtt.h"
|
||||||
|
#include "Config.h"
|
||||||
|
#include "cJSON.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "dm_wrapper.h"
|
||||||
|
|
||||||
|
char *sInfoTopic = "/info/get";
|
||||||
|
char *sOtaTopic = "/ota/get";
|
||||||
|
char *sNtpTopic = "/ntp/get";
|
||||||
|
char *sPropertyTopic = "/property/get";
|
||||||
|
char *sFunctionTopic = "/function/get";
|
||||||
|
char *sPropertyOnline = "/property-online/get";
|
||||||
|
char *sFunctionOnline = "/function-online/get";
|
||||||
|
char *sMonitorTopic = "/monitor/get";
|
||||||
|
// Mqtt发布的主题
|
||||||
|
char *pInfoTopic = "/info/post";
|
||||||
|
char *pNtpTopic = "/ntp/post";
|
||||||
|
char *pPropertyTopic = "/property/post";
|
||||||
|
char *pFunctionTopic = "/function/post";
|
||||||
|
char *pMonitorTopic = "/monitor/post";
|
||||||
|
char *pEventTopic = "/event/post";
|
||||||
|
|
||||||
|
static const char *TAG = "FASTBEE_MQTT";
|
||||||
|
// 订阅系统主题
|
||||||
|
void subscribeTopic(esp_mqtt_client_handle_t client) {
|
||||||
|
char topic[128] = {0};
|
||||||
|
int msg_id;
|
||||||
|
HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sInfoTopic);
|
||||||
|
msg_id = esp_mqtt_client_subscribe(client, topic, 0);
|
||||||
|
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||||
|
|
||||||
|
memset(topic, 0, sizeof(topic));
|
||||||
|
HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sOtaTopic);
|
||||||
|
msg_id = esp_mqtt_client_subscribe(client, topic, 0);
|
||||||
|
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||||
|
|
||||||
|
memset(topic, 0, sizeof(topic));
|
||||||
|
HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sNtpTopic);
|
||||||
|
msg_id = esp_mqtt_client_subscribe(client, topic, 0);
|
||||||
|
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||||
|
|
||||||
|
memset(topic, 0, sizeof(topic));
|
||||||
|
HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sPropertyTopic);
|
||||||
|
msg_id = esp_mqtt_client_subscribe(client, topic, 0);
|
||||||
|
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||||
|
|
||||||
|
memset(topic, 0, sizeof(topic));
|
||||||
|
HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sFunctionTopic);
|
||||||
|
msg_id = esp_mqtt_client_subscribe(client, topic, 0);
|
||||||
|
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||||
|
|
||||||
|
memset(topic, 0, sizeof(topic));
|
||||||
|
HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sPropertyOnline);
|
||||||
|
msg_id = esp_mqtt_client_subscribe(client, topic, 0);
|
||||||
|
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||||
|
|
||||||
|
memset(topic, 0, sizeof(topic));
|
||||||
|
HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sFunctionOnline);
|
||||||
|
msg_id = esp_mqtt_client_subscribe(client, topic, 0);
|
||||||
|
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||||
|
|
||||||
|
memset(topic, 0, sizeof(topic));
|
||||||
|
HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sMonitorTopic);
|
||||||
|
msg_id = esp_mqtt_client_subscribe(client, topic, 0);
|
||||||
|
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1.发布设备信息
|
||||||
|
void publishInfo(esp_mqtt_client_handle_t client) {
|
||||||
|
char topic[128] = {0};
|
||||||
|
int msg_id;
|
||||||
|
cJSON *json = cJSON_CreateObject();
|
||||||
|
HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, pInfoTopic);
|
||||||
|
// 向JSON对象中添加数据
|
||||||
|
cJSON_AddNumberToObject(json, "rssi", 3);
|
||||||
|
cJSON_AddNumberToObject(json, "firmwareVersion", firmwareVersion);
|
||||||
|
cJSON_AddNumberToObject(json, "status", 3);
|
||||||
|
cJSON_AddStringToObject(json, "userId", g_userId);
|
||||||
|
cJSON_AddNumberToObject(json, "longitude", longitude);
|
||||||
|
cJSON_AddNumberToObject(json, "latitude", latitude);
|
||||||
|
|
||||||
|
cJSON *summary = cJSON_CreateObject();
|
||||||
|
cJSON_AddStringToObject(summary, "name", "fastbee");
|
||||||
|
cJSON_AddStringToObject(summary, "chip", "esp32");
|
||||||
|
cJSON_AddStringToObject(summary, "author", "zhuangpeng.li");
|
||||||
|
cJSON_AddNumberToObject(summary, "version", 1.6);
|
||||||
|
cJSON_AddStringToObject(summary, "create", "2024-07-07");
|
||||||
|
|
||||||
|
cJSON_AddItemToObject(json, "summary", summary);
|
||||||
|
char *json_string = cJSON_Print(json);
|
||||||
|
msg_id = esp_mqtt_client_publish(client, topic, json_string, 0, 0, 0);
|
||||||
|
ESP_LOGI(TAG, "sent publish %s, msg_id= %d, msg: %s", topic, msg_id, json_string);
|
||||||
|
|
||||||
|
cJSON_Delete(json);
|
||||||
|
free(json_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.发布时钟同步信,用于获取当前时间(可选)
|
||||||
|
void publishNtp(esp_mqtt_client_handle_t client) {
|
||||||
|
char topic[128] = {0};
|
||||||
|
int msg_id;
|
||||||
|
cJSON *json = cJSON_CreateObject();
|
||||||
|
HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, pNtpTopic);
|
||||||
|
cJSON_AddStringToObject(json, "deviceSendTime", "test");
|
||||||
|
char *json_string = cJSON_Print(json);
|
||||||
|
msg_id = esp_mqtt_client_publish(client, topic, json_string, 0, 0, 0);
|
||||||
|
ESP_LOGI(TAG, "sent publish %s, msg_id= %d, msg: %s", topic, msg_id, json_string);
|
||||||
|
|
||||||
|
cJSON_Delete(json);
|
||||||
|
free(json_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.发布属性
|
||||||
|
void publishProperty(esp_mqtt_client_handle_t client, const char *msg) {
|
||||||
|
char topic[128] = {0};
|
||||||
|
int msg_id;
|
||||||
|
HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, pPropertyTopic);
|
||||||
|
msg_id = esp_mqtt_client_publish(client, topic, msg, 0, 0, 0);
|
||||||
|
ESP_LOGI(TAG, "发布属性主题: %s", topic);
|
||||||
|
ESP_LOGI(TAG, "消息id= %d, 消息: %s", msg_id, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4.发布功能
|
||||||
|
void publishFunction(esp_mqtt_client_handle_t client, const char *msg) {
|
||||||
|
char topic[128] = {0};
|
||||||
|
int msg_id;
|
||||||
|
HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, pFunctionTopic);
|
||||||
|
msg_id = esp_mqtt_client_publish(client, topic, msg, 0, 0, 0);
|
||||||
|
ESP_LOGI(TAG, "发布功能主题: %s", topic);
|
||||||
|
ESP_LOGI(TAG, "消息id= %d, 消息: %s", msg_id, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5.发布事件
|
||||||
|
void publishEvent(esp_mqtt_client_handle_t client, const char *msg) {
|
||||||
|
char topic[128] = {0};
|
||||||
|
int msg_id;
|
||||||
|
HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, pEventTopic);
|
||||||
|
msg_id = esp_mqtt_client_publish(client, topic, msg, 0, 0, 0);
|
||||||
|
ESP_LOGI(TAG, "发布事件主题: %s", topic);
|
||||||
|
ESP_LOGI(TAG, "消息id= %d, 消息: %s", msg_id, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6.发布实时监测数据
|
||||||
|
void publishMonitor(esp_mqtt_client_handle_t client, const char *msg) {
|
||||||
|
char topic[128] = {0};
|
||||||
|
int msg_id;
|
||||||
|
HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, pMonitorTopic);
|
||||||
|
// 发布实时监测数据(不会存储,需要实时存储则发布为属性)
|
||||||
|
msg_id = esp_mqtt_client_publish(client, topic, msg, 0, 0, 0);
|
||||||
|
ESP_LOGI(TAG, "发布实时监测主题: %s", topic);
|
||||||
|
ESP_LOGI(TAG, "消息id= %d, 消息: %s", msg_id, msg);
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
COMPONENT_ADD_INCLUDEDIRS := ./include
|
||||||
|
COMPONENT_SRCDIRS := ./
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fastbee-key,namespace,
|
||||||
|
MQTTUrl,data,string
|
||||||
|
MQTTUsername,data,string
|
||||||
|
MQTTPassword,data,string
|
||||||
|
MQTTClientId,data,string
|
||||||
|
UserId,data,string
|
||||||
|
DeviceSN,data,string
|
||||||
|
ProductId,data,string
|
||||||
|
@@ -0,0 +1,4 @@
|
|||||||
|
id,MQTTUrl,MQTTUsername,MQTTPassword,MQTTClientId,UserId,DeviceSN,ProductId
|
||||||
|
1,fastbee.cn:1883,FastBee,P63653937TRQ8F27,S&DCDA0C11FEBC&588&1,1,DCDA0C11FEBC,588
|
||||||
|
2,fastbee.cn:1883,FastBee,P63653937TRQ8F27,S&DCDA0C11FEBC&588&1,1,DCDA0C11FEBC,588
|
||||||
|
3,fastbee.cn:1883,FastBee,P63653937TRQ8F27,S&DCDA0C11FEBC&588&1,1,DCDA0C11FEBC,588
|
||||||
|
@@ -0,0 +1,9 @@
|
|||||||
|
key,type,encoding,value
|
||||||
|
fastbee-key,namespace,,
|
||||||
|
MQTTUrl,data,string,fastbee.cn:1883
|
||||||
|
MQTTUsername,data,string,FastBee
|
||||||
|
MQTTPassword,data,string,P63653937TRQ8F27
|
||||||
|
MQTTClientId,data,string,S&DCDA0C11FEBC&588&1
|
||||||
|
UserId,data,string,1
|
||||||
|
DeviceSN,data,string,DCDA0C11FEBC
|
||||||
|
ProductId,data,string,588
|
||||||
|
98
sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/fastbee.c
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* function: 设备交互
|
||||||
|
* board: esp8266,esp32,esp32s2,esp32s3 core for esp-idf v4.4.7
|
||||||
|
* source: https://gitee.com/zhuangpengli/IOTDeviceSDK
|
||||||
|
* copyright: zhuangpeng.li all rights reserved.
|
||||||
|
********************************************************************/
|
||||||
|
#include "fastbee.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "mqtt.h"
|
||||||
|
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "dm_wrapper.h"
|
||||||
|
|
||||||
|
static const char *TAG = "FASTBEE";
|
||||||
|
|
||||||
|
static void log_error_if_nonzero(const char *message, int error_code)
|
||||||
|
{
|
||||||
|
if (error_code != 0) {
|
||||||
|
ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* @brief Event handler registered to receive MQTT events
|
||||||
|
*
|
||||||
|
* This function is called by the MQTT client event loop.
|
||||||
|
*
|
||||||
|
* @param handler_args user data registered to the event.
|
||||||
|
* @param base Event base for the handler(always MQTT Base in this example).
|
||||||
|
* @param event_id The id for the received event.
|
||||||
|
* @param event_data The data for the event, esp_mqtt_event_handle_t.
|
||||||
|
*/
|
||||||
|
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||||
|
{
|
||||||
|
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
|
||||||
|
esp_mqtt_event_handle_t event = event_data;
|
||||||
|
esp_mqtt_client_handle_t client = event->client;
|
||||||
|
int msg_id;
|
||||||
|
switch ((esp_mqtt_event_id_t)event_id) {
|
||||||
|
case MQTT_EVENT_CONNECTED:
|
||||||
|
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||||
|
subscribeTopic(client);
|
||||||
|
publishInfo(client);
|
||||||
|
break;
|
||||||
|
case MQTT_EVENT_DISCONNECTED:
|
||||||
|
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||||
|
break;
|
||||||
|
case MQTT_EVENT_SUBSCRIBED:
|
||||||
|
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
|
||||||
|
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
|
||||||
|
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||||
|
break;
|
||||||
|
case MQTT_EVENT_UNSUBSCRIBED:
|
||||||
|
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
|
||||||
|
break;
|
||||||
|
case MQTT_EVENT_PUBLISHED:
|
||||||
|
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
|
||||||
|
break;
|
||||||
|
case MQTT_EVENT_DATA:
|
||||||
|
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||||
|
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
|
||||||
|
printf("DATA=%.*s\r\n", event->data_len, event->data);
|
||||||
|
break;
|
||||||
|
case MQTT_EVENT_ERROR:
|
||||||
|
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||||
|
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
|
||||||
|
log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
|
||||||
|
log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
|
||||||
|
log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
|
||||||
|
ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fastbee_thread(void *paras){
|
||||||
|
loadConfig();
|
||||||
|
esp_mqtt_client_config_t mqtt_cfg = {
|
||||||
|
.uri = g_mqtt_url,
|
||||||
|
.client_id = g_mqtt_clientid,
|
||||||
|
.username = g_mqtt_username,
|
||||||
|
.password = g_mqtt_password,
|
||||||
|
};
|
||||||
|
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||||
|
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
|
||||||
|
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||||
|
esp_mqtt_client_start(client);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fastbee_main(void *paras)
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
fastbee_thread(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* function: 设备交互
|
||||||
|
* board: esp8266,esp32,esp32s2,esp32s3 core for esp-idf v4.4.7
|
||||||
|
* source: https://gitee.com/zhuangpengli/IOTDeviceSDK
|
||||||
|
* copyright: zhuangpeng.li all rights reserved.
|
||||||
|
********************************************************************/
|
||||||
|
#ifndef _CONFIG_H
|
||||||
|
#define _CONFIG_H
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define MQTT_URL_LEN (64)
|
||||||
|
#define MQTT_USERNAME_LEN (64)
|
||||||
|
#define MQTT_PASSWORD_LEN (64)
|
||||||
|
#define MQTT_CLIENTID_LEN (64)
|
||||||
|
#define USER_ID_LEN (16)
|
||||||
|
#define DEVICE_SN_LEN (64)
|
||||||
|
#define PRODUCT_ID_LEN (16)
|
||||||
|
#define MQTT_PREFIX_LEN (128)
|
||||||
|
|
||||||
|
#define MFG_FASTBEE_PARTITION_NAME "fctry"
|
||||||
|
#define NVS_FASTBEE_PRODUCT "fastbee-key"
|
||||||
|
|
||||||
|
extern char g_userId[USER_ID_LEN + 1]; // 用户ID
|
||||||
|
extern char g_productId[PRODUCT_ID_LEN + 1]; // 产品ID
|
||||||
|
extern char g_deviceSN[DEVICE_SN_LEN + 1]; // 设备编号(重要,同时是Mqtt的clientId)
|
||||||
|
|
||||||
|
// Mqtt配置
|
||||||
|
extern char g_mqtt_url[MQTT_URL_LEN + 1];
|
||||||
|
extern char g_mqtt_username[MQTT_USERNAME_LEN + 1];
|
||||||
|
extern char g_mqtt_password[MQTT_PASSWORD_LEN + 1];
|
||||||
|
extern char g_mqtt_clientid[MQTT_CLIENTID_LEN + 1];
|
||||||
|
extern char g_mqtt_prefix[MQTT_PREFIX_LEN + 1];
|
||||||
|
|
||||||
|
extern float rssi; // 信号强度(信号极好4格[-55— 0],信号好3格[-70— -55],信号一般2格[-85— -70],信号差1格[-100— -85])
|
||||||
|
extern char wumei_iv[17]; // AES加密偏移量,固定值16位
|
||||||
|
extern int monitorCount; // 发布监测数据的最大次数
|
||||||
|
extern long monitorInterval; // 发布监测数据的间隔,默认1000毫秒
|
||||||
|
extern bool isApMode; // 是否进入AP配网模式
|
||||||
|
|
||||||
|
/********************************** begin 可配置的项 **********************************/
|
||||||
|
extern char *wifiSsid; // WIFI的SSID
|
||||||
|
extern char *wifiPwd; // WIFI的密码
|
||||||
|
|
||||||
|
extern char *authCode; // 产品授权码,产品未启用时为空字符串
|
||||||
|
|
||||||
|
extern float firmwareVersion; // 固件版本
|
||||||
|
extern float latitude; // 设备精度
|
||||||
|
extern float longitude; // 设备维度
|
||||||
|
|
||||||
|
extern char mqttSecret[17]; // Mqtt秘钥,16位
|
||||||
|
extern char *ntpServer; // NTP服务地址,用于获取当前时间
|
||||||
|
/********************************** end 可配置的项 **********************************/
|
||||||
|
|
||||||
|
// 加载配置
|
||||||
|
void loadConfig();
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* function: 设备交互
|
||||||
|
* board: esp8266,esp32,esp32s2,esp32s3 core for esp-idf v4.4.7
|
||||||
|
* source: https://gitee.com/zhuangpengli/IOTDeviceSDK
|
||||||
|
* copyright: zhuangpeng.li all rights reserved.
|
||||||
|
********************************************************************/
|
||||||
|
#ifndef _FASTBEE_MQTT_H
|
||||||
|
#define _FASTBEE_MQTT_H
|
||||||
|
|
||||||
|
#include "mqtt_client.h"
|
||||||
|
// 订阅的主题
|
||||||
|
extern char *sInfoTopic; // 订阅设备信息
|
||||||
|
extern char *sOtaTopic; // 订阅OTA升级
|
||||||
|
extern char *sNtpTopic; // 订阅NTP时间
|
||||||
|
extern char *sPropertyTopic; // 订阅属性
|
||||||
|
extern char *sFunctionTopic; // 订阅功能
|
||||||
|
extern char *sPropertyOnline; // 订阅属性-在线模式
|
||||||
|
extern char *sFunctionOnline; // 订阅功能-在线模式
|
||||||
|
extern char *sMonitorTopic; // 订阅实时监测
|
||||||
|
// 发布的主题
|
||||||
|
extern char *pInfoTopic; // 发布设备信息
|
||||||
|
extern char *pNtpTopic; // 发布NTP时间
|
||||||
|
extern char *pPropertyTopic; // 发布属性
|
||||||
|
extern char *pFunctionTopic; // 发布功能
|
||||||
|
extern char *pMonitorTopic; // 发布实时监测数据
|
||||||
|
extern char *pEventTopic; // 发布事件
|
||||||
|
|
||||||
|
// 订阅系统主题
|
||||||
|
void subscribeTopic(esp_mqtt_client_handle_t client);
|
||||||
|
// 发布设备信息
|
||||||
|
void publishInfo(esp_mqtt_client_handle_t client);
|
||||||
|
// 发布时钟同步信息
|
||||||
|
void publishNtp(esp_mqtt_client_handle_t client);
|
||||||
|
// 发布事件
|
||||||
|
void publishEvent(esp_mqtt_client_handle_t client, const char *msg);
|
||||||
|
// 发布实时监测数据(不会存储,需要实时存储则发布属性)
|
||||||
|
void publishMonitor(esp_mqtt_client_handle_t client, const char *msg);
|
||||||
|
// 发布属性
|
||||||
|
void publishProperty(esp_mqtt_client_handle_t client, const char *msg);
|
||||||
|
// 发布功能
|
||||||
|
void publishFunction(esp_mqtt_client_handle_t client, const char *msg);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* function: 设备交互
|
||||||
|
* board: esp8266,esp32,esp32s2,esp32s3 core for esp-idf v4.4.7
|
||||||
|
* source: https://gitee.com/zhuangpengli/IOTDeviceSDK
|
||||||
|
* copyright: zhuangpeng.li all rights reserved.
|
||||||
|
********************************************************************/
|
||||||
|
#ifndef _FASTBEE_H
|
||||||
|
#define _FASTBEE_H
|
||||||
|
|
||||||
|
void fastbee_main(void *paras);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
set(COMPONENT_ADD_INCLUDEDIRS .)
|
||||||
|
|
||||||
|
set(COMPONENT_SRCS "lightbulb.c")
|
||||||
|
|
||||||
|
set(COMPONENT_REQUIRES)
|
||||||
|
|
||||||
|
register_component()
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
COMPONENT_ADD_INCLUDEDIRS := ./
|
||||||
|
COMPONENT_SRCDIRS := ./
|
||||||
327
sdk/ESP-IDF/esp_fastbee_aliyun/components/lightbulb/lightbulb.c
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
/*
|
||||||
|
* ESPRESSIF MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
|
||||||
|
* it is 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sdkconfig.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP8266
|
||||||
|
#include "driver/pwm.h"
|
||||||
|
#else
|
||||||
|
#include "driver/ledc.h"
|
||||||
|
#endif
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
typedef struct rgb {
|
||||||
|
uint8_t r; // 0-100 %
|
||||||
|
uint8_t g; // 0-100 %
|
||||||
|
uint8_t b; // 0-100 %
|
||||||
|
} rgb_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct hsp {
|
||||||
|
uint16_t h; // 0-360
|
||||||
|
uint16_t s; // 0-100
|
||||||
|
uint16_t b; // 0-100
|
||||||
|
} hsp_t;
|
||||||
|
|
||||||
|
/* LED numbers below are for ESP-WROVER-KIT */
|
||||||
|
/* Red LED */
|
||||||
|
#define LEDC_IO_0 (0)
|
||||||
|
/* Green LED */
|
||||||
|
#define LEDC_IO_1 (2)
|
||||||
|
/* Blued LED */
|
||||||
|
#define LEDC_IO_2 (4)
|
||||||
|
|
||||||
|
#define PWM_DEPTH (1023)
|
||||||
|
#define PWM_TARGET_DUTY 8192
|
||||||
|
|
||||||
|
static hsp_t s_hsb_val;
|
||||||
|
static uint16_t s_brightness;
|
||||||
|
static bool s_on = false;
|
||||||
|
|
||||||
|
static const char *TAG = "lightbulb";
|
||||||
|
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP8266
|
||||||
|
#define PWM_PERIOD (500)
|
||||||
|
#define PWM_IO_NUM 3
|
||||||
|
|
||||||
|
// pwm pin number
|
||||||
|
const uint32_t pin_num[PWM_IO_NUM] = {
|
||||||
|
LEDC_IO_0,
|
||||||
|
LEDC_IO_1,
|
||||||
|
LEDC_IO_2
|
||||||
|
};
|
||||||
|
|
||||||
|
// dutys table, (duty/PERIOD)*depth
|
||||||
|
uint32_t duties[PWM_IO_NUM] = {
|
||||||
|
250, 250, 250,
|
||||||
|
};
|
||||||
|
|
||||||
|
// phase table, (phase/180)*depth
|
||||||
|
int16_t phase[PWM_IO_NUM] = {
|
||||||
|
0, 0, 50,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LEDC_CHANNEL_0 0
|
||||||
|
#define LEDC_CHANNEL_1 1
|
||||||
|
#define LEDC_CHANNEL_2 2
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief transform lightbulb's "RGB" and other parameter
|
||||||
|
*/
|
||||||
|
static void lightbulb_set_aim(uint32_t r, uint32_t g, uint32_t b, uint32_t cw, uint32_t ww, uint32_t period)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP8266
|
||||||
|
pwm_stop(0x3);
|
||||||
|
pwm_set_duty(LEDC_CHANNEL_0, r);
|
||||||
|
pwm_set_duty(LEDC_CHANNEL_1, g);
|
||||||
|
pwm_set_duty(LEDC_CHANNEL_2, b);
|
||||||
|
pwm_start();
|
||||||
|
#else
|
||||||
|
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, r);
|
||||||
|
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, g);
|
||||||
|
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, b);
|
||||||
|
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
|
||||||
|
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1);
|
||||||
|
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief transform lightbulb's "HSV" to "RGB"
|
||||||
|
*/
|
||||||
|
static bool lightbulb_set_hsb2rgb(uint16_t h, uint16_t s, uint16_t v, rgb_t *rgb)
|
||||||
|
{
|
||||||
|
bool res = true;
|
||||||
|
uint16_t hi, F, P, Q, T;
|
||||||
|
|
||||||
|
if (!rgb)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (h > 360) return false;
|
||||||
|
if (s > 100) return false;
|
||||||
|
if (v > 100) return false;
|
||||||
|
|
||||||
|
hi = (h / 60) % 6;
|
||||||
|
F = 100 * h / 60 - 100 * hi;
|
||||||
|
P = v * (100 - s) / 100;
|
||||||
|
Q = v * (10000 - F * s) / 10000;
|
||||||
|
T = v * (10000 - s * (100 - F)) / 10000;
|
||||||
|
|
||||||
|
switch (hi) {
|
||||||
|
case 0:
|
||||||
|
rgb->r = v;
|
||||||
|
rgb->g = T;
|
||||||
|
rgb->b = P;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
rgb->r = Q;
|
||||||
|
rgb->g = v;
|
||||||
|
rgb->b = P;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
rgb->r = P;
|
||||||
|
rgb->g = v;
|
||||||
|
rgb->b = T;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
rgb->r = P;
|
||||||
|
rgb->g = Q;
|
||||||
|
rgb->b = v;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
rgb->r = T;
|
||||||
|
rgb->g = P;
|
||||||
|
rgb->b = v;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
rgb->r = v;
|
||||||
|
rgb->g = P;
|
||||||
|
rgb->b = Q;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set the lightbulb's "HSV"
|
||||||
|
*/
|
||||||
|
static bool lightbulb_set_aim_hsv(uint16_t h, uint16_t s, uint16_t v)
|
||||||
|
{
|
||||||
|
rgb_t rgb_tmp;
|
||||||
|
bool ret = lightbulb_set_hsb2rgb(h, s, v, &rgb_tmp);
|
||||||
|
|
||||||
|
if (ret == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
lightbulb_set_aim(rgb_tmp.r * PWM_TARGET_DUTY / 100, rgb_tmp.g * PWM_TARGET_DUTY / 100,
|
||||||
|
rgb_tmp.b * PWM_TARGET_DUTY / 100, (100 - s) * 5000 / 100, v * 2000 / 100, 1000);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief update the lightbulb's state
|
||||||
|
*/
|
||||||
|
static void lightbulb_update()
|
||||||
|
{
|
||||||
|
lightbulb_set_aim_hsv(s_hsb_val.h, s_hsb_val.s, s_hsb_val.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief initialize the lightbulb lowlevel module
|
||||||
|
*/
|
||||||
|
void lightbulb_init(void)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP8266
|
||||||
|
pwm_init(PWM_PERIOD, duties, PWM_IO_NUM, pin_num);
|
||||||
|
pwm_set_channel_invert(0x1 << 0);
|
||||||
|
pwm_set_phases(phase);
|
||||||
|
pwm_start();
|
||||||
|
#else
|
||||||
|
// enable ledc module
|
||||||
|
periph_module_enable(PERIPH_LEDC_MODULE);
|
||||||
|
|
||||||
|
// config the timer
|
||||||
|
ledc_timer_config_t ledc_timer = {
|
||||||
|
//set timer counter bit number
|
||||||
|
.bit_num = LEDC_TIMER_13_BIT,
|
||||||
|
//set frequency of pwm
|
||||||
|
.freq_hz = 5000,
|
||||||
|
//timer mode,
|
||||||
|
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||||||
|
//timer index
|
||||||
|
.timer_num = LEDC_TIMER_0
|
||||||
|
};
|
||||||
|
ledc_timer_config(&ledc_timer);
|
||||||
|
|
||||||
|
//config the channel
|
||||||
|
ledc_channel_config_t ledc_channel = {
|
||||||
|
//set LEDC channel 0
|
||||||
|
.channel = LEDC_CHANNEL_0,
|
||||||
|
//set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1)
|
||||||
|
.duty = 100,
|
||||||
|
//GPIO number
|
||||||
|
.gpio_num = LEDC_IO_0,
|
||||||
|
//GPIO INTR TYPE, as an example, we enable fade_end interrupt here.
|
||||||
|
.intr_type = LEDC_INTR_FADE_END,
|
||||||
|
//set LEDC mode, from ledc_mode_t
|
||||||
|
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||||||
|
//set LEDC timer source, if different channel use one timer,
|
||||||
|
//the frequency and bit_num of these channels should be the same
|
||||||
|
.timer_sel = LEDC_TIMER_0
|
||||||
|
};
|
||||||
|
//set the configuration
|
||||||
|
ledc_channel_config(&ledc_channel);
|
||||||
|
|
||||||
|
//config ledc channel1
|
||||||
|
ledc_channel.channel = LEDC_CHANNEL_1;
|
||||||
|
ledc_channel.gpio_num = LEDC_IO_1;
|
||||||
|
ledc_channel_config(&ledc_channel);
|
||||||
|
//config ledc channel2
|
||||||
|
ledc_channel.channel = LEDC_CHANNEL_2;
|
||||||
|
ledc_channel.gpio_num = LEDC_IO_2;
|
||||||
|
ledc_channel_config(&ledc_channel);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief deinitialize the lightbulb's lowlevel module
|
||||||
|
*/
|
||||||
|
void lightbulb_deinit(void)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP8266
|
||||||
|
#else
|
||||||
|
ledc_stop(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0);
|
||||||
|
ledc_stop(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0);
|
||||||
|
ledc_stop(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief turn on/off the lowlevel lightbulb
|
||||||
|
*/
|
||||||
|
int lightbulb_set_on(bool value)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "lightbulb_set_on : %s", value == true ? "true" : "false");
|
||||||
|
|
||||||
|
if (value == true) {
|
||||||
|
s_hsb_val.b = s_brightness;
|
||||||
|
s_on = true;
|
||||||
|
} else {
|
||||||
|
s_brightness = s_hsb_val.b;
|
||||||
|
s_hsb_val.b = 0;
|
||||||
|
s_on = false;
|
||||||
|
}
|
||||||
|
lightbulb_update();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set the saturation of the lowlevel lightbulb
|
||||||
|
*/
|
||||||
|
int lightbulb_set_saturation(float value)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "lightbulb_set_saturation : %f", value);
|
||||||
|
|
||||||
|
s_hsb_val.s = value;
|
||||||
|
if (true == s_on)
|
||||||
|
lightbulb_update();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set the hue of the lowlevel lightbulb
|
||||||
|
*/
|
||||||
|
int lightbulb_set_hue(float value)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "lightbulb_set_hue : %f", value);
|
||||||
|
|
||||||
|
s_hsb_val.h = value;
|
||||||
|
if (true == s_on)
|
||||||
|
lightbulb_update();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set the brightness of the lowlevel lightbulb
|
||||||
|
*/
|
||||||
|
int lightbulb_set_brightness(int value)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "lightbulb_set_brightness : %d", value);
|
||||||
|
|
||||||
|
s_hsb_val.b = value;
|
||||||
|
s_brightness = s_hsb_val.b;
|
||||||
|
if (true == s_on)
|
||||||
|
lightbulb_update();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* ESPRESSIF MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
|
||||||
|
* it is 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 _LIGHTBULB_H_
|
||||||
|
#define _LIGHTBULB_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief initialize the lightbulb lowlevel module
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
*
|
||||||
|
* @return none
|
||||||
|
*/
|
||||||
|
void lightbulb_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief deinitialize the lightbulb's lowlevel module
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
*
|
||||||
|
* @return none
|
||||||
|
*/
|
||||||
|
void lightbulb_deinit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief turn on/off the lowlevel lightbulb
|
||||||
|
*
|
||||||
|
* @param value The "On" value
|
||||||
|
*
|
||||||
|
* @return none
|
||||||
|
*/
|
||||||
|
int lightbulb_set_on(bool value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set the saturation of the lowlevel lightbulb
|
||||||
|
*
|
||||||
|
* @param value The Saturation value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - 0 : OK
|
||||||
|
* - others : fail
|
||||||
|
*/
|
||||||
|
int lightbulb_set_saturation(float value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set the hue of the lowlevel lightbulb
|
||||||
|
*
|
||||||
|
* @param value The Hue value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - 0 : OK
|
||||||
|
* - others : fail
|
||||||
|
*/
|
||||||
|
int lightbulb_set_hue(float value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set the brightness of the lowlevel lightbulb
|
||||||
|
*
|
||||||
|
* @param value The Brightness value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - 0 : OK
|
||||||
|
* - others : fail
|
||||||
|
*/
|
||||||
|
int lightbulb_set_brightness(int value);
|
||||||
|
|
||||||
|
#endif /* _LIGHTBULB_H_ */
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
set(COMPONENT_ADD_INCLUDEDIRS .)
|
||||||
|
|
||||||
|
set(COMPONENT_SRCS "linkkit_solo.c")
|
||||||
|
|
||||||
|
set(COMPONENT_REQUIRES "esp-aliyun" "json" "lightbulb")
|
||||||
|
|
||||||
|
register_component()
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
COMPONENT_ADD_INCLUDEDIRS := ./
|
||||||
|
COMPONENT_SRCDIRS := ./
|
||||||
@@ -0,0 +1,468 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
#include "infra_config.h"
|
||||||
|
|
||||||
|
void HAL_Printf(const char *fmt, ...);
|
||||||
|
int HAL_Snprintf(char *str, const int len, const char *fmt, ...);
|
||||||
|
|
||||||
|
#ifdef DEPRECATED_LINKKIT
|
||||||
|
#include "solo.c"
|
||||||
|
#else
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "infra_types.h"
|
||||||
|
#include "infra_defs.h"
|
||||||
|
#include "infra_compat.h"
|
||||||
|
#include "infra_compat.h"
|
||||||
|
#ifdef INFRA_MEM_STATS
|
||||||
|
#include "infra_mem_stats.h"
|
||||||
|
#endif
|
||||||
|
#include "dev_model_api.h"
|
||||||
|
#include "dm_wrapper.h"
|
||||||
|
#include "cJSON.h"
|
||||||
|
#ifdef ATM_ENABLED
|
||||||
|
#include "at_api.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "lightbulb.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
static const char* TAG = "linkkit_example_solo";
|
||||||
|
|
||||||
|
#define EXAMPLE_TRACE(...) \
|
||||||
|
do { \
|
||||||
|
HAL_Printf("\033[1;32;40m%s.%d: ", __func__, __LINE__); \
|
||||||
|
HAL_Printf(__VA_ARGS__); \
|
||||||
|
HAL_Printf("\033[0m\r\n"); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define EXAMPLE_MASTER_DEVID (0)
|
||||||
|
#define EXAMPLE_YIELD_TIMEOUT_MS (200)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int master_devid;
|
||||||
|
int cloud_connected;
|
||||||
|
int master_initialized;
|
||||||
|
} user_example_ctx_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These PRODUCT_KEY|PRODUCT_SECRET|DEVICE_NAME|DEVICE_SECRET are listed for demo only
|
||||||
|
*
|
||||||
|
* When you created your own devices on iot.console.com, you SHOULD replace them with what you got from console
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
char PRODUCT_KEY[IOTX_PRODUCT_KEY_LEN + 1] = {0};
|
||||||
|
char PRODUCT_SECRET[IOTX_PRODUCT_SECRET_LEN + 1] = {0};
|
||||||
|
char DEVICE_NAME[IOTX_DEVICE_NAME_LEN + 1] = {0};
|
||||||
|
char DEVICE_SECRET[IOTX_DEVICE_SECRET_LEN + 1] = {0};
|
||||||
|
|
||||||
|
static user_example_ctx_t g_user_example_ctx;
|
||||||
|
|
||||||
|
/** Awss Status event callback */
|
||||||
|
static int user_awss_status_event_handler(int status)
|
||||||
|
{
|
||||||
|
EXAMPLE_TRACE("Awss Status %d", status);
|
||||||
|
|
||||||
|
return SUCCESS_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** cloud connected event callback */
|
||||||
|
static int user_connected_event_handler(void)
|
||||||
|
{
|
||||||
|
EXAMPLE_TRACE("Cloud Connected");
|
||||||
|
g_user_example_ctx.cloud_connected = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** cloud connect fail event callback */
|
||||||
|
static int user_connect_fail_event_handler(void)
|
||||||
|
{
|
||||||
|
EXAMPLE_TRACE("Cloud Connect Fail");
|
||||||
|
|
||||||
|
return SUCCESS_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** cloud disconnected event callback */
|
||||||
|
static int user_disconnected_event_handler(void)
|
||||||
|
{
|
||||||
|
EXAMPLE_TRACE("Cloud Disconnected");
|
||||||
|
g_user_example_ctx.cloud_connected = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** cloud raw_data arrived event callback */
|
||||||
|
static int user_rawdata_arrived_event_handler(const int devid, const unsigned char *request, const int request_len)
|
||||||
|
{
|
||||||
|
EXAMPLE_TRACE("Cloud Rawdata Arrived");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* device initialized event callback */
|
||||||
|
static int user_initialized(const int devid)
|
||||||
|
{
|
||||||
|
EXAMPLE_TRACE("Device Initialized");
|
||||||
|
g_user_example_ctx.master_initialized = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** recv property post response message from cloud **/
|
||||||
|
static int user_report_reply_event_handler(const int devid, const int msgid, const int code, const char *reply,
|
||||||
|
const int reply_len)
|
||||||
|
{
|
||||||
|
EXAMPLE_TRACE("Message Post Reply Received, Message ID: %d, Code: %d, Reply: %.*s", msgid, code,
|
||||||
|
reply_len,
|
||||||
|
(reply == NULL)? ("NULL") : (reply));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** recv event post response message from cloud **/
|
||||||
|
static int user_trigger_event_reply_event_handler(const int devid, const int msgid, const int code, const char *eventid,
|
||||||
|
const int eventid_len, const char *message, const int message_len)
|
||||||
|
{
|
||||||
|
EXAMPLE_TRACE("Trigger Event Reply Received, Message ID: %d, Code: %d, EventID: %.*s, Message: %.*s",
|
||||||
|
msgid, code,
|
||||||
|
eventid_len,
|
||||||
|
eventid, message_len, message);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int user_property_set_event_handler(const int devid, const char *request, const int request_len)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
cJSON *root = NULL, *LightSwitch = NULL, *LightColor = NULL;
|
||||||
|
ESP_LOGI(TAG,"Property Set Received, Devid: %d, Request: %s", devid, request);
|
||||||
|
|
||||||
|
lightbulb_set_brightness(78);
|
||||||
|
lightbulb_set_saturation(100);
|
||||||
|
|
||||||
|
if (!request) {
|
||||||
|
return NULL_VALUE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse Root */
|
||||||
|
root = cJSON_Parse(request);
|
||||||
|
if (!root) {
|
||||||
|
ESP_LOGI(TAG,"JSON Parse Error");
|
||||||
|
return FAIL_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Switch Lightbulb On/Off */
|
||||||
|
LightSwitch = cJSON_GetObjectItem(root, "LightSwitch");
|
||||||
|
if (LightSwitch) {
|
||||||
|
lightbulb_set_on(LightSwitch->valueint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Switch Lightbulb Hue */
|
||||||
|
LightSwitch = cJSON_GetObjectItem(root, "RGBColor");
|
||||||
|
if (LightSwitch) {
|
||||||
|
LightColor = cJSON_GetObjectItem(LightSwitch, "Red");
|
||||||
|
lightbulb_set_hue(LightColor ? LightColor->valueint : 0);
|
||||||
|
LightColor = cJSON_GetObjectItem(LightSwitch, "Green");
|
||||||
|
lightbulb_set_hue(LightColor ? LightColor->valueint : 120);
|
||||||
|
LightColor = cJSON_GetObjectItem(LightSwitch, "Blue");
|
||||||
|
lightbulb_set_hue(LightColor ? LightColor->valueint : 240);
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON_Delete(root);
|
||||||
|
|
||||||
|
res = IOT_Linkkit_Report(EXAMPLE_MASTER_DEVID, ITM_MSG_POST_PROPERTY,
|
||||||
|
(unsigned char *)request, request_len);
|
||||||
|
ESP_LOGI(TAG,"Post Property Message ID: %d", res);
|
||||||
|
|
||||||
|
return SUCCESS_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int user_property_desired_get_reply_event_handler(const char *serviceid, const int serviceid_len)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "ITE_PROPERTY_DESIRED_GET_REPLY");
|
||||||
|
|
||||||
|
return SUCCESS_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int user_property_get_event_handler(const int devid, const char *serviceid, const int serviceid_len, char **response, int *response_len)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG,"Get Property Message ID: %d", devid);
|
||||||
|
|
||||||
|
return SUCCESS_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int user_service_request_event_handler(const int devid, const char *serviceid, const int serviceid_len,
|
||||||
|
const char *request, const int request_len,
|
||||||
|
char **response, int *response_len)
|
||||||
|
{
|
||||||
|
int contrastratio = 0, to_cloud = 0;
|
||||||
|
cJSON *root = NULL, *item_transparency = NULL, *item_from_cloud = NULL;
|
||||||
|
ESP_LOGI(TAG,"Service Request Received, Devid: %d, Service ID: %.*s, Payload: %s", devid, serviceid_len,
|
||||||
|
serviceid,
|
||||||
|
request);
|
||||||
|
|
||||||
|
/* Parse Root */
|
||||||
|
root = cJSON_Parse(request);
|
||||||
|
if (root == NULL || !cJSON_IsObject(root)) {
|
||||||
|
ESP_LOGI(TAG,"JSON Parse Error");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen("Custom") == serviceid_len && memcmp("Custom", serviceid, serviceid_len) == 0) {
|
||||||
|
/* Parse Item */
|
||||||
|
const char *response_fmt = "{\"Contrastratio\":%d}";
|
||||||
|
item_transparency = cJSON_GetObjectItem(root, "transparency");
|
||||||
|
if (item_transparency == NULL || !cJSON_IsNumber(item_transparency)) {
|
||||||
|
cJSON_Delete(root);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ESP_LOGI(TAG,"transparency: %d", item_transparency->valueint);
|
||||||
|
contrastratio = item_transparency->valueint + 1;
|
||||||
|
|
||||||
|
/* Send Service Response To Cloud */
|
||||||
|
*response_len = strlen(response_fmt) + 10 + 1;
|
||||||
|
*response = malloc(*response_len);
|
||||||
|
if (*response == NULL) {
|
||||||
|
ESP_LOGW(TAG,"Memory Not Enough");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(*response, 0, *response_len);
|
||||||
|
snprintf(*response, *response_len, response_fmt, contrastratio);
|
||||||
|
*response_len = strlen(*response);
|
||||||
|
} else if (strlen("SyncService") == serviceid_len && memcmp("SyncService", serviceid, serviceid_len) == 0) {
|
||||||
|
/* Parse Item */
|
||||||
|
const char *response_fmt = "{\"ToCloud\":%d}";
|
||||||
|
item_from_cloud = cJSON_GetObjectItem(root, "FromCloud");
|
||||||
|
if (item_from_cloud == NULL || !cJSON_IsNumber(item_from_cloud)) {
|
||||||
|
cJSON_Delete(root);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ESP_LOGI(TAG,"FromCloud: %d", item_from_cloud->valueint);
|
||||||
|
to_cloud = item_from_cloud->valueint + 1;
|
||||||
|
|
||||||
|
/* Send Service Response To Cloud */
|
||||||
|
*response_len = strlen(response_fmt) + 10 + 1;
|
||||||
|
*response = malloc(*response_len);
|
||||||
|
if (*response == NULL) {
|
||||||
|
ESP_LOGW(TAG,"Memory Not Enough");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(*response, 0, *response_len);
|
||||||
|
snprintf(*response, *response_len, response_fmt, to_cloud);
|
||||||
|
*response_len = strlen(*response);
|
||||||
|
}
|
||||||
|
cJSON_Delete(root);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int user_timestamp_reply_event_handler(const char *timestamp)
|
||||||
|
{
|
||||||
|
EXAMPLE_TRACE("Current Timestamp: %s", timestamp);
|
||||||
|
|
||||||
|
return SUCCESS_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int user_toplist_reply_event_handler(const int devid, const int msgid, const int code, const char *eventid, const int eventid_len)
|
||||||
|
{
|
||||||
|
EXAMPLE_TRACE("ITE_TOPOLIST_REPLY");
|
||||||
|
|
||||||
|
return SUCCESS_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int user_permit_join_event_handler(const int devid, const int msgid, const int code, const char *eventid, const int eventid_len)
|
||||||
|
{
|
||||||
|
EXAMPLE_TRACE("ITE_PERMIT_JOIN");
|
||||||
|
|
||||||
|
return SUCCESS_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** fota event handler **/
|
||||||
|
static int user_fota_event_handler(int type, const char *version)
|
||||||
|
{
|
||||||
|
char buffer[1024] = {0};
|
||||||
|
int buffer_length = 1024;
|
||||||
|
|
||||||
|
/* 0 - new firmware exist, query the new firmware */
|
||||||
|
if (type == 0) {
|
||||||
|
EXAMPLE_TRACE("New Firmware Version: %s", version);
|
||||||
|
|
||||||
|
IOT_Linkkit_Query(EXAMPLE_MASTER_DEVID, ITM_MSG_QUERY_FOTA_DATA, (unsigned char *)buffer, buffer_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cota event handler */
|
||||||
|
static int user_cota_event_handler(int type, const char *config_id, int config_size, const char *get_type,
|
||||||
|
const char *sign, const char *sign_method, const char *url)
|
||||||
|
{
|
||||||
|
char buffer[128] = {0};
|
||||||
|
int buffer_length = 128;
|
||||||
|
|
||||||
|
/* type = 0, new config exist, query the new config */
|
||||||
|
if (type == 0) {
|
||||||
|
EXAMPLE_TRACE("New Config ID: %s", config_id);
|
||||||
|
EXAMPLE_TRACE("New Config Size: %d", config_size);
|
||||||
|
EXAMPLE_TRACE("New Config Type: %s", get_type);
|
||||||
|
EXAMPLE_TRACE("New Config Sign: %s", sign);
|
||||||
|
EXAMPLE_TRACE("New Config Sign Method: %s", sign_method);
|
||||||
|
EXAMPLE_TRACE("New Config URL: %s", url);
|
||||||
|
|
||||||
|
IOT_Linkkit_Query(EXAMPLE_MASTER_DEVID, ITM_MSG_QUERY_COTA_DATA, (unsigned char *)buffer, buffer_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int user_mqtt_connect_succ_event_handler(void)
|
||||||
|
{
|
||||||
|
EXAMPLE_TRACE("ITE_MQTT_CONNECT_SUCC");
|
||||||
|
|
||||||
|
return SUCCESS_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void user_post_property(void)
|
||||||
|
{
|
||||||
|
static int cnt = 0;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
char property_payload[30] = {0};
|
||||||
|
HAL_Snprintf(property_payload, sizeof(property_payload), "{\"Counter\": %d}", cnt++);
|
||||||
|
|
||||||
|
res = IOT_Linkkit_Report(EXAMPLE_MASTER_DEVID, ITM_MSG_POST_PROPERTY,
|
||||||
|
(unsigned char *)property_payload, strlen(property_payload));
|
||||||
|
|
||||||
|
EXAMPLE_TRACE("Post Property Message ID: %d", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void user_post_event(void)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
char *event_id = "HardwareError";
|
||||||
|
char *event_payload = "{\"ErrorCode\": 0}";
|
||||||
|
|
||||||
|
res = IOT_Linkkit_TriggerEvent(EXAMPLE_MASTER_DEVID, event_id, strlen(event_id),
|
||||||
|
event_payload, strlen(event_payload));
|
||||||
|
EXAMPLE_TRACE("Post Event Message ID: %d", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void user_deviceinfo_update(void)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
char *device_info_update = "[{\"attrKey\":\"abc\",\"attrValue\":\"hello,world\"}]";
|
||||||
|
|
||||||
|
res = IOT_Linkkit_Report(EXAMPLE_MASTER_DEVID, ITM_MSG_DEVICEINFO_UPDATE,
|
||||||
|
(unsigned char *)device_info_update, strlen(device_info_update));
|
||||||
|
EXAMPLE_TRACE("Device Info Update Message ID: %d", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void user_deviceinfo_delete(void)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
char *device_info_delete = "[{\"attrKey\":\"abc\"}]";
|
||||||
|
|
||||||
|
res = IOT_Linkkit_Report(EXAMPLE_MASTER_DEVID, ITM_MSG_DEVICEINFO_DELETE,
|
||||||
|
(unsigned char *)device_info_delete, strlen(device_info_delete));
|
||||||
|
EXAMPLE_TRACE("Device Info Delete Message ID: %d", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int linkkit_thread(void *paras)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
iotx_linkkit_dev_meta_info_t master_meta_info;
|
||||||
|
int domain_type = 0, dynamic_register = 0, post_reply_need = 0;
|
||||||
|
|
||||||
|
#ifdef ATM_ENABLED
|
||||||
|
if (IOT_ATM_Init() < 0) {
|
||||||
|
EXAMPLE_TRACE("IOT ATM init failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memset(&g_user_example_ctx, 0, sizeof(user_example_ctx_t));
|
||||||
|
|
||||||
|
HAL_GetProductKey(PRODUCT_KEY);
|
||||||
|
HAL_GetProductSecret(PRODUCT_SECRET);
|
||||||
|
HAL_GetDeviceName(DEVICE_NAME);
|
||||||
|
HAL_GetDeviceSecret(DEVICE_SECRET);
|
||||||
|
memset(&master_meta_info, 0, sizeof(iotx_linkkit_dev_meta_info_t));
|
||||||
|
memcpy(master_meta_info.product_key, PRODUCT_KEY, strlen(PRODUCT_KEY));
|
||||||
|
memcpy(master_meta_info.product_secret, PRODUCT_SECRET, strlen(PRODUCT_SECRET));
|
||||||
|
memcpy(master_meta_info.device_name, DEVICE_NAME, strlen(DEVICE_NAME));
|
||||||
|
memcpy(master_meta_info.device_secret, DEVICE_SECRET, strlen(DEVICE_SECRET));
|
||||||
|
|
||||||
|
/* Register Callback */
|
||||||
|
IOT_RegisterCallback(ITE_AWSS_STATUS, user_awss_status_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_CONNECT_SUCC, user_connected_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_CONNECT_FAIL, user_connect_fail_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_DISCONNECTED, user_disconnected_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_RAWDATA_ARRIVED, user_rawdata_arrived_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_SERVICE_REQUEST, user_service_request_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_PROPERTY_SET, user_property_set_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_PROPERTY_GET, user_property_get_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_PROPERTY_DESIRED_GET_REPLY, user_property_desired_get_reply_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_REPORT_REPLY, user_report_reply_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_TRIGGER_EVENT_REPLY, user_trigger_event_reply_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_TIMESTAMP_REPLY, user_timestamp_reply_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_TOPOLIST_REPLY, user_toplist_reply_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_PERMIT_JOIN, user_permit_join_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_INITIALIZE_COMPLETED, user_initialized);
|
||||||
|
IOT_RegisterCallback(ITE_FOTA, user_fota_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_COTA, user_cota_event_handler);
|
||||||
|
IOT_RegisterCallback(ITE_MQTT_CONNECT_SUCC, user_mqtt_connect_succ_event_handler);
|
||||||
|
|
||||||
|
#if CONFIG_MQTT_DIRECT
|
||||||
|
domain_type = IOTX_CLOUD_REGION_SHANGHAI;
|
||||||
|
#else
|
||||||
|
domain_type = IOTX_CLOUD_REGION_SINGAPORE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
IOT_Ioctl(IOTX_IOCTL_SET_DOMAIN, (void *)&domain_type);
|
||||||
|
|
||||||
|
/* Choose Login Method */
|
||||||
|
dynamic_register = 0;
|
||||||
|
IOT_Ioctl(IOTX_IOCTL_SET_DYNAMIC_REGISTER, (void *)&dynamic_register);
|
||||||
|
|
||||||
|
/* post reply doesn't need */
|
||||||
|
post_reply_need = 1;
|
||||||
|
IOT_Ioctl(IOTX_IOCTL_RECV_EVENT_REPLY, (void *)&post_reply_need);
|
||||||
|
|
||||||
|
/* Create Master Device Resources */
|
||||||
|
g_user_example_ctx.master_devid = IOT_Linkkit_Open(IOTX_LINKKIT_DEV_TYPE_MASTER, &master_meta_info);
|
||||||
|
if (g_user_example_ctx.master_devid < 0) {
|
||||||
|
EXAMPLE_TRACE("IOT_Linkkit_Open Failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start Connect Aliyun Server */
|
||||||
|
res = IOT_Linkkit_Connect(g_user_example_ctx.master_devid);
|
||||||
|
if (res < 0) {
|
||||||
|
EXAMPLE_TRACE("IOT_Linkkit_Connect Failed\n");
|
||||||
|
IOT_Linkkit_Close(g_user_example_ctx.master_devid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
IOT_Linkkit_Yield(EXAMPLE_YIELD_TIMEOUT_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
IOT_Linkkit_Close(g_user_example_ctx.master_devid);
|
||||||
|
|
||||||
|
IOT_DumpMemoryStats(IOT_LOG_DEBUG);
|
||||||
|
IOT_SetLogLevel(IOT_LOG_NONE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void linkkit_main(void *paras)
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
linkkit_thread(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* ESPRESSIF MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
|
||||||
|
* it is 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 _LINKKIT_SOLO_H__
|
||||||
|
#define _LINKKIT_SOLO_H__
|
||||||
|
|
||||||
|
void linkkit_main(void *paras);
|
||||||
|
|
||||||
|
#endif
|
||||||
66
sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/CMakeLists.txt
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
set(COMPONENT_PRIV_INCLUDEDIRS
|
||||||
|
iotkit-embedded/coap_server/CoAPPacket
|
||||||
|
iotkit-embedded/coap_server/server
|
||||||
|
iotkit-embedded/dev_bind/impl
|
||||||
|
iotkit-embedded/dev_bind/impl/os
|
||||||
|
iotkit-embedded/dev_bind/impl/awss_reset
|
||||||
|
iotkit-embedded/wifi_provision/dev_ap
|
||||||
|
iotkit-embedded/wifi_provision/frameworks
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/aplist
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/ieee80211
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/statics
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/utils
|
||||||
|
iotkit-embedded/wifi_provision/p2p
|
||||||
|
iotkit-embedded/wifi_provision/phone_ap
|
||||||
|
iotkit-embedded/wifi_provision/router_ap
|
||||||
|
iotkit-embedded/wifi_provision/smartconfig
|
||||||
|
iotkit-embedded/wifi_provision/zero_config)
|
||||||
|
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS
|
||||||
|
conn_mgr
|
||||||
|
iotkit-embedded/coap_server
|
||||||
|
iotkit-embedded/dev_bind
|
||||||
|
iotkit-embedded/dev_model
|
||||||
|
iotkit-embedded/dev_sign
|
||||||
|
iotkit-embedded/dynamic_register
|
||||||
|
iotkit-embedded/mqtt
|
||||||
|
iotkit-embedded/ota
|
||||||
|
iotkit-embedded/infra
|
||||||
|
iotkit-embedded/wifi_provision
|
||||||
|
iotkit-embedded
|
||||||
|
wrappers)
|
||||||
|
|
||||||
|
# Edit following two lines to set component requirements (see docs)
|
||||||
|
set(COMPONENT_REQUIRES "nvs_flash" "app_update" "esp-tls")
|
||||||
|
set(COMPONENT_PRIV_REQUIRES )
|
||||||
|
|
||||||
|
set(COMPONENT_SRCDIRS
|
||||||
|
conn_mgr
|
||||||
|
iotkit-embedded/certs
|
||||||
|
iotkit-embedded/dev_bind/impl
|
||||||
|
iotkit-embedded/dev_bind/impl/os
|
||||||
|
iotkit-embedded/dev_bind/impl/awss_reset
|
||||||
|
iotkit-embedded/dev_model
|
||||||
|
iotkit-embedded/dev_reset
|
||||||
|
iotkit-embedded/dev_sign
|
||||||
|
iotkit-embedded/dynamic_register
|
||||||
|
iotkit-embedded/infra
|
||||||
|
iotkit-embedded/mqtt
|
||||||
|
iotkit-embedded/ota
|
||||||
|
iotkit-embedded/wifi_provision/dev_ap
|
||||||
|
iotkit-embedded/wifi_provision/frameworks
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/aplist
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/ieee80211
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/statics
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/utils
|
||||||
|
iotkit-embedded/wifi_provision/p2p
|
||||||
|
iotkit-embedded/wifi_provision/phone_ap
|
||||||
|
iotkit-embedded/wifi_provision/router_ap
|
||||||
|
iotkit-embedded/wifi_provision/smartconfig
|
||||||
|
iotkit-embedded/wifi_provision/zero_config
|
||||||
|
iotkit-embedded/coap_server/CoAPPacket
|
||||||
|
iotkit-embedded/coap_server/server
|
||||||
|
wrappers)
|
||||||
|
|
||||||
|
register_component()
|
||||||
|
component_compile_options(-DAUTH_MODE_CERT)
|
||||||
143
sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/Kconfig
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
menu "iotkit embedded"
|
||||||
|
|
||||||
|
menu "Aliyun linkkit device version"
|
||||||
|
|
||||||
|
config LINKKIT_FIRMWARE_VERSION
|
||||||
|
string "Device version"
|
||||||
|
default "0.0.1"
|
||||||
|
help
|
||||||
|
aliyun linkkit device version
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
menu "Aliyun linkkit awss config"
|
||||||
|
config AWSS_ENCRYPT_TYPE
|
||||||
|
int "Get the security level of the `smartconfig` service"
|
||||||
|
range 1 5
|
||||||
|
default 3
|
||||||
|
help
|
||||||
|
Get the security level of the `smartconfig` service
|
||||||
|
|
||||||
|
config AWSS_CONN_ENCRYPT_TYPE
|
||||||
|
int "Get Security level for wifi configuration with connection.Used for AP solution of router and App"
|
||||||
|
range 3 5
|
||||||
|
default 4
|
||||||
|
help
|
||||||
|
Get Security level for wifi configuration with connection.Used for AP solution of router and App
|
||||||
|
|
||||||
|
config AWSS_TIMEOUT_INTERVAL_MS
|
||||||
|
int "Get the timeout period of the distribution service (`AWSS`), in milliseconds"
|
||||||
|
range 0 1800000
|
||||||
|
default 180000
|
||||||
|
help
|
||||||
|
Get the timeout period of the distribution service (`AWSS`), in milliseconds
|
||||||
|
|
||||||
|
config AWSS_CHANNELSCAN_INTERVAL_MS
|
||||||
|
int "Get the length of time scanned on each channel (`channel`), in milliseconds"
|
||||||
|
range 0 1000
|
||||||
|
default 200
|
||||||
|
help
|
||||||
|
Get the length of time scanned on each channel (`channel`), in milliseconds
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
menu "Aliyun linkkit network config"
|
||||||
|
config SUPPORT_TCP
|
||||||
|
bool "Enable tcp connection"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Select this option to enable tcp connection
|
||||||
|
|
||||||
|
config TCP_ESTABLISH_TIMEOUT_MS
|
||||||
|
int "Device tcp connection timeout wait time milliseconds"
|
||||||
|
range 0 100000
|
||||||
|
default 10000
|
||||||
|
help
|
||||||
|
Device tcp connection timeout wait time milliseconds
|
||||||
|
|
||||||
|
config TLS_ESTABLISH_TIMEOUT_MS
|
||||||
|
int "Device tls connection timeout wait time milliseconds"
|
||||||
|
range 0 100000
|
||||||
|
default 10000
|
||||||
|
help
|
||||||
|
Device tls connection timeout wait time milliseconds
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
menu "Aliyun linkkit device model config"
|
||||||
|
config DEVICE_MODEL_GATEWAY
|
||||||
|
bool "Enable device model gateway"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Select this option to enable device model gateway
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
menu "Aliyun linkkit local control"
|
||||||
|
config DEVICE_ALCS_ENABLE
|
||||||
|
bool "Enable device local control"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Select this option to enable device local control
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
menu "Aliyun linkkit security OTA"
|
||||||
|
config SUPPORT_SECURITY_OTA
|
||||||
|
bool "Enable Security OTA"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Select this option to enable security ota
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
menu "Aliyun linkkit dynamic register"
|
||||||
|
config DYNAMIC_REGISTER
|
||||||
|
bool "Enable dynamic register"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Select this option to enable dynamic register
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
menu "Aliyun linkkit mqtt config"
|
||||||
|
config MQTT_DIRECT
|
||||||
|
bool "MQTT DIRECT"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Directly connect MQTT server without perform HTTP authenticate to another HTTP server ahead
|
||||||
|
|
||||||
|
Switching to "y" leads to connect MQTT server directly and MQTT_DIRECT included into CFLAGS
|
||||||
|
Switching to "n" leads to legacy authenticate mode: connnect HTTP server first, then connect MQTT server afterwards
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
config HAL_SEM_MAX_COUNT
|
||||||
|
int "The maximum count value that can be reached of the semaphore"
|
||||||
|
default 255
|
||||||
|
range 0 255
|
||||||
|
help
|
||||||
|
The recommended value of maximum count of the semaphore is 255
|
||||||
|
|
||||||
|
config HAL_SEM_INIT_COUNT
|
||||||
|
int "The count value assigned to the semaphore when it is created"
|
||||||
|
default 0
|
||||||
|
range 0 10
|
||||||
|
help
|
||||||
|
The recommended value of count of the semaphore is 0
|
||||||
|
config HAL_TLS_HANDSHAKE_TIMEOUT
|
||||||
|
int "TLS Handsake Timeout"
|
||||||
|
default 180
|
||||||
|
range 0 65535
|
||||||
|
help
|
||||||
|
Default TLS handshake timeout to host in seconds
|
||||||
|
config HAL_USE_CUSTOMER_AP_SSID
|
||||||
|
bool "Enable use customer softap SSID"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Select this option to enable use customer softap SSID
|
||||||
|
config AP_SSID_KEY
|
||||||
|
string "AP SSID KV Key value"
|
||||||
|
default "apssid"
|
||||||
|
help
|
||||||
|
The KV key value which store AP SSID
|
||||||
|
|
||||||
|
config USE_SOFTAP_CONFIG
|
||||||
|
bool "Use softap config in smart light example"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
smart light example will use softap config when enable this option. Otherwise use smartconfig.
|
||||||
|
|
||||||
|
endmenu
|
||||||
65
sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/component.mk
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# Makefile
|
||||||
|
COMPONENT_ADD_LDFLAGS += -u ota_pubn_buf
|
||||||
|
COMPONENT_PRIV_INCLUDEDIRS := \
|
||||||
|
iotkit-embedded/coap_server/CoAPPacket \
|
||||||
|
iotkit-embedded/coap_server/server \
|
||||||
|
iotkit-embedded/dev_bind/impl \
|
||||||
|
iotkit-embedded/dev_bind/impl/os \
|
||||||
|
iotkit-embedded/dev_bind/impl/awss_reset \
|
||||||
|
iotkit-embedded/wifi_provision/dev_ap \
|
||||||
|
iotkit-embedded/wifi_provision/frameworks \
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/aplist \
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/ieee80211 \
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/statics \
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/utils \
|
||||||
|
iotkit-embedded/wifi_provision/p2p \
|
||||||
|
iotkit-embedded/wifi_provision/phone_ap \
|
||||||
|
iotkit-embedded/wifi_provision/router_ap \
|
||||||
|
iotkit-embedded/wifi_provision/smartconfig \
|
||||||
|
iotkit-embedded/wifi_provision/zero_config
|
||||||
|
|
||||||
|
COMPONENT_ADD_INCLUDEDIRS := \
|
||||||
|
conn_mgr \
|
||||||
|
iotkit-embedded/atm \
|
||||||
|
iotkit-embedded/coap_server \
|
||||||
|
iotkit-embedded/dev_bind \
|
||||||
|
iotkit-embedded/dev_model \
|
||||||
|
iotkit-embedded/dev_sign \
|
||||||
|
iotkit-embedded/dynamic_register \
|
||||||
|
iotkit-embedded/mqtt \
|
||||||
|
iotkit-embedded/ota \
|
||||||
|
iotkit-embedded/infra \
|
||||||
|
iotkit-embedded/wifi_provision \
|
||||||
|
iotkit-embedded \
|
||||||
|
wrappers
|
||||||
|
|
||||||
|
COMPONENT_SRCDIRS := \
|
||||||
|
conn_mgr \
|
||||||
|
iotkit-embedded/atm \
|
||||||
|
iotkit-embedded/certs \
|
||||||
|
iotkit-embedded/dev_bind/impl \
|
||||||
|
iotkit-embedded/dev_bind/impl/os \
|
||||||
|
iotkit-embedded/dev_bind/impl/awss_reset \
|
||||||
|
iotkit-embedded/dev_model \
|
||||||
|
iotkit-embedded/dev_reset \
|
||||||
|
iotkit-embedded/dev_sign \
|
||||||
|
iotkit-embedded/dynamic_register \
|
||||||
|
iotkit-embedded/infra \
|
||||||
|
iotkit-embedded/mqtt \
|
||||||
|
iotkit-embedded/ota \
|
||||||
|
iotkit-embedded/wifi_provision/dev_ap \
|
||||||
|
iotkit-embedded/wifi_provision/frameworks \
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/aplist \
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/ieee80211 \
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/statics \
|
||||||
|
iotkit-embedded/wifi_provision/frameworks/utils \
|
||||||
|
iotkit-embedded/wifi_provision/p2p \
|
||||||
|
iotkit-embedded/wifi_provision/phone_ap \
|
||||||
|
iotkit-embedded/wifi_provision/router_ap \
|
||||||
|
iotkit-embedded/wifi_provision/smartconfig \
|
||||||
|
iotkit-embedded/wifi_provision/zero_config \
|
||||||
|
iotkit-embedded/coap_server/CoAPPacket \
|
||||||
|
iotkit-embedded/coap_server/server \
|
||||||
|
wrappers
|
||||||
|
|
||||||
|
CFLAGS += -Wno-char-subscripts
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
# 量产说明
|
||||||
|
aliyun 在使用一机一密的情况下,需要在每个设备上烧写与设备对应的 ProductKey、ProductSecret、DeviceName、DeviceSecret。
|
||||||
|
|
||||||
|
为了使烧录和软件读取流程尽量简化,我们将使用 IDF 的 NVS 分区功能,将 ProductKey、ProductSecret、DeviceName、DeviceSecret 信息通过 NVS 分区生成工具或量产工具生成对应的 NVS 分区,该分区中利用 NVS 结构保存了 ProductKey、ProductSecret、DeviceName、DeviceSecret 的键值对。生成后的 NVS 分区 bin 可以通过 esptool 或其他烧写工具直接烧录到 NVS 分区对应的起始扇区,partition 分区表中指明了该 NVS 分区的起始地址。软件可以通过 NVS 相关接口读取到 ProductKey、ProductSecret、DeviceName、DeviceSecret 的具体值。
|
||||||
|
|
||||||
|
请参照 partitions_esp32.csv 和 partitions_esp8266.csv 中 fctry 的起始地址进行烧录,也可根据实际项目对 partitions 进行调整,但一定要保证 partitons 中 fctry 的实际地址与烧录地址保持吻合。
|
||||||
|
|
||||||
|
关于 NVS、NVS 分区生成工具、量产工具,请参考:
|
||||||
|
- [NVS](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/nvs_flash.html)
|
||||||
|
- [NVS 分区生成工具](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/nvs_partition_gen.html)
|
||||||
|
- [量产工具](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/mass_mfg.html)
|
||||||
|
|
||||||
|
## 单个 bin 生成
|
||||||
|
在调试过程中,建议使用该方式。
|
||||||
|
|
||||||
|
mass_mfg 目录中有一参考配置:single_mfg_config.csv,请拷贝成自己的配置文件,如 my_single_mfg_config.csv。
|
||||||
|
```
|
||||||
|
cp single_mfg_config.csv my_single_mfg_config.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
使用自己的 ProductKey、ProductSecret、DeviceName、DeviceSecret 对 my_single_mfg_config.csv 进行修改:
|
||||||
|
```
|
||||||
|
key,type,encoding,value
|
||||||
|
aliyun-key,namespace,,
|
||||||
|
DeviceName,data,string,config
|
||||||
|
DeviceSecret,data,string,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh
|
||||||
|
ProductKey,data,string,a10BnLLzGv4
|
||||||
|
ProductSecret,data,string,pVfLpS1u3A9JM0go
|
||||||
|
```
|
||||||
|
|
||||||
|
将 config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go 修改为你对应的值。
|
||||||
|
|
||||||
|
修改完成后,使用如下命令生成对应的 NVS 分区:
|
||||||
|
```
|
||||||
|
$IDF_PATH/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py --input single_mfg_config.csv --output single_mfg.bin --size 0x4000
|
||||||
|
python nvs_partition_gen.py generate single_mfg_config.csv single_mfg.bin 0x4000
|
||||||
|
```
|
||||||
|
如针对 esp8266 平台,请使用如下命令:
|
||||||
|
```
|
||||||
|
$IDF_PATH/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py --input my_single_mfg_config.csv --output my_single_mfg.bin --size 0x4000
|
||||||
|
```
|
||||||
|
> 说明:esp8266 的 NVS 格式当前为 v1, 默认已设置。
|
||||||
|
|
||||||
|
可以使用 esptool 工具将生成的包含秘钥的 NVS 分区烧入对应的 sector,针对 example 中默认提供的 partitions,esp32 和 esp8266 将烧写到不同的分区,其中 esp32 的默认烧录地址为 0x210000,esp8266 的默认烧录地址为 0x100000。
|
||||||
|
|
||||||
|
针对 esp32:
|
||||||
|
```
|
||||||
|
$IDF_PATH/components/esptool_py/esptool/esptool.py write_flash 0x210000 my_single_mfg.bin
|
||||||
|
```
|
||||||
|
|
||||||
|
针对 esp8266:
|
||||||
|
```
|
||||||
|
$IDF_PATH/components/esptool_py/esptool/esptool.py --port /dev/ttyUSB0 write_flash 0x100000 my_single_mfg.bin
|
||||||
|
```
|
||||||
|
|
||||||
|
> 注,当前 esp32 默认使用 4MB 的模组,esp8266 默认使用 2MB 的模组,如使用其他大小的 Flash,请适当调整 partitions 分区表,并确认烧写地址。
|
||||||
|
|
||||||
|
## 多个 bin 批量生成
|
||||||
|
量产过程中如采用以上方法单个生成对应的 NVS 分区会很繁琐,因此采用 IDF 中的量产工具,该量产工具也是基于 NVS 分区生成工具的扩充。
|
||||||
|
|
||||||
|
mass_mfg 目录中提供了一套参考的配置,其中 multipule_mfg_config.csv 为参数区配置文件,已做好针对 aliyun 的配置,用户无需修改,multipule_mfg_values.csv 中可以包含所有需要生成 NVS 分区的 ProductKey、ProductSecret、DeviceName、DeviceSecret 信息,请将 multipule_mfg_values.csv 复制为 my_multipule_mfg_values.csv 并对该文件进行修改,包含所有希望用于量产的 ProductKey、ProductSecret、DeviceName、DeviceSecret 信息。
|
||||||
|
|
||||||
|
my_multipule_mfg_values.csv 中内容如下:
|
||||||
|
```
|
||||||
|
id,DeviceName,DeviceSecret,ProductKey,ProductSecret
|
||||||
|
1,config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go
|
||||||
|
2,config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go
|
||||||
|
3,config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go
|
||||||
|
```
|
||||||
|
|
||||||
|
每一行代表了一组秘钥信息,第一列的为 id 信息,不会生成到对应的 NVS 分区中,仅用作标号。
|
||||||
|
|
||||||
|
采用如下命令批量生成 NVS 分区。
|
||||||
|
|
||||||
|
针对 esp32:
|
||||||
|
```
|
||||||
|
$IDF_PATH/tools/mass_mfg/mfg_gen.py --conf multipule_mfg_config.csv --values my_multipule_mfg_values.csv --prefix Fan --size 0x4000
|
||||||
|
```
|
||||||
|
|
||||||
|
针对 esp8266:
|
||||||
|
```
|
||||||
|
$IDF_PATH/tools/mass_mfg/mfg_gen.py --conf multipule_mfg_config.csv --values my_multipule_mfg_values.csv --prefix Fan --size 0x4000 --version v1
|
||||||
|
```
|
||||||
|
|
||||||
|
其中 --prefix 为生成的批量文件的前缀名称,可以修改为所需要的产品名称。执行完成后,会在当前目录下生成一 bin 目录,里面保持了所有可用于量产的 NVS 分区 bin。
|
||||||
|
|
||||||
|
> 注,当前不知道 aliyun 能否批量导出 ProductKey、ProductSecret、DeviceName、DeviceSecret,如有需要,可以编写特定脚本来生成 my_multipule_mfg_values.csv。
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
aliyun-key,namespace,
|
||||||
|
DeviceName,data,string
|
||||||
|
DeviceSecret,data,string
|
||||||
|
ProductKey,data,string
|
||||||
|
ProductSecret,data,string
|
||||||
|
@@ -0,0 +1,4 @@
|
|||||||
|
id,DeviceName,DeviceSecret,ProductKey,ProductSecret
|
||||||
|
1,config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go
|
||||||
|
2,config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go
|
||||||
|
3,config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go
|
||||||
|
@@ -0,0 +1,6 @@
|
|||||||
|
key,type,encoding,value
|
||||||
|
aliyun-key,namespace,,
|
||||||
|
DeviceName,data,string,DCDA0C11FEBC
|
||||||
|
DeviceSecret,data,string,8eb157145f057600459e9b7245beb59f
|
||||||
|
ProductKey,data,string,a1LCAxGhf7h
|
||||||
|
ProductSecret,data,string,c119juI2ruCDg3A7
|
||||||
|
415
sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/conn_mgr/conn_mgr.c
Normal file
@@ -0,0 +1,415 @@
|
|||||||
|
/*
|
||||||
|
* ESPRESSIF MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
|
||||||
|
* it is 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/event_groups.h"
|
||||||
|
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_event_loop.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_wifi.h"
|
||||||
|
|
||||||
|
#include "lwip/apps/sntp.h"
|
||||||
|
|
||||||
|
#include "wifi_provision_api.h"
|
||||||
|
#include "dm_wrapper.h"
|
||||||
|
|
||||||
|
#include "conn_mgr.h"
|
||||||
|
|
||||||
|
static const char *TAG = "conn_mgr";
|
||||||
|
|
||||||
|
static system_event_cb_t hal_wifi_system_cb;
|
||||||
|
|
||||||
|
static esp_err_t conn_mgr_wifi_connect(void)
|
||||||
|
{
|
||||||
|
wifi_config_t wifi_config = {0};
|
||||||
|
int ssid_len = sizeof(wifi_config.sta.ssid);
|
||||||
|
int password_len = sizeof(wifi_config.sta.password);
|
||||||
|
|
||||||
|
int ret = HAL_Kv_Get(STA_SSID_KEY, wifi_config.sta.ssid, &ssid_len);
|
||||||
|
ESP_LOGI(TAG, "HAL_Kv_Get STA_SSID_KEY: %s ", wifi_config.sta.ssid);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Failed to get stored SSID");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Even if the password is not found, it is not an error, as it could be an open network */
|
||||||
|
ret = HAL_Kv_Get(STA_PASSWORD_KEY, wifi_config.sta.password, &password_len);
|
||||||
|
ESP_LOGI(TAG, "HAL_Kv_Get STA_PASSWORD_KEY: %s ", wifi_config.sta.password);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGW(TAG, "Failed to get stored Password");
|
||||||
|
password_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_wifi_set_mode(WIFI_MODE_STA);
|
||||||
|
esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);
|
||||||
|
esp_wifi_start();
|
||||||
|
esp_wifi_connect();
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t conn_mgr_save_wifi_config(void)
|
||||||
|
{
|
||||||
|
wifi_config_t wifi_config = {0};
|
||||||
|
|
||||||
|
esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_config);
|
||||||
|
|
||||||
|
/* Do not save hotspot or router APs. */
|
||||||
|
if (strcmp((char *)(wifi_config.sta.ssid), HOTSPOT_AP) == 0 ||
|
||||||
|
strcmp((char *)(wifi_config.sta.ssid), ROUTER_AP) == 0) {
|
||||||
|
ESP_LOGI(TAG, "Do not save hotspot or router APs: %s", wifi_config.sta.ssid);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = HAL_Kv_Set(STA_SSID_KEY, wifi_config.sta.ssid, sizeof(wifi_config.sta.ssid), 0);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s key store failed with %d", STA_SSID_KEY, ret);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Password may be NULL. Save, only if it is given */
|
||||||
|
if (wifi_config.sta.password[0] != 0) {
|
||||||
|
ret = HAL_Kv_Set(STA_PASSWORD_KEY, wifi_config.sta.password, sizeof(wifi_config.sta.password), 0);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s key store failed with %d", STA_PASSWORD_KEY, ret);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t conn_mgr_obtain_time(void)
|
||||||
|
{
|
||||||
|
static bool get_time_flag = false;
|
||||||
|
if (get_time_flag) {
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
||||||
|
sntp_setservername(0, "ntp1.aliyun.com");
|
||||||
|
sntp_setservername(1, "ntp2.aliyun.com");
|
||||||
|
sntp_setservername(2, "ntp3.aliyun.com");
|
||||||
|
sntp_init();
|
||||||
|
|
||||||
|
time_t now = 0;
|
||||||
|
struct tm timeinfo = { 0 };
|
||||||
|
int sntp_retry_cnt = 0;
|
||||||
|
int sntp_retry_time = 0;
|
||||||
|
while (1) {
|
||||||
|
for (int32_t i = 0; (i < (SNTP_RECV_TIMEOUT / 100)) && timeinfo.tm_year < (2019 - 1900); i ++) {
|
||||||
|
vTaskDelay(100 / portTICK_RATE_MS);
|
||||||
|
time(&now);
|
||||||
|
localtime_r(&now, &timeinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeinfo.tm_year < (2019 - 1900) && sntp_retry_cnt < (SNTP_RECV_TIMEOUT / 100)) {
|
||||||
|
sntp_retry_time = SNTP_RECV_TIMEOUT << sntp_retry_cnt;
|
||||||
|
|
||||||
|
if (SNTP_RECV_TIMEOUT << (sntp_retry_cnt + 1) < SNTP_RETRY_TIMEOUT_MAX) {
|
||||||
|
sntp_retry_cnt ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG,"SNTP get time failed, retry after %d ms\n", sntp_retry_time);
|
||||||
|
vTaskDelay(sntp_retry_time / portTICK_RATE_MS);
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG,"SNTP get time success\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get_time_flag = true;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t conn_mgr_wifi_event_loop_handler(void *ctx, system_event_t *event)
|
||||||
|
{
|
||||||
|
system_event_info_t *info = &event->event_info;
|
||||||
|
switch (event->event_id) {
|
||||||
|
case SYSTEM_EVENT_STA_GOT_IP:
|
||||||
|
conn_mgr_save_wifi_config();
|
||||||
|
#ifdef CONFIG_ESP_TLS_USING_WOLFSSL
|
||||||
|
conn_mgr_obtain_time();
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||||
|
ESP_LOGE(TAG, "Disconnect reason : %d", info->disconnected.reason);
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP8266
|
||||||
|
if (info->disconnected.reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) {
|
||||||
|
/*Switch to 802.11 bgn mode */
|
||||||
|
esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
esp_wifi_connect();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The application loop event handle */
|
||||||
|
if (hal_wifi_system_cb) {
|
||||||
|
hal_wifi_system_cb(ctx, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void conn_mgr_register_wifi_event(system_event_cb_t cb)
|
||||||
|
{
|
||||||
|
hal_wifi_system_cb = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t conn_mgr_reset_wifi_config(void)
|
||||||
|
{
|
||||||
|
HAL_Kv_Del(STA_SSID_KEY);
|
||||||
|
HAL_Kv_Del(STA_PASSWORD_KEY);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t conn_mgr_init_wifi_config(void)
|
||||||
|
{
|
||||||
|
wifi_config_t wifi_config = {
|
||||||
|
.sta = {
|
||||||
|
.ssid = CONFIG_ESP_WIFI_SSID,
|
||||||
|
.password = CONFIG_ESP_WIFI_PASSWORD,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
int ret = HAL_Kv_Set(STA_SSID_KEY, wifi_config.sta.ssid, sizeof(wifi_config.sta.ssid), 0);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s key store failed with %d", STA_SSID_KEY, ret);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = HAL_Kv_Set(STA_PASSWORD_KEY, wifi_config.sta.password, sizeof(wifi_config.sta.password), 0);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s key store failed with %d", STA_PASSWORD_KEY, ret);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t conn_mgr_is_configured(bool *configured)
|
||||||
|
{
|
||||||
|
if (!configured) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
*configured = false;
|
||||||
|
|
||||||
|
int ssid_len = 32;
|
||||||
|
uint8_t ssid[32];
|
||||||
|
|
||||||
|
int ret = HAL_Kv_Get(STA_SSID_KEY, ssid, &ssid_len);
|
||||||
|
|
||||||
|
if (ret == ESP_OK && ssid_len) {
|
||||||
|
*configured = true;
|
||||||
|
ESP_LOGI(TAG, "Found ssid %s", ssid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t conn_mgr_set_wifi_config_ext(const uint8_t *ssid, size_t ssid_len, const uint8_t *password, size_t password_len)
|
||||||
|
{
|
||||||
|
wifi_config_t wifi_config = {0};
|
||||||
|
|
||||||
|
if (!ssid || ssid_len > sizeof(wifi_config.sta.ssid) || password_len > sizeof(wifi_config.sta.password))
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
|
||||||
|
memcpy(wifi_config.sta.ssid, ssid, ssid_len);
|
||||||
|
if (password) {
|
||||||
|
memcpy(wifi_config.sta.password, password, password_len);
|
||||||
|
}
|
||||||
|
esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);
|
||||||
|
|
||||||
|
conn_mgr_save_wifi_config();
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t conn_mgr_get_wifi_config(wifi_config_t *wifi_cfg)
|
||||||
|
{
|
||||||
|
return esp_wifi_get_config(ESP_IF_WIFI_STA, wifi_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t conn_mgr_init(void)
|
||||||
|
{
|
||||||
|
extern esp_err_t HAL_Kv_Init(void);
|
||||||
|
HAL_Kv_Init();
|
||||||
|
|
||||||
|
tcpip_adapter_init();
|
||||||
|
|
||||||
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
|
ESP_ERROR_CHECK(esp_event_loop_init(conn_mgr_wifi_event_loop_handler, NULL));
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_start());
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t conn_mgr_start(void)
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
bool configured = false;
|
||||||
|
uint8_t mode = 0;
|
||||||
|
int mode_len = sizeof(uint8_t);
|
||||||
|
conn_sc_mode_t awss_mode = CONN_SC_ZERO_MODE;
|
||||||
|
|
||||||
|
// Let's find out if the device is configured.
|
||||||
|
if (conn_mgr_is_configured(&configured) != ESP_OK) {
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get SC mode and decide to start which awss service
|
||||||
|
HAL_Kv_Get(SC_MODE, &mode, &mode_len);
|
||||||
|
if (mode_len && mode == CONN_SOFTAP_MODE) {
|
||||||
|
ESP_LOGI(TAG, "CONN_SOFTAP_MODE");
|
||||||
|
awss_mode = CONN_SOFTAP_MODE;
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "mode: %d ", mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the device is not yet configured, start awss service.
|
||||||
|
if (!configured) {
|
||||||
|
do {
|
||||||
|
if (awss_config_press() != 0) {
|
||||||
|
ret = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (awss_mode == CONN_SOFTAP_MODE) {
|
||||||
|
if (awss_dev_ap_start() != 0) {
|
||||||
|
ret = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (awss_start() != 0) {
|
||||||
|
ret = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
} else {
|
||||||
|
if (conn_mgr_wifi_connect() != ESP_OK) {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret == true ? ESP_OK : ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t conn_mgr_stop(void)
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
bool configured = false;
|
||||||
|
uint8_t mode = 0;
|
||||||
|
int mode_len = sizeof(uint8_t);
|
||||||
|
conn_sc_mode_t awss_mode = CONN_SC_ZERO_MODE;
|
||||||
|
|
||||||
|
// Let's find out if the device is configured.
|
||||||
|
if (conn_mgr_is_configured(&configured) != ESP_OK) {
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get SC mode and decide to start which awss service
|
||||||
|
HAL_Kv_Get(SC_MODE, &mode, &mode_len);
|
||||||
|
if (mode_len && mode == CONN_SOFTAP_MODE) {
|
||||||
|
awss_mode = CONN_SOFTAP_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the device is not yet configured, stop awss service.
|
||||||
|
if (!configured) {
|
||||||
|
if (awss_mode == CONN_SOFTAP_MODE) {
|
||||||
|
if (awss_dev_ap_stop() != 0) {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (awss_stop() != 0) {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret == true ? ESP_OK : ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t conn_mgr_set_ap_ssid(uint8_t *ssid, int len)
|
||||||
|
{
|
||||||
|
int ret = ESP_FAIL;
|
||||||
|
uint8_t ssid_kv[32] = {0};
|
||||||
|
int len_kv = 32;
|
||||||
|
|
||||||
|
if (!ssid || !len) {
|
||||||
|
ESP_LOGI(TAG, "input ssid and len error");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = HAL_Kv_Get(AP_SSID_KEY, ssid_kv, &len_kv);
|
||||||
|
if (ret == ESP_OK && len_kv == len) {
|
||||||
|
if (!memcmp(ssid, ssid_kv, len)) {
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = HAL_Kv_Set(AP_SSID_KEY, ssid, len, 0);
|
||||||
|
ESP_LOGI(TAG, "%s %s", __FUNCTION__, (ret == ESP_OK) ? "success" : "fail");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t conn_mgr_set_sc_mode(uint8_t mode)
|
||||||
|
{
|
||||||
|
int ret = ESP_FAIL;
|
||||||
|
uint8_t mode_kv = 0;
|
||||||
|
int len_kv = sizeof(uint8_t);
|
||||||
|
|
||||||
|
ret = HAL_Kv_Get(SC_MODE, &mode_kv, &len_kv);
|
||||||
|
if (ret == ESP_OK) {
|
||||||
|
if (mode == mode_kv) {
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = HAL_Kv_Set(SC_MODE, &mode, sizeof(uint8_t), 0);
|
||||||
|
ESP_LOGI(TAG, "%s %s", __FUNCTION__, (ret == ESP_OK) ? "success" : "fail");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
149
sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/conn_mgr/conn_mgr.h
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* ESPRESSIF MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
|
||||||
|
* it is 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_event_loop.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HOTSPOT_AP "aha"
|
||||||
|
#define ROUTER_AP "adha"
|
||||||
|
#define STA_SSID_KEY "stassid"
|
||||||
|
#define STA_PASSWORD_KEY "pswd"
|
||||||
|
#define AP_SSID_KEY CONFIG_AP_SSID_KEY
|
||||||
|
#define SC_MODE "scmode"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CONN_SC_ZERO_MODE = 1,
|
||||||
|
CONN_SOFTAP_MODE = 2,
|
||||||
|
} conn_sc_mode_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief register wifi event handler
|
||||||
|
*
|
||||||
|
* @param cb wifi event handler
|
||||||
|
*
|
||||||
|
* @return none
|
||||||
|
*/
|
||||||
|
void conn_mgr_register_wifi_event(system_event_cb_t cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief reset the stored router info, include ssid & password
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK : OK
|
||||||
|
* - others : fail
|
||||||
|
*/
|
||||||
|
esp_err_t conn_mgr_reset_wifi_config(void);
|
||||||
|
esp_err_t conn_mgr_init_wifi_config(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief connect wifi with configure information
|
||||||
|
*
|
||||||
|
* This will initiate connection to the given Wi-Fi configure information
|
||||||
|
*
|
||||||
|
* @param ssid Pointer to the target network SSID string
|
||||||
|
* @param ssid_len Length of the above SSID
|
||||||
|
* @param password Pointer to the targer network Password string. Can be NULL for open networks.
|
||||||
|
* @param password_len Length of the password
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK : OK
|
||||||
|
* - others : fail
|
||||||
|
*/
|
||||||
|
esp_err_t conn_mgr_set_wifi_config_ext(const uint8_t *ssid, size_t ssid_len, const uint8_t *password, size_t password_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get wifi configure information
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK : OK
|
||||||
|
* - others : fail
|
||||||
|
*/
|
||||||
|
esp_err_t conn_mgr_get_wifi_config(wifi_config_t *wifi_cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief init the connection management module
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK : OK
|
||||||
|
* - others : fail
|
||||||
|
*/
|
||||||
|
esp_err_t conn_mgr_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief start the connection management module
|
||||||
|
*
|
||||||
|
* If the device is configured, the device will connect to the router which is configured.
|
||||||
|
* If the device is not configured, the device will start awss service.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK : OK
|
||||||
|
* - others : fail
|
||||||
|
*/
|
||||||
|
esp_err_t conn_mgr_start(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief stop the connection management module
|
||||||
|
*
|
||||||
|
* If the device is configured, the device keep connect to the router which is configured.
|
||||||
|
* If the device is not configured, the device will stop awss service.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK : OK
|
||||||
|
* - others : fail
|
||||||
|
*/
|
||||||
|
esp_err_t conn_mgr_stop(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set softap ssid to KV
|
||||||
|
*
|
||||||
|
* @param ssid Pointer to the softap SSID string
|
||||||
|
* @param len Length of the above SSID
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK : OK
|
||||||
|
* - others : fail
|
||||||
|
*/
|
||||||
|
esp_err_t conn_mgr_set_ap_ssid(uint8_t *ssid, int len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set wifi distribution network mode to KV
|
||||||
|
*
|
||||||
|
* If mode is 1, means support smartconfig and zero-config
|
||||||
|
* If mode is 2, means support softap config
|
||||||
|
* @param mode Value of the sc mode
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK : OK
|
||||||
|
* - others : fail
|
||||||
|
*/
|
||||||
|
esp_err_t conn_mgr_set_sc_mode(uint8_t mode);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
const char *iotx_ca_crt = \
|
||||||
|
{
|
||||||
|
\
|
||||||
|
"-----BEGIN CERTIFICATE-----\r\n"
|
||||||
|
"MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\r\n" \
|
||||||
|
"A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n" \
|
||||||
|
"b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\r\n" \
|
||||||
|
"MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n" \
|
||||||
|
"YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\r\n" \
|
||||||
|
"aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\r\n" \
|
||||||
|
"jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\r\n" \
|
||||||
|
"xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\r\n" \
|
||||||
|
"1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\r\n" \
|
||||||
|
"snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\r\n" \
|
||||||
|
"U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\r\n" \
|
||||||
|
"9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\r\n" \
|
||||||
|
"BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\r\n" \
|
||||||
|
"AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\r\n" \
|
||||||
|
"yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\r\n" \
|
||||||
|
"38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\r\n" \
|
||||||
|
"AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\r\n" \
|
||||||
|
"DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\r\n" \
|
||||||
|
"HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\r\n" \
|
||||||
|
"-----END CERTIFICATE-----"
|
||||||
|
};
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Cloud_CoAPNetwork.h"
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
|
||||||
|
#ifndef CLOUD__COAP_EXPORT_H__
|
||||||
|
#define CLOUD__COAP_EXPORT_H__
|
||||||
|
|
||||||
|
/* #define COAP_DTLS_SUPPORT */
|
||||||
|
typedef CoAPMsgOption Cloud_CoAPMsgOption;
|
||||||
|
typedef CoAPMessageCode Cloud_CoAPMessageCode;
|
||||||
|
typedef CoAPMessage Cloud_CoAPMessage ;
|
||||||
|
#define COAP_OPTION_SEQ 2089
|
||||||
|
|
||||||
|
typedef void (*Cloud_CoAPRespMsgHandler)(void *data, void *message);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *user;
|
||||||
|
unsigned short msgid;
|
||||||
|
char acked;
|
||||||
|
unsigned char tokenlen;
|
||||||
|
unsigned char token[8];
|
||||||
|
unsigned char retrans_count;
|
||||||
|
unsigned short timeout;
|
||||||
|
unsigned short timeout_val;
|
||||||
|
unsigned char *message;
|
||||||
|
unsigned int msglen;
|
||||||
|
Cloud_CoAPRespMsgHandler resp;
|
||||||
|
struct list_head sendlist;
|
||||||
|
} Cloud_CoAPSendNode;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char count;
|
||||||
|
unsigned char maxcount;
|
||||||
|
struct list_head sendlist;
|
||||||
|
} Cloud_CoAPSendList;
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*Cloud_CoAPEventNotifier)(unsigned int event, void *p_message);
|
||||||
|
typedef struct {
|
||||||
|
char *url;
|
||||||
|
unsigned char maxcount; /*list maximal count*/
|
||||||
|
unsigned int waittime;
|
||||||
|
Cloud_CoAPEventNotifier notifier;
|
||||||
|
} Cloud_CoAPInitParam;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned short message_id;
|
||||||
|
coap_network_t network;
|
||||||
|
Cloud_CoAPEventNotifier notifier;
|
||||||
|
unsigned char *sendbuf;
|
||||||
|
unsigned char *recvbuf;
|
||||||
|
Cloud_CoAPSendList list;
|
||||||
|
unsigned int waittime;
|
||||||
|
} Cloud_CoAPContext;
|
||||||
|
|
||||||
|
#define COAP_TRC(...) log_debug("coap_cloud", __VA_ARGS__)
|
||||||
|
#define COAP_DUMP(...) log_debug("coap_cloud", __VA_ARGS__)
|
||||||
|
#define COAP_DEBUG(...) log_debug("coap_cloud", __VA_ARGS__)
|
||||||
|
#define COAP_INFO(...) log_info("coap_cloud", __VA_ARGS__)
|
||||||
|
#define COAP_WRN(...) log_warning("coap_cloud", __VA_ARGS__)
|
||||||
|
#define COAP_ERR(...) log_err("coap_cloud", __VA_ARGS__)
|
||||||
|
|
||||||
|
Cloud_CoAPContext *Cloud_CoAPContext_create(Cloud_CoAPInitParam *param);
|
||||||
|
void Cloud_CoAPContext_free(Cloud_CoAPContext *p_ctx);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "Cloud_CoAPExport.h"
|
||||||
|
|
||||||
|
#ifndef __COAP_HANDLE_MSG_H__
|
||||||
|
#define __COAP_HANDLE_MSG_H__
|
||||||
|
|
||||||
|
int Cloud_CoAPStrOption_add(Cloud_CoAPMessage *message, unsigned short optnum,
|
||||||
|
unsigned char *data, unsigned short datalen);
|
||||||
|
|
||||||
|
|
||||||
|
int Cloud_CoAPUintOption_add(Cloud_CoAPMessage *message, unsigned short optnum,
|
||||||
|
unsigned int data);
|
||||||
|
|
||||||
|
unsigned short Cloud_CoAPMessageId_gen(Cloud_CoAPContext *context);
|
||||||
|
|
||||||
|
int Cloud_CoAPMessageId_set(Cloud_CoAPMessage *message, unsigned short msgid);
|
||||||
|
|
||||||
|
int Cloud_CoAPMessageType_set(Cloud_CoAPMessage *message, unsigned char type);
|
||||||
|
|
||||||
|
int Cloud_CoAPMessageCode_set(Cloud_CoAPMessage *message, Cloud_CoAPMessageCode code);
|
||||||
|
|
||||||
|
int Cloud_CoAPMessageToken_set(Cloud_CoAPMessage *message, unsigned char *token,
|
||||||
|
unsigned char tokenlen);
|
||||||
|
|
||||||
|
int Cloud_CoAPMessageUserData_set(Cloud_CoAPMessage *message, void *userdata);
|
||||||
|
|
||||||
|
int Cloud_CoAPMessagePayload_set(Cloud_CoAPMessage *message, unsigned char *payload,
|
||||||
|
unsigned short payloadlen);
|
||||||
|
|
||||||
|
int Cloud_CoAPMessageHandler_set(Cloud_CoAPMessage *message, Cloud_CoAPRespMsgHandler handler);
|
||||||
|
|
||||||
|
int Cloud_CoAPMessage_init(Cloud_CoAPMessage *message);
|
||||||
|
|
||||||
|
int Cloud_CoAPMessage_destory(Cloud_CoAPMessage *message);
|
||||||
|
|
||||||
|
int Cloud_CoAPMessage_send(Cloud_CoAPContext *context, Cloud_CoAPMessage *message);
|
||||||
|
|
||||||
|
int Cloud_CoAPMessage_recv(Cloud_CoAPContext *context, unsigned int timeout, int readcount);
|
||||||
|
|
||||||
|
int Cloud_CoAPMessage_cycle(Cloud_CoAPContext *context);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifndef COAP_TRANSPORT_H__
|
||||||
|
#define COAP_TRANSPORT_H__
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
COAP_ENDPOINT_NOSEC = 0,
|
||||||
|
COAP_ENDPOINT_DTLS,
|
||||||
|
COAP_ENDPOINT_PSK,
|
||||||
|
} coap_endpoint_type;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
DTLSContext *context;
|
||||||
|
} coap_remote_session_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int socket_id;
|
||||||
|
coap_endpoint_type ep_type;
|
||||||
|
void *context;
|
||||||
|
} coap_network_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
coap_endpoint_type ep_type;
|
||||||
|
unsigned char *p_ca_cert_pem;
|
||||||
|
char *p_host;
|
||||||
|
unsigned short port;
|
||||||
|
} coap_network_init_t;
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int Cloud_CoAPNetwork_init(const coap_network_init_t *p_param, coap_network_t *p_network);
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int Cloud_CoAPNetwork_write(coap_network_t *p_network,
|
||||||
|
const unsigned char *p_data,
|
||||||
|
unsigned int datalen);
|
||||||
|
|
||||||
|
int Cloud_CoAPNetwork_read(coap_network_t *network, unsigned char *data,
|
||||||
|
unsigned int datalen, unsigned int timeout);
|
||||||
|
|
||||||
|
unsigned int Cloud_CoAPNetwork_deinit(coap_network_t *p_network);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __COAP_PLATFORM_OS_H__
|
||||||
|
#define __COAP_PLATFORM_OS_H__
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#ifdef INFRA_MEM_STATS
|
||||||
|
#include "infra_mem_stats.h"
|
||||||
|
#define coap_malloc(size) LITE_malloc(size, MEM_MAGIC, "coap.cloud")
|
||||||
|
#define coap_free(ptr) LITE_free(ptr)
|
||||||
|
#else
|
||||||
|
#define coap_malloc(size) HAL_Malloc(size)
|
||||||
|
#define coap_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __COAP_DESERIALIZE_H__
|
||||||
|
#define __COAP_DESERIALIZE_H__
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
int CoAPDeserialize_Message(CoAPMessage *msg, unsigned char *buf, int buflen);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
|
||||||
|
int CoAPDeserialize_Header(CoAPMessage *msg, unsigned char *buf)
|
||||||
|
{
|
||||||
|
msg->header.version = ((buf[0] >> 6) & 0x03);
|
||||||
|
msg->header.type = ((buf[0] >> 4) & 0x03);
|
||||||
|
msg->header.tokenlen = (buf[0] & 0x0F);
|
||||||
|
msg->header.code = buf[1];
|
||||||
|
msg->header.msgid = buf[2] << 8;
|
||||||
|
msg->header.msgid += buf[3];
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPDeserialize_Token(CoAPMessage *msg, unsigned char *buf)
|
||||||
|
{
|
||||||
|
memcpy(msg->token, buf, msg->header.tokenlen);
|
||||||
|
return msg->header.tokenlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CoAPDeserialize_Option(CoAPMsgOption *option, unsigned char *buf, unsigned short *predeltas)
|
||||||
|
{
|
||||||
|
unsigned char *ptr = buf;
|
||||||
|
unsigned short optdelta = 0;
|
||||||
|
unsigned short optlen = 0;
|
||||||
|
unsigned short predelta = 0;
|
||||||
|
|
||||||
|
optdelta = (*ptr & 0xF0) >> 4;
|
||||||
|
optlen = (*ptr & 0x0F);
|
||||||
|
ptr++;
|
||||||
|
|
||||||
|
predelta = *predeltas;
|
||||||
|
if (13 == optdelta) {
|
||||||
|
predelta += 13 + *ptr;
|
||||||
|
ptr ++;
|
||||||
|
|
||||||
|
} else if (14 == optdelta) {
|
||||||
|
predelta += 269;
|
||||||
|
predelta += (*ptr << 8);
|
||||||
|
predelta += *(ptr + 1);
|
||||||
|
ptr += 2;
|
||||||
|
} else {
|
||||||
|
predelta += optdelta;
|
||||||
|
}
|
||||||
|
option->num = predelta;
|
||||||
|
|
||||||
|
if (13 == optlen) {
|
||||||
|
optlen = 13 + *ptr;
|
||||||
|
ptr ++;
|
||||||
|
} else if (14 == optlen) {
|
||||||
|
optlen = 269;
|
||||||
|
optlen += (*ptr << 8);
|
||||||
|
optlen += *(ptr + 1);
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
option->len = optlen;
|
||||||
|
|
||||||
|
option->val = ptr;
|
||||||
|
*predeltas = option->num;
|
||||||
|
|
||||||
|
return (ptr - buf + option->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPDeserialize_Options(CoAPMessage *msg, unsigned char *buf, int buflen)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
int count = 0;
|
||||||
|
unsigned char *ptr = buf;
|
||||||
|
unsigned short len = 0;
|
||||||
|
unsigned short optdeltas = 0;
|
||||||
|
|
||||||
|
msg->optcount = 0;
|
||||||
|
while ((count < buflen) && (0xFF != *ptr)) {
|
||||||
|
len = CoAPDeserialize_Option(&msg->options[index], ptr, &optdeltas);
|
||||||
|
msg->optcount += 1;
|
||||||
|
ptr += len;
|
||||||
|
index ++;
|
||||||
|
count += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)(ptr - buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPDeserialize_Payload(CoAPMessage *msg, unsigned char *buf, int buflen)
|
||||||
|
{
|
||||||
|
unsigned char *ptr = buf;
|
||||||
|
|
||||||
|
if (0xFF == *ptr) {
|
||||||
|
ptr ++;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
msg->payloadlen = buflen - 1;
|
||||||
|
msg->payload = (unsigned char *)ptr;
|
||||||
|
|
||||||
|
return buflen;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPDeserialize_Message(CoAPMessage *msg, unsigned char *buf, int buflen)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
int remlen = buflen;
|
||||||
|
unsigned char *ptr = buf;
|
||||||
|
|
||||||
|
if (NULL == buf || NULL == msg) {
|
||||||
|
return COAP_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buflen < 4) {
|
||||||
|
return COAP_ERROR_INVALID_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deserialize CoAP header. */
|
||||||
|
count = CoAPDeserialize_Header(msg, ptr);
|
||||||
|
ptr += count;
|
||||||
|
remlen -= count;
|
||||||
|
|
||||||
|
/* Deserialize the token, if any. */
|
||||||
|
count = CoAPDeserialize_Token(msg, ptr);
|
||||||
|
ptr += count;
|
||||||
|
remlen -= count;
|
||||||
|
|
||||||
|
count = CoAPDeserialize_Options(msg, ptr, remlen);
|
||||||
|
ptr += count;
|
||||||
|
remlen -= count;
|
||||||
|
|
||||||
|
CoAPDeserialize_Payload(msg, ptr, remlen);
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
#include "ctype.h"
|
||||||
|
#include "Cloud_CoAPPlatform.h"
|
||||||
|
#include "Cloud_CoAPNetwork.h"
|
||||||
|
#include "Cloud_CoAPExport.h"
|
||||||
|
|
||||||
|
#define COAP_DEFAULT_PORT 5683 /* CoAP default UDP port */
|
||||||
|
#define COAPS_DEFAULT_PORT 5684 /* CoAP default UDP port for secure transmission */
|
||||||
|
|
||||||
|
#define COAP_DEFAULT_SCHEME "coap" /* the default scheme for CoAP URIs */
|
||||||
|
#define COAP_DEFAULT_HOST_LEN 128
|
||||||
|
#define COAP_DEFAULT_WAIT_TIME_MS 2000
|
||||||
|
|
||||||
|
unsigned int Cloud_CoAPUri_parse(char *p_uri, coap_endpoint_type *p_endpoint_type,
|
||||||
|
char host[COAP_DEFAULT_HOST_LEN], unsigned short *port)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
char *p = NULL, *q = NULL;
|
||||||
|
if (NULL == p_uri || NULL == p_endpoint_type) {
|
||||||
|
return COAP_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
COAP_DEBUG("The uri is %s", p_uri);
|
||||||
|
len = strlen(p_uri);
|
||||||
|
p = p_uri;
|
||||||
|
q = (char *)COAP_DEFAULT_SCHEME;
|
||||||
|
while (len && *q && tolower(*p) == *q) {
|
||||||
|
++p;
|
||||||
|
++q;
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*q) {
|
||||||
|
return COAP_ERROR_INVALID_URI;
|
||||||
|
}
|
||||||
|
if (tolower(*p) == 's') {
|
||||||
|
++p;
|
||||||
|
--len;
|
||||||
|
*p_endpoint_type = COAP_ENDPOINT_DTLS;
|
||||||
|
*port = COAPS_DEFAULT_PORT;
|
||||||
|
} else if (*p == '-') {
|
||||||
|
++p;
|
||||||
|
--len;
|
||||||
|
q = (char *)"psk";
|
||||||
|
while (len && *q && tolower(*p) == *q) {
|
||||||
|
++p;
|
||||||
|
++q;
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
if (*q) {
|
||||||
|
return COAP_ERROR_INVALID_URI;
|
||||||
|
}
|
||||||
|
*p_endpoint_type = COAP_ENDPOINT_PSK;
|
||||||
|
*port = COAP_DEFAULT_PORT;
|
||||||
|
} else {
|
||||||
|
*p_endpoint_type = COAP_ENDPOINT_NOSEC;
|
||||||
|
*port = COAP_DEFAULT_PORT;
|
||||||
|
}
|
||||||
|
COAP_DEBUG("The endpoint type is: %d", *p_endpoint_type);
|
||||||
|
|
||||||
|
q = (char *)"://";
|
||||||
|
while (len && *q && tolower(*p) == *q) {
|
||||||
|
++p;
|
||||||
|
++q;
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*q) {
|
||||||
|
return COAP_ERROR_INVALID_URI;
|
||||||
|
}
|
||||||
|
|
||||||
|
q = p;
|
||||||
|
while (len && *q != ':') {
|
||||||
|
++q;
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
if (p == q) {
|
||||||
|
return COAP_ERROR_INVALID_URI;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (COAP_DEFAULT_HOST_LEN - 1 < (q - p)) {
|
||||||
|
return COAP_ERROR_INVALID_URI;
|
||||||
|
} else {
|
||||||
|
memset(host, 0x00, COAP_DEFAULT_HOST_LEN);
|
||||||
|
strncpy(host, p, q - p);
|
||||||
|
}
|
||||||
|
COAP_DEBUG("The host name is: %s", host);
|
||||||
|
if (len && *q == ':') {
|
||||||
|
p = ++q;
|
||||||
|
--len;
|
||||||
|
|
||||||
|
while (len && isdigit(*q)) {
|
||||||
|
++q;
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p < q) {
|
||||||
|
int uri_port = 0;
|
||||||
|
|
||||||
|
while (p < q) {
|
||||||
|
uri_port = uri_port * 10 + (*p++ - '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uri_port > 65535) {
|
||||||
|
return COAP_ERROR_INVALID_URI;
|
||||||
|
}
|
||||||
|
*port = uri_port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
COAP_DEBUG("The port is: %d", *port);
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Cloud_CoAPContext *Cloud_CoAPContext_create(Cloud_CoAPInitParam *param)
|
||||||
|
{
|
||||||
|
unsigned int ret = COAP_SUCCESS;
|
||||||
|
Cloud_CoAPContext *p_ctx = NULL;
|
||||||
|
coap_network_init_t network_param;
|
||||||
|
char host[COAP_DEFAULT_HOST_LEN] = {0};
|
||||||
|
|
||||||
|
memset(&network_param, 0x00, sizeof(coap_network_init_t));
|
||||||
|
p_ctx = coap_malloc(sizeof(Cloud_CoAPContext));
|
||||||
|
if (NULL == p_ctx) {
|
||||||
|
COAP_ERR("malloc for coap context failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(p_ctx, 0, sizeof(Cloud_CoAPContext));
|
||||||
|
p_ctx->message_id = 1;
|
||||||
|
p_ctx->notifier = param->notifier;
|
||||||
|
p_ctx->sendbuf = coap_malloc(COAP_MSG_MAX_PDU_LEN);
|
||||||
|
if (NULL == p_ctx->sendbuf) {
|
||||||
|
COAP_ERR("not enough memory");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_ctx->recvbuf = coap_malloc(COAP_MSG_MAX_PDU_LEN);
|
||||||
|
if (NULL == p_ctx->recvbuf) {
|
||||||
|
COAP_ERR("not enough memory");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == param->waittime) {
|
||||||
|
p_ctx->waittime = COAP_DEFAULT_WAIT_TIME_MS;
|
||||||
|
} else {
|
||||||
|
p_ctx->waittime = param->waittime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*CoAP message send list*/
|
||||||
|
INIT_LIST_HEAD(&p_ctx->list.sendlist);
|
||||||
|
p_ctx->list.count = 0;
|
||||||
|
p_ctx->list.maxcount = param->maxcount;
|
||||||
|
|
||||||
|
/*set the endpoint type by uri schema*/
|
||||||
|
if (NULL != param->url) {
|
||||||
|
ret = Cloud_CoAPUri_parse(param->url, &network_param.ep_type, host, &network_param.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (COAP_SUCCESS != ret) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef COAP_DTLS_SUPPORT
|
||||||
|
if (COAP_ENDPOINT_DTLS == network_param.ep_type) {
|
||||||
|
extern const char *iotx_ca_crt;
|
||||||
|
network_param.p_ca_cert_pem = (unsigned char *)iotx_ca_crt;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (COAP_ENDPOINT_NOSEC == network_param.ep_type
|
||||||
|
|| COAP_ENDPOINT_PSK == network_param.ep_type) {
|
||||||
|
network_param.p_ca_cert_pem = NULL;
|
||||||
|
}
|
||||||
|
network_param.p_host = host;
|
||||||
|
|
||||||
|
/*CoAP network init*/
|
||||||
|
ret = Cloud_CoAPNetwork_init(&network_param, &p_ctx->network);
|
||||||
|
|
||||||
|
if (COAP_SUCCESS != ret) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p_ctx;
|
||||||
|
err:
|
||||||
|
if (NULL == p_ctx) {
|
||||||
|
return p_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != p_ctx->recvbuf) {
|
||||||
|
coap_free(p_ctx->recvbuf);
|
||||||
|
p_ctx->recvbuf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != p_ctx->sendbuf) {
|
||||||
|
coap_free(p_ctx->sendbuf);
|
||||||
|
p_ctx->sendbuf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
coap_free(p_ctx);
|
||||||
|
p_ctx = NULL;
|
||||||
|
|
||||||
|
return p_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cloud_CoAPContext_free(Cloud_CoAPContext *p_ctx)
|
||||||
|
{
|
||||||
|
Cloud_CoAPSendNode *cur, *next;
|
||||||
|
|
||||||
|
if (NULL == p_ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cloud_CoAPNetwork_deinit(&p_ctx->network);
|
||||||
|
|
||||||
|
list_for_each_entry_safe(cur, next, &p_ctx->list.sendlist, sendlist, Cloud_CoAPSendNode) {
|
||||||
|
if (NULL != cur) {
|
||||||
|
if (NULL != cur->message) {
|
||||||
|
coap_free(cur->message);
|
||||||
|
cur->message = NULL;
|
||||||
|
}
|
||||||
|
coap_free(cur);
|
||||||
|
cur = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != p_ctx->recvbuf) {
|
||||||
|
coap_free(p_ctx->recvbuf);
|
||||||
|
p_ctx->recvbuf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != p_ctx->sendbuf) {
|
||||||
|
coap_free(p_ctx->sendbuf);
|
||||||
|
p_ctx->sendbuf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (NULL != p_ctx) {
|
||||||
|
coap_free(p_ctx);
|
||||||
|
p_ctx = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,312 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
#include "Cloud_CoAPExport.h"
|
||||||
|
#include "CoAPSerialize.h"
|
||||||
|
#include "CoAPDeserialize.h"
|
||||||
|
#include "Cloud_CoAPPlatform.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define COAPAckMsg(header) \
|
||||||
|
((header.code == COAP_MSG_CODE_EMPTY_MESSAGE) \
|
||||||
|
&&(header.type == COAP_MESSAGE_TYPE_ACK))
|
||||||
|
|
||||||
|
#define Cloud_CoAPRespMsg(header)\
|
||||||
|
((header.code >= 0x40) && (header.code < 0xc0))
|
||||||
|
|
||||||
|
#define Cloud_CoAPPingMsg(header)\
|
||||||
|
((header.code == COAP_MSG_CODE_EMPTY_MESSAGE)\
|
||||||
|
&& (header.type == COAP_MESSAGE_TYPE_CON))
|
||||||
|
|
||||||
|
#define Cloud_CoAPRstMsg(header)\
|
||||||
|
(header.type == COAP_MESSAGE_TYPE_RST)
|
||||||
|
|
||||||
|
#define Cloud_CoAPCONRespMsg(header)\
|
||||||
|
((header.code == COAP_MSG_CODE_205_CONTENT) \
|
||||||
|
&& (header.type == COAP_MESSAGE_TYPE_CON))
|
||||||
|
|
||||||
|
#define Cloud_CoAPReqMsg(header)\
|
||||||
|
((1 <= header.code) && (32 > header.code))
|
||||||
|
|
||||||
|
|
||||||
|
#define COAP_CUR_VERSION 1
|
||||||
|
#define COAP_WAIT_TIME_MS 2000
|
||||||
|
#define COAP_MAX_MESSAGE_ID 65535
|
||||||
|
#define COAP_MAX_RETRY_COUNT 4
|
||||||
|
#define COAP_ACK_TIMEOUT 2
|
||||||
|
#define COAP_ACK_RANDOM_FACTOR 1
|
||||||
|
#define COAP_MAX_TRANSMISSION_SPAN 10
|
||||||
|
|
||||||
|
unsigned short Cloud_CoAPMessageId_gen(Cloud_CoAPContext *context)
|
||||||
|
{
|
||||||
|
unsigned short msg_id = 0;
|
||||||
|
msg_id = ((COAP_MAX_MESSAGE_ID == context->message_id) ? 1 : context->message_id++);
|
||||||
|
return msg_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Cloud_CoAPMessageHandler_set(Cloud_CoAPMessage *message, Cloud_CoAPRespMsgHandler resp)
|
||||||
|
{
|
||||||
|
if (NULL == message) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
message->resp = resp;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Cloud_CoAPMessageList_add(Cloud_CoAPContext *context, Cloud_CoAPMessage *message, int len)
|
||||||
|
{
|
||||||
|
Cloud_CoAPSendNode *node = NULL;
|
||||||
|
node = coap_malloc(sizeof(Cloud_CoAPSendNode));
|
||||||
|
|
||||||
|
if (NULL != node) {
|
||||||
|
node->acked = 0;
|
||||||
|
node->user = message->user;
|
||||||
|
node->msgid = message->header.msgid;
|
||||||
|
node->resp = message->resp;
|
||||||
|
node->msglen = len;
|
||||||
|
node->timeout_val = COAP_ACK_TIMEOUT * COAP_ACK_RANDOM_FACTOR;
|
||||||
|
|
||||||
|
if (COAP_MESSAGE_TYPE_CON == message->header.type) {
|
||||||
|
node->timeout = node->timeout_val;
|
||||||
|
node->retrans_count = 0;
|
||||||
|
} else {
|
||||||
|
node->timeout = COAP_MAX_TRANSMISSION_SPAN;
|
||||||
|
node->retrans_count = COAP_MAX_RETRY_COUNT;
|
||||||
|
}
|
||||||
|
node->tokenlen = message->header.tokenlen;
|
||||||
|
memcpy(node->token, message->token, message->header.tokenlen);
|
||||||
|
node->message = (unsigned char *)coap_malloc(len);
|
||||||
|
if (NULL != node->message) {
|
||||||
|
memcpy(node->message, context->sendbuf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (&context->list.count >= &context->list.maxcount) {
|
||||||
|
coap_free(node);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
list_add_tail(&node->sendlist, &context->list.sendlist);
|
||||||
|
context->list.count ++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Cloud_CoAPMessage_send(Cloud_CoAPContext *context, Cloud_CoAPMessage *message)
|
||||||
|
{
|
||||||
|
unsigned int ret = COAP_SUCCESS;
|
||||||
|
unsigned short msglen = 0;
|
||||||
|
|
||||||
|
if (NULL == message || NULL == context) {
|
||||||
|
return (COAP_ERROR_INVALID_PARAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: get the message length */
|
||||||
|
/* msglen = CoAPSerialize_MessageLength(message); */
|
||||||
|
msglen = CoAPSerialize_MessageLength(message);
|
||||||
|
if (COAP_MSG_MAX_PDU_LEN < msglen) {
|
||||||
|
COAP_INFO("The message length %d is too loog", msglen);
|
||||||
|
return COAP_ERROR_DATA_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(context->sendbuf, 0x00, COAP_MSG_MAX_PDU_LEN);
|
||||||
|
msglen = CoAPSerialize_Message(message, context->sendbuf, COAP_MSG_MAX_PDU_LEN);
|
||||||
|
COAP_DEBUG("----The message length %d-----", msglen);
|
||||||
|
|
||||||
|
|
||||||
|
ret = Cloud_CoAPNetwork_write(&context->network, context->sendbuf, (unsigned int)msglen);
|
||||||
|
if (COAP_SUCCESS == ret) {
|
||||||
|
if (Cloud_CoAPReqMsg(message->header) || Cloud_CoAPCONRespMsg(message->header)) {
|
||||||
|
COAP_DEBUG("Add message id %d len %d to the list",
|
||||||
|
message->header.msgid, msglen);
|
||||||
|
Cloud_CoAPMessageList_add(context, message, msglen);
|
||||||
|
} else {
|
||||||
|
COAP_DEBUG("The message doesn't need to be retransmitted");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
COAP_ERR("CoAP transport write failed, return %d", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int Cloud_CoAPAckMessage_handle(Cloud_CoAPContext *context, Cloud_CoAPMessage *message)
|
||||||
|
{
|
||||||
|
Cloud_CoAPSendNode *node = NULL;
|
||||||
|
|
||||||
|
list_for_each_entry(node, &context->list.sendlist, sendlist, Cloud_CoAPSendNode) {
|
||||||
|
if (node->msgid == message->header.msgid) {
|
||||||
|
node->acked = 1;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Cloud_CoAPAckMessage_send(Cloud_CoAPContext *context, unsigned short msgid)
|
||||||
|
{
|
||||||
|
Cloud_CoAPMessage message;
|
||||||
|
CoAPMessage_init(&message);
|
||||||
|
CoAPMessageId_set(&message, msgid);
|
||||||
|
return Cloud_CoAPMessage_send(context, &message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Cloud_CoAPRespMessage_handle(Cloud_CoAPContext *context, Cloud_CoAPMessage *message)
|
||||||
|
{
|
||||||
|
Cloud_CoAPSendNode *node = NULL;
|
||||||
|
|
||||||
|
if (COAP_MESSAGE_TYPE_CON == message->header.type) {
|
||||||
|
Cloud_CoAPAckMessage_send(context, message->header.msgid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
list_for_each_entry(node, &context->list.sendlist, sendlist, Cloud_CoAPSendNode) {
|
||||||
|
if (0 != node->tokenlen && node->tokenlen == message->header.tokenlen
|
||||||
|
&& 0 == memcmp(node->token, message->token, message->header.tokenlen)) {
|
||||||
|
|
||||||
|
#ifdef INFRA_LOG_NETWORK_PAYLOAD
|
||||||
|
COAP_DEBUG("Find the node by token");
|
||||||
|
COAP_INFO("Downstream Payload:");
|
||||||
|
iotx_facility_json_print((const char *)message->payload, LOG_INFO_LEVEL, '<');
|
||||||
|
#endif
|
||||||
|
message->user = node->user;
|
||||||
|
if (COAP_MSG_CODE_400_BAD_REQUEST <= message->header.code) {
|
||||||
|
/* TODO:i */
|
||||||
|
if (NULL != context->notifier) {
|
||||||
|
/* context->notifier(message->header.code, message); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != node->resp) {
|
||||||
|
node->resp(node->user, message);
|
||||||
|
}
|
||||||
|
COAP_DEBUG("Remove the message id %d from list", node->msgid);
|
||||||
|
list_del_init(&node->sendlist);
|
||||||
|
context->list.count--;
|
||||||
|
if (NULL != node->message) {
|
||||||
|
coap_free(node->message);
|
||||||
|
}
|
||||||
|
coap_free(node);
|
||||||
|
node = NULL;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return COAP_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Cloud_CoAPMessage_handle(Cloud_CoAPContext *context,
|
||||||
|
unsigned char *buf,
|
||||||
|
unsigned short datalen)
|
||||||
|
{
|
||||||
|
int ret = COAP_SUCCESS;
|
||||||
|
Cloud_CoAPMessage message;
|
||||||
|
unsigned char code, msgclass, detail;
|
||||||
|
memset(&message, 0x00, sizeof(Cloud_CoAPMessage));
|
||||||
|
|
||||||
|
ret = CoAPDeserialize_Message(&message, buf, datalen);
|
||||||
|
code = (unsigned char)message.header.code;
|
||||||
|
msgclass = code >> 5;
|
||||||
|
detail = code & 0x1F;
|
||||||
|
|
||||||
|
COAP_DEBUG("Version : %d", message.header.version);
|
||||||
|
COAP_DEBUG("Code : %d.%02d(0x%x)", msgclass, detail, code);
|
||||||
|
COAP_DEBUG("Type : 0x%x", message.header.type);
|
||||||
|
COAP_DEBUG("Msgid : %d", message.header.msgid);
|
||||||
|
COAP_DEBUG("Option : %d", message.optcount);
|
||||||
|
COAP_DEBUG("Payload Len : %d", message.payloadlen);
|
||||||
|
|
||||||
|
msgclass = msgclass;
|
||||||
|
detail = detail;
|
||||||
|
|
||||||
|
if (COAP_SUCCESS != ret) {
|
||||||
|
if (NULL != context->notifier) {
|
||||||
|
/* TODO: */
|
||||||
|
/* context->notifier(context, event); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (COAPAckMsg(message.header)) {
|
||||||
|
COAP_DEBUG("Receive CoAP ACK Message,ID %d", message.header.msgid);
|
||||||
|
Cloud_CoAPAckMessage_handle(context, &message);
|
||||||
|
|
||||||
|
} else if (Cloud_CoAPRespMsg(message.header)) {
|
||||||
|
COAP_DEBUG("Receive CoAP Response Message,ID %d", message.header.msgid);
|
||||||
|
Cloud_CoAPRespMessage_handle(context, &message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Cloud_CoAPMessage_recv(Cloud_CoAPContext *context, unsigned int timeout, int readcount)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
int count = readcount;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
len = Cloud_CoAPNetwork_read(&context->network, context->recvbuf,
|
||||||
|
COAP_MSG_MAX_PDU_LEN, timeout);
|
||||||
|
if (len > 0) {
|
||||||
|
if (0 == readcount) {
|
||||||
|
Cloud_CoAPMessage_handle(context, context->recvbuf, len);
|
||||||
|
} else {
|
||||||
|
count--;
|
||||||
|
Cloud_CoAPMessage_handle(context, context->recvbuf, len);
|
||||||
|
if (0 == count) {
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Cloud_CoAPMessage_cycle(Cloud_CoAPContext *context)
|
||||||
|
{
|
||||||
|
unsigned int ret = 0;
|
||||||
|
Cloud_CoAPSendNode *node = NULL, *next = NULL;
|
||||||
|
Cloud_CoAPMessage_recv(context, context->waittime, 0);
|
||||||
|
|
||||||
|
list_for_each_entry_safe(node, next, &context->list.sendlist, sendlist, Cloud_CoAPSendNode) {
|
||||||
|
if (NULL != node) {
|
||||||
|
if (node->timeout == 0) {
|
||||||
|
if (node->retrans_count < COAP_MAX_RETRY_COUNT && (0 == node->acked)) {
|
||||||
|
node->timeout = node->timeout_val * 2;
|
||||||
|
node->timeout_val = node->timeout;
|
||||||
|
node->retrans_count++;
|
||||||
|
COAP_DEBUG("Retansmit the message id %d len %d", node->msgid, node->msglen);
|
||||||
|
ret = Cloud_CoAPNetwork_write(&context->network, node->message, node->msglen);
|
||||||
|
if (ret != COAP_SUCCESS) {
|
||||||
|
if (NULL != context->notifier) {
|
||||||
|
/* TODO: */
|
||||||
|
/* context->notifier(context, event); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((node->timeout > COAP_MAX_TRANSMISSION_SPAN) ||
|
||||||
|
(node->retrans_count >= COAP_MAX_RETRY_COUNT)) {
|
||||||
|
if (NULL != context->notifier) {
|
||||||
|
/* TODO: */
|
||||||
|
/* context->notifier(context, event); */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Remove the node from the list*/
|
||||||
|
list_del_init(&node->sendlist);
|
||||||
|
context->list.count--;
|
||||||
|
COAP_INFO("Retransmit timeout,remove the message id %d count %d",
|
||||||
|
node->msgid, context->list.count);
|
||||||
|
coap_free(node->message);
|
||||||
|
coap_free(node);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node->timeout--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,317 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
#include "CoAPSerialize.h"
|
||||||
|
#include "CoAPDeserialize.h"
|
||||||
|
#if 0
|
||||||
|
#include "CoAPResource.h"
|
||||||
|
#include "CoAPObserve.h"
|
||||||
|
#include "CoAPInternal.h"
|
||||||
|
#endif
|
||||||
|
#include "CoAPPlatform.h"
|
||||||
|
|
||||||
|
#define COAPAckMsg(header) \
|
||||||
|
((header.code == COAP_MSG_CODE_EMPTY_MESSAGE) \
|
||||||
|
&&(header.type == COAP_MESSAGE_TYPE_ACK))
|
||||||
|
|
||||||
|
#define CoAPRespMsg(header)\
|
||||||
|
((header.code >= 0x40) && (header.code < 0xc0))
|
||||||
|
|
||||||
|
#define CoAPPingMsg(header)\
|
||||||
|
((header.code == COAP_MSG_CODE_EMPTY_MESSAGE)\
|
||||||
|
&& (header.type == COAP_MESSAGE_TYPE_CON))
|
||||||
|
|
||||||
|
#define CoAPResetMsg(header)\
|
||||||
|
(header.type == COAP_MESSAGE_TYPE_RST)
|
||||||
|
|
||||||
|
#define CoAPCONRespMsg(header)\
|
||||||
|
((header.code == COAP_MSG_CODE_205_CONTENT) \
|
||||||
|
&& (header.type == COAP_MESSAGE_TYPE_CON))
|
||||||
|
|
||||||
|
#define CoAPReqMsg(header)\
|
||||||
|
((1 <= header.code) && (32 > header.code))
|
||||||
|
|
||||||
|
|
||||||
|
#define COAP_CUR_VERSION 1
|
||||||
|
#define COAP_WAIT_TIME_MS 2000
|
||||||
|
#define COAP_MAX_MESSAGE_ID 65535
|
||||||
|
#define COAP_MAX_RETRY_COUNT 4
|
||||||
|
#define COAP_ACK_TIMEOUT 2
|
||||||
|
#define COAP_ACK_RANDOM_FACTOR 1
|
||||||
|
#define COAP_MAX_TRANSMISSION_SPAN 10
|
||||||
|
|
||||||
|
int CoAPStrOption_add(CoAPMessage *message, unsigned short optnum, unsigned char *data, unsigned short datalen)
|
||||||
|
{
|
||||||
|
unsigned char *ptr = NULL;
|
||||||
|
if (COAP_MSG_MAX_OPTION_NUM <= message->optcount) {
|
||||||
|
return COAP_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
message->options[message->optcount].num = optnum - message->optdelta;
|
||||||
|
message->options[message->optcount].len = datalen;
|
||||||
|
ptr = (unsigned char *)coap_malloc(datalen);
|
||||||
|
if (NULL == ptr) {
|
||||||
|
return COAP_ERROR_MALLOC;
|
||||||
|
}
|
||||||
|
memset(ptr, 0x00, datalen);
|
||||||
|
memcpy(ptr, data, datalen);
|
||||||
|
message->options[message->optcount].val = ptr;
|
||||||
|
message->optdelta = optnum;
|
||||||
|
message->optcount ++;
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPStrOption_get(CoAPMessage *message, unsigned short optnum, unsigned char *data, unsigned short *datalen)
|
||||||
|
{
|
||||||
|
unsigned char index = 0;
|
||||||
|
|
||||||
|
for (index = 0; index < message->optcount; index++) {
|
||||||
|
if (message->options[index].num == optnum) {
|
||||||
|
if (*datalen >= message->options[index].len) {
|
||||||
|
memcpy(data, message->options[index].val, message->options[index].len);
|
||||||
|
*datalen = message->options[index].len;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
} else {
|
||||||
|
return COAP_ERROR_INVALID_LENGTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return COAP_ERROR_NOT_FOUND;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CoAPUintOption_add(CoAPMessage *message, unsigned short optnum, unsigned int data)
|
||||||
|
{
|
||||||
|
unsigned char *ptr = NULL;
|
||||||
|
if (COAP_MSG_MAX_OPTION_NUM <= message->optcount) {
|
||||||
|
return COAP_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
message->options[message->optcount].num = optnum - message->optdelta;
|
||||||
|
|
||||||
|
if (0 == data) {
|
||||||
|
message->options[message->optcount].len = 0;
|
||||||
|
} else if (255 >= data) {
|
||||||
|
message->options[message->optcount].len = 1;
|
||||||
|
ptr = (unsigned char *)coap_malloc(1);
|
||||||
|
if (NULL != ptr) {
|
||||||
|
*ptr = (unsigned char)data;
|
||||||
|
}
|
||||||
|
} else if (65535 >= data) {
|
||||||
|
message->options[message->optcount].len = 2;
|
||||||
|
ptr = (unsigned char *)coap_malloc(2);
|
||||||
|
if (NULL != ptr) {
|
||||||
|
*ptr = (unsigned char)((data & 0xFF00) >> 8);
|
||||||
|
*(ptr + 1) = (unsigned char)(data & 0x00FF);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message->options[message->optcount].len = 4;
|
||||||
|
ptr = (unsigned char *)coap_malloc(4);
|
||||||
|
if (NULL != ptr) {
|
||||||
|
*ptr = (unsigned char)((data & 0xFF000000) >> 24);
|
||||||
|
*(ptr + 1) = (unsigned char)((data & 0x00FF0000) >> 16);
|
||||||
|
*(ptr + 2) = (unsigned char)((data & 0x0000FF00) >> 8);
|
||||||
|
*(ptr + 3) = (unsigned char)(data & 0x000000FF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message->options[message->optcount].val = ptr;
|
||||||
|
message->optdelta = optnum;
|
||||||
|
message->optcount += 1;
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPUintOption_get(CoAPMessage *message,
|
||||||
|
unsigned short optnum,
|
||||||
|
unsigned int *data)
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned char index = 0;
|
||||||
|
|
||||||
|
for (index = 0; index < message->optcount; index++) {
|
||||||
|
if (message->options[index].num == optnum) {
|
||||||
|
int byte = 0;
|
||||||
|
switch (message->options[index].len) {
|
||||||
|
case 1:
|
||||||
|
*data |= message->options[index].val[byte++];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*data |= (message->options[index].val[byte++] << 8);
|
||||||
|
*data |= message->options[index].val[byte++];
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
*data |= (message->options[index].val[byte++] << 16);
|
||||||
|
*data |= (message->options[index].val[byte++] << 8);
|
||||||
|
*data |= message->options[index].val[byte++];
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*data |= (message->options[index].val[byte++] << 24);
|
||||||
|
*data |= (message->options[index].val[byte++] << 16);
|
||||||
|
*data |= (message->options[index].val[byte++] << 8);
|
||||||
|
*data |= message->options[index].val[byte++];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*data = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return COAP_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CoAPOption_present(CoAPMessage *message, unsigned short option)
|
||||||
|
{
|
||||||
|
unsigned char index = 0;
|
||||||
|
|
||||||
|
|
||||||
|
for (index = 0; index < message->optcount; index++) {
|
||||||
|
if (message->options[index].num == option) {
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return COAP_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessageId_set(CoAPMessage *message, unsigned short msgid)
|
||||||
|
{
|
||||||
|
if (NULL == message) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
message->header.msgid = msgid;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessageType_set(CoAPMessage *message, unsigned char type)
|
||||||
|
{
|
||||||
|
if (NULL == message) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
if (COAP_MESSAGE_TYPE_CON != type && COAP_MESSAGE_TYPE_NON != type
|
||||||
|
&& COAP_MESSAGE_TYPE_ACK != type && COAP_MESSAGE_TYPE_RST != type) {
|
||||||
|
return COAP_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
message->header.type = type;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessageCode_set(CoAPMessage *message, CoAPMessageCode code)
|
||||||
|
{
|
||||||
|
if (NULL == message) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
message->header.code = code;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessageCode_get(CoAPMessage *message, CoAPMessageCode *code)
|
||||||
|
{
|
||||||
|
if (NULL == message || NULL == code) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
*code = message->header.code;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessageToken_set(CoAPMessage *message, unsigned char *token,
|
||||||
|
unsigned char tokenlen)
|
||||||
|
{
|
||||||
|
if (NULL == message || NULL == token) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
if (COAP_MSG_MAX_TOKEN_LEN < tokenlen) {
|
||||||
|
return COAP_ERROR_INVALID_LENGTH;
|
||||||
|
}
|
||||||
|
memcpy(message->token, token, tokenlen);
|
||||||
|
message->header.tokenlen = tokenlen;
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessageUserData_set(CoAPMessage *message, void *userdata)
|
||||||
|
{
|
||||||
|
if (NULL == message || NULL == userdata) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
message->user = userdata;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessageKeep_Set(CoAPMessage *message, int keep)
|
||||||
|
{
|
||||||
|
if (NULL == message || keep < 0) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
message->keep = keep;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessagePayload_set(CoAPMessage *message, unsigned char *payload,
|
||||||
|
unsigned short payloadlen)
|
||||||
|
{
|
||||||
|
if (NULL == message || (0 < payloadlen && NULL == payload)) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
message->payload = payload;
|
||||||
|
message->payloadlen = payloadlen;
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessage_init(CoAPMessage *message)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
if (NULL == message) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
memset(message, 0x00, sizeof(CoAPMessage));
|
||||||
|
message->header.version = COAP_CUR_VERSION;
|
||||||
|
message->header.type = COAP_MESSAGE_TYPE_ACK;
|
||||||
|
message->header.tokenlen = 0;
|
||||||
|
message->header.code = COAP_MSG_CODE_EMPTY_MESSAGE;
|
||||||
|
message->header.msgid = 0;
|
||||||
|
message->payload = NULL;
|
||||||
|
message->payloadlen = 0;
|
||||||
|
message->optcount = 0;
|
||||||
|
message->optdelta = 0;
|
||||||
|
message->handler = NULL;
|
||||||
|
message->keep = 0;
|
||||||
|
for (count = 0; count < COAP_MSG_MAX_OPTION_NUM; count++) {
|
||||||
|
message->options[count].len = 0;
|
||||||
|
message->options[count].num = 0;
|
||||||
|
message->options[count].val = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessage_destory(CoAPMessage *message)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
if (NULL == message) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (count = 0; count < COAP_MSG_MAX_OPTION_NUM; count++) {
|
||||||
|
if (NULL != message->options[count].val) {
|
||||||
|
coap_free(message->options[count].val);
|
||||||
|
message->options[count].val = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
#include "Cloud_CoAPExport.h"
|
||||||
|
#include "Cloud_CoAPNetwork.h"
|
||||||
|
|
||||||
|
#ifdef COAP_DTLS_SUPPORT
|
||||||
|
static void *Cloud_CoAPDTLS_Malloc(uint32_t size)
|
||||||
|
{
|
||||||
|
#ifdef INFRA_MEM_STATS
|
||||||
|
return LITE_malloc(size, MEM_MAGIC, "dtls");
|
||||||
|
#else
|
||||||
|
return HAL_Malloc(size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
static void Cloud_CoAPDTLS_Free(void *ptr)
|
||||||
|
{
|
||||||
|
#ifdef INFRA_MEM_STATS
|
||||||
|
LITE_free(ptr);
|
||||||
|
#else
|
||||||
|
HAL_Free((void *)ptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Cloud_CoAPNetworkDTLS_freeSession(void *p_session);
|
||||||
|
|
||||||
|
unsigned int Cloud_CoAPNetworkDTLS_read(void *p_session,
|
||||||
|
unsigned char *p_data,
|
||||||
|
unsigned int *p_datalen,
|
||||||
|
unsigned int timeout)
|
||||||
|
{
|
||||||
|
unsigned int err_code = DTLS_SUCCESS;
|
||||||
|
const unsigned int read_len = *p_datalen;
|
||||||
|
DTLSContext *context = NULL;
|
||||||
|
|
||||||
|
COAP_TRC("<< secure_datagram_read, read buffer len %d, timeout %d", read_len, timeout);
|
||||||
|
(void)read_len;
|
||||||
|
if (NULL != p_session) {
|
||||||
|
/* read dtls application data*/
|
||||||
|
context = (DTLSContext *)p_session;
|
||||||
|
err_code = HAL_DTLSSession_read(context, p_data, p_datalen, timeout);
|
||||||
|
if (DTLS_PEER_CLOSE_NOTIFY == err_code
|
||||||
|
|| DTLS_FATAL_ALERT_MESSAGE == err_code) {
|
||||||
|
COAP_INFO("dtls session read failed, return (0x%04x)", err_code);
|
||||||
|
Cloud_CoAPNetworkDTLS_freeSession(context);
|
||||||
|
}
|
||||||
|
if (DTLS_SUCCESS == err_code) {
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
} else {
|
||||||
|
return COAP_ERROR_READ_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return COAP_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Cloud_CoAPNetworkDTLS_write(void *p_session,
|
||||||
|
const unsigned char *p_data,
|
||||||
|
unsigned int *p_datalen)
|
||||||
|
{
|
||||||
|
unsigned int err_code = DTLS_SUCCESS;
|
||||||
|
if (NULL != p_session) {
|
||||||
|
err_code = HAL_DTLSSession_write((DTLSContext *)p_session, p_data, p_datalen);
|
||||||
|
if (DTLS_SUCCESS == err_code) {
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
} else {
|
||||||
|
return COAP_ERROR_WRITE_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return COAP_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Cloud_CoAPNetworkDTLS_freeSession(void *p_session)
|
||||||
|
{
|
||||||
|
/* Free the session.*/
|
||||||
|
HAL_DTLSSession_free((DTLSContext *)p_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Cloud_CoAPNetworkDTLS_createSession(char *p_host,
|
||||||
|
unsigned short port,
|
||||||
|
unsigned char *p_ca_cert_pem)
|
||||||
|
{
|
||||||
|
DTLSContext *context = NULL;
|
||||||
|
dtls_hooks_t dtls_hooks;
|
||||||
|
coap_dtls_options_t dtls_options;
|
||||||
|
|
||||||
|
memset(&dtls_hooks, 0, sizeof(dtls_hooks_t));
|
||||||
|
dtls_hooks.malloc = Cloud_CoAPDTLS_Malloc;
|
||||||
|
dtls_hooks.free = Cloud_CoAPDTLS_Free;
|
||||||
|
|
||||||
|
HAL_DTLSHooks_set(&dtls_hooks);
|
||||||
|
|
||||||
|
memset(&dtls_options, 0x00, sizeof(coap_dtls_options_t));
|
||||||
|
dtls_options.p_ca_cert_pem = p_ca_cert_pem;
|
||||||
|
dtls_options.p_host = p_host;
|
||||||
|
dtls_options.port = port;
|
||||||
|
|
||||||
|
context = HAL_DTLSSession_create(&dtls_options);
|
||||||
|
return (void *)context;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned int Cloud_CoAPNetwork_write(coap_network_t *p_network,
|
||||||
|
const unsigned char *p_data,
|
||||||
|
unsigned int datalen)
|
||||||
|
{
|
||||||
|
int rc = COAP_ERROR_WRITE_FAILED;
|
||||||
|
|
||||||
|
#ifdef COAP_DTLS_SUPPORT
|
||||||
|
if (COAP_ENDPOINT_DTLS == p_network->ep_type) {
|
||||||
|
rc = Cloud_CoAPNetworkDTLS_write(p_network->context, p_data, &datalen);
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
rc = HAL_UDP_write((intptr_t)p_network->context, p_data, datalen);
|
||||||
|
COAP_DEBUG("[CoAP-NWK]: Network write return %d", rc);
|
||||||
|
|
||||||
|
if (-1 == rc) {
|
||||||
|
rc = COAP_ERROR_WRITE_FAILED;
|
||||||
|
} else {
|
||||||
|
rc = COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
#ifdef COAP_DTLS_SUPPORT
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return (unsigned int)rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Cloud_CoAPNetwork_read(coap_network_t *network, unsigned char *data,
|
||||||
|
unsigned int datalen, unsigned int timeout)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
#ifdef COAP_DTLS_SUPPORT
|
||||||
|
if (COAP_ENDPOINT_DTLS == network->ep_type) {
|
||||||
|
len = datalen;
|
||||||
|
memset(data, 0x00, datalen);
|
||||||
|
Cloud_CoAPNetworkDTLS_read(network->context, data, (unsigned int *)&len, timeout);
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
memset(data, 0x00, datalen);
|
||||||
|
len = HAL_UDP_readTimeout((intptr_t)network->context,
|
||||||
|
data, COAP_MSG_MAX_PDU_LEN, timeout);
|
||||||
|
#ifdef COAP_DTLS_SUPPORT
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (len > 0) {
|
||||||
|
COAP_TRC("<< CoAP recv %d bytes data", len);
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Cloud_CoAPNetwork_init(const coap_network_init_t *p_param, coap_network_t *p_network)
|
||||||
|
{
|
||||||
|
unsigned int err_code = COAP_SUCCESS;
|
||||||
|
|
||||||
|
if (NULL == p_param || NULL == p_network) {
|
||||||
|
return COAP_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO : Parse the url here */
|
||||||
|
p_network->ep_type = p_param->ep_type;
|
||||||
|
|
||||||
|
#ifdef COAP_DTLS_SUPPORT
|
||||||
|
if (COAP_ENDPOINT_DTLS == p_param->ep_type) {
|
||||||
|
p_network->context = Cloud_CoAPNetworkDTLS_createSession(p_param->p_host,
|
||||||
|
p_param->port, p_param->p_ca_cert_pem);
|
||||||
|
if (NULL == p_network->context) {
|
||||||
|
return COAP_ERROR_NET_INIT_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (COAP_ENDPOINT_NOSEC == p_param->ep_type
|
||||||
|
|| COAP_ENDPOINT_PSK == p_param->ep_type) {
|
||||||
|
/*Create udp socket*/
|
||||||
|
p_network->context = (void *)HAL_UDP_create(p_param->p_host, p_param->port);
|
||||||
|
if ((void *) - 1 == p_network->context) {
|
||||||
|
return COAP_ERROR_NET_INIT_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int Cloud_CoAPNetwork_deinit(coap_network_t *p_network)
|
||||||
|
{
|
||||||
|
unsigned int err_code = COAP_SUCCESS;
|
||||||
|
|
||||||
|
#ifdef COAP_DTLS_SUPPORT
|
||||||
|
if (COAP_ENDPOINT_DTLS == p_network->ep_type) {
|
||||||
|
Cloud_CoAPNetworkDTLS_freeSession(p_network->context);
|
||||||
|
p_network->context = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (COAP_ENDPOINT_NOSEC == p_network->ep_type
|
||||||
|
|| COAP_ENDPOINT_PSK == p_network->ep_type) {
|
||||||
|
HAL_UDP_close_without_connect((intptr_t)p_network->context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __COAP_PLATFORM_OS_H__
|
||||||
|
#define __COAP_PLATFORM_OS_H__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#ifdef INFRA_MEM_STATS
|
||||||
|
#include "infra_mem_stats.h"
|
||||||
|
#define coap_malloc(size) LITE_malloc(size, MEM_MAGIC, "coap.local")
|
||||||
|
#define coap_free(ptr) LITE_free(ptr)
|
||||||
|
#else
|
||||||
|
#define coap_malloc(size) HAL_Malloc(size)
|
||||||
|
#define coap_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef INFRA_LOG
|
||||||
|
#include "infra_log.h"
|
||||||
|
#define COAP_ERR(...) log_err("coap_local", __VA_ARGS__)
|
||||||
|
#define COAP_WRN(...) log_warning("coap_local", __VA_ARGS__)
|
||||||
|
#define COAP_INFO(...) log_info("coap_local", __VA_ARGS__)
|
||||||
|
#define COAP_TRC(...) log_debug("coap_local", __VA_ARGS__)
|
||||||
|
#define COAP_DUMP(...) log_debug("coap_local", __VA_ARGS__)
|
||||||
|
#define COAP_DEBUG(...) log_debug("coap_local", __VA_ARGS__)
|
||||||
|
#define COAP_FLOW(...) log_flow("coap_local", __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define COAP_ERR(...)
|
||||||
|
#define COAP_WRN(...)
|
||||||
|
#define COAP_INFO(...)
|
||||||
|
#define COAP_TRC(...)
|
||||||
|
#define COAP_DUMP(...)
|
||||||
|
#define COAP_DEBUG(...)
|
||||||
|
#define COAP_FLOW(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int platform_is_multicast(const char *ip_str);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __COAP_SERIALIZE_H__
|
||||||
|
#define __COAP_SERIALIZE_H__
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
unsigned short CoAPSerialize_MessageLength(CoAPMessage *msg);
|
||||||
|
|
||||||
|
int CoAPSerialize_Message(CoAPMessage *msg, unsigned char *buf, unsigned short buflen);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "CoAPSerialize.h"
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
|
||||||
|
int CoAPSerialize_Header(CoAPMessage *msg, unsigned char *buf, unsigned short buflen)
|
||||||
|
{
|
||||||
|
if(4 > buflen){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
buf[0] = (((msg->header.version & 0x3) << 6) | ((msg->header.type & 0x3) << 4))
|
||||||
|
| (msg->header.tokenlen & 0x0F);
|
||||||
|
|
||||||
|
buf[1] = msg->header.code;
|
||||||
|
buf[2] = (msg->header.msgid & 0xFF00) >> 8;
|
||||||
|
buf[3] = (msg->header.msgid & 0x00FF);
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPSerialize_Token(CoAPMessage *msg, unsigned char * buf, unsigned short buflen)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if(buflen < msg->header.tokenlen){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < msg->header.tokenlen; i++){
|
||||||
|
buf[i] = msg->token[i];
|
||||||
|
}
|
||||||
|
return msg->header.tokenlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned short CoAPSerialize_Option(CoAPMsgOption *option, unsigned char *buf)
|
||||||
|
{
|
||||||
|
unsigned char *ptr = buf;
|
||||||
|
|
||||||
|
if(269 <= option->num){
|
||||||
|
*ptr = ((14 & 0x0F) << 4);
|
||||||
|
}
|
||||||
|
else if(13 <= option->num){
|
||||||
|
*ptr = ((13 & 0x0F) << 4);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
*ptr = option->num << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (269 <= option->len){
|
||||||
|
*ptr |= (14 & 0x0F);
|
||||||
|
}
|
||||||
|
else if(13 <= option->len){
|
||||||
|
*ptr |= (13 & 0x0F);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
*ptr |= (option->len & 0x0F);
|
||||||
|
}
|
||||||
|
ptr ++;
|
||||||
|
|
||||||
|
if (269 <= option->num){
|
||||||
|
*ptr = (unsigned char)(((option->num - 269) & 0xFF00) >> 8);
|
||||||
|
*(ptr+1) = (unsigned char)(((option->num - 269) & 0x00FF));
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
else if(13 <= option->num){
|
||||||
|
*ptr = (unsigned char)(option->num - 13);
|
||||||
|
ptr ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (269 <= option->len){
|
||||||
|
*ptr = (unsigned char)(((option->len - 269) & 0xFF00) >> 8);
|
||||||
|
*(ptr+1) = (unsigned char)(((option->len - 269) & 0x00FF));
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
else if(13 <= option->len){
|
||||||
|
*ptr = (unsigned char)(option->len - 13);
|
||||||
|
ptr ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
memcpy(ptr, option->val, option->len);
|
||||||
|
ptr += option->len;
|
||||||
|
|
||||||
|
return (int)(ptr - buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short CoAPSerialize_Options(CoAPMessage *msg, unsigned char * buf, unsigned short buflen)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
unsigned short count = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < msg->optcount; i++)
|
||||||
|
{
|
||||||
|
unsigned short len = 0;
|
||||||
|
len = CoAPSerialize_Option(&msg->options[i], &buf[count]);
|
||||||
|
if (0 < len){
|
||||||
|
count += len;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned short CoAPSerialize_OptionLen(CoAPMsgOption *option)
|
||||||
|
{
|
||||||
|
unsigned short len = 1;
|
||||||
|
|
||||||
|
if(269 <= option->num){
|
||||||
|
len += 2;
|
||||||
|
}
|
||||||
|
else if(13 <= option->num){
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
}
|
||||||
|
|
||||||
|
if (269 <= option->len){
|
||||||
|
len += 2;
|
||||||
|
}
|
||||||
|
else if(13 <= option->len){
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
}
|
||||||
|
|
||||||
|
len += option->len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned short CoAPSerialize_OptionsLen(CoAPMessage *msg)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
unsigned short count = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < msg->optcount; i++)
|
||||||
|
{
|
||||||
|
unsigned short len = 0;
|
||||||
|
len = CoAPSerialize_OptionLen(&msg->options[i]);
|
||||||
|
if (0 < len){
|
||||||
|
count += len;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CoAPSerialize_Payload(CoAPMessage *msg, unsigned char *buf, int buflen)
|
||||||
|
{
|
||||||
|
if(msg->payloadlen + 1 > buflen){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(msg->payloadlen > 0 && NULL != msg->payload)
|
||||||
|
{
|
||||||
|
*buf = 0xFF;
|
||||||
|
buf ++;
|
||||||
|
memcpy(buf, msg->payload, msg->payloadlen);
|
||||||
|
return msg->payloadlen + 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned short CoAPSerialize_MessageLength(CoAPMessage *msg)
|
||||||
|
{
|
||||||
|
unsigned short msglen = 4;
|
||||||
|
|
||||||
|
msglen += msg->header.tokenlen;
|
||||||
|
msglen += CoAPSerialize_OptionsLen(msg);
|
||||||
|
|
||||||
|
if(0 < msg->payloadlen){
|
||||||
|
msglen += msg->payloadlen;
|
||||||
|
msglen += 1; /*CoAP payload marker*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return msglen;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPSerialize_Message(CoAPMessage *msg, unsigned char *buf, unsigned short buflen)
|
||||||
|
{
|
||||||
|
unsigned char *ptr = buf;
|
||||||
|
unsigned short count = 0;
|
||||||
|
unsigned short remlen = buflen;
|
||||||
|
|
||||||
|
if(NULL == buf || NULL == msg){
|
||||||
|
return COAP_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = CoAPSerialize_Header(msg, ptr, remlen);
|
||||||
|
ptr += count;
|
||||||
|
remlen -= count;
|
||||||
|
|
||||||
|
count = CoAPSerialize_Token(msg, ptr, remlen);
|
||||||
|
ptr += count;
|
||||||
|
remlen -= count;
|
||||||
|
|
||||||
|
count = CoAPSerialize_Options(msg, ptr, remlen);
|
||||||
|
ptr += count;
|
||||||
|
remlen -= count;
|
||||||
|
|
||||||
|
count = CoAPSerialize_Payload(msg, ptr, remlen);
|
||||||
|
ptr += count;
|
||||||
|
remlen -= count;
|
||||||
|
|
||||||
|
return (buflen-remlen);
|
||||||
|
}
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __IOTX_COAP_API_H__
|
||||||
|
#define __IOTX_COAP_API_H__
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "infra_defs.h"
|
||||||
|
|
||||||
|
/*iotx return code definition*/
|
||||||
|
typedef enum {
|
||||||
|
IOTX_ERR_RECV_MSG_TIMEOUT = -9, /*Receive message timeout */
|
||||||
|
IOTX_ERR_SEND_MSG_FAILED = -8, /* Send message failed*/
|
||||||
|
IOTX_ERR_MSG_TOO_LOOG = -7, /* The payload too loog */
|
||||||
|
IOTX_ERR_URI_TOO_LOOG = -6, /* URI length too long */
|
||||||
|
IOTX_ERR_NOT_AUTHED = -5, /* Client isn't authed */
|
||||||
|
IOTX_ERR_AUTH_FAILED = -4, /* Client authed failed */
|
||||||
|
IOTX_ERR_BUFF_TOO_SHORT = -3, /* Buffer too short */
|
||||||
|
IOTX_ERR_NO_MEM = -2, /* Malloc failed */
|
||||||
|
IOTX_ERR_INVALID_PARAM = -1, /* Invalid parameter */
|
||||||
|
IOTX_SUCCESS = 0, /* Success */
|
||||||
|
} iotx_ret_code_t;
|
||||||
|
|
||||||
|
/* The message payload encode format */
|
||||||
|
typedef enum {
|
||||||
|
IOTX_CONTENT_TYPE_JSON,
|
||||||
|
IOTX_CONTENT_TYPE_CBOR,
|
||||||
|
} iotx_content_type_t;
|
||||||
|
|
||||||
|
/* The message type */
|
||||||
|
typedef enum {
|
||||||
|
IOTX_MESSAGE_CON = 0, /* confirmable message */
|
||||||
|
IOTX_MESSAGE_NON = 1, /* non-confirmable message */
|
||||||
|
IOTX_MESSAGE_ACK = 2, /* acknowledgement message */
|
||||||
|
IOTX_MESSAGE_RST = 3, /* reset message */
|
||||||
|
} iotx_msg_type_t;
|
||||||
|
|
||||||
|
/* IoTx events to notify application */
|
||||||
|
typedef enum {
|
||||||
|
IOTX_COAP_EVENT_SEND_FAILED = 0,
|
||||||
|
IOTX_COAP_EVENT_RECV_FAILED = 1,
|
||||||
|
IOTX_COAP_EVENT_AUTH_FAILED = 2,
|
||||||
|
} iotx_coap_event_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
IOTX_COAP_RESP_CODE_CONTENT = 0x45, /* Mapping to 2.05, Content*/
|
||||||
|
IOTX_COAP_RESP_CODE_BAD_REQUEST = 0x80, /* Mapping to 4.00, Bad Request*/
|
||||||
|
IOTX_COAP_RESP_CODE_UNAUTHORIZED = 0x81, /* Mapping to 4.01, Token is invalid or expire*/
|
||||||
|
IOTX_COAP_RESP_CODE_NOT_FOUND = 0x84, /* Mapping to 4.04, Path or uri is not found*/
|
||||||
|
IOTX_COAP_RESP_CODE_URL_TOO_LONG = 0x8E, /* Mapping to 4.14, The request url is too long*/
|
||||||
|
IOTX_COAP_RESP_CODE_INTERNAL_SERVER_ERROR = 0xA0,/* Mapping to 5.00, Internal server error*/
|
||||||
|
|
||||||
|
} iotx_coap_resp_code_t;
|
||||||
|
|
||||||
|
/* Callback function to notify the application events.*/
|
||||||
|
typedef void (*iotx_event_handle_t)(void *context, iotx_coap_event_t event, void *p_data);
|
||||||
|
|
||||||
|
/*IoTx device*/
|
||||||
|
typedef struct {
|
||||||
|
char product_key[IOTX_PRODUCT_KEY_LEN + 1];
|
||||||
|
char device_name[IOTX_DEVICE_NAME_LEN + 1];
|
||||||
|
char device_id[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 2];
|
||||||
|
char device_secret[IOTX_DEVICE_SECRET_LEN + 1];
|
||||||
|
} iotx_deviceinfo_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char product_key[IOTX_PRODUCT_KEY_LEN + 1];
|
||||||
|
char device_name[IOTX_DEVICE_NAME_LEN + 1];
|
||||||
|
char device_id[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 2];
|
||||||
|
char device_secret[IOTX_DEVICE_SECRET_LEN + 1];
|
||||||
|
char module_vendor_id[IOTX_PARTNER_ID_LEN + 1];
|
||||||
|
} iotx_device_info_t;
|
||||||
|
|
||||||
|
/* IoTx initializa parameters */
|
||||||
|
typedef struct {
|
||||||
|
char *p_url; /*Can be NULL*/
|
||||||
|
int wait_time_ms; /*unit is micro second*/
|
||||||
|
iotx_device_info_t *p_devinfo; /*Device info*/
|
||||||
|
iotx_event_handle_t event_handle; /*TODO, not supported now*/
|
||||||
|
} iotx_coap_config_t;
|
||||||
|
|
||||||
|
/* Callback function to handle the response message.*/
|
||||||
|
typedef void (*iotx_response_callback_t)(void *p_arg, void *p_message);
|
||||||
|
|
||||||
|
/* IoTx message definition */
|
||||||
|
typedef struct {
|
||||||
|
unsigned char *p_payload;
|
||||||
|
unsigned short payload_len;
|
||||||
|
iotx_content_type_t content_type;
|
||||||
|
iotx_msg_type_t msg_type;
|
||||||
|
void *user_data;
|
||||||
|
iotx_response_callback_t resp_callback;
|
||||||
|
} iotx_message_t;
|
||||||
|
|
||||||
|
|
||||||
|
/*iotx coap context definition*/
|
||||||
|
typedef void iotx_coap_context_t;
|
||||||
|
|
||||||
|
|
||||||
|
/** @defgroup group_api api
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @defgroup group_api_coap coap
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the CoAP client.
|
||||||
|
* This function initialize the data structures and network,
|
||||||
|
* and create the DTLS session.
|
||||||
|
*
|
||||||
|
* @param [in] p_config: Specify the CoAP client parameter.
|
||||||
|
*
|
||||||
|
* @retval NULL : Initialize failed.
|
||||||
|
* @retval NOT_NULL : The contex of CoAP client.
|
||||||
|
* @see None.
|
||||||
|
*/
|
||||||
|
iotx_coap_context_t *IOT_CoAP_Init(iotx_coap_config_t *p_config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief De-initialize the CoAP client.
|
||||||
|
* This function release CoAP DTLS session.
|
||||||
|
* and release the related resource.
|
||||||
|
*
|
||||||
|
* @param [in] p_context: Pointer of contex, specify the CoAP client.
|
||||||
|
*
|
||||||
|
* @return None.
|
||||||
|
* @see None.
|
||||||
|
*/
|
||||||
|
DLL_IOT_API void IOT_CoAP_Deinit(iotx_coap_context_t **p_context);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle device name authentication with remote server.
|
||||||
|
*
|
||||||
|
* @param [in] p_context: Pointer of contex, specify the CoAP client.
|
||||||
|
*
|
||||||
|
* @retval IOTX_SUCCESS : Authenticate success.
|
||||||
|
* @retval IOTX_ERR_SEND_MSG_FAILED : Send authentication message failed.
|
||||||
|
* @retval IOTX_ERR_AUTH_FAILED : Authenticate failed or timeout.
|
||||||
|
* @see iotx_ret_code_t.
|
||||||
|
*/
|
||||||
|
DLL_IOT_API int IOT_CoAP_DeviceNameAuth(iotx_coap_context_t *p_context);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle CoAP response packet from remote server,
|
||||||
|
* and process timeout request etc..
|
||||||
|
*
|
||||||
|
* @param [in] p_context : Pointer of contex, specify the CoAP client.
|
||||||
|
*
|
||||||
|
* @return status.
|
||||||
|
* @see iotx_ret_code_t.
|
||||||
|
*/
|
||||||
|
DLL_IOT_API int IOT_CoAP_Yield(iotx_coap_context_t *p_context);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a message with specific path to server.
|
||||||
|
* Client must authentication with server before send message.
|
||||||
|
*
|
||||||
|
* @param [in] p_context : Pointer of contex, specify the CoAP client.
|
||||||
|
* @param [in] p_path: Specify the path name.
|
||||||
|
* @param [in] p_message: Message to be sent.
|
||||||
|
*
|
||||||
|
* @retval IOTX_SUCCESS : Send the message success.
|
||||||
|
* @retval IOTX_ERR_MSG_TOO_LOOG : The message length is too long.
|
||||||
|
* @retval IOTX_ERR_NOT_AUTHED : The client hasn't authenticated with server
|
||||||
|
* @see iotx_ret_code_t.
|
||||||
|
*/
|
||||||
|
DLL_IOT_API int IOT_CoAP_SendMessage(iotx_coap_context_t *p_context, char *p_path, iotx_message_t *p_message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves the length and payload pointer of specified message.
|
||||||
|
*
|
||||||
|
* @param [in] p_message: Pointer to the message to get the payload. Should not be NULL.
|
||||||
|
* @param [out] pp_payload: Pointer to the payload.
|
||||||
|
* @param [out] p_len: Size of the payload.
|
||||||
|
*
|
||||||
|
* @retval IOTX_SUCCESS : Get the payload success.
|
||||||
|
* @retval IOTX_ERR_INVALID_PARAM : Can't get the payload due to invalid parameter.
|
||||||
|
* @see iotx_ret_code_t.
|
||||||
|
**/
|
||||||
|
DLL_IOT_API int IOT_CoAP_GetMessagePayload(void *p_message, unsigned char **pp_payload, int *p_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the response code from a CoAP message.
|
||||||
|
*
|
||||||
|
* @param [in] p_message: Pointer to the message to add the address information to.
|
||||||
|
* Should not be NULL.
|
||||||
|
* @param [out] p_resp_code: The response code.
|
||||||
|
*
|
||||||
|
* @retval IOTX_SUCCESS : When get the response code to message success.
|
||||||
|
* @retval IOTX_ERR_INVALID_PARAM : Pointer to the message is NULL.
|
||||||
|
* @see iotx_ret_code_t.
|
||||||
|
**/
|
||||||
|
DLL_IOT_API int IOT_CoAP_GetMessageCode(void *p_message, iotx_coap_resp_code_t *p_resp_code);
|
||||||
|
|
||||||
|
/** @} */ /* end of api_coap */
|
||||||
|
/** @} */ /* end of api */
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
#ifndef _COAP_WRAPPER_H_
|
||||||
|
#define _COAP_WRAPPER_H_
|
||||||
|
|
||||||
|
#include "infra_types.h"
|
||||||
|
#include "infra_defs.h"
|
||||||
|
#include "infra_compat.h"
|
||||||
|
#include "wrappers_defs.h"
|
||||||
|
|
||||||
|
void *HAL_Malloc(uint32_t size);
|
||||||
|
void HAL_Free(void *ptr);
|
||||||
|
void HAL_SleepMs(uint32_t ms);
|
||||||
|
uint64_t HAL_UptimeMs(void);
|
||||||
|
void HAL_Srandom(uint32_t seed);
|
||||||
|
uint32_t HAL_Random(uint32_t region);
|
||||||
|
void HAL_Printf(const char *fmt, ...);
|
||||||
|
int HAL_Snprintf(char *str, const int len, const char *fmt, ...);
|
||||||
|
|
||||||
|
int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN]);
|
||||||
|
int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN]);
|
||||||
|
int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN]);
|
||||||
|
|
||||||
|
int HAL_SetProductKey(char *product_key);
|
||||||
|
int HAL_SetProductSecret(char *product_secret);
|
||||||
|
int HAL_SetDeviceName(char *device_name);
|
||||||
|
int HAL_SetDeviceSecret(char *device_secret);
|
||||||
|
|
||||||
|
DLL_HAL_API int HAL_DTLSHooks_set(dtls_hooks_t *hooks);
|
||||||
|
DLL_HAL_API DTLSContext *HAL_DTLSSession_create(coap_dtls_options_t *p_options);
|
||||||
|
DLL_HAL_API unsigned int HAL_DTLSSession_write(DTLSContext *context,
|
||||||
|
const unsigned char *p_data,
|
||||||
|
unsigned int *p_datalen);
|
||||||
|
DLL_HAL_API unsigned int HAL_DTLSSession_read(DTLSContext *context,
|
||||||
|
unsigned char *p_data,
|
||||||
|
unsigned int *p_datalen,
|
||||||
|
unsigned int timeout_ms);
|
||||||
|
DLL_HAL_API unsigned int HAL_DTLSSession_free(DTLSContext *context);
|
||||||
|
intptr_t HAL_UDP_create(char *host, unsigned short port);
|
||||||
|
intptr_t HAL_UDP_create_without_connect(const char *host, unsigned short port);
|
||||||
|
int HAL_UDP_write(intptr_t p_socket,
|
||||||
|
const unsigned char *p_data,
|
||||||
|
unsigned int datalen);
|
||||||
|
int HAL_UDP_readTimeout(intptr_t p_socket,
|
||||||
|
unsigned char *p_data,
|
||||||
|
unsigned int datalen,
|
||||||
|
unsigned int timeout);
|
||||||
|
int HAL_UDP_close_without_connect(intptr_t sockfd);
|
||||||
|
int HAL_UDP_recvfrom(intptr_t sockfd,
|
||||||
|
NetworkAddr *p_remote,
|
||||||
|
unsigned char *p_data,
|
||||||
|
unsigned int datalen,
|
||||||
|
unsigned int timeout_ms);
|
||||||
|
int HAL_UDP_sendto(intptr_t sockfd,
|
||||||
|
const NetworkAddr *p_remote,
|
||||||
|
const unsigned char *p_data,
|
||||||
|
unsigned int datalen,
|
||||||
|
unsigned int timeout_ms);
|
||||||
|
int HAL_UDP_joinmulticast(intptr_t sockfd,
|
||||||
|
char *p_group);
|
||||||
|
uint32_t HAL_Wifi_Get_IP(char ip_str[NETWORK_ADDR_LEN], const char *ifname);
|
||||||
|
p_HAL_Aes128_t HAL_Aes128_Init(
|
||||||
|
const uint8_t *key,
|
||||||
|
const uint8_t *iv,
|
||||||
|
AES_DIR_t dir);
|
||||||
|
int HAL_Aes128_Destroy(p_HAL_Aes128_t aes);
|
||||||
|
int HAL_Aes128_Cbc_Encrypt(
|
||||||
|
p_HAL_Aes128_t aes,
|
||||||
|
const void *src,
|
||||||
|
size_t blockNum,
|
||||||
|
void *dst);
|
||||||
|
int HAL_Aes128_Cbc_Decrypt(
|
||||||
|
p_HAL_Aes128_t aes,
|
||||||
|
const void *src,
|
||||||
|
size_t blockNum,
|
||||||
|
void *dst);
|
||||||
|
void *HAL_MutexCreate(void);
|
||||||
|
void HAL_MutexDestroy(void *mutex);
|
||||||
|
void HAL_MutexLock(void *mutex);
|
||||||
|
void HAL_MutexUnlock(void *mutex);
|
||||||
|
void *HAL_SemaphoreCreate(void);
|
||||||
|
void HAL_SemaphoreDestroy(void *sem);
|
||||||
|
int HAL_SemaphoreWait(void *sem, uint32_t timeout_ms);
|
||||||
|
void HAL_SemaphorePost(void *sem);
|
||||||
|
int HAL_ThreadCreate(
|
||||||
|
void **thread_handle,
|
||||||
|
void *(*work_routine)(void *),
|
||||||
|
void *arg,
|
||||||
|
hal_os_thread_param_t *hal_os_thread_param,
|
||||||
|
int *stack_used);
|
||||||
|
void HAL_ThreadDelete(void *thread_handle);
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#include "CoAPServer.h"
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
@@ -0,0 +1,950 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "coap_api.h"
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
#include "Cloud_CoAPPlatform.h"
|
||||||
|
#include "Cloud_CoAPPlatform.h"
|
||||||
|
#include "Cloud_CoAPMessage.h"
|
||||||
|
#include "Cloud_CoAPExport.h"
|
||||||
|
|
||||||
|
#define IOTX_SIGN_LENGTH (40+1)
|
||||||
|
#define IOTX_SIGN_SOURCE_LEN (256)
|
||||||
|
#define IOTX_AUTH_TOKEN_LEN (192+1)
|
||||||
|
#define IOTX_COAP_INIT_TOKEN (0x01020304)
|
||||||
|
#define IOTX_LIST_MAX_ITEM (10)
|
||||||
|
|
||||||
|
#ifndef INFRA_LOG
|
||||||
|
#undef HEXDUMP_DEBUG
|
||||||
|
#undef HEXDUMP_INFO
|
||||||
|
|
||||||
|
#define HEXDUMP_DEBUG(...)
|
||||||
|
#define HEXDUMP_INFO(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IOTX_AUTH_STR "auth"
|
||||||
|
#define IOTX_SIGN_SRC_STR "clientId%sdeviceName%sproductKey%s"
|
||||||
|
#define IOTX_SIGN_SRC_STR_WITH_SEQ "clientId%sdeviceName%sproductKey%sseq%d"
|
||||||
|
|
||||||
|
#define IOTX_AUTH_DEVICENAME_STR "{\"productKey\":\"%s\",\"deviceName\":\"%s\",\"clientId\":\"%s\",\"sign\":\"%s\"}"
|
||||||
|
#define IOTX_AUTH_DEVICENAME_STR_WITH_SEQ "{\"productKey\":\"%s\",\"deviceName\":\"%s\",\"clientId\":\"%s\",\"sign\":\"%s\",\"seq\":\"%d\"}"
|
||||||
|
|
||||||
|
#define IOTX_COAP_ONLINE_DTLS_SERVER_URL "coaps://%s.coap.cn-shanghai.link.aliyuncs.com:5684"
|
||||||
|
#define IOTX_COAP_ONLINE_PSK_SERVER_URL "coap-psk://%s.coap.cn-shanghai.link.aliyuncs.com:5682"
|
||||||
|
|
||||||
|
iotx_coap_context_t *g_coap_context = NULL;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *p_auth_token;
|
||||||
|
int auth_token_len;
|
||||||
|
char is_authed;
|
||||||
|
iotx_deviceinfo_t *p_devinfo;
|
||||||
|
Cloud_CoAPContext *p_coap_ctx;
|
||||||
|
unsigned int coap_token;
|
||||||
|
unsigned int seq;
|
||||||
|
unsigned char key[32];
|
||||||
|
iotx_event_handle_t event_handle;
|
||||||
|
} iotx_coap_t;
|
||||||
|
|
||||||
|
|
||||||
|
int iotx_calc_sign(const char *p_device_secret, const char *p_client_id,
|
||||||
|
const char *p_device_name, const char *p_product_key, char sign[IOTX_SIGN_LENGTH])
|
||||||
|
{
|
||||||
|
char *p_msg = NULL;
|
||||||
|
|
||||||
|
p_msg = (char *)coap_malloc(IOTX_SIGN_SOURCE_LEN);
|
||||||
|
if (NULL == p_msg) {
|
||||||
|
return IOTX_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
memset(sign, 0x00, IOTX_SIGN_LENGTH);
|
||||||
|
memset(p_msg, 0x00, IOTX_SIGN_SOURCE_LEN);
|
||||||
|
|
||||||
|
HAL_Snprintf(p_msg, IOTX_SIGN_SOURCE_LEN,
|
||||||
|
IOTX_SIGN_SRC_STR,
|
||||||
|
p_client_id,
|
||||||
|
p_device_name,
|
||||||
|
p_product_key);
|
||||||
|
utils_hmac_md5(p_msg, strlen(p_msg), sign, p_device_secret, strlen(p_device_secret));
|
||||||
|
|
||||||
|
coap_free(p_msg);
|
||||||
|
COAP_DEBUG("The device name sign: %s", sign);
|
||||||
|
return IOTX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iotx_calc_sign_with_seq(const char *p_device_secret, const char *p_client_id,
|
||||||
|
const char *p_device_name, const char *p_product_key, unsigned int seq, char sign[IOTX_SIGN_LENGTH])
|
||||||
|
{
|
||||||
|
char *p_msg = NULL;
|
||||||
|
|
||||||
|
p_msg = (char *)coap_malloc(IOTX_SIGN_SOURCE_LEN);
|
||||||
|
if (NULL == p_msg) {
|
||||||
|
return IOTX_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
memset(sign, 0x00, IOTX_SIGN_LENGTH);
|
||||||
|
memset(p_msg, 0x00, IOTX_SIGN_SOURCE_LEN);
|
||||||
|
|
||||||
|
HAL_Snprintf(p_msg, IOTX_SIGN_SOURCE_LEN,
|
||||||
|
IOTX_SIGN_SRC_STR_WITH_SEQ,
|
||||||
|
p_client_id,
|
||||||
|
p_device_name,
|
||||||
|
p_product_key, seq);
|
||||||
|
COAP_DEBUG("The source string: %s", p_msg);
|
||||||
|
utils_hmac_md5(p_msg, strlen(p_msg), sign, p_device_secret, strlen(p_device_secret));
|
||||||
|
|
||||||
|
coap_free(p_msg);
|
||||||
|
COAP_DEBUG("The device name sign with seq: %s", sign);
|
||||||
|
return IOTX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int iotx_get_token_from_json(char *p_str, char *p_token, int len)
|
||||||
|
{
|
||||||
|
char *p_value = NULL;
|
||||||
|
if (NULL == p_str || NULL == p_token) {
|
||||||
|
COAP_ERR("Invalid paramter p_str %p, p_token %p", p_str, p_token);
|
||||||
|
return IOTX_ERR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_value = LITE_json_value_of("token", p_str, 0x1234, "coap.cloud");
|
||||||
|
if (NULL != p_value) {
|
||||||
|
if (len - 1 < strlen(p_value)) {
|
||||||
|
return IOTX_ERR_BUFF_TOO_SHORT;
|
||||||
|
}
|
||||||
|
memset(p_token, 0x00, len);
|
||||||
|
strncpy(p_token, p_value, strlen(p_value));
|
||||||
|
#ifdef INFRA_MEM_STATS
|
||||||
|
LITE_free(p_value);
|
||||||
|
#else
|
||||||
|
HAL_Free((void *)p_value);
|
||||||
|
#endif
|
||||||
|
return IOTX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IOTX_ERR_AUTH_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iotx_parse_auth_from_json(char *p_str, iotx_coap_t *p_iotx_coap)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
lite_cjson_t root;
|
||||||
|
lite_cjson_t node;
|
||||||
|
unsigned char key[32] = {0};
|
||||||
|
unsigned char buff[128] = {0};
|
||||||
|
unsigned char random[32] = {0};
|
||||||
|
|
||||||
|
if (NULL == p_str || NULL == p_iotx_coap) {
|
||||||
|
return IOTX_ERR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&root, 0x00, sizeof(lite_cjson_t));
|
||||||
|
memset(&node, 0x00, sizeof(lite_cjson_t));
|
||||||
|
ret = lite_cjson_parse(p_str, strlen(p_str), &root);
|
||||||
|
if (-1 == ret) {
|
||||||
|
return IOTX_ERR_AUTH_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = lite_cjson_object_item(&root, "token", strlen("token"), &node);
|
||||||
|
if (-1 == ret) {
|
||||||
|
return IOTX_ERR_AUTH_FAILED;
|
||||||
|
}
|
||||||
|
if (p_iotx_coap->auth_token_len - 1 < node.value_length) {
|
||||||
|
return IOTX_ERR_BUFF_TOO_SHORT;
|
||||||
|
}
|
||||||
|
memset(p_iotx_coap->p_auth_token, 0x00, node.value_length);
|
||||||
|
strncpy(p_iotx_coap->p_auth_token, node.value, node.value_length);
|
||||||
|
|
||||||
|
memset(&node, 0x00, sizeof(lite_cjson_t));
|
||||||
|
ret = lite_cjson_object_item(&root, "seqOffset", strlen("seqOffset"), &node);
|
||||||
|
if (-1 == ret) {
|
||||||
|
return IOTX_ERR_AUTH_FAILED;
|
||||||
|
}
|
||||||
|
p_iotx_coap->seq = node.value_int;
|
||||||
|
|
||||||
|
memset(&node, 0x00, sizeof(lite_cjson_t));
|
||||||
|
ret = lite_cjson_object_item(&root, "random", strlen("random"), &node);
|
||||||
|
if (-1 == ret) {
|
||||||
|
return IOTX_ERR_AUTH_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(random, node.value, node.value_length);
|
||||||
|
HAL_Snprintf((char *)buff, sizeof(buff), "%s,%s",
|
||||||
|
p_iotx_coap->p_devinfo->device_secret, random);
|
||||||
|
COAP_DEBUG("The src:%s", buff);
|
||||||
|
utils_sha256(buff, strlen((char *)buff), key);
|
||||||
|
memcpy(p_iotx_coap->key, key + 8, 16);
|
||||||
|
COAP_DEBUG("The key is:");
|
||||||
|
HEXDUMP_DEBUG(key, 32);
|
||||||
|
COAP_DEBUG("The short key:");
|
||||||
|
HEXDUMP_DEBUG(p_iotx_coap->key, 16);
|
||||||
|
|
||||||
|
return IOTX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iotx_device_name_auth_callback(void *user, void *p_message)
|
||||||
|
{
|
||||||
|
int ret_code = IOTX_SUCCESS;
|
||||||
|
iotx_coap_t *p_iotx_coap = NULL;
|
||||||
|
Cloud_CoAPMessage *message = (Cloud_CoAPMessage *)p_message;
|
||||||
|
|
||||||
|
if (NULL == user) {
|
||||||
|
COAP_ERR("Invalid paramter, p_arg %p", user);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
p_iotx_coap = (iotx_coap_t *)user;
|
||||||
|
|
||||||
|
if (NULL == message) {
|
||||||
|
COAP_ERR("Invalid paramter, message %p", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
COAP_DEBUG("Receive response message:");
|
||||||
|
COAP_DEBUG("* Response Code : 0x%x", message->header.code);
|
||||||
|
COAP_DEBUG("* Payload: %s", message->payload);
|
||||||
|
|
||||||
|
switch (message->header.code) {
|
||||||
|
case COAP_MSG_CODE_205_CONTENT: {
|
||||||
|
if (COAP_ENDPOINT_PSK == p_iotx_coap->p_coap_ctx->network.ep_type) {
|
||||||
|
ret_code = iotx_parse_auth_from_json((char *)message->payload, p_iotx_coap);
|
||||||
|
} else {
|
||||||
|
ret_code = iotx_get_token_from_json((char *)message->payload, p_iotx_coap->p_auth_token, p_iotx_coap->auth_token_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IOTX_SUCCESS == ret_code) {
|
||||||
|
p_iotx_coap->is_authed = IOT_TRUE;
|
||||||
|
COAP_INFO("CoAP authenticate success!!!");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COAP_MSG_CODE_500_INTERNAL_SERVER_ERROR: {
|
||||||
|
COAP_INFO("CoAP internal server error, authenticate failed, will retry it");
|
||||||
|
HAL_SleepMs(1000);
|
||||||
|
IOT_CoAP_DeviceNameAuth((iotx_coap_context_t *)p_iotx_coap);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int iotx_get_coap_token(iotx_coap_t *p_iotx_coap, unsigned char *p_encoded_data)
|
||||||
|
{
|
||||||
|
unsigned int value = p_iotx_coap->coap_token;
|
||||||
|
p_encoded_data[0] = (unsigned char)((value & 0x00FF) >> 0);
|
||||||
|
p_encoded_data[1] = (unsigned char)((value & 0xFF00) >> 8);
|
||||||
|
p_encoded_data[2] = (unsigned char)((value & 0xFF0000) >> 16);
|
||||||
|
p_encoded_data[3] = (unsigned char)((value & 0xFF000000) >> 24);
|
||||||
|
p_iotx_coap->coap_token++;
|
||||||
|
return sizeof(unsigned int);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iotx_event_notifyer(unsigned int code, Cloud_CoAPMessage *message)
|
||||||
|
{
|
||||||
|
if (NULL == message) {
|
||||||
|
COAP_ERR("Invalid paramter, message %p", message);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
COAP_DEBUG("Error code: 0x%x, payload: %s", code, message->payload);
|
||||||
|
switch (code) {
|
||||||
|
case COAP_MSG_CODE_402_BAD_OPTION:
|
||||||
|
case COAP_MSG_CODE_401_UNAUTHORIZED: {
|
||||||
|
iotx_coap_t *p_context = NULL;
|
||||||
|
if (NULL != message->user) {
|
||||||
|
p_context = (iotx_coap_t *)message->user;
|
||||||
|
p_context->is_authed = IOT_FALSE;
|
||||||
|
IOT_CoAP_DeviceNameAuth(p_context);
|
||||||
|
COAP_INFO("IoTx token expired, will reauthenticate");
|
||||||
|
}
|
||||||
|
/* TODO: call event handle to notify application */
|
||||||
|
/* p_context->event_handle(); */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iotx_get_well_known_handler(void *arg, void *p_response)
|
||||||
|
{
|
||||||
|
|
||||||
|
int len = 0;
|
||||||
|
unsigned char *p_payload = NULL;
|
||||||
|
iotx_coap_resp_code_t resp_code;
|
||||||
|
IOT_CoAP_GetMessageCode(p_response, &resp_code);
|
||||||
|
IOT_CoAP_GetMessagePayload(p_response, &p_payload, &len);
|
||||||
|
COAP_INFO("[APPL]: Message response code: %d", resp_code);
|
||||||
|
COAP_INFO("[APPL]: Len: %d, Payload: %s, ", len, p_payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int iotx_get_well_known(iotx_coap_context_t *p_context)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
Cloud_CoAPContext *p_coap_ctx = NULL;
|
||||||
|
iotx_coap_t *p_iotx_coap = NULL;
|
||||||
|
Cloud_CoAPMessage message;
|
||||||
|
unsigned char token[8] = {0};
|
||||||
|
|
||||||
|
p_iotx_coap = (iotx_coap_t *)p_context;
|
||||||
|
p_coap_ctx = (Cloud_CoAPContext *)p_iotx_coap->p_coap_ctx;
|
||||||
|
|
||||||
|
|
||||||
|
CoAPMessage_init(&message);
|
||||||
|
CoAPMessageType_set(&message, COAP_MESSAGE_TYPE_CON);
|
||||||
|
CoAPMessageCode_set(&message, COAP_MSG_CODE_GET);
|
||||||
|
CoAPMessageId_set(&message, Cloud_CoAPMessageId_gen(p_coap_ctx));
|
||||||
|
len = iotx_get_coap_token(p_iotx_coap, token);
|
||||||
|
CoAPMessageToken_set(&message, token, len);
|
||||||
|
Cloud_CoAPMessageHandler_set(&message, iotx_get_well_known_handler);
|
||||||
|
CoAPStrOption_add(&message, COAP_OPTION_URI_PATH, (unsigned char *)".well-known", strlen(".well-known"));
|
||||||
|
CoAPStrOption_add(&message, COAP_OPTION_URI_PATH, (unsigned char *)"core", strlen("core"));
|
||||||
|
CoAPUintOption_add(&message, COAP_OPTION_ACCEPT, COAP_CT_APP_LINK_FORMAT);
|
||||||
|
CoAPMessageUserData_set(&message, (void *)p_iotx_coap);
|
||||||
|
Cloud_CoAPMessage_send(p_coap_ctx, &message);
|
||||||
|
CoAPMessage_destory(&message);
|
||||||
|
return IOTX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iotx_coap_report_rsphdl(void *arg, void *p_response)
|
||||||
|
{
|
||||||
|
int p_payload_len = 0;
|
||||||
|
unsigned char *p_payload = NULL;
|
||||||
|
iotx_coap_resp_code_t resp_code;
|
||||||
|
|
||||||
|
IOT_CoAP_GetMessageCode(p_response, &resp_code);
|
||||||
|
IOT_CoAP_GetMessagePayload(p_response, &p_payload, &p_payload_len);
|
||||||
|
COAP_DEBUG("Report response: CoAP response code = %d", resp_code);
|
||||||
|
COAP_DEBUG("Report response: CoAP msg_len = %d", p_payload_len);
|
||||||
|
if (p_payload_len > 0) {
|
||||||
|
COAP_DEBUG("Report response: CoAP msg = '%.*s'", p_payload_len, p_payload);
|
||||||
|
} else {
|
||||||
|
COAP_WRN("Report response: CoAP response payload_len = 0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int coap_report_func(void *handle, const char *topic_name, int req_ack, void *data, int len)
|
||||||
|
{
|
||||||
|
iotx_message_t message;
|
||||||
|
char coap_topic[100] = {0};
|
||||||
|
(void)req_ack;
|
||||||
|
|
||||||
|
memset(&message, 0, sizeof(iotx_message_t));
|
||||||
|
message.p_payload = (unsigned char *)data;
|
||||||
|
message.payload_len = len;
|
||||||
|
message.resp_callback = iotx_coap_report_rsphdl;
|
||||||
|
message.msg_type = IOTX_MESSAGE_NON;
|
||||||
|
message.content_type = IOTX_CONTENT_TYPE_JSON;
|
||||||
|
HAL_Snprintf(coap_topic, 100, "/topic%s", topic_name);
|
||||||
|
return IOT_CoAP_SendMessage(handle, (char *)coap_topic, &message);
|
||||||
|
}
|
||||||
|
|
||||||
|
int iotx_aes_cbc_encrypt(const unsigned char *src, int len, const unsigned char *key, void *out)
|
||||||
|
{
|
||||||
|
char *iv = "543yhjy97ae7fyfg";
|
||||||
|
|
||||||
|
int len1 = len & 0xfffffff0;
|
||||||
|
int len2 = len1 + 16;
|
||||||
|
int pad = len2 - len;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
p_HAL_Aes128_t aes_e_h = HAL_Aes128_Init((unsigned char *)key, (unsigned char *)iv, HAL_AES_ENCRYPTION);
|
||||||
|
if (len1) {
|
||||||
|
ret = HAL_Aes128_Cbc_Encrypt(aes_e_h, src, len1 >> 4, out);
|
||||||
|
}
|
||||||
|
if (!ret && pad) {
|
||||||
|
char buf[16] = {0};
|
||||||
|
memcpy(buf, src + len1, len - len1);
|
||||||
|
memset(buf + len - len1, pad, pad);
|
||||||
|
ret = HAL_Aes128_Cbc_Encrypt(aes_e_h, buf, 1, (unsigned char *)out + len1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_Aes128_Destroy(aes_e_h);
|
||||||
|
|
||||||
|
COAP_DEBUG("to encrypt src: %s, len: %d", src, len2);
|
||||||
|
return ret == 0 ? len2 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iotx_aes_cbc_decrypt(const unsigned char *src, int len, const unsigned char *key, void *out)
|
||||||
|
{
|
||||||
|
char *iv = "543yhjy97ae7fyfg";
|
||||||
|
|
||||||
|
p_HAL_Aes128_t aes_d_h;
|
||||||
|
int ret = 0;
|
||||||
|
int n = len >> 4;
|
||||||
|
|
||||||
|
aes_d_h = HAL_Aes128_Init((uint8_t *)key, (uint8_t *)iv, HAL_AES_DECRYPTION);
|
||||||
|
if (!aes_d_h) {
|
||||||
|
COAP_INFO("fail to decrypt");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (n > 1) {
|
||||||
|
ret = HAL_Aes128_Cbc_Decrypt(aes_d_h, src, n - 1, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
char *out_c = (char *)out;
|
||||||
|
int offset = n > 0 ? ((n - 1) << 4) : 0;
|
||||||
|
out_c[offset] = 0;
|
||||||
|
|
||||||
|
if (aes_d_h) {
|
||||||
|
ret = HAL_Aes128_Cbc_Decrypt(aes_d_h, src + offset, 1, out_c + offset);
|
||||||
|
} else {
|
||||||
|
COAP_ERR("fail to decrypt remain data");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
char pad = out_c[len - 1];
|
||||||
|
out_c[len - pad] = 0;
|
||||||
|
/*
|
||||||
|
COAP_DEBUG("decrypt data:%s, len:%d", out_c, len - pad);
|
||||||
|
*/
|
||||||
|
HAL_Aes128_Destroy(aes_d_h);
|
||||||
|
return len - pad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HAL_Aes128_Destroy(aes_d_h);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if AES_CFB_NOPADDING
|
||||||
|
static int iotx_aes_cfb_encrypt(const unsigned char *src, int len, const unsigned char *key, void *out)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
char *iv = "543yhjy97ae7fyfg";
|
||||||
|
|
||||||
|
p_HAL_Aes128_t aes_e_h = HAL_Aes128_Init((unsigned char *)key, (unsigned char *)iv, HAL_AES_ENCRYPTION);
|
||||||
|
ret = HAL_Aes128_Cfb_Encrypt(aes_e_h, src, len, out);
|
||||||
|
HAL_Aes128_Destroy(aes_e_h);
|
||||||
|
|
||||||
|
COAP_DEBUG("to encrypt src:%s, len:%d", src, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iotx_aes_cfb_decrypt(const unsigned char *src, int len, const unsigned char *key, void *out)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
char *iv = "543yhjy97ae7fyfg";
|
||||||
|
|
||||||
|
p_HAL_Aes128_t aes_d_h = HAL_Aes128_Init((unsigned char *)key, (unsigned char *)iv, HAL_AES_ENCRYPTION);
|
||||||
|
ret = HAL_Aes128_Cfb_Decrypt(aes_d_h, src, len, out);
|
||||||
|
HAL_Aes128_Destroy(aes_d_h);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int IOT_CoAP_DeviceNameAuth(iotx_coap_context_t *p_context)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
int ret = COAP_SUCCESS;
|
||||||
|
Cloud_CoAPContext *p_coap_ctx = NULL;
|
||||||
|
iotx_coap_t *p_iotx_coap = NULL;
|
||||||
|
Cloud_CoAPMessage message;
|
||||||
|
unsigned char *p_payload = NULL;
|
||||||
|
unsigned char token[8] = {0};
|
||||||
|
char sign[IOTX_SIGN_LENGTH] = {0};
|
||||||
|
|
||||||
|
p_iotx_coap = (iotx_coap_t *)p_context;
|
||||||
|
if (NULL == p_iotx_coap ||
|
||||||
|
(NULL != p_iotx_coap &&
|
||||||
|
(NULL == p_iotx_coap->p_auth_token || NULL == p_iotx_coap->p_coap_ctx || 0 == p_iotx_coap->auth_token_len))) {
|
||||||
|
COAP_DEBUG("Invalid paramter");
|
||||||
|
return IOTX_ERR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_coap_ctx = (Cloud_CoAPContext *)p_iotx_coap->p_coap_ctx;
|
||||||
|
|
||||||
|
CoAPMessage_init(&message);
|
||||||
|
CoAPMessageType_set(&message, COAP_MESSAGE_TYPE_CON);
|
||||||
|
CoAPMessageCode_set(&message, COAP_MSG_CODE_POST);
|
||||||
|
CoAPMessageId_set(&message, Cloud_CoAPMessageId_gen(p_coap_ctx));
|
||||||
|
len = iotx_get_coap_token(p_iotx_coap, token);
|
||||||
|
CoAPMessageToken_set(&message, token, len);
|
||||||
|
Cloud_CoAPMessageHandler_set(&message, iotx_device_name_auth_callback);
|
||||||
|
|
||||||
|
CoAPStrOption_add(&message, COAP_OPTION_URI_PATH, (unsigned char *)IOTX_AUTH_STR, strlen(IOTX_AUTH_STR));
|
||||||
|
CoAPUintOption_add(&message, COAP_OPTION_CONTENT_FORMAT, COAP_CT_APP_JSON);
|
||||||
|
CoAPUintOption_add(&message, COAP_OPTION_ACCEPT, COAP_CT_APP_JSON);
|
||||||
|
|
||||||
|
CoAPMessageUserData_set(&message, (void *)p_iotx_coap);
|
||||||
|
|
||||||
|
p_payload = coap_malloc(COAP_MSG_MAX_PDU_LEN);
|
||||||
|
if (NULL == p_payload) {
|
||||||
|
CoAPMessage_destory(&message);
|
||||||
|
return IOTX_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
memset(p_payload, 0x00, COAP_MSG_MAX_PDU_LEN);
|
||||||
|
|
||||||
|
if (COAP_ENDPOINT_PSK == p_iotx_coap->p_coap_ctx->network.ep_type) {
|
||||||
|
iotx_calc_sign_with_seq(p_iotx_coap->p_devinfo->device_secret, p_iotx_coap->p_devinfo->device_id,
|
||||||
|
p_iotx_coap->p_devinfo->device_name, p_iotx_coap->p_devinfo->product_key, p_iotx_coap->seq, sign);
|
||||||
|
HAL_Snprintf((char *)p_payload, COAP_MSG_MAX_PDU_LEN,
|
||||||
|
IOTX_AUTH_DEVICENAME_STR_WITH_SEQ,
|
||||||
|
p_iotx_coap->p_devinfo->product_key,
|
||||||
|
p_iotx_coap->p_devinfo->device_name,
|
||||||
|
p_iotx_coap->p_devinfo->device_id,
|
||||||
|
sign, p_iotx_coap->seq);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
iotx_calc_sign(p_iotx_coap->p_devinfo->device_secret, p_iotx_coap->p_devinfo->device_id,
|
||||||
|
p_iotx_coap->p_devinfo->device_name, p_iotx_coap->p_devinfo->product_key, sign);
|
||||||
|
HAL_Snprintf((char *)p_payload, COAP_MSG_MAX_PDU_LEN,
|
||||||
|
IOTX_AUTH_DEVICENAME_STR,
|
||||||
|
p_iotx_coap->p_devinfo->product_key,
|
||||||
|
p_iotx_coap->p_devinfo->device_name,
|
||||||
|
p_iotx_coap->p_devinfo->device_id,
|
||||||
|
sign);
|
||||||
|
}
|
||||||
|
CoAPMessagePayload_set(&message, p_payload, strlen((char *)p_payload));
|
||||||
|
COAP_DEBUG("The payload is: %s", message.payload);
|
||||||
|
COAP_DEBUG("Send authentication message to server");
|
||||||
|
ret = Cloud_CoAPMessage_send(p_coap_ctx, &message);
|
||||||
|
coap_free(p_payload);
|
||||||
|
CoAPMessage_destory(&message);
|
||||||
|
|
||||||
|
if (COAP_SUCCESS != ret) {
|
||||||
|
COAP_DEBUG("Send authentication message to server failed, ret = %d", ret);
|
||||||
|
return IOTX_ERR_SEND_MSG_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = Cloud_CoAPMessage_recv(p_coap_ctx, CONFIG_COAP_AUTH_TIMEOUT, 2);
|
||||||
|
if (0 < ret && !p_iotx_coap->is_authed) {
|
||||||
|
COAP_INFO("CoAP authenticate failed");
|
||||||
|
return IOTX_ERR_AUTH_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
iotx_set_report_func(coap_report_func);
|
||||||
|
/* report module id */
|
||||||
|
ret = iotx_report_mid(p_context);
|
||||||
|
if (SUCCESS_RETURN != ret) {
|
||||||
|
COAP_WRN("Send ModuleId message to server(CoAP) failed, ret = %d", ret);
|
||||||
|
}
|
||||||
|
/* report device information */
|
||||||
|
ret = iotx_report_devinfo(p_context);
|
||||||
|
if (SUCCESS_RETURN != ret) {
|
||||||
|
COAP_WRN("Send devinfo message to server(CoAP) failed, ret = %d", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* report firmware version */
|
||||||
|
ret = iotx_report_firmware_version(p_context);
|
||||||
|
if (SUCCESS_RETURN != ret) {
|
||||||
|
COAP_DEBUG("Send firmware message to server(CoAP) failed, ret = %d", ret);
|
||||||
|
return IOTX_ERR_SEND_MSG_FAILED;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return IOTX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iotx_split_path_2_option(char *uri, Cloud_CoAPMessage *message)
|
||||||
|
{
|
||||||
|
char *ptr = NULL;
|
||||||
|
char *pstr = NULL;
|
||||||
|
char path[COAP_MSG_MAX_PATH_LEN] = {0};
|
||||||
|
|
||||||
|
if (NULL == uri || NULL == message) {
|
||||||
|
COAP_ERR("Invalid paramter p_path %p, p_message %p", uri, message);
|
||||||
|
return IOTX_ERR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
if (IOTX_URI_MAX_LEN < strlen(uri)) {
|
||||||
|
COAP_ERR("The uri length is too loog,len = %d", (int)strlen(uri));
|
||||||
|
return IOTX_ERR_URI_TOO_LOOG;
|
||||||
|
}
|
||||||
|
COAP_DEBUG("The uri is %s", uri);
|
||||||
|
ptr = pstr = uri;
|
||||||
|
while ('\0' != *ptr) {
|
||||||
|
if ('/' == *ptr) {
|
||||||
|
if (ptr != pstr) {
|
||||||
|
memset(path, 0x00, sizeof(path));
|
||||||
|
strncpy(path, pstr, ptr - pstr);
|
||||||
|
COAP_DEBUG("path: %s,len=%d", path, (int)(ptr - pstr));
|
||||||
|
CoAPStrOption_add(message, COAP_OPTION_URI_PATH,
|
||||||
|
(unsigned char *)path, (int)strlen(path));
|
||||||
|
}
|
||||||
|
pstr = ptr + 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
if ('\0' == *(ptr + 1) && '\0' != *pstr) {
|
||||||
|
memset(path, 0x00, sizeof(path));
|
||||||
|
strncpy(path, pstr, sizeof(path) - 1);
|
||||||
|
COAP_DEBUG("path: %s,len=%d", path, (int)strlen(path));
|
||||||
|
CoAPStrOption_add(message, COAP_OPTION_URI_PATH,
|
||||||
|
(unsigned char *)path, (int)strlen(path));
|
||||||
|
}
|
||||||
|
ptr ++;
|
||||||
|
}
|
||||||
|
return IOTX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t IOT_CoAP_GetCurToken(iotx_coap_context_t *p_context)
|
||||||
|
{
|
||||||
|
iotx_coap_t *p_iotx_coap = NULL;
|
||||||
|
|
||||||
|
if (p_context == NULL) {
|
||||||
|
return IOTX_ERR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
p_iotx_coap = (iotx_coap_t *)p_context;
|
||||||
|
|
||||||
|
return p_iotx_coap->coap_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOT_CoAP_SendMessage(iotx_coap_context_t *p_context, char *p_path, iotx_message_t *p_message)
|
||||||
|
{
|
||||||
|
|
||||||
|
int len = 0;
|
||||||
|
int ret = IOTX_SUCCESS;
|
||||||
|
Cloud_CoAPContext *p_coap_ctx = NULL;
|
||||||
|
iotx_coap_t *p_iotx_coap = NULL;
|
||||||
|
Cloud_CoAPMessage message;
|
||||||
|
unsigned char token[8] = {0};
|
||||||
|
unsigned char *payload = NULL;
|
||||||
|
|
||||||
|
p_iotx_coap = (iotx_coap_t *)p_context;
|
||||||
|
|
||||||
|
if (NULL == p_context || NULL == p_path || NULL == p_message ||
|
||||||
|
(NULL != p_iotx_coap && NULL == p_iotx_coap->p_coap_ctx)) {
|
||||||
|
COAP_ERR("Invalid paramter p_context %p, p_uri %p, p_message %p",
|
||||||
|
p_context, p_path, p_message);
|
||||||
|
return IOTX_ERR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef INFRA_LOG_NETWORK_PAYLOAD
|
||||||
|
COAP_INFO("Upstream Topic: '%s'", p_path);
|
||||||
|
COAP_INFO("Upstream Payload:");
|
||||||
|
iotx_facility_json_print((const char *)p_message->p_payload, LOG_INFO_LEVEL, '>');
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* as this function only support POST request message, type ACK and RST shall be considered error parameters */
|
||||||
|
if (p_message->msg_type != IOTX_MESSAGE_CON && p_message->msg_type != IOTX_MESSAGE_NON) {
|
||||||
|
return IOTX_ERR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_message->payload_len >= COAP_MSG_MAX_PDU_LEN) {
|
||||||
|
COAP_ERR("The payload length %d is too loog", p_message->payload_len);
|
||||||
|
return IOTX_ERR_MSG_TOO_LOOG;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_coap_ctx = (Cloud_CoAPContext *)p_iotx_coap->p_coap_ctx;
|
||||||
|
if (p_iotx_coap->is_authed) {
|
||||||
|
|
||||||
|
/* CoAPMessage_init(&message); */
|
||||||
|
CoAPMessage_init(&message);
|
||||||
|
CoAPMessageType_set(&message, p_message->msg_type);
|
||||||
|
CoAPMessageCode_set(&message, COAP_MSG_CODE_POST);
|
||||||
|
CoAPMessageId_set(&message, Cloud_CoAPMessageId_gen(p_coap_ctx));
|
||||||
|
len = iotx_get_coap_token(p_iotx_coap, token);
|
||||||
|
CoAPMessageToken_set(&message, token, len);
|
||||||
|
CoAPMessageUserData_set(&message, (void *)p_message->user_data);
|
||||||
|
Cloud_CoAPMessageHandler_set(&message, p_message->resp_callback);
|
||||||
|
|
||||||
|
ret = iotx_split_path_2_option(p_path, &message);
|
||||||
|
if (IOTX_SUCCESS != ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IOTX_CONTENT_TYPE_CBOR == p_message->content_type) {
|
||||||
|
CoAPUintOption_add(&message, COAP_OPTION_CONTENT_FORMAT, COAP_CT_APP_CBOR);
|
||||||
|
CoAPUintOption_add(&message, COAP_OPTION_ACCEPT, COAP_CT_APP_OCTET_STREAM);
|
||||||
|
} else {
|
||||||
|
CoAPUintOption_add(&message, COAP_OPTION_CONTENT_FORMAT, COAP_CT_APP_JSON);
|
||||||
|
CoAPUintOption_add(&message, COAP_OPTION_ACCEPT, COAP_CT_APP_OCTET_STREAM);
|
||||||
|
}
|
||||||
|
CoAPStrOption_add(&message, COAP_OPTION_AUTH_TOKEN,
|
||||||
|
(unsigned char *)p_iotx_coap->p_auth_token, strlen(p_iotx_coap->p_auth_token));
|
||||||
|
if (COAP_ENDPOINT_PSK == p_iotx_coap->p_coap_ctx->network.ep_type) {
|
||||||
|
unsigned char buff[32] = {0};
|
||||||
|
unsigned char seq[33] = {0};
|
||||||
|
HAL_Snprintf((char *)buff, sizeof(buff) - 1, "%d", p_iotx_coap->seq++);
|
||||||
|
len = iotx_aes_cbc_encrypt(buff, strlen((char *)buff), p_iotx_coap->key, seq);
|
||||||
|
if (0 < len) {
|
||||||
|
CoAPStrOption_add(&message, COAP_OPTION_SEQ, (unsigned char *)seq, len);
|
||||||
|
} else {
|
||||||
|
COAP_INFO("Encrypt seq failed");
|
||||||
|
}
|
||||||
|
HEXDUMP_DEBUG(seq, len);
|
||||||
|
|
||||||
|
payload = (unsigned char *)coap_malloc(COAP_MSG_MAX_PDU_LEN);
|
||||||
|
if (NULL == payload) {
|
||||||
|
return IOTX_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
memset(payload, 0x00, COAP_MSG_MAX_PDU_LEN);
|
||||||
|
len = iotx_aes_cbc_encrypt(p_message->p_payload, p_message->payload_len, p_iotx_coap->key, payload);
|
||||||
|
if (0 == len) {
|
||||||
|
coap_free(payload);
|
||||||
|
payload = NULL;
|
||||||
|
return IOTX_ERR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
HEXDUMP_DEBUG(payload, len);
|
||||||
|
CoAPMessagePayload_set(&message, payload, len);
|
||||||
|
} else {
|
||||||
|
CoAPMessagePayload_set(&message, p_message->p_payload, p_message->payload_len);
|
||||||
|
}
|
||||||
|
ret = Cloud_CoAPMessage_send(p_coap_ctx, &message);
|
||||||
|
CoAPMessage_destory(&message);
|
||||||
|
if (NULL != payload) {
|
||||||
|
coap_free(payload);
|
||||||
|
payload = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (COAP_ERROR_DATA_SIZE == ret) {
|
||||||
|
return IOTX_ERR_MSG_TOO_LOOG;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IOTX_SUCCESS;
|
||||||
|
} else {
|
||||||
|
COAP_ERR("The client [%s/%s] still un-authorized yet, return %d",
|
||||||
|
p_iotx_coap->p_devinfo->product_key,
|
||||||
|
p_iotx_coap->p_devinfo->device_name,
|
||||||
|
IOTX_ERR_NOT_AUTHED
|
||||||
|
);
|
||||||
|
return IOTX_ERR_NOT_AUTHED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int IOT_CoAP_GetMessagePayload(void *p_message, unsigned char **pp_payload, int *p_len)
|
||||||
|
{
|
||||||
|
Cloud_CoAPMessage *message = NULL;
|
||||||
|
iotx_coap_t *p_iotx_coap = NULL;
|
||||||
|
|
||||||
|
if (NULL == p_message || NULL == pp_payload || NULL == p_len || NULL == g_coap_context) {
|
||||||
|
COAP_ERR("Invalid parameter: p_message=%p, pp_payload=%p, p_len=%p",
|
||||||
|
p_message, pp_payload, p_len);
|
||||||
|
return IOTX_ERR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_iotx_coap = (iotx_coap_t *)g_coap_context;
|
||||||
|
message = (Cloud_CoAPMessage *)p_message;
|
||||||
|
|
||||||
|
COAP_DEBUG("message->payload: %p", message->payload);
|
||||||
|
COAP_DEBUG("message->payloadlen: %d", message->payloadlen);
|
||||||
|
|
||||||
|
if (message->payloadlen >= COAP_MSG_MAX_PDU_LEN) {
|
||||||
|
COAP_ERR("Invalid parameter: message->payloadlen(%d) out of [0, %d]",
|
||||||
|
message->payloadlen, COAP_MSG_MAX_PDU_LEN);
|
||||||
|
return IOTX_ERR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (COAP_ENDPOINT_PSK == p_iotx_coap->p_coap_ctx->network.ep_type) {
|
||||||
|
int len = 0;
|
||||||
|
unsigned char *payload = NULL;
|
||||||
|
payload = coap_malloc(COAP_MSG_MAX_PDU_LEN);
|
||||||
|
if (NULL == payload) {
|
||||||
|
return IOTX_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
memset(payload, 0x00, COAP_MSG_MAX_PDU_LEN);
|
||||||
|
|
||||||
|
HEXDUMP_DEBUG(message->payload, message->payloadlen);
|
||||||
|
|
||||||
|
len = iotx_aes_cbc_decrypt(message->payload, message->payloadlen, p_iotx_coap->key, payload);
|
||||||
|
if (len > 0) {
|
||||||
|
COAP_DEBUG("payload: %.*s, len %d", len, payload, len);
|
||||||
|
}
|
||||||
|
if (len != 0) {
|
||||||
|
memcpy(message->payload, payload, len);
|
||||||
|
message->payloadlen = len;
|
||||||
|
HEXDUMP_DEBUG(payload, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
coap_free(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
*pp_payload = message->payload;
|
||||||
|
*p_len = message->payloadlen;
|
||||||
|
|
||||||
|
return IOTX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOT_CoAP_GetMessageToken(void *p_message, unsigned int *token)
|
||||||
|
{
|
||||||
|
|
||||||
|
Cloud_CoAPMessage *message = NULL;
|
||||||
|
|
||||||
|
if (NULL == p_message || NULL == token) {
|
||||||
|
COAP_ERR("Invalid paramter p_message %p, token= %p", p_message, token);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
message = (Cloud_CoAPMessage *)p_message;
|
||||||
|
|
||||||
|
*token = ((unsigned int)(message->token[3]) & 0xff) << 24;
|
||||||
|
*token += ((unsigned int)(message->token[2]) & 0xff) << 16;
|
||||||
|
*token += ((unsigned int)(message->token[1]) & 0xff) << 8;
|
||||||
|
*token += ((unsigned int)(message->token[0]) & 0xff);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOT_CoAP_GetMessageCode(void *p_message, iotx_coap_resp_code_t *p_resp_code)
|
||||||
|
{
|
||||||
|
Cloud_CoAPMessage *message = NULL;
|
||||||
|
|
||||||
|
if (NULL == p_message || NULL == p_resp_code) {
|
||||||
|
COAP_ERR("Invalid paramter p_message %p, p_resp_code %p",
|
||||||
|
p_message, p_resp_code);
|
||||||
|
return IOTX_ERR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
message = (Cloud_CoAPMessage *)p_message;
|
||||||
|
*p_resp_code = (iotx_coap_resp_code_t) message->header.code;
|
||||||
|
|
||||||
|
return IOTX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int iotx_get_seq(void)
|
||||||
|
{
|
||||||
|
HAL_Srandom((unsigned int)HAL_UptimeMs());
|
||||||
|
return HAL_Random(0xffffffff) % 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
iotx_coap_context_t *IOT_CoAP_Init(iotx_coap_config_t *p_config)
|
||||||
|
{
|
||||||
|
Cloud_CoAPInitParam param;
|
||||||
|
char url[128] = {0};
|
||||||
|
iotx_coap_t *p_iotx_coap = NULL;
|
||||||
|
|
||||||
|
if (NULL == p_config) {
|
||||||
|
COAP_ERR("Invalid paramter p_config %p", p_config);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (NULL == p_config->p_devinfo) {
|
||||||
|
COAP_ERR("Invalid paramter p_devinfo %p", p_config->p_devinfo);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_iotx_coap = coap_malloc(sizeof(iotx_coap_t));
|
||||||
|
if (NULL == p_iotx_coap) {
|
||||||
|
COAP_ERR(" Allocate memory for iotx_coap_context_t failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(p_iotx_coap, 0x00, sizeof(iotx_coap_t));
|
||||||
|
|
||||||
|
p_iotx_coap->p_auth_token = coap_malloc(IOTX_AUTH_TOKEN_LEN);
|
||||||
|
if (NULL == p_iotx_coap->p_auth_token) {
|
||||||
|
COAP_ERR(" Allocate memory for auth token failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
memset(p_iotx_coap->p_auth_token, 0x00, IOTX_AUTH_TOKEN_LEN);
|
||||||
|
|
||||||
|
/*Set the client isn't authed*/
|
||||||
|
p_iotx_coap->is_authed = IOT_FALSE;
|
||||||
|
p_iotx_coap->auth_token_len = IOTX_AUTH_TOKEN_LEN;
|
||||||
|
|
||||||
|
/*Get deivce information*/
|
||||||
|
p_iotx_coap->p_devinfo = coap_malloc(sizeof(iotx_deviceinfo_t));
|
||||||
|
if (NULL == p_iotx_coap->p_devinfo) {
|
||||||
|
COAP_ERR(" Allocate memory for iotx_deviceinfo_t failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
memset(p_iotx_coap->p_devinfo, 0x00, sizeof(iotx_deviceinfo_t));
|
||||||
|
|
||||||
|
/*It should be implement by the user*/
|
||||||
|
if (NULL != p_config->p_devinfo) {
|
||||||
|
memset(p_iotx_coap->p_devinfo, 0x00, sizeof(iotx_deviceinfo_t));
|
||||||
|
strncpy(p_iotx_coap->p_devinfo->device_id, p_config->p_devinfo->device_id, strlen(p_config->p_devinfo->device_id));
|
||||||
|
strncpy(p_iotx_coap->p_devinfo->product_key, p_config->p_devinfo->product_key,
|
||||||
|
strlen(p_config->p_devinfo->product_key));
|
||||||
|
strncpy(p_iotx_coap->p_devinfo->device_secret, p_config->p_devinfo->device_secret,
|
||||||
|
strlen(p_config->p_devinfo->device_secret));
|
||||||
|
strncpy(p_iotx_coap->p_devinfo->device_name, p_config->p_devinfo->device_name,
|
||||||
|
strlen(p_config->p_devinfo->device_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Init coap token*/
|
||||||
|
p_iotx_coap->coap_token = IOTX_COAP_INIT_TOKEN;
|
||||||
|
p_iotx_coap->seq = iotx_get_seq();
|
||||||
|
memset(p_iotx_coap->key, 0x00, sizeof(p_iotx_coap->key));
|
||||||
|
|
||||||
|
/*Create coap context*/
|
||||||
|
memset(¶m, 0x00, sizeof(Cloud_CoAPInitParam));
|
||||||
|
|
||||||
|
if (NULL != p_config->p_url) {
|
||||||
|
param.url = p_config->p_url;
|
||||||
|
} else {
|
||||||
|
HAL_Snprintf(url, sizeof(url), IOTX_COAP_ONLINE_PSK_SERVER_URL, p_iotx_coap->p_devinfo->product_key);
|
||||||
|
param.url = url;
|
||||||
|
COAP_INFO("Using default CoAP server: %s", url);
|
||||||
|
}
|
||||||
|
param.maxcount = IOTX_LIST_MAX_ITEM;
|
||||||
|
param.notifier = (Cloud_CoAPEventNotifier)iotx_event_notifyer;
|
||||||
|
param.waittime = p_config->wait_time_ms;
|
||||||
|
p_iotx_coap->p_coap_ctx = Cloud_CoAPContext_create(¶m);
|
||||||
|
if (NULL == p_iotx_coap->p_coap_ctx) {
|
||||||
|
COAP_ERR(" Create coap context failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Register the event handle to notify the application */
|
||||||
|
p_iotx_coap->event_handle = p_config->event_handle;
|
||||||
|
|
||||||
|
g_coap_context = (iotx_coap_context_t *)p_iotx_coap;
|
||||||
|
return (iotx_coap_context_t *)p_iotx_coap;
|
||||||
|
err:
|
||||||
|
/* Error, release the memory */
|
||||||
|
if (NULL != p_iotx_coap) {
|
||||||
|
if (NULL != p_iotx_coap->p_devinfo) {
|
||||||
|
coap_free(p_iotx_coap->p_devinfo);
|
||||||
|
}
|
||||||
|
if (NULL != p_iotx_coap->p_auth_token) {
|
||||||
|
coap_free(p_iotx_coap->p_auth_token);
|
||||||
|
}
|
||||||
|
if (NULL != p_iotx_coap->p_coap_ctx) {
|
||||||
|
Cloud_CoAPContext_free(p_iotx_coap->p_coap_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
p_iotx_coap->auth_token_len = 0;
|
||||||
|
p_iotx_coap->is_authed = IOT_FALSE;
|
||||||
|
coap_free(p_iotx_coap);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IOT_CoAP_Deinit(iotx_coap_context_t **pp_context)
|
||||||
|
{
|
||||||
|
iotx_coap_t *p_iotx_coap = NULL;
|
||||||
|
|
||||||
|
if (NULL != pp_context && NULL != *pp_context) {
|
||||||
|
p_iotx_coap = (iotx_coap_t *)*pp_context;
|
||||||
|
p_iotx_coap->is_authed = IOT_FALSE;
|
||||||
|
p_iotx_coap->auth_token_len = 0;
|
||||||
|
p_iotx_coap->coap_token = IOTX_COAP_INIT_TOKEN;
|
||||||
|
|
||||||
|
if (NULL != p_iotx_coap->p_auth_token) {
|
||||||
|
coap_free(p_iotx_coap->p_auth_token);
|
||||||
|
p_iotx_coap->p_auth_token = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != p_iotx_coap->p_devinfo) {
|
||||||
|
coap_free(p_iotx_coap->p_devinfo);
|
||||||
|
p_iotx_coap->p_devinfo = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != p_iotx_coap->p_coap_ctx) {
|
||||||
|
Cloud_CoAPContext_free(p_iotx_coap->p_coap_ctx);
|
||||||
|
p_iotx_coap->p_coap_ctx = NULL;
|
||||||
|
}
|
||||||
|
coap_free(p_iotx_coap);
|
||||||
|
*pp_context = NULL;
|
||||||
|
g_coap_context = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOT_CoAP_Yield(iotx_coap_context_t *p_context)
|
||||||
|
{
|
||||||
|
iotx_coap_t *p_iotx_coap = NULL;
|
||||||
|
p_iotx_coap = (iotx_coap_t *)p_context;
|
||||||
|
if (NULL == p_iotx_coap || (NULL != p_iotx_coap && NULL == p_iotx_coap->p_coap_ctx)) {
|
||||||
|
COAP_ERR("Invalid paramter");
|
||||||
|
return IOTX_ERR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Cloud_CoAPMessage_cycle(p_iotx_coap->p_coap_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef __IOTX_COAP_CONFIG__
|
||||||
|
#define __IOTX_COAP_CONFIG__
|
||||||
|
|
||||||
|
#define COAP_MSG_MAX_TOKEN_LEN 8
|
||||||
|
#define COAP_MSG_MAX_OPTION_NUM 12
|
||||||
|
#define COAP_MSG_MAX_PATH_LEN 128
|
||||||
|
#ifndef COAP_LARGE_MEMORY_SUPPORT
|
||||||
|
#define COAP_MSG_MAX_PDU_LEN 1280
|
||||||
|
#else
|
||||||
|
#define COAP_MSG_MAX_PDU_LEN 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_COAP_AUTH_TIMEOUT
|
||||||
|
#define CONFIG_COAP_AUTH_TIMEOUT (3 * 1000)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __IOTX_COAP_INTERNAL__
|
||||||
|
#define __IOTX_COAP_INTERNAL__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "infra_string.h"
|
||||||
|
#include "infra_compat.h"
|
||||||
|
#include "infra_types.h"
|
||||||
|
#include "infra_defs.h"
|
||||||
|
#include "infra_log.h"
|
||||||
|
#include "infra_json_parser.h"
|
||||||
|
#include "infra_cjson.h"
|
||||||
|
#include "infra_list.h"
|
||||||
|
#include "infra_md5.h"
|
||||||
|
#include "infra_sha256.h"
|
||||||
|
#include "infra_report.h"
|
||||||
|
#include "iotx_coap_config.h"
|
||||||
|
#include "coap_wrapper.h"
|
||||||
|
#include "iotx_coap_config.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/*CoAP Content Type*/
|
||||||
|
#define COAP_CT_TEXT_PLAIN 0 /* text/plain (UTF-8) */
|
||||||
|
#define COAP_CT_APP_LINK_FORMAT 40 /* application/link-format */
|
||||||
|
#define COAP_CT_APP_XML 41 /* application/xml */
|
||||||
|
#define COAP_CT_APP_OCTET_STREAM 42 /* application/octet-stream */
|
||||||
|
#define COAP_CT_APP_RDF_XML 43 /* application/rdf+xml */
|
||||||
|
#define COAP_CT_APP_EXI 47 /* application/exi */
|
||||||
|
#define COAP_CT_APP_JSON 50 /* application/json */
|
||||||
|
#define COAP_CT_APP_CBOR 60 /* application/cbor */
|
||||||
|
|
||||||
|
/*CoAP option types. */
|
||||||
|
#define COAP_OPTION_IF_MATCH 1 /* C, opaque, 0-8 B, (none) */
|
||||||
|
#define COAP_OPTION_URI_HOST 3 /* C, String, 1-255 B, destination address */
|
||||||
|
#define COAP_OPTION_ETAG 4 /* E, opaque, 1-8 B, (none) */
|
||||||
|
#define COAP_OPTION_IF_NONE_MATCH 5 /* empty, 0 B, (none) */
|
||||||
|
#define COAP_OPTION_OBSERVE 6 /* E, empty/uint, 0 B/0-3 B, (none)*/
|
||||||
|
#define COAP_OPTION_URI_PORT 7 /* C, uint, 0-2 B, destination port */
|
||||||
|
#define COAP_OPTION_LOCATION_PATH 8 /* E, String, 0-255 B, - */
|
||||||
|
#define COAP_OPTION_URI_PATH 11 /* C, String, 0-255 B, (none) */
|
||||||
|
#define COAP_OPTION_CONTENT_FORMAT 12 /* E, uint, 0-2 B, (none) */
|
||||||
|
#define COAP_OPTION_MAXAGE 14 /* E, uint, 0--4 B, 60 Seconds */
|
||||||
|
#define COAP_OPTION_URI_QUERY 15 /* C, String, 1-255 B, (none) */
|
||||||
|
#define COAP_OPTION_ACCEPT 17 /* C, uint, 0-2 B, (none) */
|
||||||
|
#define COAP_OPTION_LOCATION_QUERY 20 /* E, String, 0-255 B, (none) */
|
||||||
|
#define COAP_OPTION_BLOCK2 23 /* C, uint, 0--3 B, (none) */
|
||||||
|
#define COAP_OPTION_BLOCK1 27 /* C, uint, 0--3 B, (none) */
|
||||||
|
#define COAP_OPTION_PROXY_URI 35 /* C, String, 1-1024 B, (none) */
|
||||||
|
#define COAP_OPTION_PROXY_SCHEME 39 /* C, String, 1-255 B, (none) */
|
||||||
|
#define COAP_OPTION_SIZE1 60 /* E, uint, 0-4 B, (none) */
|
||||||
|
#define COAP_OPTION_AUTH_TOKEN 61 /* C, String, 1-255B, (none)*/
|
||||||
|
|
||||||
|
#define COAP_PERM_NONE 0x0000
|
||||||
|
#define COAP_PERM_GET 0x0001
|
||||||
|
#define COAP_PERM_POST 0x0002
|
||||||
|
#define COAP_PERM_PUT 0x0004
|
||||||
|
#define COAP_PERM_DELETE 0x0008
|
||||||
|
#define COAP_PERM_OBSERVE 0x0100
|
||||||
|
|
||||||
|
/*CoAP Message types*/
|
||||||
|
#define COAP_MESSAGE_TYPE_CON 0
|
||||||
|
#define COAP_MESSAGE_TYPE_NON 1
|
||||||
|
#define COAP_MESSAGE_TYPE_ACK 2
|
||||||
|
#define COAP_MESSAGE_TYPE_RST 3
|
||||||
|
|
||||||
|
/* CoAP module error code base */
|
||||||
|
#define COAP_ERROR_BASE (1<<8)
|
||||||
|
#define COAP_ERROR_DTLS_BASE (1<<16)
|
||||||
|
|
||||||
|
/* CoAP base error code */
|
||||||
|
#define COAP_SUCCESS (0) /* Successful */
|
||||||
|
#define COAP_ERROR_INVALID_PARAM (COAP_ERROR_BASE | 1) /* Invalid Parameter */
|
||||||
|
#define COAP_ERROR_NULL (COAP_ERROR_BASE | 2) /* Null Pointer */
|
||||||
|
#define COAP_ERROR_MALLOC (COAP_ERROR_BASE | 3)
|
||||||
|
#define COAP_ERROR_INVALID_LENGTH (COAP_ERROR_BASE | 4) /* Invalid Length */
|
||||||
|
#define COAP_ERROR_DATA_SIZE (COAP_ERROR_BASE | 5) /* Data size exceeds limit */
|
||||||
|
#define COAP_ERROR_INVALID_URI (COAP_ERROR_BASE | 6)
|
||||||
|
#define COAP_ERROR_NOT_FOUND (COAP_ERROR_BASE | 7)
|
||||||
|
#define COAP_ERROR_NET_INIT_FAILED (COAP_ERROR_BASE | 8)
|
||||||
|
#define COAP_ERROR_INTERNAL (COAP_ERROR_BASE | 9) /* Internal Error */
|
||||||
|
#define COAP_ERROR_WRITE_FAILED (COAP_ERROR_BASE | 10)
|
||||||
|
#define COAP_ERROR_READ_FAILED (COAP_ERROR_BASE | 11)
|
||||||
|
#define COAP_ERROR_ENCRYPT_FAILED (COAP_ERROR_BASE | 12)
|
||||||
|
#define COAP_ERROR_UNSUPPORTED (COAP_ERROR_BASE | 13)
|
||||||
|
#define COAP_ERROR_OBJ_ALREADY_EXIST (COAP_ERROR_BASE | 14)
|
||||||
|
|
||||||
|
#define COAP_MSG_CODE_DEF(N) (((N)/100 << 5) | (N)%100)
|
||||||
|
|
||||||
|
/*CoAP Message codes*/
|
||||||
|
typedef enum {
|
||||||
|
/* CoAP Empty Message */
|
||||||
|
COAP_MSG_CODE_EMPTY_MESSAGE = COAP_MSG_CODE_DEF(0), /* Mapping to CoAP code 0.00 */
|
||||||
|
|
||||||
|
/* CoAP Method Codes */
|
||||||
|
COAP_MSG_CODE_GET = COAP_MSG_CODE_DEF(1), /* CoAP Get method */
|
||||||
|
COAP_MSG_CODE_POST = COAP_MSG_CODE_DEF(2), /* CoAP Post method */
|
||||||
|
COAP_MSG_CODE_PUT = COAP_MSG_CODE_DEF(3), /* CoAP Put method */
|
||||||
|
COAP_MSG_CODE_DELETE = COAP_MSG_CODE_DEF(4), /* CoAP Delete method */
|
||||||
|
|
||||||
|
/* CoAP Success Response Codes */
|
||||||
|
COAP_MSG_CODE_201_CREATED = COAP_MSG_CODE_DEF(201), /* Mapping to CoAP code 2.01, Hex:0x41, Created */
|
||||||
|
COAP_MSG_CODE_202_DELETED = COAP_MSG_CODE_DEF(202), /* Mapping to CoAP code 2.02, Hex:0x42, Deleted*/
|
||||||
|
COAP_MSG_CODE_203_VALID = COAP_MSG_CODE_DEF(203), /* Mapping to CoAP code 2.03, Hex:0x43, Valid*/
|
||||||
|
COAP_MSG_CODE_204_CHANGED = COAP_MSG_CODE_DEF(204), /* Mapping to CoAP code 2.04, Hex:0x44, Changed*/
|
||||||
|
COAP_MSG_CODE_205_CONTENT = COAP_MSG_CODE_DEF(205), /* Mapping to CoAP code 2.05, Hex:0x45, Content*/
|
||||||
|
COAP_MSG_CODE_231_CONTINUE = COAP_MSG_CODE_DEF(231), /* Mapping to CoAP code 2.31, Hex:0x5F, Continue*/
|
||||||
|
|
||||||
|
/* CoAP Client Error Response Codes */
|
||||||
|
COAP_MSG_CODE_400_BAD_REQUEST = COAP_MSG_CODE_DEF(400), /* Mapping to CoAP code 4.00, Hex:0x80, Bad Request */
|
||||||
|
COAP_MSG_CODE_401_UNAUTHORIZED = COAP_MSG_CODE_DEF(401), /* Mapping to CoAP code 4.01, Hex:0x81, Unauthorized */
|
||||||
|
COAP_MSG_CODE_402_BAD_OPTION = COAP_MSG_CODE_DEF(402), /* Mapping to CoAP code 4.02, Hex:0x82, Bad Option */
|
||||||
|
COAP_MSG_CODE_403_FORBIDDEN = COAP_MSG_CODE_DEF(403), /* Mapping to CoAP code 4.03, Hex:0x83, Forbidden */
|
||||||
|
COAP_MSG_CODE_404_NOT_FOUND = COAP_MSG_CODE_DEF(404), /* Mapping to CoAP code 4.04, Hex:0x84, Not Found */
|
||||||
|
COAP_MSG_CODE_405_METHOD_NOT_ALLOWED = COAP_MSG_CODE_DEF(405), /* Mapping to CoAP code 4.05, Hex:0x85, Method Not Allowed */
|
||||||
|
COAP_MSG_CODE_406_NOT_ACCEPTABLE = COAP_MSG_CODE_DEF(406), /* Mapping to CoAP code 4.06, Hex:0x86, Not Acceptable */
|
||||||
|
COAP_MSG_CODE_408_REQUEST_ENTITY_INCOMPLETE = COAP_MSG_CODE_DEF(408), /* Mapping to CoAP code 4.08, Hex:0x88, Request Entity Incomplete */
|
||||||
|
COAP_MSG_CODE_412_PRECONDITION_FAILED = COAP_MSG_CODE_DEF(412), /* Mapping to CoAP code 4.12, Hex:0x8C, Precondition Failed */
|
||||||
|
COAP_MSG_CODE_413_REQUEST_ENTITY_TOO_LARGE = COAP_MSG_CODE_DEF(413), /* Mapping to CoAP code 4.13, Hex:0x8D, Request Entity Too Large */
|
||||||
|
COAP_MSG_CODE_415_UNSUPPORTED_CONTENT_FORMAT = COAP_MSG_CODE_DEF(415), /* Mapping to CoAP code 4.15, Hex:0x8F, Unsupported Content-Format */
|
||||||
|
|
||||||
|
/* CoAP Server Error Response Codes */
|
||||||
|
COAP_MSG_CODE_500_INTERNAL_SERVER_ERROR = COAP_MSG_CODE_DEF(500), /* Mapping to CoAP code 5.00, Hex:0xA0, Internal Server Error */
|
||||||
|
COAP_MSG_CODE_501_NOT_IMPLEMENTED = COAP_MSG_CODE_DEF(501), /* Mapping to CoAP code 5.01, Hex:0xA1, Not Implemented */
|
||||||
|
COAP_MSG_CODE_502_BAD_GATEWAY = COAP_MSG_CODE_DEF(502), /* Mapping to CoAP code 5.02, Hex:0xA2, Bad Gateway */
|
||||||
|
COAP_MSG_CODE_503_SERVICE_UNAVAILABLE = COAP_MSG_CODE_DEF(503), /* Mapping to CoAP code 5.03, Hex:0xA3, Service Unavailable */
|
||||||
|
COAP_MSG_CODE_504_GATEWAY_TIMEOUT = COAP_MSG_CODE_DEF(504), /* Mapping to CoAP code 5.04, Hex:0xA4, Gateway Timeout */
|
||||||
|
COAP_MSG_CODE_505_PROXYING_NOT_SUPPORTED = COAP_MSG_CODE_DEF(505) /* Mapping to CoAP code 5.05, Hex:0xA5, Proxying Not Supported */
|
||||||
|
|
||||||
|
} CoAPMessageCode;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
COAP_REQUEST_SUCCESS = 0,
|
||||||
|
COAP_RECV_RESP_TIMEOUT,
|
||||||
|
COAP_RECV_RESP_SUC,
|
||||||
|
} CoAPReqResult;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int len;
|
||||||
|
unsigned char *data;
|
||||||
|
} CoAPLenString;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char version : 2;
|
||||||
|
unsigned char type : 2;
|
||||||
|
unsigned char tokenlen : 4;
|
||||||
|
unsigned char code;
|
||||||
|
unsigned short msgid;
|
||||||
|
} CoAPMsgHeader;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned short num;
|
||||||
|
unsigned short len;
|
||||||
|
unsigned char *val;
|
||||||
|
} CoAPMsgOption;
|
||||||
|
|
||||||
|
typedef void CoAPContext;
|
||||||
|
typedef struct CoAPMessage CoAPMessage;
|
||||||
|
|
||||||
|
typedef void (*CoAPSendMsgHandler)(CoAPContext *context, CoAPReqResult result, void *userdata, NetworkAddr *remote,
|
||||||
|
CoAPMessage *message);
|
||||||
|
|
||||||
|
typedef void (*CoAPEventNotifier)(unsigned int event, NetworkAddr *remote, void *message);
|
||||||
|
|
||||||
|
typedef void (*CoAPRecvMsgHandler)(CoAPContext *context, const char *paths, NetworkAddr *remote, CoAPMessage *message);
|
||||||
|
|
||||||
|
typedef int (*CoAPDataEncrypt)(CoAPContext *context, const char *paths, NetworkAddr *addr, CoAPMessage *message,
|
||||||
|
CoAPLenString *src, CoAPLenString *dest);
|
||||||
|
typedef void (*CoAPRespMsgHandler)(void *data, void *message);
|
||||||
|
|
||||||
|
struct CoAPMessage {
|
||||||
|
CoAPMsgHeader header;
|
||||||
|
unsigned char token[COAP_MSG_MAX_TOKEN_LEN];
|
||||||
|
CoAPMsgOption options[COAP_MSG_MAX_OPTION_NUM];
|
||||||
|
unsigned char optcount;
|
||||||
|
unsigned char optdelta;
|
||||||
|
unsigned short payloadlen;
|
||||||
|
unsigned char *payload;
|
||||||
|
CoAPSendMsgHandler handler;
|
||||||
|
CoAPRespMsgHandler resp;
|
||||||
|
void *user;
|
||||||
|
int keep;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* CoAP message options APIs*/
|
||||||
|
extern int CoAPStrOption_add(CoAPMessage *message, unsigned short optnum,
|
||||||
|
unsigned char *data, unsigned short datalen);
|
||||||
|
|
||||||
|
extern int CoAPStrOption_get(CoAPMessage *message, unsigned short optnum,
|
||||||
|
unsigned char *data, unsigned short *datalen);
|
||||||
|
|
||||||
|
extern int CoAPUintOption_add(CoAPMessage *message, unsigned short optnum,
|
||||||
|
unsigned int data);
|
||||||
|
|
||||||
|
extern int CoAPUintOption_get(CoAPMessage *message,
|
||||||
|
unsigned short optnum,
|
||||||
|
unsigned int *data);
|
||||||
|
|
||||||
|
extern int CoAPOption_present(CoAPMessage *message, unsigned short option);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern int CoAPMessageId_set(CoAPMessage *message, unsigned short msgid);
|
||||||
|
|
||||||
|
extern int CoAPMessageType_set(CoAPMessage *message, unsigned char type);
|
||||||
|
|
||||||
|
extern int CoAPMessageCode_set(CoAPMessage *message, CoAPMessageCode code);
|
||||||
|
|
||||||
|
extern int CoAPMessageCode_get(CoAPMessage *message, CoAPMessageCode *code);
|
||||||
|
|
||||||
|
extern int CoAPMessageToken_set(CoAPMessage *message, unsigned char *token,
|
||||||
|
unsigned char tokenlen);
|
||||||
|
|
||||||
|
extern int CoAPMessageUserData_set(CoAPMessage *message, void *userdata);
|
||||||
|
|
||||||
|
extern int CoAPMessageKeep_Set(CoAPMessage *message, int keep);
|
||||||
|
|
||||||
|
extern int CoAPMessagePayload_set(CoAPMessage *message, unsigned char *payload,
|
||||||
|
unsigned short payloadlen);
|
||||||
|
|
||||||
|
extern int CoAPMessageHandler_set(CoAPMessage *message, CoAPSendMsgHandler handler);
|
||||||
|
|
||||||
|
extern int CoAPMessage_init(CoAPMessage *message);
|
||||||
|
|
||||||
|
extern int CoAPMessage_destory(CoAPMessage *message);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __COAP_DESERIALIZE_H__
|
||||||
|
#define __COAP_DESERIALIZE_H__
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
int CoAPDeserialize_Message(CoAPMessage *msg, unsigned char *buf, int buflen);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
|
||||||
|
int CoAPDeserialize_Header(CoAPMessage *msg, unsigned char *buf)
|
||||||
|
{
|
||||||
|
msg->header.version = ((buf[0] >> 6) & 0x03);
|
||||||
|
msg->header.type = ((buf[0] >> 4) & 0x03);
|
||||||
|
msg->header.tokenlen = (buf[0] & 0x0F);
|
||||||
|
msg->header.code = buf[1];
|
||||||
|
msg->header.msgid = buf[2] << 8;
|
||||||
|
msg->header.msgid += buf[3];
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPDeserialize_Token(CoAPMessage *msg, unsigned char *buf)
|
||||||
|
{
|
||||||
|
memcpy(msg->token, buf, msg->header.tokenlen);
|
||||||
|
return msg->header.tokenlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CoAPDeserialize_Option(CoAPMsgOption *option, unsigned char *buf, unsigned short *predeltas)
|
||||||
|
{
|
||||||
|
unsigned char *ptr = buf;
|
||||||
|
unsigned short optdelta = 0;
|
||||||
|
unsigned short optlen = 0;
|
||||||
|
unsigned short predelta = 0;
|
||||||
|
|
||||||
|
optdelta = (*ptr & 0xF0) >> 4;
|
||||||
|
optlen = (*ptr & 0x0F);
|
||||||
|
ptr++;
|
||||||
|
|
||||||
|
predelta = *predeltas;
|
||||||
|
if (13 == optdelta) {
|
||||||
|
predelta += 13 + *ptr;
|
||||||
|
ptr ++;
|
||||||
|
|
||||||
|
} else if (14 == optdelta) {
|
||||||
|
predelta += 269;
|
||||||
|
predelta += (*ptr << 8);
|
||||||
|
predelta += *(ptr + 1);
|
||||||
|
ptr += 2;
|
||||||
|
} else {
|
||||||
|
predelta += optdelta;
|
||||||
|
}
|
||||||
|
option->num = predelta;
|
||||||
|
|
||||||
|
if (13 == optlen) {
|
||||||
|
optlen = 13 + *ptr;
|
||||||
|
ptr ++;
|
||||||
|
} else if (14 == optlen) {
|
||||||
|
optlen = 269;
|
||||||
|
optlen += (*ptr << 8);
|
||||||
|
optlen += *(ptr + 1);
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
option->len = optlen;
|
||||||
|
|
||||||
|
option->val = ptr;
|
||||||
|
*predeltas = option->num;
|
||||||
|
|
||||||
|
return (ptr - buf + option->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPDeserialize_Options(CoAPMessage *msg, unsigned char *buf, int buflen)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
int count = 0;
|
||||||
|
unsigned char *ptr = buf;
|
||||||
|
unsigned short len = 0;
|
||||||
|
unsigned short optdeltas = 0;
|
||||||
|
|
||||||
|
msg->optcount = 0;
|
||||||
|
while ((count < buflen) && (0xFF != *ptr)) {
|
||||||
|
len = CoAPDeserialize_Option(&msg->options[index], ptr, &optdeltas);
|
||||||
|
msg->optcount += 1;
|
||||||
|
ptr += len;
|
||||||
|
index ++;
|
||||||
|
count += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)(ptr - buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPDeserialize_Payload(CoAPMessage *msg, unsigned char *buf, int buflen)
|
||||||
|
{
|
||||||
|
unsigned char *ptr = buf;
|
||||||
|
|
||||||
|
if (0xFF == *ptr) {
|
||||||
|
ptr ++;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
msg->payloadlen = buflen - 1;
|
||||||
|
msg->payload = (unsigned char *)ptr;
|
||||||
|
|
||||||
|
return buflen;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPDeserialize_Message(CoAPMessage *msg, unsigned char *buf, int buflen)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
int remlen = buflen;
|
||||||
|
unsigned char *ptr = buf;
|
||||||
|
|
||||||
|
if (NULL == buf || NULL == msg) {
|
||||||
|
return COAP_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buflen < 4) {
|
||||||
|
return COAP_ERROR_INVALID_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deserialize CoAP header. */
|
||||||
|
count = CoAPDeserialize_Header(msg, ptr);
|
||||||
|
ptr += count;
|
||||||
|
remlen -= count;
|
||||||
|
|
||||||
|
/* Deserialize the token, if any. */
|
||||||
|
count = CoAPDeserialize_Token(msg, ptr);
|
||||||
|
ptr += count;
|
||||||
|
remlen -= count;
|
||||||
|
|
||||||
|
count = CoAPDeserialize_Options(msg, ptr, remlen);
|
||||||
|
ptr += count;
|
||||||
|
remlen -= count;
|
||||||
|
|
||||||
|
CoAPDeserialize_Payload(msg, ptr, remlen);
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,317 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
#include "CoAPSerialize.h"
|
||||||
|
#include "CoAPDeserialize.h"
|
||||||
|
#if 0
|
||||||
|
#include "CoAPResource.h"
|
||||||
|
#include "CoAPObserve.h"
|
||||||
|
#include "CoAPInternal.h"
|
||||||
|
#endif
|
||||||
|
#include "CoAPPlatform.h"
|
||||||
|
|
||||||
|
#define COAPAckMsg(header) \
|
||||||
|
((header.code == COAP_MSG_CODE_EMPTY_MESSAGE) \
|
||||||
|
&&(header.type == COAP_MESSAGE_TYPE_ACK))
|
||||||
|
|
||||||
|
#define CoAPRespMsg(header)\
|
||||||
|
((header.code >= 0x40) && (header.code < 0xc0))
|
||||||
|
|
||||||
|
#define CoAPPingMsg(header)\
|
||||||
|
((header.code == COAP_MSG_CODE_EMPTY_MESSAGE)\
|
||||||
|
&& (header.type == COAP_MESSAGE_TYPE_CON))
|
||||||
|
|
||||||
|
#define CoAPResetMsg(header)\
|
||||||
|
(header.type == COAP_MESSAGE_TYPE_RST)
|
||||||
|
|
||||||
|
#define CoAPCONRespMsg(header)\
|
||||||
|
((header.code == COAP_MSG_CODE_205_CONTENT) \
|
||||||
|
&& (header.type == COAP_MESSAGE_TYPE_CON))
|
||||||
|
|
||||||
|
#define CoAPReqMsg(header)\
|
||||||
|
((1 <= header.code) && (32 > header.code))
|
||||||
|
|
||||||
|
|
||||||
|
#define COAP_CUR_VERSION 1
|
||||||
|
#define COAP_WAIT_TIME_MS 2000
|
||||||
|
#define COAP_MAX_MESSAGE_ID 65535
|
||||||
|
#define COAP_MAX_RETRY_COUNT 4
|
||||||
|
#define COAP_ACK_TIMEOUT 2
|
||||||
|
#define COAP_ACK_RANDOM_FACTOR 1
|
||||||
|
#define COAP_MAX_TRANSMISSION_SPAN 10
|
||||||
|
|
||||||
|
int CoAPStrOption_add(CoAPMessage *message, unsigned short optnum, unsigned char *data, unsigned short datalen)
|
||||||
|
{
|
||||||
|
unsigned char *ptr = NULL;
|
||||||
|
if (COAP_MSG_MAX_OPTION_NUM <= message->optcount) {
|
||||||
|
return COAP_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
message->options[message->optcount].num = optnum - message->optdelta;
|
||||||
|
message->options[message->optcount].len = datalen;
|
||||||
|
ptr = (unsigned char *)coap_malloc(datalen);
|
||||||
|
if (NULL == ptr) {
|
||||||
|
return COAP_ERROR_MALLOC;
|
||||||
|
}
|
||||||
|
memset(ptr, 0x00, datalen);
|
||||||
|
memcpy(ptr, data, datalen);
|
||||||
|
message->options[message->optcount].val = ptr;
|
||||||
|
message->optdelta = optnum;
|
||||||
|
message->optcount ++;
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPStrOption_get(CoAPMessage *message, unsigned short optnum, unsigned char *data, unsigned short *datalen)
|
||||||
|
{
|
||||||
|
unsigned char index = 0;
|
||||||
|
|
||||||
|
for (index = 0; index < message->optcount; index++) {
|
||||||
|
if (message->options[index].num == optnum) {
|
||||||
|
if (*datalen >= message->options[index].len) {
|
||||||
|
memcpy(data, message->options[index].val, message->options[index].len);
|
||||||
|
*datalen = message->options[index].len;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
} else {
|
||||||
|
return COAP_ERROR_INVALID_LENGTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return COAP_ERROR_NOT_FOUND;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CoAPUintOption_add(CoAPMessage *message, unsigned short optnum, unsigned int data)
|
||||||
|
{
|
||||||
|
unsigned char *ptr = NULL;
|
||||||
|
if (COAP_MSG_MAX_OPTION_NUM <= message->optcount) {
|
||||||
|
return COAP_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
message->options[message->optcount].num = optnum - message->optdelta;
|
||||||
|
|
||||||
|
if (0 == data) {
|
||||||
|
message->options[message->optcount].len = 0;
|
||||||
|
} else if (255 >= data) {
|
||||||
|
message->options[message->optcount].len = 1;
|
||||||
|
ptr = (unsigned char *)coap_malloc(1);
|
||||||
|
if (NULL != ptr) {
|
||||||
|
*ptr = (unsigned char)data;
|
||||||
|
}
|
||||||
|
} else if (65535 >= data) {
|
||||||
|
message->options[message->optcount].len = 2;
|
||||||
|
ptr = (unsigned char *)coap_malloc(2);
|
||||||
|
if (NULL != ptr) {
|
||||||
|
*ptr = (unsigned char)((data & 0xFF00) >> 8);
|
||||||
|
*(ptr + 1) = (unsigned char)(data & 0x00FF);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message->options[message->optcount].len = 4;
|
||||||
|
ptr = (unsigned char *)coap_malloc(4);
|
||||||
|
if (NULL != ptr) {
|
||||||
|
*ptr = (unsigned char)((data & 0xFF000000) >> 24);
|
||||||
|
*(ptr + 1) = (unsigned char)((data & 0x00FF0000) >> 16);
|
||||||
|
*(ptr + 2) = (unsigned char)((data & 0x0000FF00) >> 8);
|
||||||
|
*(ptr + 3) = (unsigned char)(data & 0x000000FF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message->options[message->optcount].val = ptr;
|
||||||
|
message->optdelta = optnum;
|
||||||
|
message->optcount += 1;
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPUintOption_get(CoAPMessage *message,
|
||||||
|
unsigned short optnum,
|
||||||
|
unsigned int *data)
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned char index = 0;
|
||||||
|
|
||||||
|
for (index = 0; index < message->optcount; index++) {
|
||||||
|
if (message->options[index].num == optnum) {
|
||||||
|
int byte = 0;
|
||||||
|
switch (message->options[index].len) {
|
||||||
|
case 1:
|
||||||
|
*data |= message->options[index].val[byte++];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*data |= (message->options[index].val[byte++] << 8);
|
||||||
|
*data |= message->options[index].val[byte++];
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
*data |= (message->options[index].val[byte++] << 16);
|
||||||
|
*data |= (message->options[index].val[byte++] << 8);
|
||||||
|
*data |= message->options[index].val[byte++];
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*data |= (message->options[index].val[byte++] << 24);
|
||||||
|
*data |= (message->options[index].val[byte++] << 16);
|
||||||
|
*data |= (message->options[index].val[byte++] << 8);
|
||||||
|
*data |= message->options[index].val[byte++];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*data = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return COAP_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CoAPOption_present(CoAPMessage *message, unsigned short option)
|
||||||
|
{
|
||||||
|
unsigned char index = 0;
|
||||||
|
|
||||||
|
|
||||||
|
for (index = 0; index < message->optcount; index++) {
|
||||||
|
if (message->options[index].num == option) {
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return COAP_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessageId_set(CoAPMessage *message, unsigned short msgid)
|
||||||
|
{
|
||||||
|
if (NULL == message) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
message->header.msgid = msgid;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessageType_set(CoAPMessage *message, unsigned char type)
|
||||||
|
{
|
||||||
|
if (NULL == message) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
if (COAP_MESSAGE_TYPE_CON != type && COAP_MESSAGE_TYPE_NON != type
|
||||||
|
&& COAP_MESSAGE_TYPE_ACK != type && COAP_MESSAGE_TYPE_RST != type) {
|
||||||
|
return COAP_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
message->header.type = type;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessageCode_set(CoAPMessage *message, CoAPMessageCode code)
|
||||||
|
{
|
||||||
|
if (NULL == message) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
message->header.code = code;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessageCode_get(CoAPMessage *message, CoAPMessageCode *code)
|
||||||
|
{
|
||||||
|
if (NULL == message || NULL == code) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
*code = message->header.code;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessageToken_set(CoAPMessage *message, unsigned char *token,
|
||||||
|
unsigned char tokenlen)
|
||||||
|
{
|
||||||
|
if (NULL == message || NULL == token) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
if (COAP_MSG_MAX_TOKEN_LEN < tokenlen) {
|
||||||
|
return COAP_ERROR_INVALID_LENGTH;
|
||||||
|
}
|
||||||
|
memcpy(message->token, token, tokenlen);
|
||||||
|
message->header.tokenlen = tokenlen;
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessageUserData_set(CoAPMessage *message, void *userdata)
|
||||||
|
{
|
||||||
|
if (NULL == message || NULL == userdata) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
message->user = userdata;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessageKeep_Set(CoAPMessage *message, int keep)
|
||||||
|
{
|
||||||
|
if (NULL == message || keep < 0) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
message->keep = keep;
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessagePayload_set(CoAPMessage *message, unsigned char *payload,
|
||||||
|
unsigned short payloadlen)
|
||||||
|
{
|
||||||
|
if (NULL == message || (0 < payloadlen && NULL == payload)) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
message->payload = payload;
|
||||||
|
message->payloadlen = payloadlen;
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessage_init(CoAPMessage *message)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
if (NULL == message) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
memset(message, 0x00, sizeof(CoAPMessage));
|
||||||
|
message->header.version = COAP_CUR_VERSION;
|
||||||
|
message->header.type = COAP_MESSAGE_TYPE_ACK;
|
||||||
|
message->header.tokenlen = 0;
|
||||||
|
message->header.code = COAP_MSG_CODE_EMPTY_MESSAGE;
|
||||||
|
message->header.msgid = 0;
|
||||||
|
message->payload = NULL;
|
||||||
|
message->payloadlen = 0;
|
||||||
|
message->optcount = 0;
|
||||||
|
message->optdelta = 0;
|
||||||
|
message->handler = NULL;
|
||||||
|
message->keep = 0;
|
||||||
|
for (count = 0; count < COAP_MSG_MAX_OPTION_NUM; count++) {
|
||||||
|
message->options[count].len = 0;
|
||||||
|
message->options[count].num = 0;
|
||||||
|
message->options[count].val = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPMessage_destory(CoAPMessage *message)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
if (NULL == message) {
|
||||||
|
return COAP_ERROR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (count = 0; count < COAP_MSG_MAX_OPTION_NUM; count++) {
|
||||||
|
if (NULL != message->options[count].val) {
|
||||||
|
coap_free(message->options[count].val);
|
||||||
|
message->options[count].val = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return COAP_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __COAP_PLATFORM_OS_H__
|
||||||
|
#define __COAP_PLATFORM_OS_H__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#ifdef INFRA_MEM_STATS
|
||||||
|
#include "infra_mem_stats.h"
|
||||||
|
#define coap_malloc(size) LITE_malloc(size, MEM_MAGIC, "coap.local")
|
||||||
|
#define coap_free(ptr) LITE_free(ptr)
|
||||||
|
#else
|
||||||
|
#define coap_malloc(size) HAL_Malloc(size)
|
||||||
|
#define coap_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef INFRA_LOG
|
||||||
|
#include "infra_log.h"
|
||||||
|
#define COAP_ERR(...) log_err("coap_local", __VA_ARGS__)
|
||||||
|
#define COAP_WRN(...) log_warning("coap_local", __VA_ARGS__)
|
||||||
|
#define COAP_INFO(...) log_info("coap_local", __VA_ARGS__)
|
||||||
|
#define COAP_TRC(...) log_debug("coap_local", __VA_ARGS__)
|
||||||
|
#define COAP_DUMP(...) log_debug("coap_local", __VA_ARGS__)
|
||||||
|
#define COAP_DEBUG(...) log_debug("coap_local", __VA_ARGS__)
|
||||||
|
#define COAP_FLOW(...) log_flow("coap_local", __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define COAP_ERR(...)
|
||||||
|
#define COAP_WRN(...)
|
||||||
|
#define COAP_INFO(...)
|
||||||
|
#define COAP_TRC(...)
|
||||||
|
#define COAP_DUMP(...)
|
||||||
|
#define COAP_DEBUG(...)
|
||||||
|
#define COAP_FLOW(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int platform_is_multicast(const char *ip_str);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __COAP_SERIALIZE_H__
|
||||||
|
#define __COAP_SERIALIZE_H__
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
unsigned short CoAPSerialize_MessageLength(CoAPMessage *msg);
|
||||||
|
|
||||||
|
int CoAPSerialize_Message(CoAPMessage *msg, unsigned char *buf, unsigned short buflen);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "CoAPSerialize.h"
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
|
|
||||||
|
int CoAPSerialize_Header(CoAPMessage *msg, unsigned char *buf, unsigned short buflen)
|
||||||
|
{
|
||||||
|
if(4 > buflen){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
buf[0] = (((msg->header.version & 0x3) << 6) | ((msg->header.type & 0x3) << 4))
|
||||||
|
| (msg->header.tokenlen & 0x0F);
|
||||||
|
|
||||||
|
buf[1] = msg->header.code;
|
||||||
|
buf[2] = (msg->header.msgid & 0xFF00) >> 8;
|
||||||
|
buf[3] = (msg->header.msgid & 0x00FF);
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPSerialize_Token(CoAPMessage *msg, unsigned char * buf, unsigned short buflen)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if(buflen < msg->header.tokenlen){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < msg->header.tokenlen; i++){
|
||||||
|
buf[i] = msg->token[i];
|
||||||
|
}
|
||||||
|
return msg->header.tokenlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned short CoAPSerialize_Option(CoAPMsgOption *option, unsigned char *buf)
|
||||||
|
{
|
||||||
|
unsigned char *ptr = buf;
|
||||||
|
|
||||||
|
if(269 <= option->num){
|
||||||
|
*ptr = ((14 & 0x0F) << 4);
|
||||||
|
}
|
||||||
|
else if(13 <= option->num){
|
||||||
|
*ptr = ((13 & 0x0F) << 4);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
*ptr = option->num << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (269 <= option->len){
|
||||||
|
*ptr |= (14 & 0x0F);
|
||||||
|
}
|
||||||
|
else if(13 <= option->len){
|
||||||
|
*ptr |= (13 & 0x0F);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
*ptr |= (option->len & 0x0F);
|
||||||
|
}
|
||||||
|
ptr ++;
|
||||||
|
|
||||||
|
if (269 <= option->num){
|
||||||
|
*ptr = (unsigned char)(((option->num - 269) & 0xFF00) >> 8);
|
||||||
|
*(ptr+1) = (unsigned char)(((option->num - 269) & 0x00FF));
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
else if(13 <= option->num){
|
||||||
|
*ptr = (unsigned char)(option->num - 13);
|
||||||
|
ptr ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (269 <= option->len){
|
||||||
|
*ptr = (unsigned char)(((option->len - 269) & 0xFF00) >> 8);
|
||||||
|
*(ptr+1) = (unsigned char)(((option->len - 269) & 0x00FF));
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
else if(13 <= option->len){
|
||||||
|
*ptr = (unsigned char)(option->len - 13);
|
||||||
|
ptr ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
memcpy(ptr, option->val, option->len);
|
||||||
|
ptr += option->len;
|
||||||
|
|
||||||
|
return (int)(ptr - buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short CoAPSerialize_Options(CoAPMessage *msg, unsigned char * buf, unsigned short buflen)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
unsigned short count = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < msg->optcount; i++)
|
||||||
|
{
|
||||||
|
unsigned short len = 0;
|
||||||
|
len = CoAPSerialize_Option(&msg->options[i], &buf[count]);
|
||||||
|
if (0 < len){
|
||||||
|
count += len;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned short CoAPSerialize_OptionLen(CoAPMsgOption *option)
|
||||||
|
{
|
||||||
|
unsigned short len = 1;
|
||||||
|
|
||||||
|
if(269 <= option->num){
|
||||||
|
len += 2;
|
||||||
|
}
|
||||||
|
else if(13 <= option->num){
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
}
|
||||||
|
|
||||||
|
if (269 <= option->len){
|
||||||
|
len += 2;
|
||||||
|
}
|
||||||
|
else if(13 <= option->len){
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
}
|
||||||
|
|
||||||
|
len += option->len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned short CoAPSerialize_OptionsLen(CoAPMessage *msg)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
unsigned short count = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < msg->optcount; i++)
|
||||||
|
{
|
||||||
|
unsigned short len = 0;
|
||||||
|
len = CoAPSerialize_OptionLen(&msg->options[i]);
|
||||||
|
if (0 < len){
|
||||||
|
count += len;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CoAPSerialize_Payload(CoAPMessage *msg, unsigned char *buf, int buflen)
|
||||||
|
{
|
||||||
|
if(msg->payloadlen + 1 > buflen){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(msg->payloadlen > 0 && NULL != msg->payload)
|
||||||
|
{
|
||||||
|
*buf = 0xFF;
|
||||||
|
buf ++;
|
||||||
|
memcpy(buf, msg->payload, msg->payloadlen);
|
||||||
|
return msg->payloadlen + 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned short CoAPSerialize_MessageLength(CoAPMessage *msg)
|
||||||
|
{
|
||||||
|
unsigned short msglen = 4;
|
||||||
|
|
||||||
|
msglen += msg->header.tokenlen;
|
||||||
|
msglen += CoAPSerialize_OptionsLen(msg);
|
||||||
|
|
||||||
|
if(0 < msg->payloadlen){
|
||||||
|
msglen += msg->payloadlen;
|
||||||
|
msglen += 1; /*CoAP payload marker*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return msglen;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoAPSerialize_Message(CoAPMessage *msg, unsigned char *buf, unsigned short buflen)
|
||||||
|
{
|
||||||
|
unsigned char *ptr = buf;
|
||||||
|
unsigned short count = 0;
|
||||||
|
unsigned short remlen = buflen;
|
||||||
|
|
||||||
|
if(NULL == buf || NULL == msg){
|
||||||
|
return COAP_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = CoAPSerialize_Header(msg, ptr, remlen);
|
||||||
|
ptr += count;
|
||||||
|
remlen -= count;
|
||||||
|
|
||||||
|
count = CoAPSerialize_Token(msg, ptr, remlen);
|
||||||
|
ptr += count;
|
||||||
|
remlen -= count;
|
||||||
|
|
||||||
|
count = CoAPSerialize_Options(msg, ptr, remlen);
|
||||||
|
ptr += count;
|
||||||
|
remlen -= count;
|
||||||
|
|
||||||
|
count = CoAPSerialize_Payload(msg, ptr, remlen);
|
||||||
|
ptr += count;
|
||||||
|
remlen -= count;
|
||||||
|
|
||||||
|
return (buflen-remlen);
|
||||||
|
}
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __IOTX_COAP_API_H__
|
||||||
|
#define __IOTX_COAP_API_H__
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "infra_defs.h"
|
||||||
|
|
||||||
|
/*iotx return code definition*/
|
||||||
|
typedef enum {
|
||||||
|
IOTX_ERR_RECV_MSG_TIMEOUT = -9, /*Receive message timeout */
|
||||||
|
IOTX_ERR_SEND_MSG_FAILED = -8, /* Send message failed*/
|
||||||
|
IOTX_ERR_MSG_TOO_LOOG = -7, /* The payload too loog */
|
||||||
|
IOTX_ERR_URI_TOO_LOOG = -6, /* URI length too long */
|
||||||
|
IOTX_ERR_NOT_AUTHED = -5, /* Client isn't authed */
|
||||||
|
IOTX_ERR_AUTH_FAILED = -4, /* Client authed failed */
|
||||||
|
IOTX_ERR_BUFF_TOO_SHORT = -3, /* Buffer too short */
|
||||||
|
IOTX_ERR_NO_MEM = -2, /* Malloc failed */
|
||||||
|
IOTX_ERR_INVALID_PARAM = -1, /* Invalid parameter */
|
||||||
|
IOTX_SUCCESS = 0, /* Success */
|
||||||
|
} iotx_ret_code_t;
|
||||||
|
|
||||||
|
/* The message payload encode format */
|
||||||
|
typedef enum {
|
||||||
|
IOTX_CONTENT_TYPE_JSON,
|
||||||
|
IOTX_CONTENT_TYPE_CBOR,
|
||||||
|
} iotx_content_type_t;
|
||||||
|
|
||||||
|
/* The message type */
|
||||||
|
typedef enum {
|
||||||
|
IOTX_MESSAGE_CON = 0, /* confirmable message */
|
||||||
|
IOTX_MESSAGE_NON = 1, /* non-confirmable message */
|
||||||
|
IOTX_MESSAGE_ACK = 2, /* acknowledgement message */
|
||||||
|
IOTX_MESSAGE_RST = 3, /* reset message */
|
||||||
|
} iotx_msg_type_t;
|
||||||
|
|
||||||
|
/* IoTx events to notify application */
|
||||||
|
typedef enum {
|
||||||
|
IOTX_COAP_EVENT_SEND_FAILED = 0,
|
||||||
|
IOTX_COAP_EVENT_RECV_FAILED = 1,
|
||||||
|
IOTX_COAP_EVENT_AUTH_FAILED = 2,
|
||||||
|
} iotx_coap_event_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
IOTX_COAP_RESP_CODE_CONTENT = 0x45, /* Mapping to 2.05, Content*/
|
||||||
|
IOTX_COAP_RESP_CODE_BAD_REQUEST = 0x80, /* Mapping to 4.00, Bad Request*/
|
||||||
|
IOTX_COAP_RESP_CODE_UNAUTHORIZED = 0x81, /* Mapping to 4.01, Token is invalid or expire*/
|
||||||
|
IOTX_COAP_RESP_CODE_NOT_FOUND = 0x84, /* Mapping to 4.04, Path or uri is not found*/
|
||||||
|
IOTX_COAP_RESP_CODE_URL_TOO_LONG = 0x8E, /* Mapping to 4.14, The request url is too long*/
|
||||||
|
IOTX_COAP_RESP_CODE_INTERNAL_SERVER_ERROR = 0xA0,/* Mapping to 5.00, Internal server error*/
|
||||||
|
|
||||||
|
} iotx_coap_resp_code_t;
|
||||||
|
|
||||||
|
/* Callback function to notify the application events.*/
|
||||||
|
typedef void (*iotx_event_handle_t)(void *context, iotx_coap_event_t event, void *p_data);
|
||||||
|
|
||||||
|
/*IoTx device*/
|
||||||
|
typedef struct {
|
||||||
|
char product_key[IOTX_PRODUCT_KEY_LEN + 1];
|
||||||
|
char device_name[IOTX_DEVICE_NAME_LEN + 1];
|
||||||
|
char device_id[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 2];
|
||||||
|
char device_secret[IOTX_DEVICE_SECRET_LEN + 1];
|
||||||
|
} iotx_deviceinfo_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char product_key[IOTX_PRODUCT_KEY_LEN + 1];
|
||||||
|
char device_name[IOTX_DEVICE_NAME_LEN + 1];
|
||||||
|
char device_id[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 2];
|
||||||
|
char device_secret[IOTX_DEVICE_SECRET_LEN + 1];
|
||||||
|
char module_vendor_id[IOTX_PARTNER_ID_LEN + 1];
|
||||||
|
} iotx_device_info_t;
|
||||||
|
|
||||||
|
/* IoTx initializa parameters */
|
||||||
|
typedef struct {
|
||||||
|
char *p_url; /*Can be NULL*/
|
||||||
|
int wait_time_ms; /*unit is micro second*/
|
||||||
|
iotx_device_info_t *p_devinfo; /*Device info*/
|
||||||
|
iotx_event_handle_t event_handle; /*TODO, not supported now*/
|
||||||
|
} iotx_coap_config_t;
|
||||||
|
|
||||||
|
/* Callback function to handle the response message.*/
|
||||||
|
typedef void (*iotx_response_callback_t)(void *p_arg, void *p_message);
|
||||||
|
|
||||||
|
/* IoTx message definition */
|
||||||
|
typedef struct {
|
||||||
|
unsigned char *p_payload;
|
||||||
|
unsigned short payload_len;
|
||||||
|
iotx_content_type_t content_type;
|
||||||
|
iotx_msg_type_t msg_type;
|
||||||
|
void *user_data;
|
||||||
|
iotx_response_callback_t resp_callback;
|
||||||
|
} iotx_message_t;
|
||||||
|
|
||||||
|
|
||||||
|
/*iotx coap context definition*/
|
||||||
|
typedef void iotx_coap_context_t;
|
||||||
|
|
||||||
|
|
||||||
|
/** @defgroup group_api api
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @defgroup group_api_coap coap
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the CoAP client.
|
||||||
|
* This function initialize the data structures and network,
|
||||||
|
* and create the DTLS session.
|
||||||
|
*
|
||||||
|
* @param [in] p_config: Specify the CoAP client parameter.
|
||||||
|
*
|
||||||
|
* @retval NULL : Initialize failed.
|
||||||
|
* @retval NOT_NULL : The contex of CoAP client.
|
||||||
|
* @see None.
|
||||||
|
*/
|
||||||
|
iotx_coap_context_t *IOT_CoAP_Init(iotx_coap_config_t *p_config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief De-initialize the CoAP client.
|
||||||
|
* This function release CoAP DTLS session.
|
||||||
|
* and release the related resource.
|
||||||
|
*
|
||||||
|
* @param [in] p_context: Pointer of contex, specify the CoAP client.
|
||||||
|
*
|
||||||
|
* @return None.
|
||||||
|
* @see None.
|
||||||
|
*/
|
||||||
|
DLL_IOT_API void IOT_CoAP_Deinit(iotx_coap_context_t **p_context);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle device name authentication with remote server.
|
||||||
|
*
|
||||||
|
* @param [in] p_context: Pointer of contex, specify the CoAP client.
|
||||||
|
*
|
||||||
|
* @retval IOTX_SUCCESS : Authenticate success.
|
||||||
|
* @retval IOTX_ERR_SEND_MSG_FAILED : Send authentication message failed.
|
||||||
|
* @retval IOTX_ERR_AUTH_FAILED : Authenticate failed or timeout.
|
||||||
|
* @see iotx_ret_code_t.
|
||||||
|
*/
|
||||||
|
DLL_IOT_API int IOT_CoAP_DeviceNameAuth(iotx_coap_context_t *p_context);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle CoAP response packet from remote server,
|
||||||
|
* and process timeout request etc..
|
||||||
|
*
|
||||||
|
* @param [in] p_context : Pointer of contex, specify the CoAP client.
|
||||||
|
*
|
||||||
|
* @return status.
|
||||||
|
* @see iotx_ret_code_t.
|
||||||
|
*/
|
||||||
|
DLL_IOT_API int IOT_CoAP_Yield(iotx_coap_context_t *p_context);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a message with specific path to server.
|
||||||
|
* Client must authentication with server before send message.
|
||||||
|
*
|
||||||
|
* @param [in] p_context : Pointer of contex, specify the CoAP client.
|
||||||
|
* @param [in] p_path: Specify the path name.
|
||||||
|
* @param [in] p_message: Message to be sent.
|
||||||
|
*
|
||||||
|
* @retval IOTX_SUCCESS : Send the message success.
|
||||||
|
* @retval IOTX_ERR_MSG_TOO_LOOG : The message length is too long.
|
||||||
|
* @retval IOTX_ERR_NOT_AUTHED : The client hasn't authenticated with server
|
||||||
|
* @see iotx_ret_code_t.
|
||||||
|
*/
|
||||||
|
DLL_IOT_API int IOT_CoAP_SendMessage(iotx_coap_context_t *p_context, char *p_path, iotx_message_t *p_message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves the length and payload pointer of specified message.
|
||||||
|
*
|
||||||
|
* @param [in] p_message: Pointer to the message to get the payload. Should not be NULL.
|
||||||
|
* @param [out] pp_payload: Pointer to the payload.
|
||||||
|
* @param [out] p_len: Size of the payload.
|
||||||
|
*
|
||||||
|
* @retval IOTX_SUCCESS : Get the payload success.
|
||||||
|
* @retval IOTX_ERR_INVALID_PARAM : Can't get the payload due to invalid parameter.
|
||||||
|
* @see iotx_ret_code_t.
|
||||||
|
**/
|
||||||
|
DLL_IOT_API int IOT_CoAP_GetMessagePayload(void *p_message, unsigned char **pp_payload, int *p_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the response code from a CoAP message.
|
||||||
|
*
|
||||||
|
* @param [in] p_message: Pointer to the message to add the address information to.
|
||||||
|
* Should not be NULL.
|
||||||
|
* @param [out] p_resp_code: The response code.
|
||||||
|
*
|
||||||
|
* @retval IOTX_SUCCESS : When get the response code to message success.
|
||||||
|
* @retval IOTX_ERR_INVALID_PARAM : Pointer to the message is NULL.
|
||||||
|
* @see iotx_ret_code_t.
|
||||||
|
**/
|
||||||
|
DLL_IOT_API int IOT_CoAP_GetMessageCode(void *p_message, iotx_coap_resp_code_t *p_resp_code);
|
||||||
|
|
||||||
|
/** @} */ /* end of api_coap */
|
||||||
|
/** @} */ /* end of api */
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
#ifndef _COAP_WRAPPER_H_
|
||||||
|
#define _COAP_WRAPPER_H_
|
||||||
|
|
||||||
|
#include "infra_types.h"
|
||||||
|
#include "infra_defs.h"
|
||||||
|
#include "infra_compat.h"
|
||||||
|
#include "wrappers_defs.h"
|
||||||
|
|
||||||
|
void *HAL_Malloc(uint32_t size);
|
||||||
|
void HAL_Free(void *ptr);
|
||||||
|
void HAL_SleepMs(uint32_t ms);
|
||||||
|
uint64_t HAL_UptimeMs(void);
|
||||||
|
void HAL_Srandom(uint32_t seed);
|
||||||
|
uint32_t HAL_Random(uint32_t region);
|
||||||
|
void HAL_Printf(const char *fmt, ...);
|
||||||
|
int HAL_Snprintf(char *str, const int len, const char *fmt, ...);
|
||||||
|
|
||||||
|
int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN]);
|
||||||
|
int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN]);
|
||||||
|
int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN]);
|
||||||
|
|
||||||
|
int HAL_SetProductKey(char *product_key);
|
||||||
|
int HAL_SetProductSecret(char *product_secret);
|
||||||
|
int HAL_SetDeviceName(char *device_name);
|
||||||
|
int HAL_SetDeviceSecret(char *device_secret);
|
||||||
|
|
||||||
|
DLL_HAL_API int HAL_DTLSHooks_set(dtls_hooks_t *hooks);
|
||||||
|
DLL_HAL_API DTLSContext *HAL_DTLSSession_create(coap_dtls_options_t *p_options);
|
||||||
|
DLL_HAL_API unsigned int HAL_DTLSSession_write(DTLSContext *context,
|
||||||
|
const unsigned char *p_data,
|
||||||
|
unsigned int *p_datalen);
|
||||||
|
DLL_HAL_API unsigned int HAL_DTLSSession_read(DTLSContext *context,
|
||||||
|
unsigned char *p_data,
|
||||||
|
unsigned int *p_datalen,
|
||||||
|
unsigned int timeout_ms);
|
||||||
|
DLL_HAL_API unsigned int HAL_DTLSSession_free(DTLSContext *context);
|
||||||
|
intptr_t HAL_UDP_create(char *host, unsigned short port);
|
||||||
|
intptr_t HAL_UDP_create_without_connect(const char *host, unsigned short port);
|
||||||
|
int HAL_UDP_write(intptr_t p_socket,
|
||||||
|
const unsigned char *p_data,
|
||||||
|
unsigned int datalen);
|
||||||
|
int HAL_UDP_readTimeout(intptr_t p_socket,
|
||||||
|
unsigned char *p_data,
|
||||||
|
unsigned int datalen,
|
||||||
|
unsigned int timeout);
|
||||||
|
int HAL_UDP_close_without_connect(intptr_t sockfd);
|
||||||
|
int HAL_UDP_recvfrom(intptr_t sockfd,
|
||||||
|
NetworkAddr *p_remote,
|
||||||
|
unsigned char *p_data,
|
||||||
|
unsigned int datalen,
|
||||||
|
unsigned int timeout_ms);
|
||||||
|
int HAL_UDP_sendto(intptr_t sockfd,
|
||||||
|
const NetworkAddr *p_remote,
|
||||||
|
const unsigned char *p_data,
|
||||||
|
unsigned int datalen,
|
||||||
|
unsigned int timeout_ms);
|
||||||
|
int HAL_UDP_joinmulticast(intptr_t sockfd,
|
||||||
|
char *p_group);
|
||||||
|
uint32_t HAL_Wifi_Get_IP(char ip_str[NETWORK_ADDR_LEN], const char *ifname);
|
||||||
|
p_HAL_Aes128_t HAL_Aes128_Init(
|
||||||
|
const uint8_t *key,
|
||||||
|
const uint8_t *iv,
|
||||||
|
AES_DIR_t dir);
|
||||||
|
int HAL_Aes128_Destroy(p_HAL_Aes128_t aes);
|
||||||
|
int HAL_Aes128_Cbc_Encrypt(
|
||||||
|
p_HAL_Aes128_t aes,
|
||||||
|
const void *src,
|
||||||
|
size_t blockNum,
|
||||||
|
void *dst);
|
||||||
|
int HAL_Aes128_Cbc_Decrypt(
|
||||||
|
p_HAL_Aes128_t aes,
|
||||||
|
const void *src,
|
||||||
|
size_t blockNum,
|
||||||
|
void *dst);
|
||||||
|
void *HAL_MutexCreate(void);
|
||||||
|
void HAL_MutexDestroy(void *mutex);
|
||||||
|
void HAL_MutexLock(void *mutex);
|
||||||
|
void HAL_MutexUnlock(void *mutex);
|
||||||
|
void *HAL_SemaphoreCreate(void);
|
||||||
|
void HAL_SemaphoreDestroy(void *sem);
|
||||||
|
int HAL_SemaphoreWait(void *sem, uint32_t timeout_ms);
|
||||||
|
void HAL_SemaphorePost(void *sem);
|
||||||
|
int HAL_ThreadCreate(
|
||||||
|
void **thread_handle,
|
||||||
|
void *(*work_routine)(void *),
|
||||||
|
void *arg,
|
||||||
|
hal_os_thread_param_t *hal_os_thread_param,
|
||||||
|
int *stack_used);
|
||||||
|
void HAL_ThreadDelete(void *thread_handle);
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#include "CoAPServer.h"
|
||||||
|
#include "iotx_coap_internal.h"
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef __IOTX_COAP_CONFIG__
|
||||||
|
#define __IOTX_COAP_CONFIG__
|
||||||
|
|
||||||
|
#define COAP_MSG_MAX_TOKEN_LEN 8
|
||||||
|
#define COAP_MSG_MAX_OPTION_NUM 12
|
||||||
|
#define COAP_MSG_MAX_PATH_LEN 128
|
||||||
|
#ifndef COAP_LARGE_MEMORY_SUPPORT
|
||||||
|
#define COAP_MSG_MAX_PDU_LEN 1280
|
||||||
|
#else
|
||||||
|
#define COAP_MSG_MAX_PDU_LEN 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_COAP_AUTH_TIMEOUT
|
||||||
|
#define CONFIG_COAP_AUTH_TIMEOUT (3 * 1000)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __IOTX_COAP_INTERNAL__
|
||||||
|
#define __IOTX_COAP_INTERNAL__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "infra_string.h"
|
||||||
|
#include "infra_compat.h"
|
||||||
|
#include "infra_types.h"
|
||||||
|
#include "infra_defs.h"
|
||||||
|
#include "infra_log.h"
|
||||||
|
#include "infra_json_parser.h"
|
||||||
|
#include "infra_cjson.h"
|
||||||
|
#include "infra_list.h"
|
||||||
|
#include "infra_md5.h"
|
||||||
|
#include "infra_sha256.h"
|
||||||
|
#include "infra_report.h"
|
||||||
|
#include "iotx_coap_config.h"
|
||||||
|
#include "coap_wrapper.h"
|
||||||
|
#include "iotx_coap_config.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/*CoAP Content Type*/
|
||||||
|
#define COAP_CT_TEXT_PLAIN 0 /* text/plain (UTF-8) */
|
||||||
|
#define COAP_CT_APP_LINK_FORMAT 40 /* application/link-format */
|
||||||
|
#define COAP_CT_APP_XML 41 /* application/xml */
|
||||||
|
#define COAP_CT_APP_OCTET_STREAM 42 /* application/octet-stream */
|
||||||
|
#define COAP_CT_APP_RDF_XML 43 /* application/rdf+xml */
|
||||||
|
#define COAP_CT_APP_EXI 47 /* application/exi */
|
||||||
|
#define COAP_CT_APP_JSON 50 /* application/json */
|
||||||
|
#define COAP_CT_APP_CBOR 60 /* application/cbor */
|
||||||
|
|
||||||
|
/*CoAP option types. */
|
||||||
|
#define COAP_OPTION_IF_MATCH 1 /* C, opaque, 0-8 B, (none) */
|
||||||
|
#define COAP_OPTION_URI_HOST 3 /* C, String, 1-255 B, destination address */
|
||||||
|
#define COAP_OPTION_ETAG 4 /* E, opaque, 1-8 B, (none) */
|
||||||
|
#define COAP_OPTION_IF_NONE_MATCH 5 /* empty, 0 B, (none) */
|
||||||
|
#define COAP_OPTION_OBSERVE 6 /* E, empty/uint, 0 B/0-3 B, (none)*/
|
||||||
|
#define COAP_OPTION_URI_PORT 7 /* C, uint, 0-2 B, destination port */
|
||||||
|
#define COAP_OPTION_LOCATION_PATH 8 /* E, String, 0-255 B, - */
|
||||||
|
#define COAP_OPTION_URI_PATH 11 /* C, String, 0-255 B, (none) */
|
||||||
|
#define COAP_OPTION_CONTENT_FORMAT 12 /* E, uint, 0-2 B, (none) */
|
||||||
|
#define COAP_OPTION_MAXAGE 14 /* E, uint, 0--4 B, 60 Seconds */
|
||||||
|
#define COAP_OPTION_URI_QUERY 15 /* C, String, 1-255 B, (none) */
|
||||||
|
#define COAP_OPTION_ACCEPT 17 /* C, uint, 0-2 B, (none) */
|
||||||
|
#define COAP_OPTION_LOCATION_QUERY 20 /* E, String, 0-255 B, (none) */
|
||||||
|
#define COAP_OPTION_BLOCK2 23 /* C, uint, 0--3 B, (none) */
|
||||||
|
#define COAP_OPTION_BLOCK1 27 /* C, uint, 0--3 B, (none) */
|
||||||
|
#define COAP_OPTION_PROXY_URI 35 /* C, String, 1-1024 B, (none) */
|
||||||
|
#define COAP_OPTION_PROXY_SCHEME 39 /* C, String, 1-255 B, (none) */
|
||||||
|
#define COAP_OPTION_SIZE1 60 /* E, uint, 0-4 B, (none) */
|
||||||
|
#define COAP_OPTION_AUTH_TOKEN 61 /* C, String, 1-255B, (none)*/
|
||||||
|
|
||||||
|
#define COAP_PERM_NONE 0x0000
|
||||||
|
#define COAP_PERM_GET 0x0001
|
||||||
|
#define COAP_PERM_POST 0x0002
|
||||||
|
#define COAP_PERM_PUT 0x0004
|
||||||
|
#define COAP_PERM_DELETE 0x0008
|
||||||
|
#define COAP_PERM_OBSERVE 0x0100
|
||||||
|
|
||||||
|
/*CoAP Message types*/
|
||||||
|
#define COAP_MESSAGE_TYPE_CON 0
|
||||||
|
#define COAP_MESSAGE_TYPE_NON 1
|
||||||
|
#define COAP_MESSAGE_TYPE_ACK 2
|
||||||
|
#define COAP_MESSAGE_TYPE_RST 3
|
||||||
|
|
||||||
|
/* CoAP module error code base */
|
||||||
|
#define COAP_ERROR_BASE (1<<8)
|
||||||
|
#define COAP_ERROR_DTLS_BASE (1<<16)
|
||||||
|
|
||||||
|
/* CoAP base error code */
|
||||||
|
#define COAP_SUCCESS (0) /* Successful */
|
||||||
|
#define COAP_ERROR_INVALID_PARAM (COAP_ERROR_BASE | 1) /* Invalid Parameter */
|
||||||
|
#define COAP_ERROR_NULL (COAP_ERROR_BASE | 2) /* Null Pointer */
|
||||||
|
#define COAP_ERROR_MALLOC (COAP_ERROR_BASE | 3)
|
||||||
|
#define COAP_ERROR_INVALID_LENGTH (COAP_ERROR_BASE | 4) /* Invalid Length */
|
||||||
|
#define COAP_ERROR_DATA_SIZE (COAP_ERROR_BASE | 5) /* Data size exceeds limit */
|
||||||
|
#define COAP_ERROR_INVALID_URI (COAP_ERROR_BASE | 6)
|
||||||
|
#define COAP_ERROR_NOT_FOUND (COAP_ERROR_BASE | 7)
|
||||||
|
#define COAP_ERROR_NET_INIT_FAILED (COAP_ERROR_BASE | 8)
|
||||||
|
#define COAP_ERROR_INTERNAL (COAP_ERROR_BASE | 9) /* Internal Error */
|
||||||
|
#define COAP_ERROR_WRITE_FAILED (COAP_ERROR_BASE | 10)
|
||||||
|
#define COAP_ERROR_READ_FAILED (COAP_ERROR_BASE | 11)
|
||||||
|
#define COAP_ERROR_ENCRYPT_FAILED (COAP_ERROR_BASE | 12)
|
||||||
|
#define COAP_ERROR_UNSUPPORTED (COAP_ERROR_BASE | 13)
|
||||||
|
#define COAP_ERROR_OBJ_ALREADY_EXIST (COAP_ERROR_BASE | 14)
|
||||||
|
|
||||||
|
#define COAP_MSG_CODE_DEF(N) (((N)/100 << 5) | (N)%100)
|
||||||
|
|
||||||
|
/*CoAP Message codes*/
|
||||||
|
typedef enum {
|
||||||
|
/* CoAP Empty Message */
|
||||||
|
COAP_MSG_CODE_EMPTY_MESSAGE = COAP_MSG_CODE_DEF(0), /* Mapping to CoAP code 0.00 */
|
||||||
|
|
||||||
|
/* CoAP Method Codes */
|
||||||
|
COAP_MSG_CODE_GET = COAP_MSG_CODE_DEF(1), /* CoAP Get method */
|
||||||
|
COAP_MSG_CODE_POST = COAP_MSG_CODE_DEF(2), /* CoAP Post method */
|
||||||
|
COAP_MSG_CODE_PUT = COAP_MSG_CODE_DEF(3), /* CoAP Put method */
|
||||||
|
COAP_MSG_CODE_DELETE = COAP_MSG_CODE_DEF(4), /* CoAP Delete method */
|
||||||
|
|
||||||
|
/* CoAP Success Response Codes */
|
||||||
|
COAP_MSG_CODE_201_CREATED = COAP_MSG_CODE_DEF(201), /* Mapping to CoAP code 2.01, Hex:0x41, Created */
|
||||||
|
COAP_MSG_CODE_202_DELETED = COAP_MSG_CODE_DEF(202), /* Mapping to CoAP code 2.02, Hex:0x42, Deleted*/
|
||||||
|
COAP_MSG_CODE_203_VALID = COAP_MSG_CODE_DEF(203), /* Mapping to CoAP code 2.03, Hex:0x43, Valid*/
|
||||||
|
COAP_MSG_CODE_204_CHANGED = COAP_MSG_CODE_DEF(204), /* Mapping to CoAP code 2.04, Hex:0x44, Changed*/
|
||||||
|
COAP_MSG_CODE_205_CONTENT = COAP_MSG_CODE_DEF(205), /* Mapping to CoAP code 2.05, Hex:0x45, Content*/
|
||||||
|
COAP_MSG_CODE_231_CONTINUE = COAP_MSG_CODE_DEF(231), /* Mapping to CoAP code 2.31, Hex:0x5F, Continue*/
|
||||||
|
|
||||||
|
/* CoAP Client Error Response Codes */
|
||||||
|
COAP_MSG_CODE_400_BAD_REQUEST = COAP_MSG_CODE_DEF(400), /* Mapping to CoAP code 4.00, Hex:0x80, Bad Request */
|
||||||
|
COAP_MSG_CODE_401_UNAUTHORIZED = COAP_MSG_CODE_DEF(401), /* Mapping to CoAP code 4.01, Hex:0x81, Unauthorized */
|
||||||
|
COAP_MSG_CODE_402_BAD_OPTION = COAP_MSG_CODE_DEF(402), /* Mapping to CoAP code 4.02, Hex:0x82, Bad Option */
|
||||||
|
COAP_MSG_CODE_403_FORBIDDEN = COAP_MSG_CODE_DEF(403), /* Mapping to CoAP code 4.03, Hex:0x83, Forbidden */
|
||||||
|
COAP_MSG_CODE_404_NOT_FOUND = COAP_MSG_CODE_DEF(404), /* Mapping to CoAP code 4.04, Hex:0x84, Not Found */
|
||||||
|
COAP_MSG_CODE_405_METHOD_NOT_ALLOWED = COAP_MSG_CODE_DEF(405), /* Mapping to CoAP code 4.05, Hex:0x85, Method Not Allowed */
|
||||||
|
COAP_MSG_CODE_406_NOT_ACCEPTABLE = COAP_MSG_CODE_DEF(406), /* Mapping to CoAP code 4.06, Hex:0x86, Not Acceptable */
|
||||||
|
COAP_MSG_CODE_408_REQUEST_ENTITY_INCOMPLETE = COAP_MSG_CODE_DEF(408), /* Mapping to CoAP code 4.08, Hex:0x88, Request Entity Incomplete */
|
||||||
|
COAP_MSG_CODE_412_PRECONDITION_FAILED = COAP_MSG_CODE_DEF(412), /* Mapping to CoAP code 4.12, Hex:0x8C, Precondition Failed */
|
||||||
|
COAP_MSG_CODE_413_REQUEST_ENTITY_TOO_LARGE = COAP_MSG_CODE_DEF(413), /* Mapping to CoAP code 4.13, Hex:0x8D, Request Entity Too Large */
|
||||||
|
COAP_MSG_CODE_415_UNSUPPORTED_CONTENT_FORMAT = COAP_MSG_CODE_DEF(415), /* Mapping to CoAP code 4.15, Hex:0x8F, Unsupported Content-Format */
|
||||||
|
|
||||||
|
/* CoAP Server Error Response Codes */
|
||||||
|
COAP_MSG_CODE_500_INTERNAL_SERVER_ERROR = COAP_MSG_CODE_DEF(500), /* Mapping to CoAP code 5.00, Hex:0xA0, Internal Server Error */
|
||||||
|
COAP_MSG_CODE_501_NOT_IMPLEMENTED = COAP_MSG_CODE_DEF(501), /* Mapping to CoAP code 5.01, Hex:0xA1, Not Implemented */
|
||||||
|
COAP_MSG_CODE_502_BAD_GATEWAY = COAP_MSG_CODE_DEF(502), /* Mapping to CoAP code 5.02, Hex:0xA2, Bad Gateway */
|
||||||
|
COAP_MSG_CODE_503_SERVICE_UNAVAILABLE = COAP_MSG_CODE_DEF(503), /* Mapping to CoAP code 5.03, Hex:0xA3, Service Unavailable */
|
||||||
|
COAP_MSG_CODE_504_GATEWAY_TIMEOUT = COAP_MSG_CODE_DEF(504), /* Mapping to CoAP code 5.04, Hex:0xA4, Gateway Timeout */
|
||||||
|
COAP_MSG_CODE_505_PROXYING_NOT_SUPPORTED = COAP_MSG_CODE_DEF(505) /* Mapping to CoAP code 5.05, Hex:0xA5, Proxying Not Supported */
|
||||||
|
|
||||||
|
} CoAPMessageCode;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
COAP_REQUEST_SUCCESS = 0,
|
||||||
|
COAP_RECV_RESP_TIMEOUT,
|
||||||
|
COAP_RECV_RESP_SUC,
|
||||||
|
} CoAPReqResult;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int len;
|
||||||
|
unsigned char *data;
|
||||||
|
} CoAPLenString;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char version : 2;
|
||||||
|
unsigned char type : 2;
|
||||||
|
unsigned char tokenlen : 4;
|
||||||
|
unsigned char code;
|
||||||
|
unsigned short msgid;
|
||||||
|
} CoAPMsgHeader;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned short num;
|
||||||
|
unsigned short len;
|
||||||
|
unsigned char *val;
|
||||||
|
} CoAPMsgOption;
|
||||||
|
|
||||||
|
typedef void CoAPContext;
|
||||||
|
typedef struct CoAPMessage CoAPMessage;
|
||||||
|
|
||||||
|
typedef void (*CoAPSendMsgHandler)(CoAPContext *context, CoAPReqResult result, void *userdata, NetworkAddr *remote,
|
||||||
|
CoAPMessage *message);
|
||||||
|
|
||||||
|
typedef void (*CoAPEventNotifier)(unsigned int event, NetworkAddr *remote, void *message);
|
||||||
|
|
||||||
|
typedef void (*CoAPRecvMsgHandler)(CoAPContext *context, const char *paths, NetworkAddr *remote, CoAPMessage *message);
|
||||||
|
|
||||||
|
typedef int (*CoAPDataEncrypt)(CoAPContext *context, const char *paths, NetworkAddr *addr, CoAPMessage *message,
|
||||||
|
CoAPLenString *src, CoAPLenString *dest);
|
||||||
|
typedef void (*CoAPRespMsgHandler)(void *data, void *message);
|
||||||
|
|
||||||
|
struct CoAPMessage {
|
||||||
|
CoAPMsgHeader header;
|
||||||
|
unsigned char token[COAP_MSG_MAX_TOKEN_LEN];
|
||||||
|
CoAPMsgOption options[COAP_MSG_MAX_OPTION_NUM];
|
||||||
|
unsigned char optcount;
|
||||||
|
unsigned char optdelta;
|
||||||
|
unsigned short payloadlen;
|
||||||
|
unsigned char *payload;
|
||||||
|
CoAPSendMsgHandler handler;
|
||||||
|
CoAPRespMsgHandler resp;
|
||||||
|
void *user;
|
||||||
|
int keep;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* CoAP message options APIs*/
|
||||||
|
extern int CoAPStrOption_add(CoAPMessage *message, unsigned short optnum,
|
||||||
|
unsigned char *data, unsigned short datalen);
|
||||||
|
|
||||||
|
extern int CoAPStrOption_get(CoAPMessage *message, unsigned short optnum,
|
||||||
|
unsigned char *data, unsigned short *datalen);
|
||||||
|
|
||||||
|
extern int CoAPUintOption_add(CoAPMessage *message, unsigned short optnum,
|
||||||
|
unsigned int data);
|
||||||
|
|
||||||
|
extern int CoAPUintOption_get(CoAPMessage *message,
|
||||||
|
unsigned short optnum,
|
||||||
|
unsigned int *data);
|
||||||
|
|
||||||
|
extern int CoAPOption_present(CoAPMessage *message, unsigned short option);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern int CoAPMessageId_set(CoAPMessage *message, unsigned short msgid);
|
||||||
|
|
||||||
|
extern int CoAPMessageType_set(CoAPMessage *message, unsigned char type);
|
||||||
|
|
||||||
|
extern int CoAPMessageCode_set(CoAPMessage *message, CoAPMessageCode code);
|
||||||
|
|
||||||
|
extern int CoAPMessageCode_get(CoAPMessage *message, CoAPMessageCode *code);
|
||||||
|
|
||||||
|
extern int CoAPMessageToken_set(CoAPMessage *message, unsigned char *token,
|
||||||
|
unsigned char tokenlen);
|
||||||
|
|
||||||
|
extern int CoAPMessageUserData_set(CoAPMessage *message, void *userdata);
|
||||||
|
|
||||||
|
extern int CoAPMessageKeep_Set(CoAPMessage *message, int keep);
|
||||||
|
|
||||||
|
extern int CoAPMessagePayload_set(CoAPMessage *message, unsigned char *payload,
|
||||||
|
unsigned short payloadlen);
|
||||||
|
|
||||||
|
extern int CoAPMessageHandler_set(CoAPMessage *message, CoAPSendMsgHandler handler);
|
||||||
|
|
||||||
|
extern int CoAPMessage_init(CoAPMessage *message);
|
||||||
|
|
||||||
|
extern int CoAPMessage_destory(CoAPMessage *message);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||