فهرست منبع

refactor: 使用coreMqtt重构

RyanCW 6 ماه پیش
والد
کامیت
a867343c74
72فایلهای تغییر یافته به همراه9305 افزوده شده و 6983 حذف شده
  1. 118 0
      .clang-format
  2. 2 0
      .clang-format-ignore
  3. 79 0
      .clang-tidy
  4. 22 4
      .vscode/settings.json
  5. 2 0
      Makefile
  6. 60 50
      common/RyanList.c
  7. 36 46
      common/RyanList.h
  8. 40 0
      common/RyanMqttLog.c
  9. 9 64
      common/RyanMqttLog.h
  10. 191 0
      coreMqtt/core_mqtt_config_defaults.h
  11. 2706 0
      coreMqtt/core_mqtt_serializer.c
  12. 1314 0
      coreMqtt/core_mqtt_serializer.h
  13. 408 418
      example/RyanMqttTest.c
  14. 635 277
      mqttclient/RyanMqttClient.c
  15. 157 125
      mqttclient/RyanMqttClient.h
  16. 223 152
      mqttclient/RyanMqttPublic.h
  17. 666 545
      mqttclient/RyanMqttThread.c
  18. 7 10
      mqttclient/RyanMqttThread.h
  19. 555 351
      mqttclient/RyanMqttUtile.c
  20. 46 29
      mqttclient/RyanMqttUtile.h
  21. 0 148
      pahoMqtt/MQTTConnect.h
  22. 0 214
      pahoMqtt/MQTTConnectClient.c
  23. 0 148
      pahoMqtt/MQTTConnectServer.c
  24. 0 107
      pahoMqtt/MQTTDeserializePublish.c
  25. 0 262
      pahoMqtt/MQTTFormat.c
  26. 0 37
      pahoMqtt/MQTTFormat.h
  27. 0 413
      pahoMqtt/MQTTPacket.c
  28. 0 133
      pahoMqtt/MQTTPacket.h
  29. 0 38
      pahoMqtt/MQTTPublish.h
  30. 0 169
      pahoMqtt/MQTTSerializePublish.c
  31. 0 39
      pahoMqtt/MQTTSubscribe.h
  32. 0 137
      pahoMqtt/MQTTSubscribeClient.c
  33. 0 117
      pahoMqtt/MQTTSubscribeServer.c
  34. 0 38
      pahoMqtt/MQTTUnsubscribe.h
  35. 0 106
      pahoMqtt/MQTTUnsubscribeClient.c
  36. 0 102
      pahoMqtt/MQTTUnsubscribeServer.c
  37. 0 78
      pahoMqtt/StackTrace.h
  38. 172 271
      platform/linux/platformNetwork.c
  39. 22 18
      platform/linux/platformNetwork.h
  40. 57 50
      platform/linux/platformSystem.c
  41. 37 39
      platform/linux/platformSystem.h
  42. 0 42
      platform/linux/platformTimer.c
  43. 0 24
      platform/linux/platformTimer.h
  44. 70 56
      platform/linux/valloc/valloc.c
  45. 2 2
      platform/linux/valloc/valloc.h
  46. 169 175
      platform/openLuat/platformNetwork.c
  47. 14 12
      platform/openLuat/platformNetwork.h
  48. 51 42
      platform/openLuat/platformSystem.c
  49. 38 42
      platform/openLuat/platformSystem.h
  50. 0 66
      platform/openLuat/platformTimer.c
  51. 0 25
      platform/openLuat/platformTimer.h
  52. 0 318
      platform/quecOpen/platformNetwork.c
  53. 0 37
      platform/quecOpen/platformNetwork.h
  54. 0 224
      platform/quecOpen/platformSystem.c
  55. 0 64
      platform/quecOpen/platformSystem.h
  56. 0 69
      platform/quecOpen/platformTimer.c
  57. 0 24
      platform/quecOpen/platformTimer.h
  58. 179 179
      platform/rtthread/platformNetwork.c
  59. 14 12
      platform/rtthread/platformNetwork.h
  60. 52 44
      platform/rtthread/platformSystem.c
  61. 39 43
      platform/rtthread/platformSystem.h
  62. 0 69
      platform/rtthread/platformTimer.c
  63. 0 25
      platform/rtthread/platformTimer.h
  64. 52 0
      test/RyanMqttDestoryTest.c
  65. 49 0
      test/RyanMqttKeepAliveTest.c
  66. 270 0
      test/RyanMqttPubTest.c
  67. 44 0
      test/RyanMqttReconnectTest.c
  68. 301 0
      test/RyanMqttSubTest.c
  69. 291 0
      test/RyanMqttTest.c
  70. 72 0
      test/RyanMqttTest.h
  71. 0 648
      test/RyanMqttTestLinux.c
  72. 34 6
      xmake.lua

+ 118 - 0
.clang-format

@@ -0,0 +1,118 @@
+# SPDX-License-Identifier: Apache-2.0
+#
+# Note: The list of ForEachMacros can be obtained using:
+#
+#    git grep -h '^#define [^[:space:]]*FOR_EACH[^[:space:]]*(' include/ \
+#    | sed "s,^#define \([^[:space:]]*FOR_EACH[^[:space:]]*\)(.*$,  - '\1'," \
+#    | sort | uniq
+#
+# References:
+#   - https://clang.llvm.org/docs/ClangFormatStyleOptions.html
+
+---
+# 基于 LLVM 的代码风格
+BasedOnStyle: LLVM
+# 连续宏定义的对齐方式:跨注释对齐
+AlignConsecutiveMacros: AcrossComments
+# 短代码块不允许单行显示
+AllowShortBlocksOnASingleLine: Never
+# 短 case 标签不允许单行显示
+AllowShortCaseLabelsOnASingleLine: true
+# 短枚举不允许单行显示
+AllowShortEnumsOnASingleLine: false
+# 短函数不允许单行显示(None 表示对所有函数都应用此规则)
+AllowShortFunctionsOnASingleLine: None
+# 短 if 语句不允许单行显示
+AllowShortIfStatementsOnASingleLine: true
+# 短循环不允许单行显示
+AllowShortLoopsOnASingleLine: true
+
+# 属性宏列表
+AttributeMacros:
+  - __aligned
+  - __deprecated
+  - __packed
+  - __printf_like
+  - __syscall
+  - __syscall_always_inline
+  - __subsystem
+
+# 位字段冒号后的空格位置:冒号后
+BitFieldColonSpacing: After
+
+BreakBeforeBraces: Custom
+BraceWrapping:
+  AfterCaseLabel: false
+  AfterClass: true
+  AfterControlStatement: Always
+  AfterEnum: true
+  AfterExternBlock: false
+  AfterFunction: true
+  AfterNamespace: true
+  AfterObjCDeclaration: true
+  AfterStruct: true
+  AfterUnion: false
+  BeforeCatch: true
+  BeforeElse: true
+  BeforeLambdaBody: false
+  BeforeWhile: false
+  IndentBraces: false
+  SplitEmptyFunction: true
+  SplitEmptyRecord: true
+  SplitEmptyNamespace: true
+
+# 单行代码的最大列数
+ColumnLimit: 120
+# 构造函数初始化列表的缩进宽度
+ConstructorInitializerIndentWidth: 8
+# 折行缩进宽度
+ContinuationIndentWidth: 8
+# ForEach 宏列表
+ForEachMacros:
+  - "ARRAY_FOR_EACH"
+  - "ARRAY_FOR_EACH_PTR"
+  - "FOR_EACH"
+
+# If 宏列表
+IfMacros:
+  - "CHECKIF"
+
+# 包含文件的分类和优先级
+IncludeCategories:
+  - Regex: '^".*\.h"$'
+    Priority: 0
+  - Regex: '^<(assert|complex|ctype|errno|fenv|float|inttypes|limits|locale|math|setjmp|signal|stdarg|stdbool|stddef|stdint|stdio|stdlib|string|tgmath|time|wchar|wctype)\.h>$'
+    Priority: 1
+  - Regex: '^\<Ryan/.*\.h\>$'
+    Priority: 2
+  - Regex: ".*"
+    Priority: 3
+
+# case 标签不缩进
+IndentCaseLabels: false
+# goto 标签不缩进
+IndentGotoLabels: false
+# 缩进宽度
+IndentWidth: 8
+# 自动插入大括号
+InsertBraces: true
+# 文件末尾自动插入新行
+InsertNewlineAtEOF: true
+# 继承冒号前不加空格
+SpaceBeforeInheritanceColon: False
+# 控制语句(除了控制宏)前加空格
+SpaceBeforeParens: ControlStatementsExceptControlMacros
+# 从不排序包含文件
+SortIncludes: Never
+# 使用制表符进行续行和缩进
+UseTab: ForContinuationAndIndentation
+# 对空白字符敏感的宏列表
+WhitespaceSensitiveMacros:
+  - COND_CODE_0
+  - COND_CODE_1
+  - IF_DISABLED
+  - IF_ENABLED
+  - LISTIFY
+  - STRINGIFY
+  - Z_STRINGIFY
+  - DT_FOREACH_PROP_ELEM_SEP

+ 2 - 0
.clang-format-ignore

@@ -0,0 +1,2 @@
+# 忽略coreMqtt
+coreMqtt/*

+ 79 - 0
.clang-tidy

@@ -0,0 +1,79 @@
+# abseil-   与 Abseil 库相关的检查。
+# altera-   与用于 FPGA 的开源 CL 编程相关的检查。
+# android-    与 Android 相关的检查。
+# boost-    与 Boost 库相关的检查。
+# bugprone-   检查易出错代码结构。
+# cert-   与 CERT 安全编码指南相关的检查。
+# clang-analyzer-Clang    静态分析器检查。
+# concurrency-    与并发编程相关的检查(包括线程、纤程、协程等)。
+# cppcoreguidelines-    与 C++核心指南相关的检查。
+# darwin-   与达尔文编码规范相关的检查。
+# fuchsia-    与 Fuchsia 编码规范相关的检查。
+# google-   与 Google 编码规范相关的检查。
+# hicpp-    与高完整性 C++编码标准相关的检查。
+# linuxkernel-    与 Linux 内核编码规范相关的检查。
+# llvm-   与 LLVM 编码规范相关的检查。
+# llvmlibc-   与 LLVM-libc 编码标准相关的检查。
+# misc-   我们没有一个更好的类别的检查。
+# modernize-    提倡使用现代(目前“现代”意味着“C++11”)语言结构的检查。
+# mpi-    与 MPI(消息传递接口)相关的检查。
+# objc-   与 Objective-C 编码规范相关的检查。
+# openmp-   与 OpenMP API 相关的检查。
+# performance-    针对性能相关问题的检查。
+# portability-    针对与特定编码风格无关的可移植性问题进行检查。
+# readability-    检查与特定编码风格无关的目标可读性问题。
+# zircon-     检查与 Zircon 内核编码约定相关的内容。
+
+# Checks: '-*,clang-diagnostic-*,llvm-*,misc-*,-misc-const-correctness,-misc-unused-parameters,-misc-non-private-member-variables-in-classes,-misc-no-recursion,-misc-use-anonymous-namespace,readability-identifier-naming,-misc-include-cleaner'
+
+Checks: 
+  - "-*,clang-diagnostic-*,clang-analyzer-*,llvm-*,concurrency-*,performance-*,cert-*"
+  # 静默的窄化转换交给编译器来判断?
+  - 'bugprone-*,-bugprone-easily-swappable-parameters'
+  - 'readability-identifier-naming'
+  - 'misc-*,-misc-const-correctness,-misc-unused-parameters,-misc-non-private-member-variables-in-classes,-misc-no-recursion,-misc-use-anonymous-namespace,-misc-include-cleaner'
+
+CheckOptions:
+  # 类名使用帕斯卡命名法(如 MyClass)
+  - key: readability-identifier-naming.ClassCase
+    value: camelCase
+
+  # 枚举名使用帕斯卡命名法(如 ColorMode)
+  - key: readability-identifier-naming.EnumCase
+    value: camelCase
+
+  # 函数名使用驼峰命名法(如 getValue())
+  - key: readability-identifier-naming.FunctionCase
+    value: camelBack,CamelBack
+
+  # 忽略符合正则表达式的函数名(常用于兼容外部接口)
+  - key: readability-identifier-naming.FunctionIgnoredRegexp
+    value: "LLVMFuzzerTestOneInput"
+
+  # 成员变量名使用帕斯卡命名法(如 MemberVar)
+  - key: readability-identifier-naming.MemberCase
+    value: camelCase
+
+  # 参数名使用帕斯卡命名法(如 ParamName)
+  - key: readability-identifier-naming.ParameterCase
+    value: camelBack
+
+  # 联合体名使用帕斯卡命名法(如 MyUnion)
+  - key: readability-identifier-naming.UnionCase
+    value: camelCase
+
+  # 变量名使用帕斯卡命名法(如 LocalVar)
+  - key: readability-identifier-naming.VariableCase
+    value: camelCase
+
+  # 忽略main-like函数(如测试入口函数)
+  - key: readability-identifier-naming.IgnoreMainLikeFunctions
+    value: 1
+
+  # 忽略拷贝构造函数中的基类成员初始化检查
+  - key: readability-redundant-member-init.IgnoreBaseInCopyConstructors
+    value: 1
+
+  # 使用赋值初始化而非就地初始化(C++11特性)
+  - key: modernize-use-default-member-init.UseAssignment
+    value: 1

+ 22 - 4
.vscode/settings.json

@@ -1,5 +1,23 @@
 {
-    "files.associations": {
-        "string.h": "c"
-    }
-}
+    "clangd.enable": false,
+    "C_Cpp.intelliSenseEngine": "default",
+    "C_Cpp.codeAnalysis.clangTidy.enabled": true,
+    "c-cpp-flylint.enable": true,
+    "c-cpp-flylint.cppcheck.severityLevels": {
+        "error": "Error",
+        "warning": "Warning",
+        "style": "Information",
+        "performance": "Information",
+        "portability": "Information",
+        "information": "Information"
+    },
+    "c-cpp-flylint.cppcheck.extraArgs": [
+        // "--suppress=constParameterPointer",
+        // "--suppress=constParameterCallback",
+        "--check-level=exhaustive",
+        // "--suppress=variableScope",
+        // "--suppress=unreadVariable",
+        // "--suppress=constVariablePointer",
+        // "--suppress=constParameter",
+    ],
+}

+ 2 - 0
Makefile

@@ -5,6 +5,7 @@ CC = gcc
 CFLAGS += -I common \
           -I pahoMqtt \
           -I mqttclient \
+          -I coreMqtt \
           -I platform/linux \
           -I platform/linux/valloc
 
@@ -18,6 +19,7 @@ SRCS += $(wildcard ./platform/linux/*.c)
 SRCS += $(wildcard ./platform/linux/valloc/*.c)
 SRCS += $(wildcard ./pahoMqtt/*.c)
 SRCS += $(wildcard ./mqttclient/*.c)
+SRCS += $(wildcard ./coreMqtt/*.c)
 
 # 定义目标文件和输出文件
 OBJS = $(patsubst %.c,%.o,$(SRCS))

+ 60 - 50
common/RyanList.c

@@ -1,129 +1,139 @@
 
-
 #include "RyanList.h"
 
 /**
- * @brief 在prev和next之前插入节点
+ * @brief 内部函数:在prev和next节点之间插入新节点
  *
- * @param node
- * @param prev
- * @param next
+ * @param node 要插入的新节点指针
+ * @param prev 前驱节点指针
+ * @param next 后继节点指针
+ * @note 这是一个静态内部函数,不对外暴露
  */
 static void _RyanListAdd(RyanList_t *node, RyanList_t *prev, RyanList_t *next)
 {
-    next->prev = node;
-    node->next = next;
-    node->prev = prev;
-    prev->next = node;
+	next->prev = node; // 后继节点的前驱指向新节点
+	node->next = next; // 新节点的后继指向原后继节点
+	node->prev = prev; // 新节点的前驱指向原前驱节点
+	prev->next = node; // 前驱节点的后继指向新节点
 }
 
 /**
- * @brief 删除prev和next之间的节点
+ * @brief 内部函数:删除prev和next之间的节点
  *
- * @param prev
- * @param next
+ * @param prev 要删除区间的前驱节点
+ * @param next 要删除区间的后继节点
+ * @note 这是一个静态内部函数,不对外暴露
  */
 static void _RyanListDel(RyanList_t *prev, RyanList_t *next)
 {
-    prev->next = next;
-    next->prev = prev;
+	prev->next = next; // 前驱节点直接指向后继节点
+	next->prev = prev; // 后继节点直接指向前驱节点
 }
 
 /**
- * @brief 删除自己
+ * @brief 内部函数:删除指定节点自身
  *
- * @param entry
+ * @param entry 要删除的节点指针
+ * @note 通过修改前后节点的指针关系实现自我删除
  */
 static void _RyanListDel_entry(RyanList_t *entry)
 {
-    _RyanListDel(entry->prev, entry->next);
+	_RyanListDel(entry->prev, entry->next); // 调用区间删除函数
 }
 
 /**
- * @brief 初始链表
+ * @brief 初始链表头节点
  *
- * @param list
+ * @param list 链表头节点指针
+ * @note 将头节点的前后指针都指向自己,形成空链表
  */
 void RyanListInit(RyanList_t *list)
 {
-    list->next = list;
-    list->prev = list;
+	list->next = list; // 后继指向自己
+	list->prev = list; // 前驱指向自己
 }
 
 /**
- * @brief 链表头插
+ * @brief 链表头入节点
  *
- * @param node
- * @param list
+ * @param node 要插入的新节点
+ * @param list 链表头节点
+ * @note 新节点将插入到头节点之后,成为第一个有效节点
  */
 void RyanListAdd(RyanList_t *node, RyanList_t *list)
 {
-    _RyanListAdd(node, list, list->next);
+	_RyanListAdd(node, list, list->next); // 在头节点和第一个节点间插入
 }
 
 /**
- * @brief 链表尾插
+ * @brief 链表尾入节点
  *
- * @param node
- * @param list
+ * @param node 要插入的新节点
+ * @param list 链表头节点
+ * @note 新节点将插入到头节点之前,成为最后一个有效节点
  */
 void RyanListAddTail(RyanList_t *node, RyanList_t *list)
 {
-    _RyanListAdd(node, list->prev, list);
+	_RyanListAdd(node, list->prev, list); // 在尾节点和头节点间插入
 }
 
 /**
- * @brief 删除自己
+ * @brief 从链表中删除指定节点
  *
- * @param entry
+ * @param entry 要删除的节点
+ * @note 只删除节点,不重新初始化该节点
  */
 void RyanListDel(RyanList_t *entry)
 {
-    _RyanListDel_entry(entry);
+	_RyanListDel_entry(entry); // 调用内部删除函数
 }
 
 /**
- * @brief 删除自己
+ * @brief 从链表中删除并重新初始化指定节点
  *
- * @param entry
+ * @param entry 要删除的节点
+ * @note 删除后会将该节点初始化为独立节点
  */
 void RyanListDelInit(RyanList_t *entry)
 {
-    _RyanListDel_entry(entry);
-    RyanListInit(entry);
+	_RyanListDel_entry(entry); // 先删除节点
+	RyanListInit(entry);       // 再重新初始化该节点
 }
 
 /**
- * @brief 将节点移到链表头部
+ * @brief 将节点移到链表头部
  *
- * @param node
- * @param list
+ * @param node 要移动的节点
+ * @param list 链表头节点
+ * @note 先删除节点,再插入到头部
  */
 void RyanListMove(RyanList_t *node, RyanList_t *list)
 {
-    _RyanListDel_entry(node);
-    RyanListAdd(node, list);
+	_RyanListDel_entry(node); // 先从原位置删除
+	RyanListAdd(node, list);  // 再插入到头部
 }
 
 /**
- * @brief 将节点移到链表尾部
+ * @brief 将节点移到链表尾部
  *
- * @param node
- * @param list
+ * @param node 要移动的节点
+ * @param list 链表头节点
+ * @note 先删除节点,再插入到尾部
  */
 void RyanListMoveTail(RyanList_t *node, RyanList_t *list)
 {
-    _RyanListDel_entry(node);
-    RyanListAddTail(node, list);
+	_RyanListDel_entry(node);    // 先从原位置删除
+	RyanListAddTail(node, list); // 再插入到尾部
 }
 
 /**
- * @brief 链表是否为空
+ * @brief 检查链表是否为空
  *
- * @param list
- * @return int
+ * @param list 链表头节点
+ * @return int 返回1表示空链表,0表示非空
+ * @note 通过判断头节点是否指向自己来确定是否为空
  */
 int RyanListIsEmpty(RyanList_t *list)
 {
-    return list->next == list;
+	return list->next == list; // 头节点的next指向自己说明为空
 }

+ 36 - 46
common/RyanList.h

@@ -1,72 +1,62 @@
-
 #ifndef __RyanMqttList__
 #define __RyanMqttList__
 
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif
 
+// 计算结构体成员偏移量的宏
 #define RyanOffsetOf(type, member) ((size_t)&(((type *)0)->member))
 
-#define RyanContainerOf(ptr, type, member) \
-    ((type *)((unsigned char *)(ptr) - RyanOffsetOf(type, member)))
+// 通过成员指针获取包含该成员的结构体指针
+#define RyanContainerOf(ptr, type, member) ((type *)((unsigned char *)(ptr) - RyanOffsetOf(type, member)))
 
-// 通过链表获取节点首地址
-#define RyanListEntry(list, type, member) \
-    RyanContainerOf(list, type, member)
+// 通过链表节点获取所属结构体的首地址
+#define RyanListEntry(list, type, member) RyanContainerOf(list, type, member)
 
-// 从链表指针ptr的下一指针中获得包含该链表的结构体指针
-#define RyanListFirstEntry(list, type, member) \
-    RyanListEntry((list)->next, type, member)
+// 获取链表第一个元素所属结构体
+#define RyanListFirstEntry(list, type, member) RyanListEntry((list)->next, type, member)
 
-// 从链表指针ptr的上一指针中获得包含该链表的结构体指针
-#define RyanListPrevEntry(list, type, member) \
-    RyanListEntry((list)->prev, type, member)
+// 获取链表最后一个元素所属结构体
+#define RyanListPrevEntry(list, type, member) RyanListEntry((list)->prev, type, member)
 
-// 遍历链表正序
-#define RyanListForEach(curr, list) \
-    for ((curr) = (list)->next; (curr) != (list); (curr) = (curr)->next)
+// 正向遍历链表
+#define RyanListForEach(curr, list) for ((curr) = (list)->next; (curr) != (list); (curr) = (curr)->next)
 
-// 遍历链表反序
-#define RyanListForEachPrev(curr, list) \
-    for ((curr) = (list)->prev; (curr) != (list); (curr) = (curr)->prev)
+// 反向遍历链表
+#define RyanListForEachPrev(curr, list) for ((curr) = (list)->prev; (curr) != (list); (curr) = (curr)->prev)
 
-// 安全遍历链表正序
-#define RyanListForEachSafe(curr, next, list)          \
-    for ((curr) = (list)->next, (next) = (curr)->next; \
-         (curr) != (list);                             \
-         (curr) = (next), (next) = (curr)->next)
+// 安全的正向遍历链表(支持遍历中删除)
+#define RyanListForEachSafe(curr, next, list)                                                                          \
+	for ((curr) = (list)->next, (next) = (curr)->next; (curr) != (list); (curr) = (next), (next) = (curr)->next)
 
-// 安全遍历链表反序
-#define RyanListForEachPrevSafe(curr, next, list)      \
-    for ((curr) = (list)->prev, (next) = (curr)->prev; \
-         (curr) != (list);                             \
-         (curr) = (next), (next) = (curr)->prev)
+// 安全的反向遍历链表(支持遍历中删除)
+#define RyanListForEachPrevSafe(curr, next, list)                                                                      \
+	for ((curr) = (list)->prev, (next) = (curr)->prev; (curr) != (list); (curr) = (next), (next) = (curr)->prev)
 
-    // 定义枚举类型
+// 定义枚举类型
 
-    // 定义结构体类型
-    typedef struct RyanListNode
-    {
-        struct RyanListNode *next;
-        struct RyanListNode *prev;
-    } RyanList_t;
+// 定义结构体类型
+typedef struct RyanListNode
+{
+	struct RyanListNode *next;
+	struct RyanListNode *prev;
+} RyanList_t;
 
-    /* extern variables-----------------------------------------------------------*/
+/* extern variables-----------------------------------------------------------*/
 
-    extern void RyanListInit(RyanList_t *list);
+extern void RyanListInit(RyanList_t *list);
 
-    extern void RyanListAdd(RyanList_t *node, RyanList_t *list);
-    extern void RyanListAddTail(RyanList_t *node, RyanList_t *list);
+extern void RyanListAdd(RyanList_t *node, RyanList_t *list);
+extern void RyanListAddTail(RyanList_t *node, RyanList_t *list);
 
-    extern void RyanListDel(RyanList_t *entry);
-    extern void RyanListDelInit(RyanList_t *entry);
+extern void RyanListDel(RyanList_t *entry);
+extern void RyanListDelInit(RyanList_t *entry);
 
-    extern void RyanListMove(RyanList_t *node, RyanList_t *list);
-    extern void RyanListMoveTail(RyanList_t *node, RyanList_t *list);
+extern void RyanListMove(RyanList_t *node, RyanList_t *list);
+extern void RyanListMoveTail(RyanList_t *node, RyanList_t *list);
 
-    extern int RyanListIsEmpty(RyanList_t *list);
+extern int RyanListIsEmpty(RyanList_t *list);
 
 #ifdef __cplusplus
 }

+ 40 - 0
common/RyanMqttLog.c

@@ -0,0 +1,40 @@
+#include "RyanMqttLog.h"
+#include "platformSystem.h"
+
+void rlog_output(char *lvl, uint8_t color, char *fileStr, uint32_t lineNum, char *const fmt, ...)
+{
+	// RyanLogPrintf("\033[字背景颜色;字体颜色m  用户字符串 \033[0m" );
+	char dbgBuffer[256];
+	uint16_t len = 0;
+
+	// 打印颜色、提示符、打印文件路径、行号
+	len += snprintf(dbgBuffer + len, sizeof(dbgBuffer) - len, "\033[%dm[%s] %s:%" PRIu32 " ", color, lvl, fileStr,
+			lineNum);
+
+	// platformPrint(dbgBuffer, len);
+	// len = 0;
+
+	// 打印用户输入
+	va_list args;
+	va_start(args, fmt);
+	len += vsnprintf(dbgBuffer + len, sizeof(dbgBuffer) - len, fmt, args);
+	va_end(args);
+
+	// 打印颜色
+	len += snprintf(dbgBuffer + len, sizeof(dbgBuffer) - len, "\033[0m\r\n");
+
+	platformPrint(dbgBuffer, len);
+}
+
+void rlog_output_raw(char *const fmt, ...)
+{
+	char dbgBuffer[256];
+	uint16_t len;
+
+	va_list args;
+	va_start(args, fmt);
+	len = vsnprintf(dbgBuffer, sizeof(dbgBuffer), fmt, args);
+	va_end(args);
+
+	platformPrint(dbgBuffer, len);
+}

+ 9 - 64
common/RyanMqttLog.h

@@ -1,15 +1,16 @@
 #ifndef __RyanMqttLog__
 #define __RyanMqttLog__
 
-#include <stdio.h>
+#include <stdint.h>
 #include <stdarg.h>
-#include "platformSystem.h"
+#include <inttypes.h>
 
 // 日志等级
-#define rlogLvlError 0
-#define rlogLvlWarning 1
-#define rlogLvlInfo 2
-#define rlogLvlDebug 3
+#define rlogLvlAssert  0
+#define rlogLvlError   1
+#define rlogLvlWarning 2
+#define rlogLvlInfo    2
+#define rlogLvlDebug   3
 
 // 日志打印等级
 #ifndef rlogLevel
@@ -21,64 +22,8 @@
 #define rlogTag "LOG"
 #endif
 
-/**
- * @brief 日志相关
- *
- */
-#ifdef rlogEnable
-static void rlog_output(char *lvl, uint8_t color_n, char *fileStr, uint32_t lineNum, char *const fmt, ...)
-{
-    // RyanLogPrintf("\033[字背景颜色;字体颜色m  用户字符串 \033[0m" );
-    char dbgBuffer[256] = {0};
-    uint16_t len = 0;
-
-// 打印颜色
-#ifdef rlogColorEnable
-    len += snprintf(dbgBuffer + len, sizeof(dbgBuffer) - len, "\033[%dm", color_n);
-#endif
-
-    // 打印提示符
-    len += snprintf(dbgBuffer + len, sizeof(dbgBuffer) - len, "[%s/%s]", lvl, rlogTag);
-
-    // 打印文件路径和行号
-    len += snprintf(dbgBuffer + len, sizeof(dbgBuffer) - len, " %s:%d ", fileStr, lineNum);
-
-    platformPrint(dbgBuffer, len);
-    len = 0;
-
-    // 打印用户输入
-    va_list args;
-    va_start(args, fmt);
-    len += vsnprintf(dbgBuffer + len, sizeof(dbgBuffer) - len, fmt, args);
-    va_end(args);
-
-// 打印颜色
-#ifdef rlogColorEnable
-    len += snprintf(dbgBuffer + len, sizeof(dbgBuffer) - len, "\033[0m");
-#endif
-
-    len += snprintf(dbgBuffer + len, sizeof(dbgBuffer) - len, "\r\n");
-
-    platformPrint(dbgBuffer, len);
-}
-
-static void rlog_output_raw(char *const fmt, ...)
-{
-    char dbgBuffer[256];
-    uint16_t len;
-
-    va_list args;
-    va_start(args, fmt);
-    len = vsnprintf(dbgBuffer, sizeof(dbgBuffer), fmt, args);
-    va_end(args);
-
-    platformPrint(dbgBuffer, len);
-}
-
-#else
-#define rlog_output(...)
-#define rlog_output_raw(...)
-#endif
+extern void rlog_output_raw(char *const fmt, ...);
+extern void rlog_output(char *lvl, uint8_t color, char *fileStr, uint32_t lineNum, char *const fmt, ...);
 
 /**
  * @brief log等级检索

+ 191 - 0
coreMqtt/core_mqtt_config_defaults.h

@@ -0,0 +1,191 @@
+/*
+ * coreMQTT <DEVELOPMENT BRANCH>
+ * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file core_mqtt_config_defaults.h
+ * @brief This represents the default values for the configuration macros
+ * for the MQTT library.
+ *
+ * @note This file SHOULD NOT be modified. If custom values are needed for
+ * any configuration macro, a core_mqtt_config.h file should be provided to
+ * the MQTT library to override the default values defined in this file.
+ * To use the custom config file, the MQTT_DO_NOT_USE_CUSTOM_CONFIG preprocessor
+ * macro SHOULD NOT be set.
+ */
+
+#ifndef CORE_MQTT_CONFIG_DEFAULTS_H_
+#define CORE_MQTT_CONFIG_DEFAULTS_H_
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* *INDENT-ON* */
+
+/* The macro definition for MQTT_DO_NOT_USE_CUSTOM_CONFIG is for Doxygen
+ * documentation only. */
+
+/**
+ * @brief Define this macro to build the MQTT library without the custom config
+ * file core_mqtt_config.h.
+ *
+ * Without the custom config, the MQTT library builds with
+ * default values of config macros defined in core_mqtt_config_defaults.h file.
+ *
+ * If a custom config is provided, then MQTT_DO_NOT_USE_CUSTOM_CONFIG should not
+ * be defined.
+ */
+#ifdef DOXYGEN
+#define MQTT_DO_NOT_USE_CUSTOM_CONFIG
+#endif
+
+/**
+ * @brief Macro that is called in the MQTT library for logging "Error" level
+ * messages.
+ *
+ * To enable error level logging in the MQTT library, this macro should be mapped to the
+ * application-specific logging implementation that supports error logging.
+ *
+ * @note This logging macro is called in the MQTT library with parameters wrapped in
+ * double parentheses to be ISO C89/C90 standard compliant. For a reference
+ * POSIX implementation of the logging macros, refer to core_mqtt_config.h files, and the
+ * logging-stack in demos folder of the
+ * [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
+ *
+ * <b>Default value</b>: Error logging is turned off, and no code is generated for calls
+ * to the macro in the MQTT library on compilation.
+ */
+#ifndef LogError
+#define LogError(message)
+#endif
+
+/**
+ * @brief Macro that is called in the MQTT library for logging "Warning" level
+ * messages.
+ *
+ * To enable warning level logging in the MQTT library, this macro should be mapped to the
+ * application-specific logging implementation that supports warning logging.
+ *
+ * @note This logging macro is called in the MQTT library with parameters wrapped in
+ * double parentheses to be ISO C89/C90 standard compliant. For a reference
+ * POSIX implementation of the logging macros, refer to core_mqtt_config.h files, and the
+ * logging-stack in demos folder of the
+ * [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C/).
+ *
+ * <b>Default value</b>: Warning logs are turned off, and no code is generated for calls
+ * to the macro in the MQTT library on compilation.
+ */
+#ifndef LogWarn
+#define LogWarn(message)
+#endif
+
+/**
+ * @brief Macro that is called in the MQTT library for logging "Info" level
+ * messages.
+ *
+ * To enable info level logging in the MQTT library, this macro should be mapped to the
+ * application-specific logging implementation that supports info logging.
+ *
+ * @note This logging macro is called in the MQTT library with parameters wrapped in
+ * double parentheses to be ISO C89/C90 standard compliant. For a reference
+ * POSIX implementation of the logging macros, refer to core_mqtt_config.h files, and the
+ * logging-stack in demos folder of the
+ * [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C/).
+ *
+ * <b>Default value</b>: Info logging is turned off, and no code is generated for calls
+ * to the macro in the MQTT library on compilation.
+ */
+#ifndef LogInfo
+#define LogInfo(message)
+#endif
+
+/**
+ * @brief Macro that is called in the MQTT library for logging "Debug" level
+ * messages.
+ *
+ * To enable debug level logging from MQTT library, this macro should be mapped to the
+ * application-specific logging implementation that supports debug logging.
+ *
+ * @note This logging macro is called in the MQTT library with parameters wrapped in
+ * double parentheses to be ISO C89/C90 standard compliant. For a reference
+ * POSIX implementation of the logging macros, refer to core_mqtt_config.h files, and the
+ * logging-stack in demos folder of the
+ * [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C/).
+ *
+ * <b>Default value</b>: Debug logging is turned off, and no code is generated for calls
+ * to the macro in the MQTT library on compilation.
+ */
+#ifndef LogDebug
+#define LogDebug(message)
+#endif
+
+    /**
+     * @transportstruct
+     * @typedef NetworkContext_t
+     * @brief The NetworkContext is an incomplete type. An implementation of this
+     * interface must define struct NetworkContext for the system requirements.
+     * This context is passed into the network interface functions.
+     */
+    /* @[define_networkcontext] */
+    typedef struct NetworkContext NetworkContext_t;
+
+    /**
+     * @transportcallback
+     * @brief Transport interface for receiving data on the network.
+     *
+     * @note It is HIGHLY RECOMMENDED that the transport receive
+     * implementation does NOT block.
+     * coreMQTT will continue to call the transport interface if it receives
+     * a partial packet until it accumulates enough data to get the complete
+     * MQTT packet.
+     * A non‐blocking implementation is also essential so that the library's inbuilt
+     * keep‐alive mechanism can work properly, given the user chooses to use
+     * that over their own keep alive mechanism.
+     *
+     * @param[in] pNetworkContext Implementation-defined network context.
+     * @param[in] pBuffer Buffer to receive the data into.
+     * @param[in] bytesToRecv Number of bytes requested from the network.
+     *
+     * @return The number of bytes received or a negative value to indicate
+     * error.
+     *
+     * @note If no data is available on the network to read and no error
+     * has occurred, zero MUST be the return value. A zero return value
+     * SHOULD represent that the read operation can be retried by calling
+     * the API function. Zero MUST NOT be returned if a network disconnection
+     * has occurred.
+     */
+    /* @[define_transportrecv] */
+    typedef int32_t (*TransportRecv_t)(NetworkContext_t *pNetworkContext,
+                                       void *pBuffer,
+                                       size_t bytesToRecv);
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+}
+#endif
+/* *INDENT-ON* */
+
+#endif /* ifndef CORE_MQTT_CONFIG_DEFAULTS_H_ */

+ 2706 - 0
coreMqtt/core_mqtt_serializer.c

@@ -0,0 +1,2706 @@
+/*
+ * coreMQTT <DEVELOPMENT BRANCH>
+ * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file core_mqtt_serializer.c
+ * @brief Implements the user-facing functions in core_mqtt_serializer.h.
+ */
+#include <string.h>
+#include <assert.h>
+
+#include "core_mqtt_serializer.h"
+
+/* Include config defaults header to get default values of configs. */
+#include "core_mqtt_config_defaults.h"
+
+/**
+ * @brief MQTT protocol version 3.1.1.
+ */
+#define MQTT_VERSION_3_1_1                          ( ( uint8_t ) 4U )
+
+/**
+ * @brief Size of the fixed and variable header of a CONNECT packet.
+ */
+#define MQTT_PACKET_CONNECT_HEADER_SIZE             ( 10UL )
+
+/* MQTT CONNECT flags. */
+#define MQTT_CONNECT_FLAG_CLEAN                     ( 1 ) /**< @brief Clean session. */
+#define MQTT_CONNECT_FLAG_WILL                      ( 2 ) /**< @brief Will present. */
+#define MQTT_CONNECT_FLAG_WILL_QOS1                 ( 3 ) /**< @brief Will QoS 1. */
+#define MQTT_CONNECT_FLAG_WILL_QOS2                 ( 4 ) /**< @brief Will QoS 2. */
+#define MQTT_CONNECT_FLAG_WILL_RETAIN               ( 5 ) /**< @brief Will retain. */
+#define MQTT_CONNECT_FLAG_PASSWORD                  ( 6 ) /**< @brief Password present. */
+#define MQTT_CONNECT_FLAG_USERNAME                  ( 7 ) /**< @brief User name present. */
+
+/*
+ * Positions of each flag in the first byte of an MQTT PUBLISH packet's
+ * fixed header.
+ */
+#define MQTT_PUBLISH_FLAG_RETAIN                    ( 0 ) /**< @brief MQTT PUBLISH retain flag. */
+#define MQTT_PUBLISH_FLAG_QOS1                      ( 1 ) /**< @brief MQTT PUBLISH QoS1 flag. */
+#define MQTT_PUBLISH_FLAG_QOS2                      ( 2 ) /**< @brief MQTT PUBLISH QoS2 flag. */
+#define MQTT_PUBLISH_FLAG_DUP                       ( 3 ) /**< @brief MQTT PUBLISH duplicate flag. */
+
+/**
+ * @brief The size of MQTT DISCONNECT packets, per MQTT spec.
+ */
+#define MQTT_DISCONNECT_PACKET_SIZE                 ( 2UL )
+
+/**
+ * @brief A PINGREQ packet is always 2 bytes in size, defined by MQTT 3.1.1 spec.
+ */
+#define MQTT_PACKET_PINGREQ_SIZE                    ( 2UL )
+
+/**
+ * @brief The Remaining Length field of MQTT disconnect packets, per MQTT spec.
+ */
+#define MQTT_DISCONNECT_REMAINING_LENGTH            ( ( uint8_t ) 0 )
+
+/*
+ * Constants relating to CONNACK packets, defined by MQTT 3.1.1 spec.
+ */
+#define MQTT_PACKET_CONNACK_REMAINING_LENGTH        ( ( uint8_t ) 2U )    /**< @brief A CONNACK packet always has a "Remaining length" of 2. */
+#define MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK    ( ( uint8_t ) 0x01U ) /**< @brief The "Session Present" bit is always the lowest bit. */
+
+/*
+ * UNSUBACK, PUBACK, PUBREC, PUBREL, and PUBCOMP always have a remaining length
+ * of 2.
+ */
+#define MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH     ( ( uint8_t ) 2 ) /**< @brief PUBACK, PUBREC, PUBREl, PUBCOMP, UNSUBACK Remaining length. */
+#define MQTT_PACKET_PINGRESP_REMAINING_LENGTH       ( 0U )            /**< @brief A PINGRESP packet always has a "Remaining length" of 0. */
+
+/**
+ * @brief Per the MQTT 3.1.1 spec, the largest "Remaining Length" of an MQTT
+ * packet is this value, 256 MB.
+ */
+#define MQTT_MAX_REMAINING_LENGTH                   ( 268435455UL )
+
+/**
+ * @brief Set a bit in an 8-bit unsigned integer.
+ */
+#define UINT8_SET_BIT( x, position )      ( ( x ) = ( uint8_t ) ( ( x ) | ( 0x01U << ( position ) ) ) )
+
+/**
+ * @brief Clear a bit in an 8-bit unsigned integer.
+ */
+#define UINT8_CLEAR_BIT( x, position )    ( ( x ) = ( uint8_t ) ( ( x ) & ( ~( 0x01U << ( position ) ) ) ) )
+
+/**
+ * @brief Macro for checking if a bit is set in a 1-byte unsigned int.
+ *
+ * @param[in] x The unsigned int to check.
+ * @param[in] position Which bit to check.
+ */
+#define UINT8_CHECK_BIT( x, position )    ( ( ( x ) & ( 0x01U << ( position ) ) ) == ( 0x01U << ( position ) ) )
+
+/**
+ * @brief Get the high byte of a 16-bit unsigned integer.
+ */
+#define UINT16_HIGH_BYTE( x )             ( ( uint8_t ) ( ( x ) >> 8 ) )
+
+/**
+ * @brief Get the low byte of a 16-bit unsigned integer.
+ */
+#define UINT16_LOW_BYTE( x )              ( ( uint8_t ) ( ( x ) & 0x00ffU ) )
+
+/**
+ * @brief Macro for decoding a 2-byte unsigned int from a sequence of bytes.
+ *
+ * @param[in] ptr A uint8_t* that points to the high byte.
+ */
+#define UINT16_DECODE( ptr )                            \
+    ( uint16_t ) ( ( ( ( uint16_t ) ptr[ 0 ] ) << 8 ) | \
+                   ( ( uint16_t ) ptr[ 1 ] ) )
+
+/**
+ * @brief A value that represents an invalid remaining length.
+ *
+ * This value is greater than what is allowed by the MQTT specification.
+ */
+#define MQTT_REMAINING_LENGTH_INVALID             ( ( size_t ) 268435456 )
+
+/**
+ * @brief The minimum remaining length for a QoS 0 PUBLISH.
+ *
+ * Includes two bytes for topic name length and one byte for topic name.
+ */
+#define MQTT_MIN_PUBLISH_REMAINING_LENGTH_QOS0    ( 3U )
+
+/*-----------------------------------------------------------*/
+
+
+/**
+ * @brief MQTT Subscription packet types.
+ */
+typedef enum MQTTSubscriptionType
+{
+    MQTT_SUBSCRIBE,  /**< @brief The type is a SUBSCRIBE packet. */
+    MQTT_UNSUBSCRIBE /**< @brief The type is a UNSUBSCRIBE packet. */
+} MQTTSubscriptionType_t;
+
+/*-----------------------------------------------------------*/
+
+/**
+ * @brief Serializes MQTT PUBLISH packet into the buffer provided.
+ *
+ * This function serializes MQTT PUBLISH packet into #MQTTFixedBuffer_t.pBuffer.
+ * Copy of the payload into the buffer is done as part of the serialization
+ * only if @p serializePayload is true.
+ *
+ * @brief param[in] pPublishInfo Publish information.
+ * @brief param[in] remainingLength Remaining length of the PUBLISH packet.
+ * @brief param[in] packetIdentifier Packet identifier of PUBLISH packet.
+ * @brief param[in, out] pFixedBuffer Buffer to which PUBLISH packet will be
+ * serialized.
+ * @brief param[in] serializePayload Copy payload to the serialized buffer
+ * only if true. Only PUBLISH header will be serialized if false.
+ */
+static void serializePublishCommon( const MQTTPublishInfo_t * pPublishInfo,
+                                    size_t remainingLength,
+                                    uint16_t packetIdentifier,
+                                    const MQTTFixedBuffer_t * pFixedBuffer,
+                                    bool serializePayload );
+
+/**
+ * @brief Calculates the packet size and remaining length of an MQTT
+ * PUBLISH packet.
+ *
+ * @param[in] pPublishInfo MQTT PUBLISH packet parameters.
+ * @param[out] pRemainingLength The Remaining Length of the MQTT PUBLISH packet.
+ * @param[out] pPacketSize The total size of the MQTT PUBLISH packet.
+ *
+ * @return false if the packet would exceed the size allowed by the
+ * MQTT spec; true otherwise.
+ */
+static bool calculatePublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
+                                        size_t * pRemainingLength,
+                                        size_t * pPacketSize );
+
+/**
+ * @brief Calculates the packet size and remaining length of an MQTT
+ * SUBSCRIBE or UNSUBSCRIBE packet.
+ *
+ * @param[in] pSubscriptionList List of MQTT subscription info.
+ * @param[in] subscriptionCount The number of elements in pSubscriptionList.
+ * @param[out] pRemainingLength The Remaining Length of the MQTT SUBSCRIBE or
+ * UNSUBSCRIBE packet.
+ * @param[out] pPacketSize The total size of the MQTT MQTT SUBSCRIBE or
+ * UNSUBSCRIBE packet.
+ * @param[in] subscriptionType #MQTT_SUBSCRIBE or #MQTT_UNSUBSCRIBE.
+ *
+ * #MQTTBadParameter if the packet would exceed the size allowed by the
+ * MQTT spec or a subscription is empty; #MQTTSuccess otherwise.
+ */
+static MQTTStatus_t calculateSubscriptionPacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
+                                                     size_t subscriptionCount,
+                                                     size_t * pRemainingLength,
+                                                     size_t * pPacketSize,
+                                                     MQTTSubscriptionType_t subscriptionType );
+
+/**
+ * @brief Validates parameters of #MQTT_SerializeSubscribe or
+ * #MQTT_SerializeUnsubscribe.
+ *
+ * @param[in] pSubscriptionList List of MQTT subscription info.
+ * @param[in] subscriptionCount The number of elements in pSubscriptionList.
+ * @param[in] packetId Packet identifier.
+ * @param[in] remainingLength Remaining length of the packet.
+ * @param[in] pFixedBuffer Buffer for packet serialization.
+ *
+ * @return #MQTTNoMemory if pBuffer is too small to hold the MQTT packet;
+ * #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSuccess otherwise.
+ */
+static MQTTStatus_t validateSubscriptionSerializeParams( const MQTTSubscribeInfo_t * pSubscriptionList,
+                                                         size_t subscriptionCount,
+                                                         uint16_t packetId,
+                                                         size_t remainingLength,
+                                                         const MQTTFixedBuffer_t * pFixedBuffer );
+
+/**
+ * @brief Serialize an MQTT CONNECT packet in the given buffer.
+ *
+ * @param[in] pConnectInfo MQTT CONNECT packet parameters.
+ * @param[in] pWillInfo Last Will and Testament. Pass NULL if not used.
+ * @param[in] remainingLength Remaining Length of MQTT CONNECT packet.
+ * @param[out] pFixedBuffer Buffer for packet serialization.
+ */
+static void serializeConnectPacket( const MQTTConnectInfo_t * pConnectInfo,
+                                    const MQTTPublishInfo_t * pWillInfo,
+                                    size_t remainingLength,
+                                    const MQTTFixedBuffer_t * pFixedBuffer );
+
+/**
+ * @brief Prints the appropriate message for the CONNACK response code if logs
+ * are enabled.
+ *
+ * @param[in] responseCode MQTT standard CONNACK response code.
+ */
+static void logConnackResponse( uint8_t responseCode );
+
+/**
+ * @brief Encodes the remaining length of the packet using the variable length
+ * encoding scheme provided in the MQTT v3.1.1 specification.
+ *
+ * @param[out] pDestination The destination buffer to store the encoded remaining
+ * length.
+ * @param[in] length The remaining length to encode.
+ *
+ * @return The location of the byte following the encoded value.
+ */
+static uint8_t * encodeRemainingLength( uint8_t * pDestination,
+                                        size_t length );
+
+/**
+ * @brief Retrieve the size of the remaining length if it were to be encoded.
+ *
+ * @param[in] length The remaining length to be encoded.
+ *
+ * @return The size of the remaining length if it were to be encoded.
+ */
+static size_t remainingLengthEncodedSize( size_t length );
+
+/**
+ * @brief Encode a string whose size is at maximum 16 bits in length.
+ *
+ * @param[out] pDestination Destination buffer for the encoding.
+ * @param[in] pSource The source string to encode.
+ * @param[in] sourceLength The length of the source string to encode.
+ *
+ * @return A pointer to the end of the encoded string.
+ */
+static uint8_t * encodeString( uint8_t * pDestination,
+                               const char * pSource,
+                               uint16_t sourceLength );
+
+/**
+ * @brief Retrieves and decodes the Remaining Length from the network interface
+ * by reading a single byte at a time.
+ *
+ * @param[in] recvFunc Network interface receive function.
+ * @param[in] pNetworkContext Network interface context to the receive function.
+ *
+ * @return The Remaining Length of the incoming packet.
+ */
+static size_t getRemainingLength( TransportRecv_t recvFunc,
+                                  NetworkContext_t * pNetworkContext );
+
+/**
+ * @brief Retrieves, decodes and stores the Remaining Length from the network
+ * interface by reading a single byte at a time.
+ *
+ * @param[in] pBuffer The buffer holding the raw data to be processed
+ * @param[in] pIndex Pointer to the index within the buffer to marking the end of raw data
+ *            available.
+ * @param[in] pIncomingPacket Structure used to hold the fields of the
+ *            incoming packet.
+ *
+ * @return MQTTNeedMoreBytes is returned to show that the incoming
+ *         packet is not yet fully received and decoded. Otherwise, MQTTSuccess
+ *         shows that processing of the packet was successful.
+ */
+static MQTTStatus_t processRemainingLength( const uint8_t * pBuffer,
+                                            const size_t * pIndex,
+                                            MQTTPacketInfo_t * pIncomingPacket );
+
+/**
+ * @brief Check if an incoming packet type is valid.
+ *
+ * @param[in] packetType The packet type to check.
+ *
+ * @return `true` if the packet type is valid; `false` otherwise.
+ */
+static bool incomingPacketValid( uint8_t packetType );
+
+/**
+ * @brief Check the remaining length of an incoming PUBLISH packet against some
+ * value for QoS 0, or for QoS 1 and 2.
+ *
+ * The remaining length for a QoS 1 and 2 packet will always be two greater than
+ * for a QoS 0.
+ *
+ * @param[in] remainingLength Remaining length of the PUBLISH packet.
+ * @param[in] qos The QoS of the PUBLISH.
+ * @param[in] qos0Minimum Minimum possible remaining length for a QoS 0 PUBLISH.
+ *
+ * @return #MQTTSuccess or #MQTTBadResponse.
+ */
+static MQTTStatus_t checkPublishRemainingLength( size_t remainingLength,
+                                                 MQTTQoS_t qos,
+                                                 size_t qos0Minimum );
+
+/**
+ * @brief Process the flags of an incoming PUBLISH packet.
+ *
+ * @param[in] publishFlags Flags of an incoming PUBLISH.
+ * @param[in, out] pPublishInfo Pointer to #MQTTPublishInfo_t struct where
+ * output will be written.
+ *
+ * @return #MQTTSuccess or #MQTTBadResponse.
+ */
+static MQTTStatus_t processPublishFlags( uint8_t publishFlags,
+                                         MQTTPublishInfo_t * pPublishInfo );
+
+/**
+ * @brief Deserialize a CONNACK packet.
+ *
+ * Converts the packet from a stream of bytes to an #MQTTStatus_t.
+ *
+ * @param[in] pConnack Pointer to an MQTT packet struct representing a
+ * CONNACK.
+ * @param[out] pSessionPresent Whether a previous session was present.
+ *
+ * @return #MQTTSuccess if CONNACK specifies that CONNECT was accepted;
+ * #MQTTServerRefused if CONNACK specifies that CONNECT was rejected;
+ * #MQTTBadResponse if the CONNACK packet doesn't follow MQTT spec.
+ */
+static MQTTStatus_t deserializeConnack( const MQTTPacketInfo_t * pConnack,
+                                        bool * pSessionPresent );
+
+/**
+ * @brief Decode the status bytes of a SUBACK packet to a #MQTTStatus_t.
+ *
+ * @param[in] statusCount Number of status bytes in the SUBACK.
+ * @param[in] pStatusStart The first status byte in the SUBACK.
+ *
+ * @return #MQTTSuccess, #MQTTServerRefused, or #MQTTBadResponse.
+ */
+static MQTTStatus_t readSubackStatus( size_t statusCount,
+                                      const uint8_t * pStatusStart );
+
+/**
+ * @brief Deserialize a SUBACK packet.
+ *
+ * Converts the packet from a stream of bytes to an #MQTTStatus_t and extracts
+ * the packet identifier.
+ *
+ * @param[in] pSuback Pointer to an MQTT packet struct representing a SUBACK.
+ * @param[out] pPacketIdentifier Packet ID of the SUBACK.
+ *
+ * @return #MQTTSuccess if SUBACK is valid; #MQTTBadResponse if SUBACK packet
+ * doesn't follow the MQTT spec.
+ */
+static MQTTStatus_t deserializeSuback( const MQTTPacketInfo_t * pSuback,
+                                       uint16_t * pPacketIdentifier );
+
+/**
+ * @brief Deserialize a PUBLISH packet received from the server.
+ *
+ * Converts the packet from a stream of bytes to an #MQTTPublishInfo_t and
+ * extracts the packet identifier. Also prints out debug log messages about the
+ * packet.
+ *
+ * @param[in] pIncomingPacket Pointer to an MQTT packet struct representing a
+ * PUBLISH.
+ * @param[out] pPacketId Packet identifier of the PUBLISH.
+ * @param[out] pPublishInfo Pointer to #MQTTPublishInfo_t where output is
+ * written.
+ *
+ * @return #MQTTSuccess if PUBLISH is valid; #MQTTBadResponse
+ * if the PUBLISH packet doesn't follow MQTT spec.
+ */
+static MQTTStatus_t deserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
+                                        uint16_t * pPacketId,
+                                        MQTTPublishInfo_t * pPublishInfo );
+
+/**
+ * @brief Deserialize an UNSUBACK, PUBACK, PUBREC, PUBREL, or PUBCOMP packet.
+ *
+ * Converts the packet from a stream of bytes to an #MQTTStatus_t and extracts
+ * the packet identifier.
+ *
+ * @param[in] pAck Pointer to the MQTT packet structure representing the packet.
+ * @param[out] pPacketIdentifier Packet ID of the ack type packet.
+ *
+ * @return #MQTTSuccess if UNSUBACK, PUBACK, PUBREC, PUBREL, or PUBCOMP is valid;
+ * #MQTTBadResponse if the packet doesn't follow the MQTT spec.
+ */
+static MQTTStatus_t deserializeSimpleAck( const MQTTPacketInfo_t * pAck,
+                                          uint16_t * pPacketIdentifier );
+
+/**
+ * @brief Deserialize a PINGRESP packet.
+ *
+ * Converts the packet from a stream of bytes to an #MQTTStatus_t.
+ *
+ * @param[in] pPingresp Pointer to an MQTT packet struct representing a PINGRESP.
+ *
+ * @return #MQTTSuccess if PINGRESP is valid; #MQTTBadResponse if the PINGRESP
+ * packet doesn't follow MQTT spec.
+ */
+static MQTTStatus_t deserializePingresp( const MQTTPacketInfo_t * pPingresp );
+
+/*-----------------------------------------------------------*/
+
+static size_t remainingLengthEncodedSize( size_t length )
+{
+    size_t encodedSize;
+
+    /* Determine how many bytes are needed to encode length.
+     * The values below are taken from the MQTT 3.1.1 spec. */
+
+    /* 1 byte is needed to encode lengths between 0 and 127. */
+    if( length < 128U )
+    {
+        encodedSize = 1U;
+    }
+    /* 2 bytes are needed to encode lengths between 128 and 16,383. */
+    else if( length < 16384U )
+    {
+        encodedSize = 2U;
+    }
+    /* 3 bytes are needed to encode lengths between 16,384 and 2,097,151. */
+    else if( length < 2097152U )
+    {
+        encodedSize = 3U;
+    }
+    /* 4 bytes are needed to encode lengths between 2,097,152 and 268,435,455. */
+    else
+    {
+        encodedSize = 4U;
+    }
+
+    LogDebug( ( "Encoded size for length %lu is %lu bytes.",
+                ( unsigned long ) length,
+                ( unsigned long ) encodedSize ) );
+
+    return encodedSize;
+}
+
+/*-----------------------------------------------------------*/
+
+static uint8_t * encodeRemainingLength( uint8_t * pDestination,
+                                        size_t length )
+{
+    uint8_t lengthByte;
+    uint8_t * pLengthEnd = NULL;
+    size_t remainingLength = length;
+
+    assert( pDestination != NULL );
+
+    pLengthEnd = pDestination;
+
+    /* This algorithm is copied from the MQTT v3.1.1 spec. */
+    do
+    {
+        lengthByte = ( uint8_t ) ( remainingLength % 128U );
+        remainingLength = remainingLength / 128U;
+
+        /* Set the high bit of this byte, indicating that there's more data. */
+        if( remainingLength > 0U )
+        {
+            UINT8_SET_BIT( lengthByte, 7 );
+        }
+
+        /* Output a single encoded byte. */
+        *pLengthEnd = lengthByte;
+        pLengthEnd++;
+    } while( remainingLength > 0U );
+
+    return pLengthEnd;
+}
+
+/*-----------------------------------------------------------*/
+
+static uint8_t * encodeString( uint8_t * pDestination,
+                               const char * pSource,
+                               uint16_t sourceLength )
+{
+    uint8_t * pBuffer = NULL;
+
+    assert( pDestination != NULL );
+
+    pBuffer = pDestination;
+
+    /* The first byte of a UTF-8 string is the high byte of the string length. */
+    *pBuffer = UINT16_HIGH_BYTE( sourceLength );
+    pBuffer++;
+
+    /* The second byte of a UTF-8 string is the low byte of the string length. */
+    *pBuffer = UINT16_LOW_BYTE( sourceLength );
+    pBuffer++;
+
+    /* Copy the string into pBuffer. */
+    if( pSource != NULL )
+    {
+        ( void ) memcpy( ( void * ) pBuffer, ( const void * ) pSource, sourceLength );
+    }
+
+    /* Return the pointer to the end of the encoded string. */
+    pBuffer = &pBuffer[ sourceLength ];
+
+    return pBuffer;
+}
+
+/*-----------------------------------------------------------*/
+
+static bool calculatePublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
+                                        size_t * pRemainingLength,
+                                        size_t * pPacketSize )
+{
+    bool status = true;
+    size_t packetSize = 0, payloadLimit = 0;
+
+    assert( pPublishInfo != NULL );
+    assert( pRemainingLength != NULL );
+    assert( pPacketSize != NULL );
+
+    /* The variable header of a PUBLISH packet always contains the topic name.
+     * The first 2 bytes of UTF-8 string contains length of the string.
+     */
+    packetSize += pPublishInfo->topicNameLength + sizeof( uint16_t );
+
+    /* The variable header of a QoS 1 or 2 PUBLISH packet contains a 2-byte
+     * packet identifier. */
+    if( pPublishInfo->qos > MQTTQoS0 )
+    {
+        packetSize += sizeof( uint16_t );
+    }
+
+    /* Calculate the maximum allowed size of the payload for the given parameters.
+     * This calculation excludes the "Remaining length" encoding, whose size is not
+     * yet known. */
+    payloadLimit = MQTT_MAX_REMAINING_LENGTH - packetSize - 1U;
+
+    /* Ensure that the given payload fits within the calculated limit. */
+    if( pPublishInfo->payloadLength > payloadLimit )
+    {
+        LogError( ( "PUBLISH payload length of %lu cannot exceed "
+                    "%lu so as not to exceed the maximum "
+                    "remaining length of MQTT 3.1.1 packet( %lu ).",
+                    ( unsigned long ) pPublishInfo->payloadLength,
+                    ( unsigned long ) payloadLimit,
+                    MQTT_MAX_REMAINING_LENGTH ) );
+        status = false;
+    }
+    else
+    {
+        /* Add the length of the PUBLISH payload. At this point, the "Remaining length"
+         * has been calculated. */
+        packetSize += pPublishInfo->payloadLength;
+
+        /* Now that the "Remaining length" is known, recalculate the payload limit
+         * based on the size of its encoding. */
+        payloadLimit -= remainingLengthEncodedSize( packetSize );
+
+        /* Check that the given payload fits within the size allowed by MQTT spec. */
+        if( pPublishInfo->payloadLength > payloadLimit )
+        {
+            LogError( ( "PUBLISH payload length of %lu cannot exceed "
+                        "%lu so as not to exceed the maximum "
+                        "remaining length of MQTT 3.1.1 packet( %lu ).",
+                        ( unsigned long ) pPublishInfo->payloadLength,
+                        ( unsigned long ) payloadLimit,
+                        MQTT_MAX_REMAINING_LENGTH ) );
+            status = false;
+        }
+        else
+        {
+            /* Set the "Remaining length" output parameter and calculate the full
+             * size of the PUBLISH packet. */
+            *pRemainingLength = packetSize;
+
+            packetSize += 1U + remainingLengthEncodedSize( packetSize );
+            *pPacketSize = packetSize;
+        }
+    }
+
+    LogDebug( ( "PUBLISH packet remaining length=%lu and packet size=%lu.",
+                ( unsigned long ) *pRemainingLength,
+                ( unsigned long ) *pPacketSize ) );
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_SerializePublishHeaderWithoutTopic( const MQTTPublishInfo_t * pPublishInfo,
+                                                      size_t remainingLength,
+                                                      uint8_t * pBuffer,
+                                                      size_t * headerSize )
+{
+    size_t headerLength;
+    uint8_t * pIndex;
+    MQTTStatus_t status = MQTTSuccess;
+
+    /* The first byte of a PUBLISH packet contains the packet type and flags. */
+    uint8_t publishFlags = MQTT_PACKET_TYPE_PUBLISH;
+
+    /* Get the start address of the buffer. */
+    pIndex = pBuffer;
+
+    /* Length of serialized packet = First byte
+     *                               + Length of encoded remaining length
+     *                               + Encoded topic length. */
+    headerLength = 1U + remainingLengthEncodedSize( remainingLength ) + 2U;
+
+    if( pPublishInfo->qos == MQTTQoS1 )
+    {
+        LogDebug( ( "Adding QoS as QoS1 in PUBLISH flags." ) );
+        UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 );
+    }
+    else if( pPublishInfo->qos == MQTTQoS2 )
+    {
+        LogDebug( ( "Adding QoS as QoS2 in PUBLISH flags." ) );
+        UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 );
+    }
+    else
+    {
+        /* Empty else MISRA 15.7 */
+    }
+
+    if( pPublishInfo->retain == true )
+    {
+        LogDebug( ( "Adding retain bit in PUBLISH flags." ) );
+        UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );
+    }
+
+    if( pPublishInfo->dup == true )
+    {
+        LogDebug( ( "Adding dup bit in PUBLISH flags." ) );
+        UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP );
+    }
+
+    *pIndex = publishFlags;
+    pIndex++;
+
+    /* The "Remaining length" is encoded from the second byte. */
+    pIndex = encodeRemainingLength( pIndex, remainingLength );
+
+    /* The first byte of a UTF-8 string is the high byte of the string length. */
+    *pIndex = UINT16_HIGH_BYTE( pPublishInfo->topicNameLength );
+    pIndex++;
+
+    /* The second byte of a UTF-8 string is the low byte of the string length. */
+    *pIndex = UINT16_LOW_BYTE( pPublishInfo->topicNameLength );
+    pIndex++;
+
+    *headerSize = headerLength;
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static void serializePublishCommon( const MQTTPublishInfo_t * pPublishInfo,
+                                    size_t remainingLength,
+                                    uint16_t packetIdentifier,
+                                    const MQTTFixedBuffer_t * pFixedBuffer,
+                                    bool serializePayload )
+{
+    uint8_t * pIndex = NULL;
+
+    /* The first byte of a PUBLISH packet contains the packet type and flags. */
+    uint8_t publishFlags = MQTT_PACKET_TYPE_PUBLISH;
+
+    assert( pPublishInfo != NULL );
+    assert( pFixedBuffer != NULL );
+    assert( pFixedBuffer->pBuffer != NULL );
+    /* Packet Id should be non zero for Qos 1 and Qos 2. */
+    assert( ( pPublishInfo->qos == MQTTQoS0 ) || ( packetIdentifier != 0U ) );
+    /* Duplicate flag should be set only for Qos 1 or Qos 2. */
+    assert( ( pPublishInfo->dup != true ) || ( pPublishInfo->qos != MQTTQoS0 ) );
+
+    /* Get the start address of the buffer. */
+    pIndex = pFixedBuffer->pBuffer;
+
+    if( pPublishInfo->qos == MQTTQoS1 )
+    {
+        LogDebug( ( "Adding QoS as QoS1 in PUBLISH flags." ) );
+        UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 );
+    }
+    else if( pPublishInfo->qos == MQTTQoS2 )
+    {
+        LogDebug( ( "Adding QoS as QoS2 in PUBLISH flags." ) );
+        UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 );
+    }
+    else
+    {
+        /* Empty else MISRA 15.7 */
+    }
+
+    if( pPublishInfo->retain == true )
+    {
+        LogDebug( ( "Adding retain bit in PUBLISH flags." ) );
+        UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );
+    }
+
+    if( pPublishInfo->dup == true )
+    {
+        LogDebug( ( "Adding dup bit in PUBLISH flags." ) );
+        UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP );
+    }
+
+    *pIndex = publishFlags;
+    pIndex++;
+
+    /* The "Remaining length" is encoded from the second byte. */
+    pIndex = encodeRemainingLength( pIndex, remainingLength );
+
+    /* The topic name is placed after the "Remaining length". */
+    pIndex = encodeString( pIndex,
+                           pPublishInfo->pTopicName,
+                           pPublishInfo->topicNameLength );
+
+    /* A packet identifier is required for QoS 1 and 2 messages. */
+    if( pPublishInfo->qos > MQTTQoS0 )
+    {
+        LogDebug( ( "Adding packet Id in PUBLISH packet." ) );
+        /* Place the packet identifier into the PUBLISH packet. */
+        *pIndex = UINT16_HIGH_BYTE( packetIdentifier );
+        pIndex[ 1U ] = UINT16_LOW_BYTE( packetIdentifier );
+        pIndex = &pIndex[ 2U ];
+    }
+
+    /* The payload is placed after the packet identifier.
+     * Payload is copied over only if required by the flag serializePayload.
+     * This will help reduce an unnecessary copy of the payload into the buffer.
+     */
+    if( ( pPublishInfo->payloadLength > 0U ) &&
+        ( serializePayload == true ) )
+    {
+        LogDebug( ( "Copying PUBLISH payload of length =%lu to buffer",
+                    ( unsigned long ) pPublishInfo->payloadLength ) );
+
+        ( void ) memcpy( ( void * ) pIndex, ( const void * ) pPublishInfo->pPayload, pPublishInfo->payloadLength );
+        /* Move the index to after the payload. */
+        pIndex = &pIndex[ pPublishInfo->payloadLength ];
+    }
+
+    /* Ensure that the difference between the end and beginning of the buffer
+     * is less than the buffer size. */
+    assert( ( ( size_t ) ( pIndex - pFixedBuffer->pBuffer ) ) <= pFixedBuffer->size );
+}
+
+static size_t getRemainingLength( TransportRecv_t recvFunc,
+                                  NetworkContext_t * pNetworkContext )
+{
+    size_t remainingLength = 0, multiplier = 1, bytesDecoded = 0, expectedSize = 0;
+    uint8_t encodedByte = 0;
+    int32_t bytesReceived = 0;
+
+    /* This algorithm is copied from the MQTT v3.1.1 spec. */
+    do
+    {
+        if( multiplier > 2097152U ) /* 128 ^ 3 */
+        {
+            remainingLength = MQTT_REMAINING_LENGTH_INVALID;
+        }
+        else
+        {
+            bytesReceived = recvFunc( pNetworkContext, &encodedByte, 1U );
+
+            if( bytesReceived == 1 )
+            {
+                remainingLength += ( ( size_t ) encodedByte & 0x7FU ) * multiplier;
+                multiplier *= 128U;
+                bytesDecoded++;
+            }
+            else
+            {
+                remainingLength = MQTT_REMAINING_LENGTH_INVALID;
+            }
+        }
+
+        if( remainingLength == MQTT_REMAINING_LENGTH_INVALID )
+        {
+            break;
+        }
+    } while( ( encodedByte & 0x80U ) != 0U );
+
+    /* Check that the decoded remaining length conforms to the MQTT specification. */
+    if( remainingLength != MQTT_REMAINING_LENGTH_INVALID )
+    {
+        expectedSize = remainingLengthEncodedSize( remainingLength );
+
+        if( bytesDecoded != expectedSize )
+        {
+            remainingLength = MQTT_REMAINING_LENGTH_INVALID;
+        }
+    }
+
+    return remainingLength;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t processRemainingLength( const uint8_t * pBuffer,
+                                            const size_t * pIndex,
+                                            MQTTPacketInfo_t * pIncomingPacket )
+{
+    size_t remainingLength = 0;
+    size_t multiplier = 1;
+    size_t bytesDecoded = 0;
+    size_t expectedSize = 0;
+    uint8_t encodedByte = 0;
+    MQTTStatus_t status = MQTTSuccess;
+
+    /* This algorithm is copied from the MQTT v3.1.1 spec. */
+    do
+    {
+        if( multiplier > 2097152U ) /* 128 ^ 3 */
+        {
+            remainingLength = MQTT_REMAINING_LENGTH_INVALID;
+
+            LogError( ( "Invalid remaining length in the packet.\n" ) );
+
+            status = MQTTBadResponse;
+        }
+        else
+        {
+            if( *pIndex > ( bytesDecoded + 1U ) )
+            {
+                /* Get the next byte. It is at the next position after the bytes
+                 * decoded till now since the header of one byte was read before. */
+                encodedByte = pBuffer[ bytesDecoded + 1U ];
+
+                remainingLength += ( ( size_t ) encodedByte & 0x7FU ) * multiplier;
+                multiplier *= 128U;
+                bytesDecoded++;
+            }
+            else
+            {
+                status = MQTTNeedMoreBytes;
+            }
+        }
+
+        /* If the response is incorrect, or no more data is available, then
+         * break out of the loop. */
+        if( ( remainingLength == MQTT_REMAINING_LENGTH_INVALID ) ||
+            ( status != MQTTSuccess ) )
+        {
+            break;
+        }
+    } while( ( encodedByte & 0x80U ) != 0U );
+
+    if( status == MQTTSuccess )
+    {
+        /* Check that the decoded remaining length conforms to the MQTT specification. */
+        expectedSize = remainingLengthEncodedSize( remainingLength );
+
+        if( bytesDecoded != expectedSize )
+        {
+            LogError( ( "Expected and actual length of decoded bytes do not match.\n" ) );
+            status = MQTTBadResponse;
+        }
+        else
+        {
+            pIncomingPacket->remainingLength = remainingLength;
+            pIncomingPacket->headerLength = bytesDecoded + 1U;
+        }
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static bool incomingPacketValid( uint8_t packetType )
+{
+    bool status = false;
+
+    /* Check packet type. Mask out lower bits to ignore flags. */
+    switch( packetType & 0xF0U )
+    {
+        /* Valid incoming packet types. */
+        case MQTT_PACKET_TYPE_CONNACK:
+        case MQTT_PACKET_TYPE_PUBLISH:
+        case MQTT_PACKET_TYPE_PUBACK:
+        case MQTT_PACKET_TYPE_PUBREC:
+        case MQTT_PACKET_TYPE_PUBCOMP:
+        case MQTT_PACKET_TYPE_SUBACK:
+        case MQTT_PACKET_TYPE_UNSUBACK:
+        case MQTT_PACKET_TYPE_PINGRESP:
+            status = true;
+            break;
+
+        case ( MQTT_PACKET_TYPE_PUBREL & 0xF0U ):
+
+            /* The second bit of a PUBREL must be set. */
+            if( ( packetType & 0x02U ) > 0U )
+            {
+                status = true;
+            }
+
+            break;
+
+        /* Any other packet type is invalid. */
+        default:
+            LogWarn( ( "Incoming packet invalid: Packet type=%u.",
+                       ( unsigned int ) packetType ) );
+            break;
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t checkPublishRemainingLength( size_t remainingLength,
+                                                 MQTTQoS_t qos,
+                                                 size_t qos0Minimum )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    /* Sanity checks for "Remaining length". */
+    if( qos == MQTTQoS0 )
+    {
+        /* Check that the "Remaining length" is greater than the minimum. */
+        if( remainingLength < qos0Minimum )
+        {
+            LogError( ( "QoS 0 PUBLISH cannot have a remaining length less than %lu.",
+                        ( unsigned long ) qos0Minimum ) );
+
+            status = MQTTBadResponse;
+        }
+    }
+    else
+    {
+        /* Check that the "Remaining length" is greater than the minimum. For
+         * QoS 1 or 2, this will be two bytes greater than for QoS 0 due to the
+         * packet identifier. */
+        if( remainingLength < ( qos0Minimum + 2U ) )
+        {
+            LogError( ( "QoS 1 or 2 PUBLISH cannot have a remaining length less than %lu.",
+                        ( unsigned long ) ( qos0Minimum + 2U ) ) );
+
+            status = MQTTBadResponse;
+        }
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t processPublishFlags( uint8_t publishFlags,
+                                         MQTTPublishInfo_t * pPublishInfo )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    assert( pPublishInfo != NULL );
+
+    /* Check for QoS 2. */
+    if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 ) )
+    {
+        /* PUBLISH packet is invalid if both QoS 1 and QoS 2 bits are set. */
+        if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) )
+        {
+            LogError( ( "Bad QoS: 3." ) );
+
+            status = MQTTBadResponse;
+        }
+        else
+        {
+            pPublishInfo->qos = MQTTQoS2;
+        }
+    }
+    /* Check for QoS 1. */
+    else if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) )
+    {
+        pPublishInfo->qos = MQTTQoS1;
+    }
+    /* If the PUBLISH isn't QoS 1 or 2, then it's QoS 0. */
+    else
+    {
+        pPublishInfo->qos = MQTTQoS0;
+    }
+
+    if( status == MQTTSuccess )
+    {
+        LogDebug( ( "QoS is %d.", ( int ) pPublishInfo->qos ) );
+
+        /* Parse the Retain bit. */
+        pPublishInfo->retain = UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );
+
+        LogDebug( ( "Retain bit is %d.", ( int ) pPublishInfo->retain ) );
+
+        /* Parse the DUP bit. */
+        pPublishInfo->dup = UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP );
+
+        LogDebug( ( "DUP bit is %d.", ( int ) pPublishInfo->dup ) );
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static void logConnackResponse( uint8_t responseCode )
+{
+    const char * const pConnackResponses[ 6 ] =
+    {
+        "Connection accepted.",                               /* 0 */
+        "Connection refused: unacceptable protocol version.", /* 1 */
+        "Connection refused: identifier rejected.",           /* 2 */
+        "Connection refused: server unavailable",             /* 3 */
+        "Connection refused: bad user name or password.",     /* 4 */
+        "Connection refused: not authorized."                 /* 5 */
+    };
+
+    /* Avoid unused parameter warning when assert and logs are disabled. */
+    ( void ) responseCode;
+    ( void ) pConnackResponses;
+
+    assert( responseCode <= 5U );
+
+    if( responseCode == 0u )
+    {
+        /* Log at Debug level for a success CONNACK response. */
+        LogDebug( ( "%s", pConnackResponses[ 0 ] ) );
+    }
+    else
+    {
+        /* Log an error based on the CONNACK response code. */
+        LogError( ( "%s", pConnackResponses[ responseCode ] ) );
+    }
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t deserializeConnack( const MQTTPacketInfo_t * pConnack,
+                                        bool * pSessionPresent )
+{
+    MQTTStatus_t status = MQTTSuccess;
+    const uint8_t * pRemainingData = NULL;
+
+    assert( pConnack != NULL );
+    assert( pSessionPresent != NULL );
+    pRemainingData = pConnack->pRemainingData;
+
+    /* According to MQTT 3.1.1, the second byte of CONNACK must specify a
+     * "Remaining length" of 2. */
+    if( pConnack->remainingLength != MQTT_PACKET_CONNACK_REMAINING_LENGTH )
+    {
+        LogError( ( "CONNACK does not have remaining length of %u.",
+                    ( unsigned int ) MQTT_PACKET_CONNACK_REMAINING_LENGTH ) );
+
+        status = MQTTBadResponse;
+    }
+
+    /* Check the reserved bits in CONNACK. The high 7 bits of the third byte
+     * in CONNACK must be 0. */
+    else if( ( pRemainingData[ 0 ] | 0x01U ) != 0x01U )
+    {
+        LogError( ( "Reserved bits in CONNACK incorrect." ) );
+
+        status = MQTTBadResponse;
+    }
+    else
+    {
+        /* Determine if the "Session Present" bit is set. This is the lowest bit of
+         * the third byte in CONNACK. */
+        if( ( pRemainingData[ 0 ] & MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK )
+            == MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK )
+        {
+            LogDebug( ( "CONNACK session present bit set." ) );
+            *pSessionPresent = true;
+
+            /* MQTT 3.1.1 specifies that the fourth byte in CONNACK must be 0 if the
+             * "Session Present" bit is set. */
+            if( pRemainingData[ 1 ] != 0U )
+            {
+                LogError( ( "Session Present bit is set, but connect return code in CONNACK is %u (nonzero).",
+                            ( unsigned int ) pRemainingData[ 1 ] ) );
+                status = MQTTBadResponse;
+            }
+        }
+        else
+        {
+            LogDebug( ( "CONNACK session present bit not set." ) );
+            *pSessionPresent = false;
+        }
+    }
+
+    if( status == MQTTSuccess )
+    {
+        /* In MQTT 3.1.1, only values 0 through 5 are valid CONNACK response codes. */
+        if( pRemainingData[ 1 ] > 5U )
+        {
+            LogError( ( "CONNACK response %u is invalid.",
+                        ( unsigned int ) pRemainingData[ 1 ] ) );
+
+            status = MQTTBadResponse;
+        }
+        else
+        {
+            /* Print the appropriate message for the CONNACK response code if logs are
+             * enabled. */
+            logConnackResponse( pRemainingData[ 1 ] );
+
+            /* A nonzero CONNACK response code means the connection was refused. */
+            if( pRemainingData[ 1 ] > 0U )
+            {
+                status = MQTTServerRefused;
+            }
+        }
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t calculateSubscriptionPacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
+                                                     size_t subscriptionCount,
+                                                     size_t * pRemainingLength,
+                                                     size_t * pPacketSize,
+                                                     MQTTSubscriptionType_t subscriptionType )
+{
+    MQTTStatus_t status = MQTTSuccess;
+    size_t i = 0, packetSize = 0;
+
+    assert( pSubscriptionList != NULL );
+    assert( subscriptionCount != 0U );
+    assert( pRemainingLength != NULL );
+    assert( pPacketSize != NULL );
+
+    /* The variable header of a subscription packet consists of a 2-byte packet
+     * identifier. */
+    packetSize += sizeof( uint16_t );
+
+    /* Sum the lengths of all subscription topic filters; add 1 byte for each
+     * subscription's QoS if type is MQTT_SUBSCRIBE. */
+    for( i = 0; i < subscriptionCount; i++ )
+    {
+        /* Add the length of the topic filter. MQTT strings are prepended
+         * with 2 byte string length field. Hence 2 bytes are added to size. */
+        packetSize += pSubscriptionList[ i ].topicFilterLength + sizeof( uint16_t );
+
+        /* Only SUBSCRIBE packets include the QoS. */
+        if( subscriptionType == MQTT_SUBSCRIBE )
+        {
+            packetSize += 1U;
+        }
+
+        /* Validate each topic filter. */
+        if( ( pSubscriptionList[ i ].topicFilterLength == 0U ) ||
+            ( pSubscriptionList[ i ].pTopicFilter == NULL ) )
+        {
+            status = MQTTBadParameter;
+            LogError( ( "Subscription #%lu in %sSUBSCRIBE packet cannot be empty.",
+                        ( unsigned long ) i,
+                        ( subscriptionType == MQTT_SUBSCRIBE ) ? "" : "UN" ) );
+            /* It is not necessary to break as an error status has already been set. */
+        }
+    }
+
+    /* At this point, the "Remaining length" has been calculated. Return error
+     * if the "Remaining length" exceeds what is allowed by MQTT 3.1.1. Otherwise,
+     * set the output parameter.*/
+    if( packetSize > MQTT_MAX_REMAINING_LENGTH )
+    {
+        LogError( ( "Subscription packet length of %lu exceeds"
+                    "the MQTT 3.1.1 maximum packet length of %lu.",
+                    ( unsigned long ) packetSize,
+                    MQTT_MAX_REMAINING_LENGTH ) );
+        status = MQTTBadParameter;
+    }
+
+    if( status == MQTTSuccess )
+    {
+        *pRemainingLength = packetSize;
+
+        /* Calculate the full size of the subscription packet by adding
+         * number of bytes required to encode the "Remaining length" field
+         * plus 1 byte for the "Packet type" field. */
+        packetSize += 1U + remainingLengthEncodedSize( packetSize );
+
+        /*Set the pPacketSize output parameter. */
+        *pPacketSize = packetSize;
+    }
+
+    LogDebug( ( "Subscription packet remaining length=%lu and packet size=%lu.",
+                ( unsigned long ) *pRemainingLength,
+                ( unsigned long ) *pPacketSize ) );
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t readSubackStatus( size_t statusCount,
+                                      const uint8_t * pStatusStart )
+{
+    MQTTStatus_t status = MQTTSuccess;
+    uint8_t subscriptionStatus = 0;
+    size_t i = 0;
+
+    assert( pStatusStart != NULL );
+
+    /* Iterate through each status byte in the SUBACK packet. */
+    for( i = 0; i < statusCount; i++ )
+    {
+        /* Read a single status byte in SUBACK. */
+        subscriptionStatus = pStatusStart[ i ];
+
+        /* MQTT 3.1.1 defines the following values as status codes. */
+        switch( subscriptionStatus )
+        {
+            case 0x00:
+            case 0x01:
+            case 0x02:
+
+                LogDebug( ( "Topic filter %lu accepted, max QoS %u.",
+                            ( unsigned long ) i,
+                            ( unsigned int ) subscriptionStatus ) );
+                break;
+
+            case 0x80:
+
+                LogWarn( ( "Topic filter %lu refused.", ( unsigned long ) i ) );
+
+                /* Application should remove subscription from the list */
+                status = MQTTServerRefused;
+
+                break;
+
+            default:
+                LogError( ( "Bad SUBSCRIBE status %u.",
+                            ( unsigned int ) subscriptionStatus ) );
+
+                status = MQTTBadResponse;
+
+                break;
+        }
+
+        /* Stop parsing the subscription statuses if a bad response was received. */
+        if( status == MQTTBadResponse )
+        {
+            break;
+        }
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t deserializeSuback( const MQTTPacketInfo_t * pSuback,
+                                       uint16_t * pPacketIdentifier )
+{
+    MQTTStatus_t status = MQTTSuccess;
+    size_t remainingLength;
+    const uint8_t * pVariableHeader = NULL;
+
+    assert( pSuback != NULL );
+    assert( pPacketIdentifier != NULL );
+
+    remainingLength = pSuback->remainingLength;
+    pVariableHeader = pSuback->pRemainingData;
+
+    /* A SUBACK must have a remaining length of at least 3 to accommodate the
+     * packet identifier and at least 1 return code. */
+    if( remainingLength < 3U )
+    {
+        LogError( ( "SUBACK cannot have a remaining length less than 3." ) );
+        status = MQTTBadResponse;
+    }
+    else
+    {
+        /* Extract the packet identifier (first 2 bytes of variable header) from SUBACK. */
+        *pPacketIdentifier = UINT16_DECODE( pVariableHeader );
+
+        LogDebug( ( "Packet identifier %hu.",
+                    ( unsigned short ) *pPacketIdentifier ) );
+
+        if( *pPacketIdentifier == 0U )
+        {
+            status = MQTTBadResponse;
+        }
+        else
+        {
+            status = readSubackStatus( remainingLength - sizeof( uint16_t ),
+                                       &pVariableHeader[ sizeof( uint16_t ) ] );
+        }
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t validateSubscriptionSerializeParams( const MQTTSubscribeInfo_t * pSubscriptionList,
+                                                         size_t subscriptionCount,
+                                                         uint16_t packetId,
+                                                         size_t remainingLength,
+                                                         const MQTTFixedBuffer_t * pFixedBuffer )
+{
+    MQTTStatus_t status = MQTTSuccess;
+    size_t packetSize = 0;
+
+    /* Validate all the parameters. */
+    if( ( pFixedBuffer == NULL ) || ( pSubscriptionList == NULL ) )
+    {
+        LogError( ( "Argument cannot be NULL: pFixedBuffer=%p, "
+                    "pSubscriptionList=%p.",
+                    ( void * ) pFixedBuffer,
+                    ( void * ) pSubscriptionList ) );
+        status = MQTTBadParameter;
+    }
+    /* A buffer must be configured for serialization. */
+    else if( pFixedBuffer->pBuffer == NULL )
+    {
+        LogError( ( "Argument cannot be NULL: pFixedBuffer->pBuffer is NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else if( subscriptionCount == 0U )
+    {
+        LogError( ( "Subscription count is 0." ) );
+        status = MQTTBadParameter;
+    }
+    else if( packetId == 0U )
+    {
+        LogError( ( "Packet Id for subscription packet is 0." ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        /* The serialized packet size = First byte
+         * + length of encoded size of remaining length
+         * + remaining length. */
+        packetSize = 1U + remainingLengthEncodedSize( remainingLength )
+                     + remainingLength;
+
+        if( packetSize > pFixedBuffer->size )
+        {
+            LogError( ( "Buffer size of %lu is not sufficient to hold "
+                        "serialized packet of size of %lu.",
+                        ( unsigned long ) pFixedBuffer->size,
+                        ( unsigned long ) packetSize ) );
+            status = MQTTNoMemory;
+        }
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t deserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
+                                        uint16_t * pPacketId,
+                                        MQTTPublishInfo_t * pPublishInfo )
+{
+    MQTTStatus_t status = MQTTSuccess;
+    const uint8_t * pVariableHeader, * pPacketIdentifierHigh = NULL;
+
+    assert( pIncomingPacket != NULL );
+    assert( pPacketId != NULL );
+    assert( pPublishInfo != NULL );
+    assert( pIncomingPacket->pRemainingData != NULL );
+
+    pVariableHeader = pIncomingPacket->pRemainingData;
+    /* The flags are the lower 4 bits of the first byte in PUBLISH. */
+    status = processPublishFlags( ( pIncomingPacket->type & 0x0FU ), pPublishInfo );
+
+    if( status == MQTTSuccess )
+    {
+        /* Sanity checks for "Remaining length". A QoS 0 PUBLISH  must have a remaining
+         * length of at least 3 to accommodate topic name length (2 bytes) and topic
+         * name (at least 1 byte). A QoS 1 or 2 PUBLISH must have a remaining length of
+         * at least 5 for the packet identifier in addition to the topic name length and
+         * topic name. */
+        status = checkPublishRemainingLength( pIncomingPacket->remainingLength,
+                                              pPublishInfo->qos,
+                                              MQTT_MIN_PUBLISH_REMAINING_LENGTH_QOS0 );
+    }
+
+    if( status == MQTTSuccess )
+    {
+        /* Extract the topic name starting from the first byte of the variable header.
+         * The topic name string starts at byte 3 in the variable header. */
+        pPublishInfo->topicNameLength = UINT16_DECODE( pVariableHeader );
+
+        /* Sanity checks for topic name length and "Remaining length". The remaining
+         * length must be at least as large as the variable length header. */
+        status = checkPublishRemainingLength( pIncomingPacket->remainingLength,
+                                              pPublishInfo->qos,
+                                              pPublishInfo->topicNameLength + sizeof( uint16_t ) );
+    }
+
+    if( status == MQTTSuccess )
+    {
+        /* Parse the topic. */
+        pPublishInfo->pTopicName = ( const char * ) ( &pVariableHeader[ sizeof( uint16_t ) ] );
+        LogDebug( ( "Topic name length: %hu.", ( unsigned short ) pPublishInfo->topicNameLength ) );
+
+        /* Extract the packet identifier for QoS 1 or 2 PUBLISH packets. Packet
+         * identifier starts immediately after the topic name. */
+        /* coverity[tainted_scalar] */
+        pPacketIdentifierHigh = ( const uint8_t * ) ( &pPublishInfo->pTopicName[ pPublishInfo->topicNameLength ] );
+
+        if( pPublishInfo->qos > MQTTQoS0 )
+        {
+            *pPacketId = UINT16_DECODE( pPacketIdentifierHigh );
+
+            LogDebug( ( "Packet identifier %hu.",
+                        ( unsigned short ) *pPacketId ) );
+
+            /* Advance pointer two bytes to start of payload as in the QoS 0 case. */
+            pPacketIdentifierHigh = &pPacketIdentifierHigh[ sizeof( uint16_t ) ];
+
+            /* Packet identifier cannot be 0. */
+            if( *pPacketId == 0U )
+            {
+                LogError( ( "Packet identifier cannot be 0." ) );
+                status = MQTTBadResponse;
+            }
+        }
+    }
+
+    if( status == MQTTSuccess )
+    {
+        /* Calculate the length of the payload. QoS 1 or 2 PUBLISH packets contain
+         * a packet identifier, but QoS 0 PUBLISH packets do not. */
+        pPublishInfo->payloadLength = pIncomingPacket->remainingLength - pPublishInfo->topicNameLength - sizeof( uint16_t );
+
+        if( pPublishInfo->qos != MQTTQoS0 )
+        {
+            /* Two more bytes for the packet identifier. */
+            pPublishInfo->payloadLength -= sizeof( uint16_t );
+        }
+
+        /* Set payload if it exists. */
+        pPublishInfo->pPayload = ( pPublishInfo->payloadLength != 0U ) ? pPacketIdentifierHigh : NULL;
+
+        LogDebug( ( "Payload length %lu.",
+                    ( unsigned long ) pPublishInfo->payloadLength ) );
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t deserializeSimpleAck( const MQTTPacketInfo_t * pAck,
+                                          uint16_t * pPacketIdentifier )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    assert( pAck != NULL );
+    assert( pPacketIdentifier != NULL );
+
+    /* Check that the "Remaining length" of the received ACK is 2. */
+    if( pAck->remainingLength != MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH )
+    {
+        LogError( ( "ACK does not have remaining length of %u.",
+                    ( unsigned int ) MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH ) );
+
+        status = MQTTBadResponse;
+    }
+    else
+    {
+        /* Extract the packet identifier (third and fourth bytes) from ACK. */
+        *pPacketIdentifier = UINT16_DECODE( pAck->pRemainingData );
+
+        LogDebug( ( "Packet identifier %hu.",
+                    ( unsigned short ) *pPacketIdentifier ) );
+
+        /* Packet identifier cannot be 0. */
+        if( *pPacketIdentifier == 0U )
+        {
+            LogError( ( "Packet identifier cannot be 0." ) );
+            status = MQTTBadResponse;
+        }
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t deserializePingresp( const MQTTPacketInfo_t * pPingresp )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    assert( pPingresp != NULL );
+
+    /* Check the "Remaining length" (second byte) of the received PINGRESP is 0. */
+    if( pPingresp->remainingLength != MQTT_PACKET_PINGRESP_REMAINING_LENGTH )
+    {
+        LogError( ( "PINGRESP does not have remaining length of %u.",
+                    MQTT_PACKET_PINGRESP_REMAINING_LENGTH ) );
+
+        status = MQTTBadResponse;
+    }
+
+    return status;
+}
+
+uint8_t * MQTT_SerializeConnectFixedHeader( uint8_t * pIndex,
+                                            const MQTTConnectInfo_t * pConnectInfo,
+                                            const MQTTPublishInfo_t * pWillInfo,
+                                            size_t remainingLength )
+{
+    uint8_t * pIndexLocal = pIndex;
+    uint8_t connectFlags = 0U;
+
+    /* The first byte in the CONNECT packet is the control packet type. */
+    *pIndexLocal = MQTT_PACKET_TYPE_CONNECT;
+    pIndexLocal++;
+
+    /* The remaining length of the CONNECT packet is encoded starting from the
+     * second byte. The remaining length does not include the length of the fixed
+     * header or the encoding of the remaining length. */
+    pIndexLocal = encodeRemainingLength( pIndexLocal, remainingLength );
+
+    /* The string "MQTT" is placed at the beginning of the CONNECT packet's variable
+     * header. This string is 4 bytes long. */
+    pIndexLocal = encodeString( pIndexLocal, "MQTT", 4 );
+
+    /* The MQTT protocol version is the second field of the variable header. */
+    *pIndexLocal = MQTT_VERSION_3_1_1;
+    pIndexLocal++;
+
+    /* Set the clean session flag if needed. */
+    if( pConnectInfo->cleanSession == true )
+    {
+        UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_CLEAN );
+    }
+
+    /* Set the flags for username and password if provided. */
+    if( pConnectInfo->pUserName != NULL )
+    {
+        UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_USERNAME );
+    }
+
+    if( pConnectInfo->pPassword != NULL )
+    {
+        UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_PASSWORD );
+    }
+
+    /* Set will flag if a Last Will and Testament is provided. */
+    if( pWillInfo != NULL )
+    {
+        UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL );
+
+        /* Flags only need to be changed for Will QoS 1 or 2. */
+        if( pWillInfo->qos == MQTTQoS1 )
+        {
+            UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS1 );
+        }
+        else if( pWillInfo->qos == MQTTQoS2 )
+        {
+            UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS2 );
+        }
+        else
+        {
+            /* Empty else MISRA 15.7 */
+        }
+
+        if( pWillInfo->retain == true )
+        {
+            UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_RETAIN );
+        }
+    }
+
+    *pIndexLocal = connectFlags;
+    pIndexLocal++;
+
+    /* Write the 2 bytes of the keep alive interval into the CONNECT packet. */
+    pIndexLocal[ 0 ] = UINT16_HIGH_BYTE( pConnectInfo->keepAliveSeconds );
+    pIndexLocal[ 1 ] = UINT16_LOW_BYTE( pConnectInfo->keepAliveSeconds );
+    pIndexLocal = &pIndexLocal[ 2 ];
+
+    return pIndexLocal;
+}
+/*-----------------------------------------------------------*/
+
+static void serializeConnectPacket( const MQTTConnectInfo_t * pConnectInfo,
+                                    const MQTTPublishInfo_t * pWillInfo,
+                                    size_t remainingLength,
+                                    const MQTTFixedBuffer_t * pFixedBuffer )
+{
+    uint8_t * pIndex = NULL;
+
+    assert( pConnectInfo != NULL );
+    assert( pFixedBuffer != NULL );
+    assert( pFixedBuffer->pBuffer != NULL );
+
+    pIndex = pFixedBuffer->pBuffer;
+
+    /* Serialize the header. */
+    pIndex = MQTT_SerializeConnectFixedHeader( pIndex,
+                                               pConnectInfo,
+                                               pWillInfo,
+                                               remainingLength );
+
+    /* Write the client identifier into the CONNECT packet. */
+    pIndex = encodeString( pIndex,
+                           pConnectInfo->pClientIdentifier,
+                           pConnectInfo->clientIdentifierLength );
+
+    /* Write the will topic name and message into the CONNECT packet if provided. */
+    if( pWillInfo != NULL )
+    {
+        pIndex = encodeString( pIndex,
+                               pWillInfo->pTopicName,
+                               pWillInfo->topicNameLength );
+
+        pIndex = encodeString( pIndex,
+                               pWillInfo->pPayload,
+                               ( uint16_t ) pWillInfo->payloadLength );
+    }
+
+    /* Encode the user name if provided. */
+    if( pConnectInfo->pUserName != NULL )
+    {
+        pIndex = encodeString( pIndex, pConnectInfo->pUserName, pConnectInfo->userNameLength );
+    }
+
+    /* Encode the password if provided. */
+    if( pConnectInfo->pPassword != NULL )
+    {
+        pIndex = encodeString( pIndex, pConnectInfo->pPassword, pConnectInfo->passwordLength );
+    }
+
+    LogDebug( ( "Length of serialized CONNECT packet is %lu.",
+                ( ( unsigned long ) ( pIndex - pFixedBuffer->pBuffer ) ) ) );
+
+    /* Ensure that the difference between the end and beginning of the buffer
+     * is less than the buffer size. */
+    assert( ( ( size_t ) ( pIndex - pFixedBuffer->pBuffer ) ) <= pFixedBuffer->size );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_GetConnectPacketSize( const MQTTConnectInfo_t * pConnectInfo,
+                                        const MQTTPublishInfo_t * pWillInfo,
+                                        size_t * pRemainingLength,
+                                        size_t * pPacketSize )
+{
+    MQTTStatus_t status = MQTTSuccess;
+    size_t remainingLength;
+
+    /* The CONNECT packet will always include a 10-byte variable header. */
+    size_t connectPacketSize = MQTT_PACKET_CONNECT_HEADER_SIZE;
+
+    /* Validate arguments. */
+    if( ( pConnectInfo == NULL ) || ( pRemainingLength == NULL ) ||
+        ( pPacketSize == NULL ) )
+    {
+        LogError( ( "Argument cannot be NULL: pConnectInfo=%p, "
+                    "pRemainingLength=%p, pPacketSize=%p.",
+                    ( void * ) pConnectInfo,
+                    ( void * ) pRemainingLength,
+                    ( void * ) pPacketSize ) );
+        status = MQTTBadParameter;
+    }
+    else if( ( pConnectInfo->clientIdentifierLength == 0U ) || ( pConnectInfo->pClientIdentifier == NULL ) )
+    {
+        LogError( ( "Mqtt_GetConnectPacketSize() client identifier must be set." ) );
+        status = MQTTBadParameter;
+    }
+    else if( ( pWillInfo != NULL ) && ( pWillInfo->payloadLength > ( size_t ) UINT16_MAX ) )
+    {
+        /* The MQTTPublishInfo_t is reused for the will message. The payload
+         * length for any other message could be larger than 65,535, but
+         * the will message length is required to be represented in 2 bytes.
+         * By bounding the payloadLength of the will message, the CONNECT
+         * packet will never be larger than 327699 bytes. */
+        LogError( ( "The Will Message length must not exceed %d. "
+                    "pWillInfo->payloadLength=%lu.",
+                    UINT16_MAX,
+                    ( unsigned long ) pWillInfo->payloadLength ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        /* Add the length of the client identifier. */
+        connectPacketSize += pConnectInfo->clientIdentifierLength + sizeof( uint16_t );
+
+        /* Add the lengths of the will message and topic name if provided. */
+        if( pWillInfo != NULL )
+        {
+            connectPacketSize += pWillInfo->topicNameLength + sizeof( uint16_t ) +
+                                 pWillInfo->payloadLength + sizeof( uint16_t );
+        }
+
+        /* Add the lengths of the user name and password if provided. */
+        if( pConnectInfo->pUserName != NULL )
+        {
+            connectPacketSize += pConnectInfo->userNameLength + sizeof( uint16_t );
+        }
+
+        if( pConnectInfo->pPassword != NULL )
+        {
+            connectPacketSize += pConnectInfo->passwordLength + sizeof( uint16_t );
+        }
+
+        /* At this point, the "Remaining Length" field of the MQTT CONNECT packet has
+         * been calculated. */
+        remainingLength = connectPacketSize;
+
+        /* Calculate the full size of the MQTT CONNECT packet by adding the size of
+         * the "Remaining Length" field plus 1 byte for the "Packet Type" field. */
+        connectPacketSize += 1U + remainingLengthEncodedSize( connectPacketSize );
+
+        /* The connectPacketSize calculated from this function's parameters is
+         * guaranteed to be less than the maximum MQTT CONNECT packet size, which
+         * is 327700. If the maximum client identifier length, the maximum will
+         * message topic length, the maximum will topic payload length, the
+         * maximum username length, and the maximum password length are all present
+         * in the MQTT CONNECT packet, the total size will be calculated to be
+         * 327699:
+         * (variable length header)10 +
+         * (maximum client identifier length) 65535 + (encoded length) 2 +
+         * (maximum will message topic name length) 65535 + (encoded length)2 +
+         * (maximum will message payload length) 65535 + 2 +
+         * (maximum username length) 65535 + (encoded length) 2 +
+         * (maximum password length) 65535 + (encoded length) 2 +
+         * (packet type field length) 1 +
+         * (CONNECT packet encoded length) 3 = 327699 */
+
+        *pRemainingLength = remainingLength;
+        *pPacketSize = connectPacketSize;
+
+        LogDebug( ( "CONNECT packet remaining length=%lu and packet size=%lu.",
+                    ( unsigned long ) *pRemainingLength,
+                    ( unsigned long ) *pPacketSize ) );
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_SerializeConnect( const MQTTConnectInfo_t * pConnectInfo,
+                                    const MQTTPublishInfo_t * pWillInfo,
+                                    size_t remainingLength,
+                                    const MQTTFixedBuffer_t * pFixedBuffer )
+{
+    MQTTStatus_t status = MQTTSuccess;
+    size_t connectPacketSize = 0;
+
+    /* Validate arguments. */
+    if( ( pConnectInfo == NULL ) || ( pFixedBuffer == NULL ) )
+    {
+        LogError( ( "Argument cannot be NULL: pConnectInfo=%p, "
+                    "pFixedBuffer=%p.",
+                    ( void * ) pConnectInfo,
+                    ( void * ) pFixedBuffer ) );
+        status = MQTTBadParameter;
+    }
+    /* A buffer must be configured for serialization. */
+    else if( pFixedBuffer->pBuffer == NULL )
+    {
+        LogError( ( "Argument cannot be NULL: pFixedBuffer->pBuffer is NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else if( ( pWillInfo != NULL ) && ( pWillInfo->pTopicName == NULL ) )
+    {
+        LogError( ( "pWillInfo->pTopicName cannot be NULL if Will is present." ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        /* Calculate CONNECT packet size. Overflow in in this addition is not checked
+         * because it is part of the API contract to call Mqtt_GetConnectPacketSize()
+         * before this function. */
+        connectPacketSize = remainingLength + remainingLengthEncodedSize( remainingLength ) + 1U;
+
+        /* Check that the full packet size fits within the given buffer. */
+        if( connectPacketSize > pFixedBuffer->size )
+        {
+            LogError( ( "Buffer size of %lu is not sufficient to hold "
+                        "serialized CONNECT packet of size of %lu.",
+                        ( unsigned long ) pFixedBuffer->size,
+                        ( unsigned long ) connectPacketSize ) );
+            status = MQTTNoMemory;
+        }
+        else
+        {
+            serializeConnectPacket( pConnectInfo,
+                                    pWillInfo,
+                                    remainingLength,
+                                    pFixedBuffer );
+        }
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_GetSubscribePacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
+                                          size_t subscriptionCount,
+                                          size_t * pRemainingLength,
+                                          size_t * pPacketSize )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    /* Validate parameters. */
+    if( ( pSubscriptionList == NULL ) || ( pRemainingLength == NULL ) ||
+        ( pPacketSize == NULL ) )
+    {
+        LogError( ( "Argument cannot be NULL: pSubscriptionList=%p, "
+                    "pRemainingLength=%p, pPacketSize=%p.",
+                    ( void * ) pSubscriptionList,
+                    ( void * ) pRemainingLength,
+                    ( void * ) pPacketSize ) );
+        status = MQTTBadParameter;
+    }
+    else if( subscriptionCount == 0U )
+    {
+        LogError( ( "subscriptionCount is 0." ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        /* Calculate the MQTT SUBSCRIBE packet size. */
+        status = calculateSubscriptionPacketSize( pSubscriptionList,
+                                                  subscriptionCount,
+                                                  pRemainingLength,
+                                                  pPacketSize,
+                                                  MQTT_SUBSCRIBE );
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+uint8_t * MQTT_SerializeSubscribeHeader( size_t remainingLength,
+                                         uint8_t * pIndex,
+                                         uint16_t packetId )
+{
+    uint8_t * pIterator = pIndex;
+
+    /* The first byte in SUBSCRIBE is the packet type. */
+    *pIterator = MQTT_PACKET_TYPE_SUBSCRIBE;
+    pIterator++;
+
+    /* Encode the "Remaining length" starting from the second byte. */
+    pIterator = encodeRemainingLength( pIterator, remainingLength );
+
+    /* Place the packet identifier into the SUBSCRIBE packet. */
+    pIterator[ 0 ] = UINT16_HIGH_BYTE( packetId );
+    pIterator[ 1 ] = UINT16_LOW_BYTE( packetId );
+    /* Advance the pointer. */
+    pIterator = &pIterator[ 2 ];
+
+    return pIterator;
+}
+
+/*-----------------------------------------------------------*/
+
+uint8_t * MQTT_SerializeUnsubscribeHeader( size_t remainingLength,
+                                           uint8_t * pIndex,
+                                           uint16_t packetId )
+{
+    uint8_t * pIterator = pIndex;
+
+    /* The first byte in UNSUBSCRIBE is the packet type. */
+    *pIterator = MQTT_PACKET_TYPE_UNSUBSCRIBE;
+    pIterator++;
+
+    /* Encode the "Remaining length" starting from the second byte. */
+    pIterator = encodeRemainingLength( pIterator, remainingLength );
+
+    /* Place the packet identifier into the SUBSCRIBE packet. */
+    pIterator[ 0 ] = UINT16_HIGH_BYTE( packetId );
+    pIterator[ 1 ] = UINT16_LOW_BYTE( packetId );
+    /* Increment the pointer. */
+    pIterator = &pIterator[ 2 ];
+
+    return pIterator;
+}
+
+MQTTStatus_t MQTT_SerializeSubscribe( const MQTTSubscribeInfo_t * pSubscriptionList,
+                                      size_t subscriptionCount,
+                                      uint16_t packetId,
+                                      size_t remainingLength,
+                                      const MQTTFixedBuffer_t * pFixedBuffer )
+{
+    size_t i = 0;
+    uint8_t * pIndex = NULL;
+
+    /* Validate all the parameters. */
+    MQTTStatus_t status =
+        validateSubscriptionSerializeParams( pSubscriptionList,
+                                             subscriptionCount,
+                                             packetId,
+                                             remainingLength,
+                                             pFixedBuffer );
+
+    if( status == MQTTSuccess )
+    {
+        pIndex = pFixedBuffer->pBuffer;
+
+        pIndex = MQTT_SerializeSubscribeHeader( remainingLength,
+                                                pIndex,
+                                                packetId );
+
+        /* Serialize each subscription topic filter and QoS. */
+        for( i = 0; i < subscriptionCount; i++ )
+        {
+            pIndex = encodeString( pIndex,
+                                   pSubscriptionList[ i ].pTopicFilter,
+                                   pSubscriptionList[ i ].topicFilterLength );
+
+            /* Place the QoS in the SUBSCRIBE packet. */
+            *pIndex = ( uint8_t ) ( pSubscriptionList[ i ].qos );
+            pIndex++;
+        }
+
+        LogDebug( ( "Length of serialized SUBSCRIBE packet is %lu.",
+                    ( ( unsigned long ) ( pIndex - pFixedBuffer->pBuffer ) ) ) );
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_GetUnsubscribePacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
+                                            size_t subscriptionCount,
+                                            size_t * pRemainingLength,
+                                            size_t * pPacketSize )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    /* Validate parameters. */
+    if( ( pSubscriptionList == NULL ) || ( pRemainingLength == NULL ) ||
+        ( pPacketSize == NULL ) )
+    {
+        LogError( ( "Argument cannot be NULL: pSubscriptionList=%p, "
+                    "pRemainingLength=%p, pPacketSize=%p.",
+                    ( void * ) pSubscriptionList,
+                    ( void * ) pRemainingLength,
+                    ( void * ) pPacketSize ) );
+        status = MQTTBadParameter;
+    }
+    else if( subscriptionCount == 0U )
+    {
+        LogError( ( "Subscription count is 0." ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        /* Calculate the MQTT UNSUBSCRIBE packet size. */
+        status = calculateSubscriptionPacketSize( pSubscriptionList,
+                                                  subscriptionCount,
+                                                  pRemainingLength,
+                                                  pPacketSize,
+                                                  MQTT_UNSUBSCRIBE );
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_SerializeUnsubscribe( const MQTTSubscribeInfo_t * pSubscriptionList,
+                                        size_t subscriptionCount,
+                                        uint16_t packetId,
+                                        size_t remainingLength,
+                                        const MQTTFixedBuffer_t * pFixedBuffer )
+{
+    MQTTStatus_t status = MQTTSuccess;
+    size_t i = 0;
+    uint8_t * pIndex = NULL;
+
+    /* Validate all the parameters. */
+    status = validateSubscriptionSerializeParams( pSubscriptionList,
+                                                  subscriptionCount,
+                                                  packetId,
+                                                  remainingLength,
+                                                  pFixedBuffer );
+
+    if( status == MQTTSuccess )
+    {
+        /* Get the start of the buffer to the iterator variable. */
+        pIndex = pFixedBuffer->pBuffer;
+
+        pIndex = MQTT_SerializeUnsubscribeHeader( remainingLength, pIndex, packetId );
+
+        /* Serialize each subscription topic filter. */
+        for( i = 0; i < subscriptionCount; i++ )
+        {
+            pIndex = encodeString( pIndex,
+                                   pSubscriptionList[ i ].pTopicFilter,
+                                   pSubscriptionList[ i ].topicFilterLength );
+        }
+
+        LogDebug( ( "Length of serialized UNSUBSCRIBE packet is %lu.",
+                    ( ( unsigned long ) ( pIndex - pFixedBuffer->pBuffer ) ) ) );
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_GetPublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
+                                        size_t * pRemainingLength,
+                                        size_t * pPacketSize )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    if( ( pPublishInfo == NULL ) || ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) )
+    {
+        LogError( ( "Argument cannot be NULL: pPublishInfo=%p, "
+                    "pRemainingLength=%p, pPacketSize=%p.",
+                    ( void * ) pPublishInfo,
+                    ( void * ) pRemainingLength,
+                    ( void * ) pPacketSize ) );
+        status = MQTTBadParameter;
+    }
+    else if( ( pPublishInfo->pTopicName == NULL ) || ( pPublishInfo->topicNameLength == 0U ) )
+    {
+        LogError( ( "Invalid topic name for PUBLISH: pTopicName=%p, "
+                    "topicNameLength=%hu.",
+                    ( void * ) pPublishInfo->pTopicName,
+                    ( unsigned short ) pPublishInfo->topicNameLength ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        /* Calculate the "Remaining length" field and total packet size. If it exceeds
+         * what is allowed in the MQTT standard, return an error. */
+        if( calculatePublishPacketSize( pPublishInfo, pRemainingLength, pPacketSize ) == false )
+        {
+            LogError( ( "PUBLISH packet remaining length exceeds %lu, which is the "
+                        "maximum size allowed by MQTT 3.1.1.",
+                        MQTT_MAX_REMAINING_LENGTH ) );
+            status = MQTTBadParameter;
+        }
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_SerializePublish( const MQTTPublishInfo_t * pPublishInfo,
+                                    uint16_t packetId,
+                                    size_t remainingLength,
+                                    const MQTTFixedBuffer_t * pFixedBuffer )
+{
+    MQTTStatus_t status = MQTTSuccess;
+    size_t packetSize = 0;
+
+    if( ( pFixedBuffer == NULL ) || ( pPublishInfo == NULL ) )
+    {
+        LogError( ( "Argument cannot be NULL: pFixedBuffer=%p, "
+                    "pPublishInfo=%p.",
+                    ( void * ) pFixedBuffer,
+                    ( void * ) pPublishInfo ) );
+        status = MQTTBadParameter;
+    }
+    /* A buffer must be configured for serialization. */
+    else if( pFixedBuffer->pBuffer == NULL )
+    {
+        LogError( ( "Argument cannot be NULL: pFixedBuffer->pBuffer is NULL." ) );
+        status = MQTTBadParameter;
+    }
+
+    /* For serializing a publish, if there exists a payload, then the buffer
+     * cannot be NULL. */
+    else if( ( pPublishInfo->payloadLength > 0U ) && ( pPublishInfo->pPayload == NULL ) )
+    {
+        LogError( ( "A nonzero payload length requires a non-NULL payload: "
+                    "payloadLength=%lu, pPayload=%p.",
+                    ( unsigned long ) pPublishInfo->payloadLength,
+                    pPublishInfo->pPayload ) );
+        status = MQTTBadParameter;
+    }
+    else if( ( pPublishInfo->pTopicName == NULL ) || ( pPublishInfo->topicNameLength == 0U ) )
+    {
+        LogError( ( "Invalid topic name for PUBLISH: pTopicName=%p, "
+                    "topicNameLength=%hu.",
+                    ( void * ) pPublishInfo->pTopicName,
+                    ( unsigned short ) pPublishInfo->topicNameLength ) );
+        status = MQTTBadParameter;
+    }
+    else if( ( pPublishInfo->qos != MQTTQoS0 ) && ( packetId == 0U ) )
+    {
+        LogError( ( "Packet ID is 0 for PUBLISH with QoS=%u.",
+                    ( unsigned int ) pPublishInfo->qos ) );
+        status = MQTTBadParameter;
+    }
+    else if( ( pPublishInfo->dup == true ) && ( pPublishInfo->qos == MQTTQoS0 ) )
+    {
+        LogError( ( "Duplicate flag is set for PUBLISH with Qos 0." ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        /* Length of serialized packet = First byte
+         *                                + Length of encoded remaining length
+         *                                + Remaining length. */
+        packetSize = 1U + remainingLengthEncodedSize( remainingLength )
+                     + remainingLength;
+    }
+
+    if( ( status == MQTTSuccess ) && ( packetSize > pFixedBuffer->size ) )
+    {
+        LogError( ( "Buffer size of %lu is not sufficient to hold "
+                    "serialized PUBLISH packet of size of %lu.",
+                    ( unsigned long ) pFixedBuffer->size,
+                    ( unsigned long ) packetSize ) );
+        status = MQTTNoMemory;
+    }
+
+    if( status == MQTTSuccess )
+    {
+        /* Serialize publish with header and payload. */
+        serializePublishCommon( pPublishInfo,
+                                remainingLength,
+                                packetId,
+                                pFixedBuffer,
+                                true );
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_SerializePublishHeader( const MQTTPublishInfo_t * pPublishInfo,
+                                          uint16_t packetId,
+                                          size_t remainingLength,
+                                          const MQTTFixedBuffer_t * pFixedBuffer,
+                                          size_t * pHeaderSize )
+{
+    MQTTStatus_t status = MQTTSuccess;
+    size_t packetSize = 0;
+
+    if( ( pFixedBuffer == NULL ) || ( pPublishInfo == NULL ) ||
+        ( pHeaderSize == NULL ) )
+    {
+        LogError( ( "Argument cannot be NULL: pFixedBuffer=%p, "
+                    "pPublishInfo=%p, pHeaderSize=%p.",
+                    ( void * ) pFixedBuffer,
+                    ( void * ) pPublishInfo,
+                    ( void * ) pHeaderSize ) );
+        status = MQTTBadParameter;
+    }
+    /* A buffer must be configured for serialization. */
+    else if( pFixedBuffer->pBuffer == NULL )
+    {
+        LogError( ( "Argument cannot be NULL: pFixedBuffer->pBuffer is NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else if( ( pPublishInfo->pTopicName == NULL ) || ( pPublishInfo->topicNameLength == 0U ) )
+    {
+        LogError( ( "Invalid topic name for publish: pTopicName=%p, "
+                    "topicNameLength=%hu.",
+                    ( void * ) pPublishInfo->pTopicName,
+                    ( unsigned short ) pPublishInfo->topicNameLength ) );
+        status = MQTTBadParameter;
+    }
+    else if( ( pPublishInfo->qos != MQTTQoS0 ) && ( packetId == 0U ) )
+    {
+        LogError( ( "Packet Id is 0 for publish with QoS=%hu.",
+                    ( unsigned short ) pPublishInfo->qos ) );
+        status = MQTTBadParameter;
+    }
+    else if( ( pPublishInfo->dup == true ) && ( pPublishInfo->qos == MQTTQoS0 ) )
+    {
+        LogError( ( "Duplicate flag is set for PUBLISH with Qos 0." ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        /* Length of serialized packet = First byte
+         *                               + Length of encoded remaining length
+         *                               + Remaining length
+         *                               - Payload Length.
+         */
+        packetSize = 1U + remainingLengthEncodedSize( remainingLength )
+                     + remainingLength
+                     - pPublishInfo->payloadLength;
+    }
+
+    if( ( status == MQTTSuccess ) && ( packetSize > pFixedBuffer->size ) )
+    {
+        LogError( ( "Buffer size of %lu is not sufficient to hold "
+                    "serialized PUBLISH header packet of size of %lu.",
+                    ( unsigned long ) pFixedBuffer->size,
+                    ( unsigned long ) ( packetSize - pPublishInfo->payloadLength ) ) );
+        status = MQTTNoMemory;
+    }
+
+    if( status == MQTTSuccess )
+    {
+        /* Serialize publish without copying the payload. */
+        serializePublishCommon( pPublishInfo,
+                                remainingLength,
+                                packetId,
+                                pFixedBuffer,
+                                false );
+
+        /* Header size is the same as calculated packet size. */
+        *pHeaderSize = packetSize;
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_SerializeAck( const MQTTFixedBuffer_t * pFixedBuffer,
+                                uint8_t packetType,
+                                uint16_t packetId )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    if( pFixedBuffer == NULL )
+    {
+        LogError( ( "Provided buffer is NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else if( pFixedBuffer->pBuffer == NULL )
+    {
+        LogError( ( "pFixedBuffer->pBuffer cannot be NULL." ) );
+        status = MQTTBadParameter;
+    }
+    /* The buffer must be able to fit 4 bytes for the packet. */
+    else if( pFixedBuffer->size < MQTT_PUBLISH_ACK_PACKET_SIZE )
+    {
+        LogError( ( "Insufficient memory for packet." ) );
+        status = MQTTNoMemory;
+    }
+    else if( packetId == 0U )
+    {
+        LogError( ( "Packet ID cannot be 0." ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        switch( packetType )
+        {
+            /* Only publish acks are serialized by the client. */
+            case MQTT_PACKET_TYPE_PUBACK:
+            case MQTT_PACKET_TYPE_PUBREC:
+            case MQTT_PACKET_TYPE_PUBREL:
+            case MQTT_PACKET_TYPE_PUBCOMP:
+                pFixedBuffer->pBuffer[ 0 ] = packetType;
+                pFixedBuffer->pBuffer[ 1 ] = MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH;
+                pFixedBuffer->pBuffer[ 2 ] = UINT16_HIGH_BYTE( packetId );
+                pFixedBuffer->pBuffer[ 3 ] = UINT16_LOW_BYTE( packetId );
+                break;
+
+            default:
+                LogError( ( "Packet type is not a publish ACK: Packet type=%02x",
+                            ( unsigned int ) packetType ) );
+                status = MQTTBadParameter;
+                break;
+        }
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_GetDisconnectPacketSize( size_t * pPacketSize )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    if( pPacketSize == NULL )
+    {
+        LogError( ( "pPacketSize is NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        /* MQTT DISCONNECT packets always have the same size. */
+        *pPacketSize = MQTT_DISCONNECT_PACKET_SIZE;
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_SerializeDisconnect( const MQTTFixedBuffer_t * pFixedBuffer )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    /* Validate arguments. */
+    if( pFixedBuffer == NULL )
+    {
+        LogError( ( "pFixedBuffer cannot be NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else if( pFixedBuffer->pBuffer == NULL )
+    {
+        LogError( ( "pFixedBuffer->pBuffer cannot be NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        /* Empty else MISRA 15.7 */
+    }
+
+    if( status == MQTTSuccess )
+    {
+        if( pFixedBuffer->size < MQTT_DISCONNECT_PACKET_SIZE )
+        {
+            LogError( ( "Buffer size of %lu is not sufficient to hold "
+                        "serialized DISCONNECT packet of size of %lu.",
+                        ( unsigned long ) pFixedBuffer->size,
+                        MQTT_DISCONNECT_PACKET_SIZE ) );
+            status = MQTTNoMemory;
+        }
+    }
+
+    if( status == MQTTSuccess )
+    {
+        pFixedBuffer->pBuffer[ 0 ] = MQTT_PACKET_TYPE_DISCONNECT;
+        pFixedBuffer->pBuffer[ 1 ] = MQTT_DISCONNECT_REMAINING_LENGTH;
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_GetPingreqPacketSize( size_t * pPacketSize )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    if( pPacketSize == NULL )
+    {
+        LogError( ( "pPacketSize is NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        /* MQTT PINGREQ packets always have the same size. */
+        *pPacketSize = MQTT_PACKET_PINGREQ_SIZE;
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_SerializePingreq( const MQTTFixedBuffer_t * pFixedBuffer )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    if( pFixedBuffer == NULL )
+    {
+        LogError( ( "pFixedBuffer is NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else if( pFixedBuffer->pBuffer == NULL )
+    {
+        LogError( ( "pFixedBuffer->pBuffer cannot be NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        /* Empty else MISRA 15.7 */
+    }
+
+    if( status == MQTTSuccess )
+    {
+        if( pFixedBuffer->size < MQTT_PACKET_PINGREQ_SIZE )
+        {
+            LogError( ( "Buffer size of %lu is not sufficient to hold "
+                        "serialized PINGREQ packet of size of %lu.",
+                        ( unsigned long ) pFixedBuffer->size,
+                        MQTT_PACKET_PINGREQ_SIZE ) );
+            status = MQTTNoMemory;
+        }
+    }
+
+    if( status == MQTTSuccess )
+    {
+        /* Ping request packets are always the same. */
+        pFixedBuffer->pBuffer[ 0 ] = MQTT_PACKET_TYPE_PINGREQ;
+        pFixedBuffer->pBuffer[ 1 ] = 0x00;
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_DeserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
+                                      uint16_t * pPacketId,
+                                      MQTTPublishInfo_t * pPublishInfo )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    if( ( pIncomingPacket == NULL ) || ( pPacketId == NULL ) || ( pPublishInfo == NULL ) )
+    {
+        LogError( ( "Argument cannot be NULL: pIncomingPacket=%p, "
+                    "pPacketId=%p, pPublishInfo=%p",
+                    ( void * ) pIncomingPacket,
+                    ( void * ) pPacketId,
+                    ( void * ) pPublishInfo ) );
+        status = MQTTBadParameter;
+    }
+    else if( ( pIncomingPacket->type & 0xF0U ) != MQTT_PACKET_TYPE_PUBLISH )
+    {
+        LogError( ( "Packet is not publish. Packet type: %02x.",
+                    ( unsigned int ) pIncomingPacket->type ) );
+        status = MQTTBadParameter;
+    }
+    else if( pIncomingPacket->pRemainingData == NULL )
+    {
+        LogError( ( "Argument cannot be NULL: "
+                    "pIncomingPacket->pRemainingData is NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        status = deserializePublish( pIncomingPacket, pPacketId, pPublishInfo );
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_DeserializeAck( const MQTTPacketInfo_t * pIncomingPacket,
+                                  uint16_t * pPacketId,
+                                  bool * pSessionPresent )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    if( pIncomingPacket == NULL )
+    {
+        LogError( ( "pIncomingPacket cannot be NULL." ) );
+        status = MQTTBadParameter;
+    }
+
+    /* Pointer for packet identifier cannot be NULL for packets other than
+     * CONNACK and PINGRESP. */
+    else if( ( pPacketId == NULL ) &&
+             ( ( pIncomingPacket->type != MQTT_PACKET_TYPE_CONNACK ) &&
+               ( pIncomingPacket->type != MQTT_PACKET_TYPE_PINGRESP ) ) )
+    {
+        LogError( ( "pPacketId cannot be NULL for packet type %02x.",
+                    ( unsigned int ) pIncomingPacket->type ) );
+        status = MQTTBadParameter;
+    }
+    /* Pointer for session present cannot be NULL for CONNACK. */
+    else if( ( pSessionPresent == NULL ) &&
+             ( pIncomingPacket->type == MQTT_PACKET_TYPE_CONNACK ) )
+    {
+        LogError( ( "pSessionPresent cannot be NULL for CONNACK packet." ) );
+        status = MQTTBadParameter;
+    }
+
+    /* Pointer for remaining data cannot be NULL for packets other
+     * than PINGRESP. */
+    else if( ( pIncomingPacket->pRemainingData == NULL ) &&
+             ( pIncomingPacket->type != MQTT_PACKET_TYPE_PINGRESP ) )
+    {
+        LogError( ( "Remaining data of incoming packet is NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        /* Make sure response packet is a valid ack. */
+        switch( pIncomingPacket->type )
+        {
+            case MQTT_PACKET_TYPE_CONNACK:
+                status = deserializeConnack( pIncomingPacket, pSessionPresent );
+                break;
+
+            case MQTT_PACKET_TYPE_SUBACK:
+                status = deserializeSuback( pIncomingPacket, pPacketId );
+                break;
+
+            case MQTT_PACKET_TYPE_PINGRESP:
+                status = deserializePingresp( pIncomingPacket );
+                break;
+
+            case MQTT_PACKET_TYPE_UNSUBACK:
+            case MQTT_PACKET_TYPE_PUBACK:
+            case MQTT_PACKET_TYPE_PUBREC:
+            case MQTT_PACKET_TYPE_PUBREL:
+            case MQTT_PACKET_TYPE_PUBCOMP:
+                status = deserializeSimpleAck( pIncomingPacket, pPacketId );
+                break;
+
+            /* Any other packet type is invalid. */
+            default:
+                LogError( ( "IotMqtt_DeserializeResponse() called with unknown packet type:(%02x).",
+                            ( unsigned int ) pIncomingPacket->type ) );
+                status = MQTTBadResponse;
+                break;
+        }
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_GetIncomingPacketTypeAndLength( TransportRecv_t readFunc,
+                                                  NetworkContext_t * pNetworkContext,
+                                                  MQTTPacketInfo_t * pIncomingPacket )
+{
+    MQTTStatus_t status = MQTTSuccess;
+    int32_t bytesReceived = 0;
+
+    if( pIncomingPacket == NULL )
+    {
+        LogError( ( "Invalid parameter: pIncomingPacket is NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else
+    {
+        /* Read a single byte. */
+        bytesReceived = readFunc( pNetworkContext,
+                                  &( pIncomingPacket->type ),
+                                  1U );
+    }
+
+    if( bytesReceived == 1 )
+    {
+        /* Check validity. */
+        if( incomingPacketValid( pIncomingPacket->type ) == true )
+        {
+            pIncomingPacket->remainingLength = getRemainingLength( readFunc,
+                                                                   pNetworkContext );
+
+            if( pIncomingPacket->remainingLength == MQTT_REMAINING_LENGTH_INVALID )
+            {
+                LogError( ( "Incoming packet remaining length invalid." ) );
+                status = MQTTBadResponse;
+            }
+        }
+        else
+        {
+            LogError( ( "Incoming packet invalid: Packet type=%u.",
+                        ( unsigned int ) pIncomingPacket->type ) );
+            status = MQTTBadResponse;
+        }
+    }
+    else if( ( status != MQTTBadParameter ) && ( bytesReceived == 0 ) )
+    {
+        status = MQTTNoDataAvailable;
+    }
+
+    /* If the input packet was valid, then any other number of bytes received is
+     * a failure. */
+    else if( status != MQTTBadParameter )
+    {
+        LogError( ( "A single byte was not read from the transport: "
+                    "transportStatus=%ld.",
+                    ( long int ) bytesReceived ) );
+        status = MQTTRecvFailed;
+    }
+    else
+    {
+        /* Empty else MISRA 15.7 */
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_UpdateDuplicatePublishFlag( uint8_t * pHeader,
+                                              bool set )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    if( pHeader == NULL )
+    {
+        LogError( ( "Header cannot be NULL" ) );
+        status = MQTTBadParameter;
+    }
+    else if( ( ( *pHeader ) & 0xF0U ) != MQTT_PACKET_TYPE_PUBLISH )
+    {
+        LogError( ( "Header is not publish packet header" ) );
+        status = MQTTBadParameter;
+    }
+    else if( set == true )
+    {
+        UINT8_SET_BIT( *pHeader, MQTT_PUBLISH_FLAG_DUP );
+    }
+    else
+    {
+        UINT8_CLEAR_BIT( *pHeader, MQTT_PUBLISH_FLAG_DUP );
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_ProcessIncomingPacketTypeAndLength( const uint8_t * pBuffer,
+                                                      const size_t * pIndex,
+                                                      MQTTPacketInfo_t * pIncomingPacket )
+{
+    MQTTStatus_t status = MQTTSuccess;
+
+    if( pIncomingPacket == NULL )
+    {
+        LogError( ( "Invalid parameter: pIncomingPacket is NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else if( pIndex == NULL )
+    {
+        LogError( ( "Invalid parameter: pIndex is NULL." ) );
+        status = MQTTBadParameter;
+    }
+    else if( pBuffer == NULL )
+    {
+        LogError( ( "Invalid parameter: pBuffer is NULL." ) );
+        status = MQTTBadParameter;
+    }
+    /* There should be at least one byte in the buffer */
+    else if( *pIndex < 1U )
+    {
+        /* No data is available. There are 0 bytes received from the network
+         * receive function. */
+        status = MQTTNoDataAvailable;
+    }
+    else
+    {
+        /* At least one byte is present which should be deciphered. */
+        pIncomingPacket->type = pBuffer[ 0 ];
+    }
+
+    if( status == MQTTSuccess )
+    {
+        /* Check validity. */
+        if( incomingPacketValid( pIncomingPacket->type ) == true )
+        {
+            status = processRemainingLength( pBuffer,
+                                             pIndex,
+                                             pIncomingPacket );
+        }
+        else
+        {
+            LogError( ( "Incoming packet invalid: Packet type=%u.",
+                        ( unsigned int ) pIncomingPacket->type ) );
+            status = MQTTBadResponse;
+        }
+    }
+
+    return status;
+}
+
+/*-----------------------------------------------------------*/

+ 1314 - 0
coreMqtt/core_mqtt_serializer.h

@@ -0,0 +1,1314 @@
+/*
+ * coreMQTT <DEVELOPMENT BRANCH>
+ * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file core_mqtt_serializer.h
+ * @brief User-facing functions for serializing and deserializing MQTT 3.1.1
+ * packets. This header should be included for building a lighter weight MQTT
+ * client than the managed CSDK MQTT library API in core_mqtt.h, by using the
+ * serializer and de-serializer functions exposed in this file's API.
+ */
+#ifndef CORE_MQTT_SERIALIZER_H
+#define CORE_MQTT_SERIALIZER_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+    extern "C" {
+#endif
+/* *INDENT-ON */
+
+#include "core_mqtt_config_defaults.h"
+
+/* MQTT packet types. */
+
+/**
+ * @addtogroup mqtt_constants
+ * @{
+ */
+#define MQTT_PACKET_TYPE_CONNECT        ( ( uint8_t ) 0x10U )  /**< @brief CONNECT (client-to-server). */
+#define MQTT_PACKET_TYPE_CONNACK        ( ( uint8_t ) 0x20U )  /**< @brief CONNACK (server-to-client). */
+#define MQTT_PACKET_TYPE_PUBLISH        ( ( uint8_t ) 0x30U )  /**< @brief PUBLISH (bidirectional). */
+#define MQTT_PACKET_TYPE_PUBACK         ( ( uint8_t ) 0x40U )  /**< @brief PUBACK (bidirectional). */
+#define MQTT_PACKET_TYPE_PUBREC         ( ( uint8_t ) 0x50U )  /**< @brief PUBREC (bidirectional). */
+#define MQTT_PACKET_TYPE_PUBREL         ( ( uint8_t ) 0x62U )  /**< @brief PUBREL (bidirectional). */
+#define MQTT_PACKET_TYPE_PUBCOMP        ( ( uint8_t ) 0x70U )  /**< @brief PUBCOMP (bidirectional). */
+#define MQTT_PACKET_TYPE_SUBSCRIBE      ( ( uint8_t ) 0x82U )  /**< @brief SUBSCRIBE (client-to-server). */
+#define MQTT_PACKET_TYPE_SUBACK         ( ( uint8_t ) 0x90U )  /**< @brief SUBACK (server-to-client). */
+#define MQTT_PACKET_TYPE_UNSUBSCRIBE    ( ( uint8_t ) 0xA2U )  /**< @brief UNSUBSCRIBE (client-to-server). */
+#define MQTT_PACKET_TYPE_UNSUBACK       ( ( uint8_t ) 0xB0U )  /**< @brief UNSUBACK (server-to-client). */
+#define MQTT_PACKET_TYPE_PINGREQ        ( ( uint8_t ) 0xC0U )  /**< @brief PINGREQ (client-to-server). */
+#define MQTT_PACKET_TYPE_PINGRESP       ( ( uint8_t ) 0xD0U )  /**< @brief PINGRESP (server-to-client). */
+#define MQTT_PACKET_TYPE_DISCONNECT     ( ( uint8_t ) 0xE0U )  /**< @brief DISCONNECT (client-to-server). */
+/** @} */
+
+/**
+ * @ingroup mqtt_constants
+ * @brief The size of MQTT PUBACK, PUBREC, PUBREL, and PUBCOMP packets, per MQTT spec.
+ */
+#define MQTT_PUBLISH_ACK_PACKET_SIZE    ( 4UL )
+
+/* Structures defined in this file. */
+struct MQTTFixedBuffer;
+struct MQTTConnectInfo;
+struct MQTTSubscribeInfo;
+struct MQTTPublishInfo;
+struct MQTTPacketInfo;
+
+/**
+ * @ingroup mqtt_enum_types
+ * @brief Return codes from MQTT functions.
+ */
+typedef enum MQTTStatus
+{
+    MQTTSuccess = 0,                /**< Function completed successfully. */
+    MQTTBadParameter,               /**< At least one parameter was invalid. */
+    MQTTNoMemory,                   /**< A provided buffer was too small. */
+    MQTTSendFailed,                 /**< The transport send function failed. */
+    MQTTRecvFailed,                 /**< The transport receive function failed. */
+    MQTTBadResponse,                /**< An invalid packet was received from the server. */
+    MQTTServerRefused,              /**< The server refused a CONNECT or SUBSCRIBE. */
+    MQTTNoDataAvailable,            /**< No data available from the transport interface. */
+    MQTTIllegalState,               /**< An illegal state in the state record. */
+    MQTTStateCollision,             /**< A collision with an existing state record entry. */
+    MQTTKeepAliveTimeout,           /**< Timeout while waiting for PINGRESP. */
+    MQTTNeedMoreBytes,              /**< MQTT_ProcessLoop/MQTT_ReceiveLoop has received
+                                    incomplete data; it should be called again (probably after
+                                    a delay). */
+    MQTTStatusConnected,            /**< MQTT connection is established with the broker. */
+    MQTTStatusNotConnected,         /**< MQTT connection is not established with the broker. */
+    MQTTStatusDisconnectPending,    /**< Transport Interface has failed and MQTT connection needs to be closed. */
+    MQTTPublishStoreFailed,         /**< User provided API to store a copy of outgoing publish for retransmission  purposes,
+                                    has failed. */
+    MQTTPublishRetrieveFailed       /**< User provided API to retrieve the copy of a publish while reconnecting
+                                    with an unclean session has failed. */
+} MQTTStatus_t;
+
+/**
+ * @ingroup mqtt_enum_types
+ * @brief MQTT Quality of Service values.
+ */
+typedef enum MQTTQoS
+{
+    MQTTQoS0 = 0, /**< Delivery at most once. */
+    MQTTQoS1 = 1, /**< Delivery at least once. */
+    MQTTQoS2 = 2  /**< Delivery exactly once. */
+} MQTTQoS_t;
+
+/**
+ * @ingroup mqtt_struct_types
+ * @brief Buffer passed to MQTT library.
+ *
+ * These buffers are not copied and must remain in scope for the duration of the
+ * MQTT operation.
+ */
+typedef struct MQTTFixedBuffer
+{
+    uint8_t * pBuffer; /**< @brief Pointer to buffer. */
+    size_t size;       /**< @brief Size of buffer. */
+} MQTTFixedBuffer_t;
+
+/**
+ * @ingroup mqtt_struct_types
+ * @brief MQTT CONNECT packet parameters.
+ */
+typedef struct MQTTConnectInfo
+{
+    /**
+     * @brief Whether to establish a new, clean session or resume a previous session.
+     */
+    bool cleanSession;
+
+    /**
+     * @brief MQTT keep alive period.
+     */
+    uint16_t keepAliveSeconds;
+
+    /**
+     * @brief MQTT client identifier. Must be unique per client.
+     */
+    const char * pClientIdentifier;
+
+    /**
+     * @brief Length of the client identifier.
+     */
+    uint16_t clientIdentifierLength;
+
+    /**
+     * @brief MQTT user name. Set to NULL if not used.
+     */
+    const char * pUserName;
+
+    /**
+     * @brief Length of MQTT user name. Set to 0 if not used.
+     */
+    uint16_t userNameLength;
+
+    /**
+     * @brief MQTT password. Set to NULL if not used.
+     */
+    const char * pPassword;
+
+    /**
+     * @brief Length of MQTT password. Set to 0 if not used.
+     */
+    uint16_t passwordLength;
+} MQTTConnectInfo_t;
+
+/**
+ * @ingroup mqtt_struct_types
+ * @brief MQTT SUBSCRIBE packet parameters.
+ */
+typedef struct MQTTSubscribeInfo
+{
+    /**
+     * @brief Quality of Service for subscription.
+     */
+    MQTTQoS_t qos;
+
+    /**
+     * @brief Topic filter to subscribe to.
+     */
+    const char * pTopicFilter;
+
+    /**
+     * @brief Length of subscription topic filter.
+     */
+    uint16_t topicFilterLength;
+} MQTTSubscribeInfo_t;
+
+/**
+ * @ingroup mqtt_struct_types
+ * @brief MQTT PUBLISH packet parameters.
+ */
+typedef struct MQTTPublishInfo
+{
+    /**
+     * @brief Quality of Service for message.
+     */
+    MQTTQoS_t qos;
+
+    /**
+     * @brief Whether this is a retained message.
+     */
+    bool retain;
+
+    /**
+     * @brief Whether this is a duplicate publish message.
+     */
+    bool dup;
+
+    /**
+     * @brief Topic name on which the message is published.
+     */
+    const char * pTopicName;
+
+    /**
+     * @brief Length of topic name.
+     */
+    uint16_t topicNameLength;
+
+    /**
+     * @brief Message payload.
+     */
+    const void * pPayload;
+
+    /**
+     * @brief Message payload length.
+     */
+    size_t payloadLength;
+} MQTTPublishInfo_t;
+
+/**
+ * @ingroup mqtt_struct_types
+ * @brief MQTT incoming packet parameters.
+ */
+typedef struct MQTTPacketInfo
+{
+    /**
+     * @brief Type of incoming MQTT packet.
+     */
+    uint8_t type;
+
+    /**
+     * @brief Remaining serialized data in the MQTT packet.
+     */
+    uint8_t * pRemainingData;
+
+    /**
+     * @brief Length of remaining serialized data.
+     */
+    size_t remainingLength;
+
+    /**
+     * @brief The length of the MQTT header including the type and length.
+     */
+    size_t headerLength;
+} MQTTPacketInfo_t;
+
+/**
+ * @brief Get the size and Remaining Length of an MQTT CONNECT packet.
+ *
+ * This function must be called before #MQTT_SerializeConnect in order to get
+ * the size of the MQTT CONNECT packet that is generated from #MQTTConnectInfo_t
+ * and optional #MQTTPublishInfo_t. The size of the #MQTTFixedBuffer_t supplied
+ * to #MQTT_SerializeConnect must be at least @p pPacketSize. The provided
+ * @p pConnectInfo and @p pWillInfo are valid for serialization with
+ * #MQTT_SerializeConnect only if this function returns #MQTTSuccess. The
+ * remaining length returned in @p pRemainingLength and the packet size returned
+ * in @p pPacketSize are valid only if this function returns #MQTTSuccess.
+ *
+ * @param[in] pConnectInfo MQTT CONNECT packet parameters.
+ * @param[in] pWillInfo Last Will and Testament. Pass NULL if not used.
+ * @param[out] pRemainingLength The Remaining Length of the MQTT CONNECT packet.
+ * @param[out] pPacketSize The total size of the MQTT CONNECT packet.
+ *
+ * @return #MQTTBadParameter if the packet would exceed the size allowed by the
+ * MQTT spec; #MQTTSuccess otherwise.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTConnectInfo_t connectInfo = { 0 };
+ * MQTTPublishInfo_t willInfo = { 0 };
+ * size_t remainingLength = 0, packetSize = 0;
+ *
+ * // Initialize the connection info, the details are out of scope for this example.
+ * initializeConnectInfo( &connectInfo );
+ *
+ * // Initialize the optional will info, the details are out of scope for this example.
+ * initializeWillInfo( &willInfo );
+ *
+ * // Get the size requirement for the connect packet.
+ * status = MQTT_GetConnectPacketSize(
+ *      &connectInfo, &willInfo, &remainingLength, &packetSize
+ * );
+ *
+ * if( status == MQTTSuccess )
+ * {
+ *      // The application should allocate or use a static #MQTTFixedBuffer_t
+ *      // of size >= packetSize to serialize the connect request.
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_getconnectpacketsize] */
+MQTTStatus_t MQTT_GetConnectPacketSize( const MQTTConnectInfo_t * pConnectInfo,
+                                        const MQTTPublishInfo_t * pWillInfo,
+                                        size_t * pRemainingLength,
+                                        size_t * pPacketSize );
+/* @[declare_mqtt_getconnectpacketsize] */
+
+/**
+ * @brief Serialize an MQTT CONNECT packet in the given fixed buffer @p pFixedBuffer.
+ *
+ * #MQTT_GetConnectPacketSize should be called with @p pConnectInfo and
+ * @p pWillInfo before invoking this function to get the size of the required
+ * #MQTTFixedBuffer_t and @p remainingLength. The @p remainingLength must be
+ * the same as returned by #MQTT_GetConnectPacketSize. The #MQTTFixedBuffer_t
+ * must be at least as large as the size returned by #MQTT_GetConnectPacketSize.
+ *
+ * @param[in] pConnectInfo MQTT CONNECT packet parameters.
+ * @param[in] pWillInfo Last Will and Testament. Pass NULL if not used.
+ * @param[in] remainingLength Remaining Length provided by #MQTT_GetConnectPacketSize.
+ * @param[out] pFixedBuffer Buffer for packet serialization.
+ *
+ * @return #MQTTNoMemory if pFixedBuffer is too small to hold the MQTT packet;
+ * #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSuccess otherwise.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTConnectInfo_t connectInfo = { 0 };
+ * MQTTPublishInfo_t willInfo = { 0 };
+ * MQTTFixedBuffer_t fixedBuffer;
+ * uint8_t buffer[ BUFFER_SIZE ];
+ * size_t remainingLength = 0, packetSize = 0;
+ *
+ * fixedBuffer.pBuffer = buffer;
+ * fixedBuffer.size = BUFFER_SIZE;
+ *
+ * // Assume connectInfo and willInfo are initialized. Get the size requirement for
+ * // the connect packet.
+ * status = MQTT_GetConnectPacketSize(
+ *      &connectInfo, &willInfo, &remainingLength, &packetSize
+ * );
+ * assert( status == MQTTSuccess );
+ * assert( packetSize <= BUFFER_SIZE );
+ *
+ * // Serialize the connect packet into the fixed buffer.
+ * status = MQTT_SerializeConnect( &connectInfo, &willInfo, remainingLength, &fixedBuffer );
+ *
+ * if( status == MQTTSuccess )
+ * {
+ *      // The connect packet can now be sent to the broker.
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_serializeconnect] */
+MQTTStatus_t MQTT_SerializeConnect( const MQTTConnectInfo_t * pConnectInfo,
+                                    const MQTTPublishInfo_t * pWillInfo,
+                                    size_t remainingLength,
+                                    const MQTTFixedBuffer_t * pFixedBuffer );
+/* @[declare_mqtt_serializeconnect] */
+
+/**
+ * @brief Get packet size and Remaining Length of an MQTT SUBSCRIBE packet.
+ *
+ * This function must be called before #MQTT_SerializeSubscribe in order to get
+ * the size of the MQTT SUBSCRIBE packet that is generated from the list of
+ * #MQTTSubscribeInfo_t. The size of the #MQTTFixedBuffer_t supplied
+ * to #MQTT_SerializeSubscribe must be at least @p pPacketSize. The provided
+ * @p pSubscriptionList is valid for serialization with #MQTT_SerializeSubscribe
+ * only if this function returns #MQTTSuccess. The remaining length returned in
+ * @p pRemainingLength and the packet size returned in @p pPacketSize are valid
+ * only if this function returns #MQTTSuccess.
+ *
+ * @param[in] pSubscriptionList List of MQTT subscription info.
+ * @param[in] subscriptionCount The number of elements in pSubscriptionList.
+ * @param[out] pRemainingLength The Remaining Length of the MQTT SUBSCRIBE packet.
+ * @param[out] pPacketSize The total size of the MQTT SUBSCRIBE packet.
+ *
+ * @return #MQTTBadParameter if the packet would exceed the size allowed by the
+ * MQTT spec; #MQTTSuccess otherwise.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTSubscribeInfo_t subscriptionList[ NUMBER_OF_SUBSCRIPTIONS ] = { 0 };
+ * size_t remainingLength = 0, packetSize = 0;
+ * // This is assumed to be a list of filters we want to subscribe to.
+ * const char * filters[ NUMBER_OF_SUBSCRIPTIONS ];
+ *
+ * // Set each subscription.
+ * for( int i = 0; i < NUMBER_OF_SUBSCRIPTIONS; i++ )
+ * {
+ *      subscriptionList[ i ].qos = MQTTQoS0;
+ *      // Each subscription needs a topic filter.
+ *      subscriptionList[ i ].pTopicFilter = filters[ i ];
+ *      subscriptionList[ i ].topicFilterLength = strlen( filters[ i ] );
+ * }
+ *
+ * // Get the size requirement for the subscribe packet.
+ * status = MQTT_GetSubscribePacketSize(
+ *      &subscriptionList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, &remainingLength, &packetSize
+ * );
+ *
+ * if( status == MQTTSuccess )
+ * {
+ *      // The application should allocate or use a static #MQTTFixedBuffer_t
+ *      // of size >= packetSize to serialize the subscribe request.
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_getsubscribepacketsize] */
+MQTTStatus_t MQTT_GetSubscribePacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
+                                          size_t subscriptionCount,
+                                          size_t * pRemainingLength,
+                                          size_t * pPacketSize );
+/* @[declare_mqtt_getsubscribepacketsize] */
+
+/**
+ * @brief Serialize an MQTT SUBSCRIBE packet in the given buffer.
+ *
+ * #MQTT_GetSubscribePacketSize should be called with @p pSubscriptionList
+ * before invoking this function to get the size of the required
+ * #MQTTFixedBuffer_t and @p remainingLength. The @p remainingLength must be
+ * the same as returned by #MQTT_GetSubscribePacketSize. The #MQTTFixedBuffer_t
+ * must be at least as large as the size returned by #MQTT_GetSubscribePacketSize.
+ *
+ * @param[in] pSubscriptionList List of MQTT subscription info.
+ * @param[in] subscriptionCount The number of elements in pSubscriptionList.
+ * @param[in] packetId packet ID generated by #MQTT_GetPacketId.
+ * @param[in] remainingLength Remaining Length provided by #MQTT_GetSubscribePacketSize.
+ * @param[out] pFixedBuffer Buffer for packet serialization.
+ *
+ * @return #MQTTNoMemory if pFixedBuffer is too small to hold the MQTT packet;
+ * #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSuccess otherwise.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTSubscribeInfo_t subscriptionList[ NUMBER_OF_SUBSCRIPTIONS ] = { 0 };
+ * MQTTFixedBuffer_t fixedBuffer;
+ * uint8_t buffer[ BUFFER_SIZE ];
+ * size_t remainingLength = 0, packetSize = 0;
+ * uint16_t packetId;
+ *
+ * fixedBuffer.pBuffer = buffer;
+ * fixedBuffer.size = BUFFER_SIZE;
+ *
+ * // Function to return a valid, unused packet identifier. The details are out of
+ * // scope for this example.
+ * packetId = getNewPacketId();
+ *
+ * // Assume subscriptionList has been initialized. Get the subscribe packet size.
+ * status = MQTT_GetSubscribePacketSize(
+ *      &subscriptionList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, &remainingLength, &packetSize
+ * );
+ * assert( status == MQTTSuccess );
+ * assert( packetSize <= BUFFER_SIZE );
+ *
+ * // Serialize the subscribe packet into the fixed buffer.
+ * status = MQTT_SerializeSubscribe(
+ *      &subscriptionList[ 0 ],
+ *      NUMBER_OF_SUBSCRIPTIONS,
+ *      packetId,
+ *      remainingLength,
+ *      &fixedBuffer
+ * );
+ *
+ * if( status == MQTTSuccess )
+ * {
+ *      // The subscribe packet can now be sent to the broker.
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_serializesubscribe] */
+MQTTStatus_t MQTT_SerializeSubscribe( const MQTTSubscribeInfo_t * pSubscriptionList,
+                                      size_t subscriptionCount,
+                                      uint16_t packetId,
+                                      size_t remainingLength,
+                                      const MQTTFixedBuffer_t * pFixedBuffer );
+/* @[declare_mqtt_serializesubscribe] */
+
+/**
+ * @brief Get packet size and Remaining Length of an MQTT UNSUBSCRIBE packet.
+ *
+ * This function must be called before #MQTT_SerializeUnsubscribe in order to
+ * get the size of the MQTT UNSUBSCRIBE packet that is generated from the list
+ * of #MQTTSubscribeInfo_t. The size of the #MQTTFixedBuffer_t supplied
+ * to #MQTT_SerializeUnsubscribe must be at least @p pPacketSize. The provided
+ * @p pSubscriptionList is valid for serialization with #MQTT_SerializeUnsubscribe
+ * only if this function returns #MQTTSuccess. The remaining length returned in
+ * @p pRemainingLength and the packet size returned in @p pPacketSize are valid
+ * only if this function returns #MQTTSuccess.
+ *
+ * @param[in] pSubscriptionList List of MQTT subscription info.
+ * @param[in] subscriptionCount The number of elements in pSubscriptionList.
+ * @param[out] pRemainingLength The Remaining Length of the MQTT UNSUBSCRIBE packet.
+ * @param[out] pPacketSize The total size of the MQTT UNSUBSCRIBE packet.
+ *
+ * @return #MQTTBadParameter if the packet would exceed the size allowed by the
+ * MQTT spec; #MQTTSuccess otherwise.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTSubscribeInfo_t subscriptionList[ NUMBER_OF_SUBSCRIPTIONS ] = { 0 };
+ * size_t remainingLength = 0, packetSize = 0;
+ *
+ * // Initialize the subscribe info. The details are out of scope for this example.
+ * initializeSubscribeInfo( &subscriptionList[ 0 ] );
+ *
+ * // Get the size requirement for the unsubscribe packet.
+ * status = MQTT_GetUnsubscribePacketSize(
+ *      &subscriptionList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, &remainingLength, &packetSize
+ * );
+ *
+ * if( status == MQTTSuccess )
+ * {
+ *      // The application should allocate or use a static #MQTTFixedBuffer_t
+ *      // of size >= packetSize to serialize the unsubscribe request.
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_getunsubscribepacketsize] */
+MQTTStatus_t MQTT_GetUnsubscribePacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
+                                            size_t subscriptionCount,
+                                            size_t * pRemainingLength,
+                                            size_t * pPacketSize );
+/* @[declare_mqtt_getunsubscribepacketsize] */
+
+/**
+ * @brief Serialize an MQTT UNSUBSCRIBE packet in the given buffer.
+ *
+ * #MQTT_GetUnsubscribePacketSize should be called with @p pSubscriptionList
+ * before invoking this function to get the size of the required
+ * #MQTTFixedBuffer_t and @p remainingLength. The @p remainingLength must be
+ * the same as returned by #MQTT_GetUnsubscribePacketSize. The #MQTTFixedBuffer_t
+ * must be at least as large as the size returned by #MQTT_GetUnsubscribePacketSize.
+ *
+ * @param[in] pSubscriptionList List of MQTT subscription info.
+ * @param[in] subscriptionCount The number of elements in pSubscriptionList.
+ * @param[in] packetId packet ID generated by #MQTT_GetPacketId.
+ * @param[in] remainingLength Remaining Length provided by #MQTT_GetUnsubscribePacketSize.
+ * @param[out] pFixedBuffer Buffer for packet serialization.
+ *
+ * @return #MQTTNoMemory if pFixedBuffer is too small to hold the MQTT packet;
+ * #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSuccess otherwise.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTSubscribeInfo_t subscriptionList[ NUMBER_OF_SUBSCRIPTIONS ] = { 0 };
+ * MQTTFixedBuffer_t fixedBuffer;
+ * uint8_t buffer[ BUFFER_SIZE ];
+ * size_t remainingLength = 0, packetSize = 0;
+ * uint16_t packetId;
+ *
+ * fixedBuffer.pBuffer = buffer;
+ * fixedBuffer.size = BUFFER_SIZE;
+ *
+ * // Function to return a valid, unused packet identifier. The details are out of
+ * // scope for this example.
+ * packetId = getNewPacketId();
+ *
+ * // Assume subscriptionList has been initialized. Get the unsubscribe packet size.
+ * status = MQTT_GetUnsubscribePacketSize(
+ *      &subscriptionList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, &remainingLength, &packetSize
+ * );
+ * assert( status == MQTTSuccess );
+ * assert( packetSize <= BUFFER_SIZE );
+ *
+ * // Serialize the unsubscribe packet into the fixed buffer.
+ * status = MQTT_SerializeUnsubscribe(
+ *      &subscriptionList[ 0 ],
+ *      NUMBER_OF_SUBSCRIPTIONS,
+ *      packetId,
+ *      remainingLength,
+ *      &fixedBuffer
+ * );
+ *
+ * if( status == MQTTSuccess )
+ * {
+ *      // The unsubscribe packet can now be sent to the broker.
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_serializeunsubscribe] */
+MQTTStatus_t MQTT_SerializeUnsubscribe( const MQTTSubscribeInfo_t * pSubscriptionList,
+                                        size_t subscriptionCount,
+                                        uint16_t packetId,
+                                        size_t remainingLength,
+                                        const MQTTFixedBuffer_t * pFixedBuffer );
+/* @[declare_mqtt_serializeunsubscribe] */
+
+/**
+ * @brief Get the packet size and remaining length of an MQTT PUBLISH packet.
+ *
+ * This function must be called before #MQTT_SerializePublish in order to get
+ * the size of the MQTT PUBLISH packet that is generated from #MQTTPublishInfo_t.
+ * The size of the #MQTTFixedBuffer_t supplied to #MQTT_SerializePublish must be
+ * at least @p pPacketSize. The provided @p pPublishInfo is valid for
+ * serialization with #MQTT_SerializePublish only if this function returns
+ * #MQTTSuccess. The remaining length returned in @p pRemainingLength and the
+ * packet size returned in @p pPacketSize are valid only if this function
+ * returns #MQTTSuccess.
+ *
+ * @param[in] pPublishInfo MQTT PUBLISH packet parameters.
+ * @param[out] pRemainingLength The Remaining Length of the MQTT PUBLISH packet.
+ * @param[out] pPacketSize The total size of the MQTT PUBLISH packet.
+ *
+ * @return #MQTTBadParameter if the packet would exceed the size allowed by the
+ * MQTT spec or if invalid parameters are passed; #MQTTSuccess otherwise.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTPublishInfo_t publishInfo = { 0 };
+ * size_t remainingLength = 0, packetSize = 0;
+ *
+ * // Initialize the publish info.
+ * publishInfo.qos = MQTTQoS0;
+ * publishInfo.pTopicName = "/some/topic/name";
+ * publishInfo.topicNameLength = strlen( publishInfo.pTopicName );
+ * publishInfo.pPayload = "Hello World!";
+ * publishInfo.payloadLength = strlen( "Hello World!" );
+ *
+ * // Get the size requirement for the publish packet.
+ * status = MQTT_GetPublishPacketSize(
+ *      &publishInfo, &remainingLength, &packetSize
+ * );
+ *
+ * if( status == MQTTSuccess )
+ * {
+ *      // The application should allocate or use a static #MQTTFixedBuffer_t
+ *      // of size >= packetSize to serialize the publish.
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_getpublishpacketsize] */
+MQTTStatus_t MQTT_GetPublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
+                                        size_t * pRemainingLength,
+                                        size_t * pPacketSize );
+/* @[declare_mqtt_getpublishpacketsize] */
+
+/**
+ * @brief Serialize an MQTT PUBLISH packet in the given buffer.
+ *
+ * This function will serialize complete MQTT PUBLISH packet into
+ * the given buffer. If the PUBLISH payload can be sent separately,
+ * consider using #MQTT_SerializePublishHeader, which will serialize
+ * only the PUBLISH header into the buffer.
+ *
+ * #MQTT_GetPublishPacketSize should be called with @p pPublishInfo before
+ * invoking this function to get the size of the required #MQTTFixedBuffer_t and
+ * @p remainingLength. The @p remainingLength must be the same as returned by
+ * #MQTT_GetPublishPacketSize. The #MQTTFixedBuffer_t must be at least as large
+ * as the size returned by #MQTT_GetPublishPacketSize.
+ *
+ * @param[in] pPublishInfo MQTT PUBLISH packet parameters.
+ * @param[in] packetId packet ID generated by #MQTT_GetPacketId.
+ * @param[in] remainingLength Remaining Length provided by #MQTT_GetPublishPacketSize.
+ * @param[out] pFixedBuffer Buffer for packet serialization.
+ *
+ * @return #MQTTNoMemory if pFixedBuffer is too small to hold the MQTT packet;
+ * #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSuccess otherwise.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTPublishInfo_t publishInfo = { 0 };
+ * MQTTFixedBuffer_t fixedBuffer;
+ * uint8_t buffer[ BUFFER_SIZE ];
+ * size_t remainingLength = 0, packetSize = 0;
+ * uint16_t packetId;
+ *
+ * fixedBuffer.pBuffer = buffer;
+ * fixedBuffer.size = BUFFER_SIZE;
+ *
+ * // A packet identifier is unused for QoS 0 publishes. Otherwise, a valid, unused packet
+ * // identifier must be used.
+ * packetId = 0;
+ *
+ * // Assume publishInfo has been initialized. Get publish packet size.
+ * status = MQTT_GetPublishPacketSize(
+ *      &publishInfo, &remainingLength, &packetSize
+ * );
+ * assert( status == MQTTSuccess );
+ * assert( packetSize <= BUFFER_SIZE );
+ *
+ * // Serialize the publish packet into the fixed buffer.
+ * status = MQTT_SerializePublish(
+ *      &publishInfo,
+ *      packetId,
+ *      remainingLength,
+ *      &fixedBuffer
+ * );
+ *
+ * if( status == MQTTSuccess )
+ * {
+ *      // The publish packet can now be sent to the broker.
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_serializepublish] */
+MQTTStatus_t MQTT_SerializePublish( const MQTTPublishInfo_t * pPublishInfo,
+                                    uint16_t packetId,
+                                    size_t remainingLength,
+                                    const MQTTFixedBuffer_t * pFixedBuffer );
+/* @[declare_mqtt_serializepublish] */
+
+/**
+ * @brief Serialize an MQTT PUBLISH packet header without the topic string in the
+ * given buffer. This function will add the topic string length to the provided
+ * buffer. This helps reduce an unnecessary copy of the topic string into the
+ * buffer.
+ *
+ * @param[in] pPublishInfo MQTT PUBLISH packet parameters.
+ * @param[in] remainingLength Remaining Length provided by #MQTT_GetPublishPacketSize.
+ * @param[out] pBuffer Buffer for packet serialization.
+ * @param[out] headerSize Size of the serialized MQTT PUBLISH header.
+ *
+ * @return #MQTTSuccess if the serialization is successful. Otherwise, #MQTTBadParameter.
+ */
+MQTTStatus_t MQTT_SerializePublishHeaderWithoutTopic( const MQTTPublishInfo_t * pPublishInfo,
+                                                      size_t remainingLength,
+                                                      uint8_t * pBuffer,
+                                                      size_t * headerSize );
+
+/**
+ * @brief Serialize an MQTT PUBLISH packet header in the given buffer.
+ *
+ * This function serializes PUBLISH header in to the given buffer. The payload
+ * for PUBLISH will not be copied over to the buffer. This will help reduce
+ * the memory needed for the buffer and avoid an unwanted copy operation of the
+ * PUBLISH payload into the buffer. If the payload also would need to be part of
+ * the serialized buffer, consider using #MQTT_SerializePublish.
+ *
+ * #MQTT_GetPublishPacketSize should be called with @p pPublishInfo before
+ * invoking this function to get the size of the required #MQTTFixedBuffer_t and
+ * @p remainingLength. The @p remainingLength must be the same as returned by
+ * #MQTT_GetPublishPacketSize. The #MQTTFixedBuffer_t must be at least as large
+ * as the size returned by #MQTT_GetPublishPacketSize.
+ *
+ * @param[in] pPublishInfo MQTT PUBLISH packet parameters.
+ * @param[in] packetId packet ID generated by #MQTT_GetPacketId.
+ * @param[in] remainingLength Remaining Length provided by #MQTT_GetPublishPacketSize.
+ * @param[out] pFixedBuffer Buffer for packet serialization.
+ * @param[out] pHeaderSize Size of the serialized MQTT PUBLISH header.
+ *
+ * @return #MQTTNoMemory if pFixedBuffer is too small to hold the MQTT packet;
+ * #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSuccess otherwise.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTPublishInfo_t publishInfo = { 0 };
+ * MQTTFixedBuffer_t fixedBuffer;
+ * uint8_t buffer[ BUFFER_SIZE ];
+ * size_t remainingLength = 0, packetSize = 0, headerSize = 0;
+ * uint16_t packetId;
+ * int32_t bytesSent;
+ *
+ * fixedBuffer.pBuffer = buffer;
+ * fixedBuffer.size = BUFFER_SIZE;
+ *
+ * // A packet identifier is unused for QoS 0 publishes. Otherwise, a valid, unused packet
+ * // identifier must be used.
+ * packetId = 0;
+ *
+ * // Assume publishInfo has been initialized. Get the publish packet size.
+ * status = MQTT_GetPublishPacketSize(
+ *      &publishInfo, &remainingLength, &packetSize
+ * );
+ * assert( status == MQTTSuccess );
+ * // The payload will not be serialized, so the the fixed buffer does not need to hold it.
+ * assert( ( packetSize - publishInfo.payloadLength ) <= BUFFER_SIZE );
+ *
+ * // Serialize the publish packet header into the fixed buffer.
+ * status = MQTT_SerializePublishHeader(
+ *      &publishInfo,
+ *      packetId,
+ *      remainingLength,
+ *      &fixedBuffer,
+ *      &headerSize
+ * );
+ *
+ * if( status == MQTTSuccess )
+ * {
+ *      // The publish header and payload can now be sent to the broker.
+ *      // mqttSocket here is a socket descriptor created and connected to the MQTT
+ *      // broker outside of this function.
+ *      bytesSent = send( mqttSocket, ( void * ) fixedBuffer.pBuffer, headerSize, 0 );
+ *      assert( bytesSent == headerSize );
+ *      bytesSent = send( mqttSocket, publishInfo.pPayload, publishInfo.payloadLength, 0 );
+ *      assert( bytesSent == publishInfo.payloadLength );
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_serializepublishheader] */
+MQTTStatus_t MQTT_SerializePublishHeader( const MQTTPublishInfo_t * pPublishInfo,
+                                          uint16_t packetId,
+                                          size_t remainingLength,
+                                          const MQTTFixedBuffer_t * pFixedBuffer,
+                                          size_t * pHeaderSize );
+/* @[declare_mqtt_serializepublishheader] */
+
+/**
+ * @brief Serialize an MQTT PUBACK, PUBREC, PUBREL, or PUBCOMP into the given
+ * buffer.
+ *
+ * @param[out] pFixedBuffer Buffer for packet serialization.
+ * @param[in] packetType Byte of the corresponding packet fixed header per the
+ * MQTT spec.
+ * @param[in] packetId Packet ID of the publish.
+ *
+ * @return #MQTTBadParameter, #MQTTNoMemory, or #MQTTSuccess.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTFixedBuffer_t fixedBuffer;
+ * uint8_t buffer[ BUFFER_SIZE ];
+ * uint16_t packetId;
+ * uint8_t packetType;
+ *
+ * fixedBuffer.pBuffer = buffer;
+ * fixedBuffer.size = BUFFER_SIZE;
+ * // The fixed buffer must be large enough to hold 4 bytes.
+ * assert( BUFFER_SIZE >= MQTT_PUBLISH_ACK_PACKET_SIZE );
+ *
+ * // The packet ID must be the same as the original publish packet.
+ * packetId = publishPacketId;
+ *
+ * // The byte representing a packet of type ACK. This function accepts PUBACK, PUBREC, PUBREL, or PUBCOMP.
+ * packetType = MQTT_PACKET_TYPE_PUBACK;
+ *
+ * // Serialize the publish acknowledgment into the fixed buffer.
+ * status = MQTT_SerializeAck( &fixedBuffer, packetType, packetId );
+ *
+ * if( status == MQTTSuccess )
+ * {
+ *      // The publish acknowledgment can now be sent to the broker.
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_serializeack] */
+MQTTStatus_t MQTT_SerializeAck( const MQTTFixedBuffer_t * pFixedBuffer,
+                                uint8_t packetType,
+                                uint16_t packetId );
+/* @[declare_mqtt_serializeack] */
+
+/**
+ * @brief Get the size of an MQTT DISCONNECT packet.
+ *
+ * @param[out] pPacketSize The size of the MQTT DISCONNECT packet.
+ *
+ * @return #MQTTSuccess, or #MQTTBadParameter if @p pPacketSize is NULL.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * size_t packetSize = 0;
+ *
+ * // Get the size requirement for the disconnect packet.
+ * status = MQTT_GetDisconnectPacketSize( &packetSize );
+ * assert( status == MQTTSuccess );
+ * assert( packetSize == 2 );
+ *
+ * // The application should allocate or use a static #MQTTFixedBuffer_t of
+ * // size >= 2 to serialize the disconnect packet.
+ *
+ * @endcode
+ */
+/* @[declare_mqtt_getdisconnectpacketsize] */
+MQTTStatus_t MQTT_GetDisconnectPacketSize( size_t * pPacketSize );
+/* @[declare_mqtt_getdisconnectpacketsize] */
+
+/**
+ * @brief Serialize an MQTT DISCONNECT packet into the given buffer.
+ *
+ * The input #MQTTFixedBuffer_t.size must be at least as large as the size
+ * returned by #MQTT_GetDisconnectPacketSize.
+ *
+ * @param[out] pFixedBuffer Buffer for packet serialization.
+ *
+ * @return #MQTTNoMemory if pFixedBuffer is too small to hold the MQTT packet;
+ * #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSuccess otherwise.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTFixedBuffer_t fixedBuffer;
+ * uint8_t buffer[ BUFFER_SIZE ];
+ *
+ * fixedBuffer.pBuffer = buffer;
+ * fixedBuffer.size = BUFFER_SIZE;
+ *
+ * // Get the disconnect packet size.
+ * status = MQTT_GetDisconnectPacketSize( &packetSize );
+ * assert( status == MQTTSuccess );
+ * assert( packetSize <= BUFFER_SIZE );
+ *
+ * // Serialize the disconnect into the fixed buffer.
+ * status = MQTT_SerializeDisconnect( &fixedBuffer );
+ *
+ * if( status == MQTTSuccess )
+ * {
+ *      // The disconnect packet can now be sent to the broker.
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_serializedisconnect] */
+MQTTStatus_t MQTT_SerializeDisconnect( const MQTTFixedBuffer_t * pFixedBuffer );
+/* @[declare_mqtt_serializedisconnect] */
+
+/**
+ * @brief Get the size of an MQTT PINGREQ packet.
+ *
+ * @param[out] pPacketSize The size of the MQTT PINGREQ packet.
+ *
+ * @return  #MQTTSuccess or #MQTTBadParameter if pPacketSize is NULL.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * size_t packetSize = 0;
+ *
+ * // Get the size requirement for the ping request packet.
+ * status = MQTT_GetPingreqPacketSize( &packetSize );
+ * assert( status == MQTTSuccess );
+ * assert( packetSize == 2 );
+ *
+ * // The application should allocate or use a static #MQTTFixedBuffer_t of
+ * // size >= 2 to serialize the ping request.
+ *
+ * @endcode
+ */
+/* @[declare_mqtt_getpingreqpacketsize] */
+MQTTStatus_t MQTT_GetPingreqPacketSize( size_t * pPacketSize );
+/* @[declare_mqtt_getpingreqpacketsize] */
+
+/**
+ * @brief Serialize an MQTT PINGREQ packet into the given buffer.
+ *
+ * The input #MQTTFixedBuffer_t.size must be at least as large as the size
+ * returned by #MQTT_GetPingreqPacketSize.
+ *
+ * @param[out] pFixedBuffer Buffer for packet serialization.
+ *
+ * @return #MQTTNoMemory if pFixedBuffer is too small to hold the MQTT packet;
+ * #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSuccess otherwise.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTFixedBuffer_t fixedBuffer;
+ * uint8_t buffer[ BUFFER_SIZE ];
+ *
+ * fixedBuffer.pBuffer = buffer;
+ * fixedBuffer.size = BUFFER_SIZE;
+ *
+ * // Get the ping request packet size.
+ * status = MQTT_GetPingreqPacketSize( &packetSize );
+ * assert( status == MQTTSuccess );
+ * assert( packetSize <= BUFFER_SIZE );
+ *
+ * // Serialize the ping request into the fixed buffer.
+ * status = MQTT_SerializePingreq( &fixedBuffer );
+ *
+ * if( status == MQTTSuccess )
+ * {
+ *      // The ping request can now be sent to the broker.
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_serializepingreq] */
+MQTTStatus_t MQTT_SerializePingreq( const MQTTFixedBuffer_t * pFixedBuffer );
+/* @[declare_mqtt_serializepingreq] */
+
+/**
+ * @brief Deserialize an MQTT PUBLISH packet.
+ *
+ * @param[in] pIncomingPacket #MQTTPacketInfo_t containing the buffer.
+ * @param[out] pPacketId The packet ID obtained from the buffer.
+ * @param[out] pPublishInfo Struct containing information about the publish.
+ *
+ * @return #MQTTBadParameter, #MQTTBadResponse, or #MQTTSuccess.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // TransportRecv_t function for reading from the network.
+ * int32_t socket_recv(
+ *      NetworkContext_t * pNetworkContext,
+ *      void * pBuffer,
+ *      size_t bytesToRecv
+ * );
+ * // Some context to be used with the above transport receive function.
+ * NetworkContext_t networkContext;
+ *
+ * // Other variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTPacketInfo_t incomingPacket;
+ * MQTTPublishInfo_t publishInfo = { 0 };
+ * uint16_t packetId;
+ *
+ * int32_t bytesRecvd;
+ * // A buffer to hold remaining data of the incoming packet.
+ * uint8_t buffer[ BUFFER_SIZE ];
+ *
+ * // Populate all fields of the incoming packet.
+ * status = MQTT_GetIncomingPacketTypeAndLength(
+ *      socket_recv,
+ *      &networkContext,
+ *      &incomingPacket
+ * );
+ * assert( status == MQTTSuccess );
+ * assert( incomingPacket.remainingLength <= BUFFER_SIZE );
+ * bytesRecvd = socket_recv(
+ *      &networkContext,
+ *      ( void * ) buffer,
+ *      incomingPacket.remainingLength
+ * );
+ * incomingPacket.pRemainingData = buffer;
+ *
+ * // Deserialize the publish information if the incoming packet is a publish.
+ * if( ( incomingPacket.type & 0xF0 ) == MQTT_PACKET_TYPE_PUBLISH )
+ * {
+ *      status = MQTT_DeserializePublish( &incomingPacket, &packetId, &publishInfo );
+ *      if( status == MQTTSuccess )
+ *      {
+ *          // The deserialized publish information can now be used from `publishInfo`.
+ *      }
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_deserializepublish] */
+MQTTStatus_t MQTT_DeserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
+                                      uint16_t * pPacketId,
+                                      MQTTPublishInfo_t * pPublishInfo );
+/* @[declare_mqtt_deserializepublish] */
+
+/**
+ * @brief Deserialize an MQTT CONNACK, SUBACK, UNSUBACK, PUBACK, PUBREC, PUBREL,
+ * PUBCOMP, or PINGRESP.
+ *
+ * @param[in] pIncomingPacket #MQTTPacketInfo_t containing the buffer.
+ * @param[out] pPacketId The packet ID of obtained from the buffer. Not used
+ * in CONNACK or PINGRESP.
+ * @param[out] pSessionPresent Boolean flag from a CONNACK indicating present session.
+ *
+ * @return #MQTTBadParameter, #MQTTBadResponse, #MQTTServerRefused, or #MQTTSuccess.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTPacketInfo_t incomingPacket;
+ * // Used for SUBACK, UNSUBACK, PUBACK, PUBREC, PUBREL, and PUBCOMP.
+ * uint16_t packetId;
+ * // Used for CONNACK.
+ * bool sessionPresent;
+ *
+ * // Receive an incoming packet and populate all fields. The details are out of scope
+ * // for this example.
+ * receiveIncomingPacket( &incomingPacket );
+ *
+ * // Deserialize ack information if the incoming packet is not a publish.
+ * if( ( incomingPacket.type & 0xF0 ) != MQTT_PACKET_TYPE_PUBLISH )
+ * {
+ *      status = MQTT_DeserializeAck( &incomingPacket, &packetId, &sessionPresent );
+ *      if( status == MQTTSuccess )
+ *      {
+ *          // The packet ID or session present flag information is available. For
+ *          // ping response packets, the only information is the status code.
+ *      }
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_deserializeack] */
+MQTTStatus_t MQTT_DeserializeAck( const MQTTPacketInfo_t * pIncomingPacket,
+                                  uint16_t * pPacketId,
+                                  bool * pSessionPresent );
+/* @[declare_mqtt_deserializeack] */
+
+/**
+ * @brief Extract the MQTT packet type and length from incoming packet.
+ *
+ * This function must be called for every incoming packet to retrieve the
+ * #MQTTPacketInfo_t.type and #MQTTPacketInfo_t.remainingLength. A
+ * #MQTTPacketInfo_t is not valid until this routine has been invoked.
+ *
+ * @param[in] readFunc Transport layer read function pointer.
+ * @param[in] pNetworkContext The network context pointer provided by the application.
+ * @param[out] pIncomingPacket Pointer to MQTTPacketInfo_t structure. This is
+ * where type, remaining length and packet identifier are stored.
+ *
+ * @return #MQTTSuccess on successful extraction of type and length,
+ * #MQTTBadParameter if @p pIncomingPacket is invalid,
+ * #MQTTRecvFailed on transport receive failure,
+ * #MQTTBadResponse if an invalid packet is read, and
+ * #MQTTNoDataAvailable if there is nothing to read.
+ *
+ * <b>Example</b>
+ * @code{c}
+ *
+ * // TransportRecv_t function for reading from the network.
+ * int32_t socket_recv(
+ *      NetworkContext_t * pNetworkContext,
+ *      void * pBuffer,
+ *      size_t bytesToRecv
+ * );
+ * // Some context to be used with above transport receive function.
+ * NetworkContext_t networkContext;
+ *
+ * // Struct to hold the incoming packet information.
+ * MQTTPacketInfo_t incomingPacket;
+ * MQTTStatus_t status = MQTTSuccess;
+ * int32_t bytesRecvd;
+ * // Buffer to hold the remaining data of the incoming packet.
+ * uint8_t buffer[ BUFFER_SIZE ];
+ *
+ * // Loop until data is available to be received.
+ * do{
+ *      status = MQTT_GetIncomingPacketTypeAndLength(
+ *          socket_recv,
+ *          &networkContext,
+ *          &incomingPacket
+ *      );
+ * } while( status == MQTTNoDataAvailable );
+ *
+ * assert( status == MQTTSuccess );
+ *
+ * // Receive the rest of the incoming packet.
+ * assert( incomingPacket.remainingLength <= BUFFER_SIZE );
+ * bytesRecvd = socket_recv(
+ *      &networkContext,
+ *      ( void * ) buffer,
+ *      incomingPacket.remainingLength
+ * );
+ *
+ * // Set the remaining data field.
+ * incomingPacket.pRemainingData = buffer;
+ * @endcode
+ */
+/* @[declare_mqtt_getincomingpackettypeandlength] */
+MQTTStatus_t MQTT_GetIncomingPacketTypeAndLength( TransportRecv_t readFunc,
+                                                  NetworkContext_t * pNetworkContext,
+                                                  MQTTPacketInfo_t * pIncomingPacket );
+/* @[declare_mqtt_getincomingpackettypeandlength] */
+
+/**
+ * @brief Extract the MQTT packet type and length from incoming packet.
+ *
+ * This function must be called for every incoming packet to retrieve the
+ * #MQTTPacketInfo_t.type and #MQTTPacketInfo_t.remainingLength. A
+ * #MQTTPacketInfo_t is not valid until this routine has been invoked.
+ *
+ * @param[in] pBuffer The buffer holding the raw data to be processed
+ * @param[in] pIndex Pointer to the index within the buffer to marking the end
+ *            of raw data available.
+ * @param[out] pIncomingPacket Structure used to hold the fields of the
+ *            incoming packet.
+ *
+ * @return #MQTTSuccess on successful extraction of type and length,
+ * #MQTTBadParameter if @p pIncomingPacket is invalid,
+ * #MQTTBadResponse if an invalid packet is read, and
+ * #MQTTNoDataAvailable if there is nothing to read.
+ */
+ /* @[declare_mqtt_processincomingpackettypeandlength] */
+MQTTStatus_t MQTT_ProcessIncomingPacketTypeAndLength( const uint8_t * pBuffer,
+                                                      const size_t * pIndex,
+                                                      MQTTPacketInfo_t * pIncomingPacket );
+/* @[declare_mqtt_processincomingpackettypeandlength] */
+
+/**
+ * @brief Update the duplicate publish flag within the given header of the publish packet.
+ *
+ * @param[in] pHeader The buffer holding the header content
+ * @param[in] set If true then the flag will be set else cleared
+ *
+ * @return #MQTTSuccess on successful setting of the duplicate flag,
+ * #MQTTBadParameter for invalid parameters
+ */
+ /* @[declare_mqtt_updateduplicatepublishflag] */
+MQTTStatus_t MQTT_UpdateDuplicatePublishFlag( uint8_t * pHeader , bool set);
+/* @[declare_mqtt_updateduplicatepublishflag] */
+
+/**
+ * @fn uint8_t * MQTT_SerializeConnectFixedHeader( uint8_t * pIndex, const MQTTConnectInfo_t * pConnectInfo, const MQTTPublishInfo_t * pWillInfo, size_t remainingLength );
+ * @brief Serialize the fixed part of the connect packet header.
+ *
+ * @param[out] pIndex Pointer to the buffer where the header is to
+ * be serialized.
+ * @param[in] pConnectInfo The connect information.
+ * @param[in] pWillInfo The last will and testament information.
+ * @param[in] remainingLength The remaining length of the packet to be
+ * serialized.
+ *
+ * @return A pointer to the end of the encoded string.
+ */
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+uint8_t * MQTT_SerializeConnectFixedHeader( uint8_t * pIndex,
+                                            const MQTTConnectInfo_t * pConnectInfo,
+                                            const MQTTPublishInfo_t * pWillInfo,
+                                            size_t remainingLength );
+/** @endcond */
+
+/**
+ * @fn  uint8_t * MQTT_SerializeSubscribeHeader( size_t remainingLength, uint8_t * pIndex, uint16_t packetId );
+ * @brief Serialize the fixed part of the subscribe packet header.
+ *
+ * @param[in] remainingLength The remaining length of the packet to be
+ * serialized.
+ * @param[in] pIndex Pointer to the buffer where the header is to
+ * be serialized.
+ * @param[in] packetId The packet ID to be serialized.
+ *
+ * @return A pointer to the end of the encoded string.
+ */
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+uint8_t * MQTT_SerializeSubscribeHeader( size_t remainingLength,
+                                         uint8_t * pIndex,
+                                         uint16_t packetId );
+/** @endcond */
+
+/**
+ * @fn uint8_t * MQTT_SerializeUnsubscribeHeader( size_t remainingLength, uint8_t * pIndex, uint16_t packetId );
+ * @brief Serialize the fixed part of the unsubscribe packet header.
+ *
+ * @param[in] remainingLength The remaining length of the packet to be
+ * serialized.
+ * @param[in] pIndex Pointer to the buffer where the header is to
+ * be serialized.
+ * @param[in] packetId The packet ID to be serialized.
+ *
+ * @return A pointer to the end of the encoded string.
+ */
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+uint8_t * MQTT_SerializeUnsubscribeHeader( size_t remainingLength,
+                                           uint8_t * pIndex,
+                                           uint16_t packetId );
+/** @endcond */
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+    }
+#endif
+/* *INDENT-ON* */
+
+#endif /* ifndef CORE_MQTT_SERIALIZER_H */

+ 408 - 418
example/RyanMqttTest.c

@@ -1,8 +1,8 @@
 #include "rtconfig.h"
 
 #define RyanMqttClientId ("RyanMqttTessdfwrt") // 填写mqtt客户端id,要求唯一
-#define RyanMqttHost ("broker.emqx.io")        // 填写你的mqtt服务器ip
-#define RyanMqttPort (1883)                    // mqtt服务器端口
+#define RyanMqttHost     ("broker.emqx.io")    // 填写你的mqtt服务器ip
+#define RyanMqttPort     (1883)                // mqtt服务器端口
 #define RyanMqttUserName (NULL)                // 填写你的用户名,没有填NULL
 #define RyanMqttPassword (NULL)                // 填写你的密码,没有填NULL
 
@@ -17,10 +17,8 @@
 #include <rtdevice.h>
 #include <rtdbg.h>
 
-#define rlogEnable               // 是否使能日志
-#define rlogColorEnable          // 是否使能日志颜色
 #define rlogLevel (rlogLvlDebug) // 日志打印等级
-#define rlogTag "RyanMqttTest"   // 日志tag
+
 #include "RyanMqttLog.h"
 #include "RyanMqttClient.h"
 
@@ -33,16 +31,18 @@ static char mqttSendBuffer[512];
 
 // 具体数值计算可以查看事件回调函数
 static uint32_t mqttTest[10] = {0};
-#define dataEventCount (0)      // 接收到数据次数统计
+#define dataEventCount      (0) // 接收到数据次数统计
 #define PublishedEventCount (1) // qos1和qos2发布成功的次数统计
 
 static void printfArrStr(char *buf, uint32_t len, char *userData)
 {
-    rlog_raw("%s", userData);
-    for (uint32_t i = 0; i < len; i++)
-        rlog_raw("%x", buf[i]);
+	rlog_raw("%s", userData);
+	for (uint32_t i = 0; i < len; i++)
+	{
+		rlog_raw("%x", buf[i]);
+	}
 
-    rlog_raw("\r\n");
+	rlog_raw("\r\n");
 }
 
 /**
@@ -55,118 +55,106 @@ static void printfArrStr(char *buf, uint32_t len, char *userData)
  */
 static void mqttEventHandle(void *pclient, RyanMqttEventId_e event, const void *eventData)
 {
-    RyanMqttClient_t *client = (RyanMqttClient_t *)pclient;
-
-    switch (event)
-    {
-    case RyanMqttEventError:
-        break;
-
-    case RyanMqttEventConnected: // 不管有没有使能clearSession,都非常推荐在连接成功回调函数中订阅主题
-        rlog_i("mqtt连接成功回调 %d", *(int32_t *)eventData);
-        break;
-
-    case RyanMqttEventDisconnected:
-        rlog_w("mqtt断开连接回调 %d", *(int32_t *)eventData);
-        break;
-
-    case RyanMqttEventSubscribed:
-    {
-        RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
-        rlog_w("mqtt订阅成功回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
-        break;
-    }
-
-    case RyanMqttEventSubscribedFaile:
-    {
-        RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
-        rlog_w("mqtt订阅失败回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
-        break;
-    }
-
-    case RyanMqttEventUnSubscribed:
-    {
-        RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
-        rlog_w("mqtt取消订阅成功回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
-        break;
-    }
-
-    case RyanMqttEventUnSubscribedFaile:
-    {
-        RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
-        rlog_w("mqtt取消订阅失败回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
-        break;
-    }
-
-    case RyanMqttEventPublished:
-    {
-        RyanMqttMsgHandler_t *msgHandler = ((RyanMqttAckHandler_t *)eventData)->msgHandler;
-        rlog_w("qos1 / qos2发送成功事件回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
-        mqttTest[PublishedEventCount]++;
-        break;
-    }
-
-    case RyanMqttEventData:
-    {
-        RyanMqttMsgData_t *msgData = (RyanMqttMsgData_t *)eventData;
-        rlog_i("接收到mqtt消息事件回调 topic: %.*s, packetId: %d, payload len: %d",
-               msgData->topicLen, msgData->topic, msgData->packetId, msgData->payloadLen);
-
-        rlog_i("%.*s", msgData->payloadLen, msgData->payload);
-
-        mqttTest[dataEventCount]++;
-        break;
-    }
-
-    case RyanMqttEventRepeatPublishPacket: // qos2 / qos1重发事件回调
-    {
-        RyanMqttAckHandler_t *ackHandler = (RyanMqttAckHandler_t *)eventData;
-        rlog_w("发布消息进行重发了,packetType: %d, packetId: %d, topic: %s, qos: %d",
-               ackHandler->packetType, ackHandler->packetId, ackHandler->msgHandler->topic, ackHandler->msgHandler->qos);
-
-        printfArrStr(ackHandler->packet, ackHandler->packetLen, "重发数据: ");
-        break;
-    }
-
-    case RyanMqttEventReconnectBefore:
-        // 如果每次connect都需要修改连接信息,这里是最好的选择。 否则需要注意资源互斥
-        rlog_i("重连前事件回调");
-        break;
-
-    case RyanMqttEventAckCountWarning: // qos2 / qos1的ack链表超过警戒值,不进行释放会一直重发,占用额外内存
-    {
-        // 根据实际情况清除ack, 这里等待每个ack重发次数到达警戒值后清除。
-        // 在资源有限的单片机中也不应频繁发送qos2 / qos1消息
-        uint16_t ackHandlerCount = *(uint16_t *)eventData;
-        rlog_i("ack记数值超过警戒值回调: %d", ackHandlerCount);
-        break;
-    }
-
-    case RyanMqttEventAckRepeatCountWarning: // 重发次数到达警戒值事件
-    {
-        // 这里选择直接丢弃该消息
-        RyanMqttAckHandler_t *ackHandler = (RyanMqttAckHandler_t *)eventData;
-        rlog_w("ack重发次数超过警戒值回调 packetType: %d, packetId: %d, topic: %s, qos: %d", ackHandler->packetType, ackHandler->packetId, ackHandler->msgHandler->topic, ackHandler->msgHandler->qos);
-        RyanMqttDiscardAckHandler(client, ackHandler->packetType, ackHandler->packetId);
-
-        break;
-    }
-
-    case RyanMqttEventAckHandlerdiscard:
-    {
-        RyanMqttAckHandler_t *ackHandler = (RyanMqttAckHandler_t *)eventData;
-        rlog_i("ack丢弃回调: packetType: %d, packetId: %d, topic: %s, qos: %d",
-               ackHandler->packetType, ackHandler->packetId, ackHandler->msgHandler->topic, ackHandler->msgHandler->qos);
-        break;
-    }
-
-    case RyanMqttEventDestoryBefore:
-        rlog_i("销毁mqtt客户端前回调");
-        break;
-
-    default:
-        break;
-    }
+	RyanMqttClient_t *client = (RyanMqttClient_t *)pclient;
+
+	switch (event)
+	{
+	case RyanMqttEventError: break;
+
+	case RyanMqttEventConnected: // 不管有没有使能clearSession,都非常推荐在连接成功回调函数中订阅主题
+		rlog_i("mqtt连接成功回调 %d", *(int32_t *)eventData);
+		break;
+
+	case RyanMqttEventDisconnected: rlog_w("mqtt断开连接回调 %d", *(int32_t *)eventData); break;
+
+	case RyanMqttEventSubscribed: {
+		RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
+		rlog_w("mqtt订阅成功回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		break;
+	}
+
+	case RyanMqttEventSubscribedFaile: {
+		RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
+		rlog_w("mqtt订阅失败回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		break;
+	}
+
+	case RyanMqttEventUnSubscribed: {
+		RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
+		rlog_w("mqtt取消订阅成功回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		break;
+	}
+
+	case RyanMqttEventUnSubscribedFaile: {
+		RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
+		rlog_w("mqtt取消订阅失败回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		break;
+	}
+
+	case RyanMqttEventPublished: {
+		RyanMqttMsgHandler_t *msgHandler = ((RyanMqttAckHandler_t *)eventData)->msgHandler;
+		rlog_w("qos1 / qos2发送成功事件回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		pubTestPublishedEventCount++;
+		break;
+	}
+
+	case RyanMqttEventData: {
+		RyanMqttMsgData_t *msgData = (RyanMqttMsgData_t *)eventData;
+		rlog_i("接收到mqtt消息事件回调 topic: %.*s, packetId: %d, payload len: %d", msgData->topicLen,
+		       msgData->topic, msgData->packetId, msgData->payloadLen);
+
+		rlog_i("%.*s", msgData->payloadLen, msgData->payload);
+
+		pubTestDataEventCount++;
+		break;
+	}
+
+	case RyanMqttEventRepeatPublishPacket: // qos2 / qos1重发事件回调
+	{
+		RyanMqttAckHandler_t *ackHandler = (RyanMqttAckHandler_t *)eventData;
+		rlog_w("发布消息进行重发了,packetType: %d, packetId: %d, topic: %s, qos: %d", ackHandler->packetType,
+		       ackHandler->packetId, ackHandler->msgHandler->topic, ackHandler->msgHandler->qos);
+
+		printfArrStr(ackHandler->packet, ackHandler->packetLen, "重发数据: ");
+		break;
+	}
+
+	case RyanMqttEventReconnectBefore:
+		// 如果每次connect都需要修改连接信息,这里是最好的选择。 否则需要注意资源互斥
+		rlog_i("重连前事件回调");
+		break;
+
+	case RyanMqttEventAckCountWarning: // qos2 / qos1的ack链表超过警戒值,不进行释放会一直重发,占用额外内存
+	{
+		// 根据实际情况清除ack, 这里等待每个ack重发次数到达警戒值后清除。
+		// 在资源有限的单片机中也不应频繁发送qos2 / qos1消息
+		uint16_t ackHandlerCount = *(uint16_t *)eventData;
+		rlog_i("ack记数值超过警戒值回调: %d", ackHandlerCount);
+		break;
+	}
+
+	case RyanMqttEventAckRepeatCountWarning: // 重发次数到达警戒值事件
+	{
+		// 这里选择直接丢弃该消息
+		RyanMqttAckHandler_t *ackHandler = (RyanMqttAckHandler_t *)eventData;
+		rlog_w("ack重发次数超过警戒值回调 packetType: %d, packetId: %d, topic: %s, qos: %d",
+		       ackHandler->packetType, ackHandler->packetId, ackHandler->msgHandler->topic,
+		       ackHandler->msgHandler->qos);
+		RyanMqttDiscardAckHandler(client, ackHandler->packetType, ackHandler->packetId);
+		break;
+	}
+
+	case RyanMqttEventAckHandlerdiscard: {
+		RyanMqttAckHandler_t *ackHandler = (RyanMqttAckHandler_t *)eventData;
+		rlog_i("ack丢弃回调: packetType: %d, packetId: %d, topic: %s, qos: %d", ackHandler->packetType,
+		       ackHandler->packetId, ackHandler->msgHandler->topic, ackHandler->msgHandler->qos);
+		break;
+	}
+
+	case RyanMqttEventDestoryBefore: rlog_i("销毁mqtt客户端前回调"); break;
+
+	default: break;
+	}
 }
 
 /**
@@ -175,9 +163,9 @@ static void mqttEventHandle(void *pclient, RyanMqttEventId_e event, const void *
  */
 struct RyanMqttCmdDes
 {
-    const char *cmd;
-    const char *explain;
-    int (*fun)(int argc, char *argv[]);
+	const char *cmd;
+	const char *explain;
+	int (*fun)(int argc, char *argv[]);
 };
 
 static int MqttHelp(int argc, char *argv[]);
@@ -191,42 +179,28 @@ static int MqttHelp(int argc, char *argv[]);
  */
 static int MqttState(int argc, char *argv[])
 {
-    char *str = NULL;
-    RyanMqttState_e clientState = RyanMqttGetState(client);
-    switch (clientState)
-    {
-    case RyanMqttInvalidState:
-        str = "无效状态";
-        break;
-
-    case RyanMqttInitState:
-        str = "初始化状态";
-        break;
-
-    case RyanMqttStartState:
-        str = "mqtt开始状态";
-        break;
-
-    case RyanMqttConnectState:
-        str = "连接状态";
-        break;
-
-    case RyanMqttDisconnectState:
-        str = "断开连接状态";
-        break;
-
-    case RyanMqttReconnectState:
-        str = "重新连接状态";
-        break;
-
-    default:
-        RyanMqttCheck(NULL, RyanMqttFailedError, rlog_d);
-        break;
-    }
-
-    rlog_i("client state: %s", str);
-
-    return 0;
+	char *str = NULL;
+	RyanMqttState_e clientState = RyanMqttGetState(client);
+	switch (clientState)
+	{
+	case RyanMqttInvalidState: str = "无效状态"; break;
+
+	case RyanMqttInitState: str = "初始化状态"; break;
+
+	case RyanMqttStartState: str = "mqtt开始状态"; break;
+
+	case RyanMqttConnectState: str = "连接状态"; break;
+
+	case RyanMqttDisconnectState: str = "断开连接状态"; break;
+
+	case RyanMqttReconnectState: str = "重新连接状态"; break;
+
+	default: RyanMqttCheck(NULL, RyanMqttFailedError, rlog_d); break;
+	}
+
+	rlog_i("client state: %s", str);
+
+	return 0;
 }
 
 /**
@@ -238,59 +212,54 @@ static int MqttState(int argc, char *argv[])
  */
 static int MqttConnect(int argc, char *argv[])
 {
-    if (RyanMqttConnectState == RyanMqttGetState(client))
-    {
-        rlog_w("mqtt客户端已经连接,请不要重复连接");
-        return 0;
-    }
-
-    RyanMqttError_e result = RyanMqttSuccessError;
-    RyanMqttClientConfig_t mqttConfig = {
-        .clientId = RyanMqttClientId,
-        .userName = RyanMqttUserName,
-        .password = RyanMqttPassword,
-        .host = RyanMqttHost,
-        .port = RyanMqttPort,
-        .taskName = "mqttThread",
-        .taskPrio = 16,
-        .taskStack = 2048,
-        .recvBufferSize = sizeof(mqttRecvBuffer),
-        .sendBufferSize = sizeof(mqttSendBuffer),
-        .recvBuffer = mqttRecvBuffer,
-        .sendBuffer = mqttSendBuffer,
-        .mqttVersion = 4,
-        .ackHandlerRepeatCountWarning = 6,
-        .ackHandlerCountWarning = 20,
-        .autoReconnectFlag = RyanMqttTrue,
-        .cleanSessionFlag = RyanMqttFalse,
-        .reconnectTimeout = 3000,
-        .recvTimeout = 5000,
-        .sendTimeout = 2000,
-        .ackTimeout = 10000,
-        .keepaliveTimeoutS = 120,
-        .mqttEventHandle = mqttEventHandle,
-        .userData = NULL};
-
-    // 初始化mqtt客户端
-    result = RyanMqttInit(&client);
-    RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_d);
-
-    // 注册需要的事件回调
-    result = RyanMqttRegisterEventId(client, RyanMqttEventAnyId);
-    RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_d);
-
-    // 设置mqtt客户端config
-    result = RyanMqttSetConfig(client, &mqttConfig);
-    RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_d);
-
-    // 设置遗嘱消息
-    result = RyanMqttSetLwt(client, "pub/test", "this is will", strlen("this is will"), RyanMqttQos0, 0);
-    RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_d);
-
-    // 启动mqtt客户端线程
-    result = RyanMqttStart(client);
-    RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_d);
-    return 0;
+	if (RyanMqttConnectState == RyanMqttGetState(client))
+	{
+		rlog_w("mqtt客户端已经连接,请不要重复连接");
+		return 0;
+	}
+
+	RyanMqttError_e result = RyanMqttSuccessError;
+	RyanMqttClientConfig_t mqttConfig = {.clientId = RyanMqttClientId,
+					     .userName = RyanMqttUserName,
+					     .password = RyanMqttPassword,
+					     .host = RyanMqttHost,
+					     .port = RyanMqttPort,
+					     .taskName = "mqttThread",
+					     .taskPrio = 16,
+					     .taskStack = 2048,
+					     .mqttVersion = 4,
+					     .ackHandlerRepeatCountWarning = 6,
+					     .ackHandlerCountWarning = 20,
+					     .autoReconnectFlag = RyanMqttTrue,
+					     .cleanSessionFlag = RyanMqttFalse,
+					     .reconnectTimeout = 3000,
+					     .recvTimeout = 5000,
+					     .sendTimeout = 2000,
+					     .ackTimeout = 10000,
+					     .keepaliveTimeoutS = 120,
+					     .mqttEventHandle = mqttEventHandle,
+					     .userData = NULL};
+
+	// 初始化mqtt客户端
+	result = RyanMqttInit(&client);
+	RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_d);
+
+	// 注册需要的事件回调
+	result = RyanMqttRegisterEventId(client, RyanMqttEventAnyId);
+	RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_d);
+
+	// 设置mqtt客户端config
+	result = RyanMqttSetConfig(client, &mqttConfig);
+	RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_d);
+
+	// 设置遗嘱消息
+	result = RyanMqttSetLwt(client, "pub/test", "this is will", strlen("this is will"), RyanMqttQos0, 0);
+	RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_d);
+
+	// 启动mqtt客户端线程
+	result = RyanMqttStart(client);
+	RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_d);
+	return 0;
 }
 
 /**
@@ -302,8 +271,8 @@ static int MqttConnect(int argc, char *argv[])
  */
 static int MqttReconnect(int argc, char *argv[])
 {
-    RyanMqttReconnect(client);
-    return 0;
+	RyanMqttReconnect(client);
+	return 0;
 }
 
 /**
@@ -315,9 +284,9 @@ static int MqttReconnect(int argc, char *argv[])
  */
 static int MqttDestroy(int argc, char *argv[])
 {
-    RyanMqttDestroy(client);
-    client = NULL;
-    return 0;
+	RyanMqttDestroy(client);
+	client = NULL;
+	return 0;
 }
 
 /**
@@ -329,13 +298,13 @@ static int MqttDestroy(int argc, char *argv[])
  */
 static int MqttDisconnect(int argc, char *argv[])
 {
-    if (RyanMqttConnectState != RyanMqttGetState(client))
-    {
-        rlog_w("mqtt客户端没有连接");
-        return 0;
-    }
-    RyanMqttDisconnect(client, RyanMqttTrue);
-    return 0;
+	if (RyanMqttConnectState != RyanMqttGetState(client))
+	{
+		rlog_w("mqtt客户端没有连接");
+		return 0;
+	}
+	RyanMqttDisconnect(client, RyanMqttTrue);
+	return 0;
 }
 
 /**
@@ -347,36 +316,38 @@ static int MqttDisconnect(int argc, char *argv[])
  */
 static int Mqttpublish(int argc, char *argv[])
 {
-    if (argc < 7)
-    {
-        rlog_w("参数不完整! 请输入 topic、 qos、 payload内容、 发送条数、 间隔时间(可以为0) ");
-        return 0;
-    }
-
-    if (RyanMqttConnectState != RyanMqttGetState(client))
-    {
-        rlog_w("mqtt客户端没有连接");
-        return 0;
-    }
-
-    char *topic = argv[2];
-    RyanMqttQos_e qos = atoi(argv[3]);
-    char *payload = argv[4];
-    uint16_t count = atoi(argv[5]);
-    uint16_t delayTime = atoi(argv[6]);
-
-    uint16_t pubCount = 0;
-    rlog_i("qos: %d, count: %d, delayTime: %d, payload: %s", qos, count, delayTime, payload);
-
-    for (uint16_t i = 0; i < count; i++)
-    {
-        if (RyanMqttSuccessError == RyanMqttPublish(client, topic, payload, strlen(payload), qos, 0))
-            pubCount++;
-        delay(delayTime);
-    }
-
-    rlog_w("pubCount: %d", pubCount);
-    return 0;
+	if (argc < 7)
+	{
+		rlog_w("参数不完整! 请输入 topic、 qos、 payload内容、 发送条数、 间隔时间(可以为0) ");
+		return 0;
+	}
+
+	if (RyanMqttConnectState != RyanMqttGetState(client))
+	{
+		rlog_w("mqtt客户端没有连接");
+		return 0;
+	}
+
+	char *topic = argv[2];
+	RyanMqttQos_e qos = atoi(argv[3]);
+	char *payload = argv[4];
+	uint16_t count = atoi(argv[5]);
+	uint16_t delayTime = atoi(argv[6]);
+
+	uint16_t pubCount = 0;
+	rlog_i("qos: %d, count: %d, delayTime: %d, payload: %s", qos, count, delayTime, payload);
+
+	for (uint16_t i = 0; i < count; i++)
+	{
+		if (RyanMqttSuccessError == RyanMqttPublish(client, topic, payload, strlen(payload), qos, 0))
+		{
+			pubCount++;
+		}
+		delay(delayTime);
+	}
+
+	rlog_w("pubCount: %d", pubCount);
+	return 0;
 }
 
 /**
@@ -388,20 +359,20 @@ static int Mqttpublish(int argc, char *argv[])
  */
 static int Mqttsubscribe(int argc, char *argv[])
 {
-    if (argc < 4)
-    {
-        rlog_w("参数不完整! 请输入 topic、 qos ");
-        return 0;
-    }
-
-    if (RyanMqttConnectState != RyanMqttGetState(client))
-    {
-        rlog_w("mqtt客户端没有连接");
-        return 0;
-    }
-
-    RyanMqttSubscribe(client, argv[2], atoi(argv[3]));
-    return 0;
+	if (argc < 4)
+	{
+		rlog_w("参数不完整! 请输入 topic、 qos ");
+		return 0;
+	}
+
+	if (RyanMqttConnectState != RyanMqttGetState(client))
+	{
+		rlog_w("mqtt客户端没有连接");
+		return 0;
+	}
+
+	RyanMqttSubscribe(client, argv[2], atoi(argv[3]));
+	return 0;
 }
 
 /**
@@ -413,20 +384,20 @@ static int Mqttsubscribe(int argc, char *argv[])
  */
 static int MqttUnSubscribe(int argc, char *argv[])
 {
-    if (argc < 3)
-    {
-        rlog_w("参数不完整! 请输入 取消订阅主题");
-        return 0;
-    }
-
-    if (RyanMqttConnectState != RyanMqttGetState(client))
-    {
-        rlog_w("mqtt客户端没有连接");
-        return 0;
-    }
-
-    RyanMqttUnSubscribe(client, argv[2]);
-    return 0;
+	if (argc < 3)
+	{
+		rlog_w("参数不完整! 请输入 取消订阅主题");
+		return 0;
+	}
+
+	if (RyanMqttConnectState != RyanMqttGetState(client))
+	{
+		rlog_w("mqtt客户端没有连接");
+		return 0;
+	}
+
+	RyanMqttUnSubscribe(client, argv[2]);
+	return 0;
 }
 
 /**
@@ -438,27 +409,39 @@ static int MqttUnSubscribe(int argc, char *argv[])
  */
 static int MqttListSubscribe(int argc, char *argv[])
 {
-    if (RyanMqttConnectState != RyanMqttGetState(client))
-    {
-        rlog_w("mqtt客户端没有连接");
-        return 0;
-    }
-
-    RyanMqttMsgHandler_t msgHandles[100] = {0};
-    int32_t subscribeNum = 0;
-    int32_t result = RyanMqttSuccessError;
-
-    result = RyanMqttGetSubscribe(client, msgHandles, sizeof(msgHandles) / sizeof(msgHandles[0]), &subscribeNum);
-
-    if (result == RyanMqttNoRescourceError)
-        rlog_w("订阅主题数超过缓冲区%d个,已截断,请修改msgHandles缓冲区", sizeof(msgHandles) / sizeof(msgHandles[0]));
-
-    rlog_i("mqtt客户端已订阅的主题数: %d", subscribeNum);
-
-    for (int32_t i = 0; i < subscribeNum; i++)
-        rlog_i("已经订阅主题: %d, topic: %s, QOS: %d", i, msgHandles[i].topic, msgHandles[i].qos);
-
-    return 0;
+	if (RyanMqttConnectState != RyanMqttGetState(client))
+	{
+		rlog_w("mqtt客户端没有连接");
+		return 0;
+	}
+
+	RyanMqttMsgHandler_t *msgHandles = NULL;
+	int32_t subscribeNum = 0;
+	int32_t result = RyanMqttSuccessError;
+
+	result = RyanMqttGetSubscribeSafe(client, &msgHandles, &subscribeNum);
+	if (RyanMqttSuccessError != result)
+	{
+		if (RyanMqttNoRescourceError == result)
+		{
+			rlog_w("没用订阅的主题~~~");
+		}
+		else
+		{
+			rlog_e("获取订阅主题数失败可能没用内存");
+		}
+	}
+
+	rlog_i("mqtt客户端已订阅的主题数: %d", subscribeNum);
+
+	for (int32_t i = 0; i < subscribeNum; i++)
+	{
+		rlog_i("已经订阅主题: %d, topic: %s, QOS: %d", i, msgHandles[i].topic, msgHandles[i].qos);
+	}
+
+	RyanMqttSafeFreeSubscribeResources(msgHandles, subscribeNum);
+
+	return 0;
 }
 
 /**
@@ -470,28 +453,29 @@ static int MqttListSubscribe(int argc, char *argv[])
  */
 static int MqttListAck(int argc, char *argv[])
 {
-    RyanList_t *curr = NULL,
-               *next = NULL;
-    RyanMqttAckHandler_t *ackHandler = NULL;
-
-    if (RyanListIsEmpty(&client->ackHandlerList))
-    {
-        rlog_w("ack链表为空,没有等待ack的消息");
-        return 0;
-    }
-
-    // 遍历链表
-    RyanListForEachSafe(curr, next, &client->ackHandlerList)
-    {
-        // 获取此节点的结构体
-        ackHandler = RyanListEntry(curr, RyanMqttAckHandler_t, list);
-
-        // 发送qos1 / qos2消息服务器ack响应超时。需要重新发送它们。
-        rlog_i(" type: %d, packetId is %d ", ackHandler->packetType, ackHandler->packetId);
-        if (NULL != ackHandler->msgHandler)
-            rlog_i("topic: %s, qos: %d", ackHandler->msgHandler->topic, ackHandler->msgHandler->qos);
-    }
-    return 0;
+	RyanList_t *curr, *next;
+	RyanMqttAckHandler_t *ackHandler = NULL;
+
+	if (RyanListIsEmpty(&client->ackHandlerList))
+	{
+		rlog_w("ack链表为空,没有等待ack的消息");
+		return 0;
+	}
+
+	// 遍历链表
+	RyanListForEachSafe(curr, next, &client->ackHandlerList)
+	{
+		// 获取此节点的结构体
+		ackHandler = RyanListEntry(curr, RyanMqttAckHandler_t, list);
+
+		// 发送qos1 / qos2消息服务器ack响应超时。需要重新发送它们。
+		rlog_i(" type: %d, packetId is %d ", ackHandler->packetType, ackHandler->packetId);
+		if (NULL != ackHandler->msgHandler)
+		{
+			rlog_i("topic: %s, qos: %d", ackHandler->msgHandler->topic, ackHandler->msgHandler->qos);
+		}
+	}
+	return 0;
 }
 
 /**
@@ -503,22 +487,21 @@ static int MqttListAck(int argc, char *argv[])
  */
 static int MqttListMsg(int argc, char *argv[])
 {
-    RyanList_t *curr = NULL,
-               *next = NULL;
-    RyanMqttMsgHandler_t *msgHandler = NULL;
-
-    if (RyanListIsEmpty(&client->msgHandlerList))
-    {
-        rlog_w("msg链表为空,没有等待的msg消息");
-        return 0;
-    }
-
-    RyanListForEachSafe(curr, next, &client->msgHandlerList)
-    {
-        msgHandler = RyanListEntry(curr, RyanMqttMsgHandler_t, list);
-        rlog_i("topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
-    }
-    return 0;
+	RyanList_t *curr = NULL, *next = NULL;
+	RyanMqttMsgHandler_t *msgHandler = NULL;
+
+	if (RyanListIsEmpty(&client->msgHandlerList))
+	{
+		rlog_w("msg链表为空,没有等待的msg消息");
+		return 0;
+	}
+
+	RyanListForEachSafe(curr, next, &client->msgHandlerList)
+	{
+		msgHandler = RyanListEntry(curr, RyanMqttMsgHandler_t, list);
+		rlog_i("topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+	}
+	return 0;
 }
 
 /**
@@ -530,93 +513,100 @@ static int MqttListMsg(int argc, char *argv[])
  */
 static int Mqttdata(int argc, char *argv[])
 {
-    // mqtt data
-    if (argc == 3)
-    {
-        uint32_t num = atoi(argv[2]);
-        if (num < sizeof(mqttTest) / sizeof(mqttTest[0]) - 1)
-            mqttTest[num] = 0;
-        else
-            rlog_e("数组越界");
-    }
-
-    rlog_i("接收到数据次数统计: %d, qos1和qos2发布成功的次数统计: %d",
-           mqttTest[dataEventCount], mqttTest[PublishedEventCount]);
-
-    return 0;
+	// mqtt data
+	if (argc == 3)
+	{
+		uint32_t num = atoi(argv[2]);
+		if (num < sizeof(mqttTest) / sizeof(mqttTest[0]) - 1)
+		{
+			mqttTest[num] = 0;
+		}
+		else
+		{
+			rlog_e("数组越界");
+		}
+	}
+
+	rlog_i("接收到数据次数统计: %d, qos1和qos2发布成功的次数统计: %d", pubTestDataEventCount,
+	       pubTestPublishedEventCount);
+
+	return 0;
 }
 
-static const struct RyanMqttCmdDes cmdTab[] =
-    {
-        // {"help",        "打印帮助信息               params: null", MqttHelp},
-        // {"state",       "打印mqtt客户端状态         params: null", MqttState},
-        // {"connect",     "mqtt客户端连接服务器       params: null", MqttConnect},
-        // {"disc",        "mqtt客户端断开连接         params: null", MqttDisconnect},
-        // {"reconnect",   "mqtt断开连接时重新连接     params: null", MqttReconnect},
-        // {"destory",     "mqtt销毁客户端             params: null", MqttDestroy},
-        // {"pub",         "mqtt发布消息               params: topic、qos、payload内容、发送条数、间隔时间(可以为0)", Mqttpublish},
-        // {"sub",         "mqtt订阅主题               params: topic、qos", Mqttsubscribe},
-        // {"unsub",       "mqtt取消订阅主题           params: 取消订阅主题", MqttUnSubscribe},
-        // {"listsub",     "mqtt获取已订阅主题         params: null", MqttListSubscribe},
-        // {"listack",     "打印ack链表                params: null", MqttListAck},
-        // {"listmsg",     "打印msg链表                params: null", MqttListMsg},
-        // {"data",        "打印测试信息用户自定义的    params: null", Mqttdata},
-
-        {"help", "打印帮助信息               params: null", MqttHelp},
-        {"state", "打印mqtt客户端状态         params: null", MqttState},
-        {"connect", "mqtt客户端连接服务器       params: null", MqttConnect},
-        {"disc", "mqtt客户端断开连接         params: null", MqttDisconnect},
-        {"reconnect", "mqtt断开连接时重新连接     params: null", MqttReconnect},
-        {"destory", "mqtt销毁客户端             params: null", MqttDestroy},
-        {"pub", "mqtt发布消息               params: topic、qos、payload内容、发送条数、间隔时间(可以为0)", Mqttpublish},
-        {"sub", "mqtt订阅主题               params: topic、qos", Mqttsubscribe},
-        {"unsub", "mqtt取消订阅主题           params: 取消订阅主题", MqttUnSubscribe},
-        {"listsub", "mqtt获取已订阅主题         params: null", MqttListSubscribe},
-        {"listack", "打印ack链表                params: null", MqttListAck},
-        {"listmsg", "打印msg链表                params: null", MqttListMsg},
-        {"data", "打印测试信息用户自定义的   params: null", Mqttdata},
+static const struct RyanMqttCmdDes cmdTab[] = {
+	// {"help",        "打印帮助信息               params: null", MqttHelp},
+	// {"state",       "打印mqtt客户端状态         params: null", MqttState},
+	// {"connect",     "mqtt客户端连接服务器       params: null", MqttConnect},
+	// {"disc",        "mqtt客户端断开连接         params: null", MqttDisconnect},
+	// {"reconnect",   "mqtt断开连接时重新连接     params: null", MqttReconnect},
+	// {"destory",     "mqtt销毁客户端             params: null", MqttDestroy},
+	// {"pub",         "mqtt发布消息               params: topic、qos、payload内容、发送条数、间隔时间(可以为0)",
+	// Mqttpublish},
+	// {"sub",         "mqtt订阅主题               params: topic、qos", Mqttsubscribe},
+	// {"unsub",       "mqtt取消订阅主题           params: 取消订阅主题", MqttUnSubscribe},
+	// {"listsub",     "mqtt获取已订阅主题         params: null", MqttListSubscribe},
+	// {"listack",     "打印ack链表                params: null", MqttListAck},
+	// {"listmsg",     "打印msg链表                params: null", MqttListMsg},
+	// {"data",        "打印测试信息用户自定义的    params: null", Mqttdata},
+
+	{"help", "打印帮助信息               params: null", MqttHelp},
+	{"state", "打印mqtt客户端状态         params: null", MqttState},
+	{"connect", "mqtt客户端连接服务器       params: null", MqttConnect},
+	{"disc", "mqtt客户端断开连接         params: null", MqttDisconnect},
+	{"reconnect", "mqtt断开连接时重新连接     params: null", MqttReconnect},
+	{"destory", "mqtt销毁客户端             params: null", MqttDestroy},
+	{"pub", "mqtt发布消息               params: topic、qos、payload内容、发送条数、间隔时间(可以为0)", Mqttpublish},
+	{"sub", "mqtt订阅主题               params: topic、qos", Mqttsubscribe},
+	{"unsub", "mqtt取消订阅主题           params: 取消订阅主题", MqttUnSubscribe},
+	{"listsub", "mqtt获取已订阅主题         params: null", MqttListSubscribe},
+	{"listack", "打印ack链表                params: null", MqttListAck},
+	{"listmsg", "打印msg链表                params: null", MqttListMsg},
+	{"data", "打印测试信息用户自定义的   params: null", Mqttdata},
 };
 
 static int MqttHelp(int argc, char *argv[])
 {
 
-    for (uint8_t i = 0; i < sizeof(cmdTab) / sizeof(cmdTab[0]); i++)
-        rlog_raw("mqtt %-16s %s\r\n", cmdTab[i].cmd, cmdTab[i].explain);
+	for (uint8_t i = 0; i < sizeof(cmdTab) / sizeof(cmdTab[0]); i++)
+	{
+		rlog_raw("mqtt %-16s %s\r\n", cmdTab[i].cmd, cmdTab[i].explain);
+	}
 
-    return 0;
+	return 0;
 }
 
 static int RyanMqttMsh(int argc, char *argv[])
 {
-    int32_t i = 0,
-            result = 0;
-    const struct RyanMqttCmdDes *runCmd = NULL;
-
-    if (argc == 1)
-    {
-        MqttHelp(argc, argv);
-        return 0;
-    }
-
-    for (i = 0; i < sizeof(cmdTab) / sizeof(cmdTab[0]); i++)
-    {
-        if (rt_strcmp(cmdTab[i].cmd, argv[1]) == 0)
-        {
-            runCmd = &cmdTab[i];
-            break;
-        }
-    }
-
-    if (runCmd == NULL)
-    {
-        MqttHelp(argc, argv);
-        return 0;
-    }
-
-    if (runCmd->fun != NULL)
-        result = runCmd->fun(argc, argv);
-
-    return result;
+	int32_t i = 0, result = 0;
+	const struct RyanMqttCmdDes *runCmd = NULL;
+
+	if (argc == 1)
+	{
+		MqttHelp(argc, argv);
+		return 0;
+	}
+
+	for (i = 0; i < sizeof(cmdTab) / sizeof(cmdTab[0]); i++)
+	{
+		if (rt_strcmp(cmdTab[i].cmd, argv[1]) == 0)
+		{
+			runCmd = &cmdTab[i];
+			break;
+		}
+	}
+
+	if (runCmd == NULL)
+	{
+		MqttHelp(argc, argv);
+		return 0;
+	}
+
+	if (runCmd->fun != NULL)
+	{
+		result = runCmd->fun(argc, argv);
+	}
+
+	return result;
 }
 
 #if defined(RT_USING_MSH)

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 635 - 277
mqttclient/RyanMqttClient.c


+ 157 - 125
mqttclient/RyanMqttClient.h

@@ -2,138 +2,170 @@
 #define __RyanMqttClient__
 
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif
 
-#include "MQTTPacket.h"
-#include "platformTimer.h"
 #include "platformSystem.h"
 #include "platformNetwork.h"
-
+#include "RyanMqttLog.h"
 #include "RyanList.h"
 #include "RyanMqttPublic.h"
 
-    // 接收到订阅消息回调函数类型,eventData用户不要进行修改否则mqtt客户端可能崩溃
-    typedef void (*RyanMqttEventHandle)(void *client, RyanMqttEventId_e event, const void *eventData);
-
-    // 定义枚举类型
-
-    // 定义结构体类型
-    typedef struct
-    {
-        uint8_t retained;    // retained 标志位
-        uint8_t dup;         // 重发标志
-        uint16_t packetId;   // packetId 系统生成
-        RyanMqttQos_e qos;   // QOS等级
-        uint32_t payloadLen; // 数据长度
-        uint32_t topicLen;   // topic长度
-        char *topic;         // 主题信息
-        char *payload;       // 数据内容
-    } RyanMqttMsgData_t;
-
-    typedef struct
-    {
-        uint16_t topicLen; // 主题长度
-        RyanMqttQos_e qos; // qos等级
-        RyanList_t list;   // 链表节点,用户勿动
-        char *topic;       // 主题
-    } RyanMqttMsgHandler_t;
-
-    typedef struct
-    {
-        uint16_t repeatCount;             // 当前ack超时重发次数
-        uint16_t packetId;                // 报文标识符 系统生成,用户勿动
-        uint32_t packetLen;               // 报文长度
-        enum msgTypes packetType;         // 期望接收到的ack报文类型
-        RyanList_t list;                  // 链表节点,用户勿动
-        platformTimer_t timer;            // ack超时定时器,用户勿动
-        RyanMqttMsgHandler_t *msgHandler; // msg信息
-        char *packet;                     // 没有收到期望ack,重新发送的原始报文
-    } RyanMqttAckHandler_t;
-
-    typedef struct
-    {
-
-        uint8_t retain;      // 遗嘱保留标志位
-        uint32_t payloadLen; // 消息长度
-        RyanMqttQos_e qos;   // 遗嘱qos等级
-        char *topic;         // 遗嘱主题
-        char *payload;       // 遗嘱消息
-    } lwtOptions_t;
-
-    typedef struct
-    {
-        char *clientId;                        // 客户端ID
-        char *userName;                        // 用户名
-        char *password;                        // 密码
-        char *host;                            // mqtt服务器地址
-        char *taskName;                        // 线程名字
-        char *recvBuffer;                      // mqtt接收缓冲区
-        char *sendBuffer;                      // mqtt发送缓冲区
-        RyanMqttBool_e autoReconnectFlag : 1;  // 自动重连标志位
-        RyanMqttBool_e cleanSessionFlag : 1;   // 清除会话标志位
-        uint8_t mqttVersion : 4;               // mqtt版本 3.1.1是4, 3.1是3
-        uint16_t port;                         // mqtt服务器端口
-        uint16_t ackHandlerRepeatCountWarning; // ack重发超过这个数值后触发事件回调,根据实际硬件选择。典型值为 * ackTimeout ~= 300秒
-        uint16_t taskPrio;                     // mqtt线程优先级
-        uint16_t taskStack;                    // 线程栈大小
-        uint16_t recvTimeout;                  // mqtt等待接收命令超时时间, 根据实际硬件选择。推荐 > ackTimeout && <= (keepaliveTimeoutS / 2)
-        uint16_t sendTimeout;                  // mqtt发送给命令超时时间, 根据实际硬件选择。
-        uint16_t ackTimeout;                   // mqtack等待命令超时时间, 典型值为5 - 30
-        uint16_t keepaliveTimeoutS;            // mqtt心跳时间间隔秒
-        uint16_t ackHandlerCountWarning;       // 等待ack的警告数 每次添加ack,ack总数大于或等于该值将触发事件回调,根据实际硬件选择。典型值是32
-        uint32_t recvBufferSize;               // mqtt接收缓冲区大小
-        uint32_t sendBufferSize;               // mqtt发送缓冲区大小
-        uint16_t reconnectTimeout;             // mqtt重连间隔时间
-        RyanMqttEventHandle mqttEventHandle;   // mqtt事件回调函数
-        void *userData;                        // 用户自定义数据,用户需要保证指针指向内容的持久性
-    } RyanMqttClientConfig_t;
-
-    typedef struct
-    {
-        RyanMqttBool_e lwtFlag : 1;             // 遗嘱标志位
-        RyanMqttBool_e destoryFlag : 1;         // 销毁标志位
-        uint16_t ackHandlerCount;               // 等待ack的记录个数
-        uint16_t packetId;                      // mqtt报文标识符,控制报文必须包含一个非零的 16 位报文标识符
-        uint32_t eventFlag;                     // 事件标志位
-        RyanMqttState_e clientState;            // mqtt客户端的状态
-        RyanList_t msgHandlerList;              // 维护消息处理列表,这是mqtt协议必须实现的内容,所有来自服务器的publish报文都会被处理(前提是订阅了对应的消息,或者设置了拦截器)
-        RyanList_t ackHandlerList;              // 维护ack链表
-        RyanList_t userAckHandlerList;          // 用户接口的ack链表,会由mqtt线程移动到ack链表
-        platformTimer_t ackScanThrottleTimer;   // ack链表检查节流定时器
-        platformTimer_t keepaliveTimer;         // 保活定时器
-        platformTimer_t keepaliveThrottleTimer; // 保活检查节流定时器
-        platformNetwork_t network;              // 网络组件
-        RyanMqttClientConfig_t config;          // mqtt config
-        platformThread_t mqttThread;            // mqtt线程
-        platformMutex_t msgHandleLock;          // msg链表锁
-        platformMutex_t ackHandleLock;          // ack链表锁
-        platformMutex_t userAckHandleLock;      // 用户接口的ack链表锁
-        platformMutex_t sendBufLock;            // 写缓冲区锁
-        platformCritical_t criticalLock;        // 临界区锁
-        lwtOptions_t lwtOptions;                // 遗嘱相关配置
-    } RyanMqttClient_t;
-
-    /* extern variables-----------------------------------------------------------*/
-
-    extern RyanMqttError_e RyanMqttInit(RyanMqttClient_t **pClient);
-    extern RyanMqttError_e RyanMqttDestroy(RyanMqttClient_t *client);
-    extern RyanMqttError_e RyanMqttStart(RyanMqttClient_t *client);
-    extern RyanMqttError_e RyanMqttDisconnect(RyanMqttClient_t *client, RyanMqttBool_e sendDiscFlag);
-    extern RyanMqttError_e RyanMqttReconnect(RyanMqttClient_t *client);
-    extern RyanMqttError_e RyanMqttSubscribe(RyanMqttClient_t *client, char *topic, RyanMqttQos_e qos);
-    extern RyanMqttError_e RyanMqttUnSubscribe(RyanMqttClient_t *client, char *topic);
-    extern RyanMqttError_e RyanMqttPublish(RyanMqttClient_t *client, char *topic, char *payload, uint32_t payloadLen, RyanMqttQos_e qos, RyanMqttBool_e retain);
-
-    extern RyanMqttState_e RyanMqttGetState(RyanMqttClient_t *client);
-    extern RyanMqttError_e RyanMqttGetSubscribe(RyanMqttClient_t *client, RyanMqttMsgHandler_t *msgHandles, int32_t msgHandleSize, int32_t *subscribeNum);
-    extern RyanMqttError_e RyanMqttSetConfig(RyanMqttClient_t *client, RyanMqttClientConfig_t *clientConfig);
-    extern RyanMqttError_e RyanMqttSetLwt(RyanMqttClient_t *client, char *topicName, char *payload, uint32_t payloadLen, RyanMqttQos_e qos, RyanMqttBool_e retain);
-
-    extern RyanMqttError_e RyanMqttDiscardAckHandler(RyanMqttClient_t *client, enum msgTypes packetType, uint16_t packetId);
-    extern RyanMqttError_e RyanMqttRegisterEventId(RyanMqttClient_t *client, RyanMqttEventId_e eventId);
-    extern RyanMqttError_e RyanMqttCancelEventId(RyanMqttClient_t *client, RyanMqttEventId_e eventId);
+// 接收到订阅消息回调函数类型,eventData用户不要进行修改否则mqtt客户端可能崩溃
+typedef void (*RyanMqttEventHandle)(void *client, RyanMqttEventId_e event, const void *eventData);
+
+// 定义枚举类型
+
+// 定义结构体类型
+typedef struct
+{
+	RyanMqttBool_e retained: 1; // retained 标志位
+	RyanMqttBool_e dup: 1;      // 重发标志
+	uint16_t packetId;          // packetId 系统生成
+	RyanMqttQos_e qos;          // QOS等级
+	uint32_t payloadLen;        // 数据长度
+	uint32_t topicLen;          // topic长度
+	char *topic;                // 主题信息
+	char *payload;              // 数据内容
+} RyanMqttMsgData_t;
+
+typedef struct
+{
+	uint16_t packetId; // 关联的packetId
+	uint16_t topicLen; // 主题长度
+	RyanMqttQos_e qos; // qos等级
+	RyanList_t list;   // 链表节点,用户勿动
+	char *topic;       // 主题
+} RyanMqttMsgHandler_t;
+
+typedef struct
+{
+	uint8_t packetType;                  // 期望接收到的ack报文类型
+	uint16_t repeatCount;                // 当前ack超时重发次数
+	uint16_t packetId;                   // 报文标识符 系统生成,用户勿动
+	RyanMqttBool_e isPreallocatedPacket; // 是否是预分配的内存
+	uint32_t packetLen;                  // 报文长度
+	RyanList_t list;                     // 链表节点,用户勿动
+	RyanMqttTimer_t timer;               // ack超时定时器,用户勿动
+	RyanMqttMsgHandler_t *msgHandler;    // msg信息
+	uint8_t *packet;                     // 没有收到期望ack,重新发送的原始报文
+} RyanMqttAckHandler_t;
+
+typedef struct
+{
+	uint8_t retain;      // 遗嘱保留标志位
+	RyanMqttQos_e qos;   // 遗嘱qos等级
+	uint32_t payloadLen; // 消息长度
+	char *topic;         // 遗嘱主题
+	char *payload;       // 遗嘱消息
+} lwtOptions_t;
+
+typedef struct
+{
+	char *topic;
+	uint16_t topicLen;
+	RyanMqttQos_e qos;
+} RyanMqttSubscribeData_t;
+
+typedef struct
+{
+	char *topic;
+	uint16_t topicLen;
+} RyanMqttUnSubscribeData_t;
+
+typedef struct
+{
+	char *clientId;                   // 客户端ID
+	char *userName;                   // 用户名
+	char *password;                   // 密码
+	char *host;                       // mqtt服务器地址
+	char *taskName;                   // 线程名字
+	RyanMqttBool_e autoReconnectFlag; // 自动重连标志位
+	RyanMqttBool_e cleanSessionFlag;  // 清除会话标志位
+	uint8_t mqttVersion;              // mqtt版本 3.1.1是4, 3.1是3
+	uint16_t port;                    // mqtt服务器端口
+
+	// ack重发超过这个数值后触发事件回调,根据实际硬件选择。典型值为 *
+	// ackTimeout ~= 300秒
+	uint16_t ackHandlerRepeatCountWarning;
+	uint16_t taskPrio;  // mqtt线程优先级
+	uint16_t taskStack; // 线程栈大小
+
+	// mqtt等待接收命令超时时间, 根据实际硬件选择。推荐 > ackTimeout && <= (keepaliveTimeoutS / 2)
+	uint16_t recvTimeout;
+	uint16_t sendTimeout;       // mqtt发送给命令超时时间, 根据实际硬件选择。
+	uint16_t ackTimeout;        // mqtack等待命令超时时间, 典型值为5 - 30
+	uint16_t keepaliveTimeoutS; // mqtt心跳时间间隔秒
+
+	// 等待ack的警告数.每次添加ack,ack总数大于或等于该值将触发事件回调,根据实际硬件选择。典型值是32
+	uint16_t ackHandlerCountWarning;
+
+	uint16_t reconnectTimeout;           // mqtt重连间隔时间
+	RyanMqttEventHandle mqttEventHandle; // mqtt事件回调函数
+	void *userData;                      // 用户自定义数据,用户需要保证指针指向内容的持久性
+} RyanMqttClientConfig_t;
+
+typedef struct
+{
+	RyanMqttBool_e lwtFlag;      // 遗嘱标志位
+	RyanMqttBool_e destoryFlag;  // 销毁标志位
+	uint16_t ackHandlerCount;    // 等待ack的记录个数
+	uint16_t packetId;           // mqtt报文标识符,控制报文必须包含一个非零的 16 位报文标识符
+	uint32_t eventFlag;          // 事件标志位
+	RyanMqttState_e clientState; // mqtt客户端的状态
+
+	// 维护消息处理列表,这是mqtt协议必须实现的内容,所有来自服务器的publish报文都会被处理(前提是订阅了对应的消息,或者设置了拦截器)
+	RyanList_t msgHandlerList;
+	RyanList_t ackHandlerList;              // 维护ack链表
+	RyanList_t userAckHandlerList;          // 用户接口的ack链表,会由mqtt线程移动到ack链表
+	RyanMqttTimer_t ackScanThrottleTimer;   // ack链表检查节流定时器
+	RyanMqttTimer_t keepaliveTimer;         // 保活定时器
+	RyanMqttTimer_t keepaliveThrottleTimer; // 保活检查节流定时器
+	platformNetwork_t network;              // 网络组件
+	RyanMqttClientConfig_t config;          // mqtt config
+	platformThread_t mqttThread;            // mqtt线程
+	platformMutex_t sendLock;               // 写缓冲区锁
+	platformMutex_t msgHandleLock;          // msg链表锁
+	platformMutex_t ackHandleLock;          // ack链表锁
+	platformMutex_t userAckHandleLock;      // 用户接口的ack链表锁
+	platformCritical_t criticalLock;        // 临界区锁
+	lwtOptions_t lwtOptions;                // 遗嘱相关配置
+} RyanMqttClient_t;
+
+/* extern variables-----------------------------------------------------------*/
+
+extern RyanMqttError_e RyanMqttInit(RyanMqttClient_t **pClient);
+extern RyanMqttError_e RyanMqttDestroy(RyanMqttClient_t *client);
+extern RyanMqttError_e RyanMqttStart(RyanMqttClient_t *client);
+extern RyanMqttError_e RyanMqttDisconnect(RyanMqttClient_t *client, RyanMqttBool_e sendDiscFlag);
+extern RyanMqttError_e RyanMqttReconnect(RyanMqttClient_t *client);
+
+extern RyanMqttError_e RyanMqttPublish(RyanMqttClient_t *client, char *topic, char *payload, uint32_t payloadLen,
+				       RyanMqttQos_e qos, RyanMqttBool_e retain);
+
+extern RyanMqttError_e RyanMqttSubscribeMany(RyanMqttClient_t *client, int32_t count,
+					     RyanMqttSubscribeData_t subscribeManyData[]);
+extern RyanMqttError_e RyanMqttSubscribe(RyanMqttClient_t *client, char *topic, RyanMqttQos_e qos);
+extern RyanMqttError_e RyanMqttUnSubscribeMany(RyanMqttClient_t *client, int32_t count,
+					       RyanMqttUnSubscribeData_t unSubscribeManyData[]);
+extern RyanMqttError_e RyanMqttUnSubscribe(RyanMqttClient_t *client, char *topic);
+
+extern RyanMqttState_e RyanMqttGetState(RyanMqttClient_t *client);
+extern RyanMqttError_e RyanMqttGetKeepAliveRemain(RyanMqttClient_t *client, uint32_t *keepAliveRemain);
+extern RyanMqttError_e RyanMqttSetConfig(RyanMqttClient_t *client, RyanMqttClientConfig_t *clientConfig);
+extern RyanMqttError_e RyanMqttSetLwt(RyanMqttClient_t *client, char *topicName, char *payload, uint32_t payloadLen,
+				      RyanMqttQos_e qos, RyanMqttBool_e retain);
+
+extern RyanMqttError_e RyanMqttGetSubscribeTotalCount(RyanMqttClient_t *client, int32_t *subscribeTotalCount);
+extern RyanMqttError_e RyanMqttGetSubscribe(RyanMqttClient_t *client, RyanMqttMsgHandler_t *msgHandles,
+					    int32_t msgHandleSize, int32_t *subscribeNum);
+extern RyanMqttError_e RyanMqttSafeFreeSubscribeResources(RyanMqttMsgHandler_t *msgHandles, int32_t subscribeNum);
+extern RyanMqttError_e RyanMqttGetSubscribeSafe(RyanMqttClient_t *client, RyanMqttMsgHandler_t **msgHandles,
+						int32_t *subscribeNum);
+
+extern RyanMqttError_e RyanMqttDiscardAckHandler(RyanMqttClient_t *client, uint8_t packetType, uint16_t packetId);
+extern RyanMqttError_e RyanMqttRegisterEventId(RyanMqttClient_t *client, RyanMqttEventId_e eventId);
+extern RyanMqttError_e RyanMqttCancelEventId(RyanMqttClient_t *client, RyanMqttEventId_e eventId);
 
 #ifdef __cplusplus
 }

+ 223 - 152
mqttclient/RyanMqttPublic.h

@@ -1,166 +1,237 @@
-
-
 #ifndef __mqttClientPublic__
 #define __mqttClientPublic__
 
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif
 #include <stdio.h>
 #include <stdint.h>
 #include <string.h>
 
-#define RyanMqttMaxPacketId (0xFFFFU - 1U)  // 你允许的mqtt paketid最大值,协议标准为个非零的 16 位数
-#define RyanMqttMaxPayloadLen (268435455UL) // 你允许的mqtt可变报头和有效载荷最长长度。默认值为协议标准
-#define RyanMqttVersion ("1.2.0")
-
-    // 定义枚举类型
-    typedef enum
-    {
-        RyanMqttBit31 = 0x80000000,
-        RyanMqttBit30 = 0x40000000,
-        RyanMqttBit29 = 0x20000000,
-        RyanMqttBit28 = 0x10000000,
-        RyanMqttBit27 = 0x08000000,
-        RyanMqttBit26 = 0x04000000,
-        RyanMqttBit25 = 0x02000000,
-        RyanMqttBit24 = 0x01000000,
-        RyanMqttBit23 = 0x00800000,
-        RyanMqttBit22 = 0x00400000,
-        RyanMqttBit21 = 0x00200000,
-        RyanMqttBit20 = 0x00100000,
-        RyanMqttBit19 = 0x00080000,
-        RyanMqttBit18 = 0x00040000,
-        RyanMqttBit17 = 0x00020000,
-        RyanMqttBit16 = 0x00010000,
-        RyanMqttBit15 = 0x00008000,
-        RyanMqttBit14 = 0x00004000,
-        RyanMqttBit13 = 0x00002000,
-        RyanMqttBit12 = 0x00001000,
-        RyanMqttBit11 = 0x00000800,
-        RyanMqttBit10 = 0x00000400,
-        RyanMqttBit9 = 0x00000200,
-        RyanMqttBit8 = 0x00000100,
-        RyanMqttBit7 = 0x00000080,
-        RyanMqttBit6 = 0x00000040,
-        RyanMqttBit5 = 0x00000020,
-        RyanMqttBit4 = 0x00000010,
-        RyanMqttBit3 = 0x00000008,
-        RyanMqttBit2 = 0x00000004,
-        RyanMqttBit1 = 0x00000002,
-        RyanMqttBit0 = 0x00000001,
-    } RyanMqttBit_e;
-
-    typedef enum
-    {
-        RyanMqttFalse = 0,
-        RyanMqttTrue = 1
-    } RyanMqttBool_e;
-
-    typedef enum
-    {
-        RyanMqttQos0 = 0x00,
-        RyanMqttQos1 = 0x01,
-        RyanMqttQos2 = 0x02,
-        RyanMqttSubFail = 0x80
-    } RyanMqttQos_e;
-
-    typedef enum
-    {
-        RyanMqttInvalidState = -1, // 无效状态
-        RyanMqttInitState = 0,     // 初始化状态
-        RyanMqttStartState,        // 开始状态
-        RyanMqttConnectState,      // 连接状态
-        RyanMqttDisconnectState,   // 断开连接状态
-        RyanMqttReconnectState,    // 重新连接状态
-    } RyanMqttState_e;
-
-    typedef enum
-    {
-        RyanMqttEventError = RyanMqttBit0,                 // 保留事件
-        RyanMqttEventConnected = RyanMqttBit1,             // 连接成功                                                      eventData: 正数为RyanMqttConnectStatus_e*, 负数为RyanMqttError_e*
-        RyanMqttEventDisconnected = RyanMqttBit2,          // 可能由用户触发,断开连接                                        eventData: 正数为RyanMqttConnectStatus_e*, 负数为RyanMqttError_e*
-        RyanMqttEventSubscribed = RyanMqttBit3,            // 订阅成功事件,服务端可以授予比订阅者要求的低的QoS等级。            eventData: RyanMqttMsgHandler_t*
-        RyanMqttEventSubscribedFaile = RyanMqttBit4,       // 订阅失败事件,超时 / 服务器返回订阅失败                           eventData: RyanMqttMsgHandler_t*
-        RyanMqttEventUnSubscribed = RyanMqttBit5,          // 取消订阅事件                                                   eventData: RyanMqttMsgHandler_t*
-        RyanMqttEventUnSubscribedFaile = RyanMqttBit6,     // 取消订阅失败事件,超时                                          eventData: RyanMqttMsgHandler_t*
-        RyanMqttEventPublished = RyanMqttBit7,             // qos1 / qos2发送成功事件。发送没有失败,只会重发或者用户手动丢弃。   eventData: RyanMqttAckHandler_t*
-        RyanMqttEventRepeatPublishPacket = RyanMqttBit8,   // qos1 / qos2数据(或者ack)重发回调函数                            eventData: RyanMqttAckHandler_t*
-        RyanMqttEventAckRepeatCountWarning = RyanMqttBit9, // ack重发次数超过警戒值                                           eventData: RyanMqttAckHandler_t*
-        RyanMqttEventAckCountWarning = RyanMqttBit10,      // ack记数值超过警戒值                                             eventData: uint16_t* ackHandlerCount;  等待ack的记录个数
-        RyanMqttEventAckHandlerdiscard = RyanMqttBit11,    /* 用户触发,ack句柄丢弃事件,由用户手动调用RyanMqttDestroyAckHandler函数触发
-                                                            * 可能是发送qos1 / qos2消息丢弃、ack丢弃,也可能是publish报文的ack丢弃
-                                                            * eventData: RyanMqttAckHandler_t*
-                                                            */
-        RyanMqttEventReconnectBefore = RyanMqttBit12,      // 重连前事件,用户可以在此时更改connect信息                          eventData: NULL
-        RyanMqttEventDestoryBefore = RyanMqttBit13,        // 用户触发,销毁客户端前回调                                        eventData: NULL
-        RyanMqttEventData = RyanMqttBit14,                 // 接收到订阅主题数据事件,支持通配符识别,返回的主题信息是报文主题       eventData: RyanMqttMsgData_t*
-        RyanMqttEventAnyId = UINT32_MAX,
-    } RyanMqttEventId_e;
-
-    // 定义枚举类型
-    typedef enum
-    {
-        RyanMqttParamInvalidError = -0x100, // 参数无效
-        RyanMqttRecvPacketTimeOutError,     // 读取数据超时
-        RyanMqttSendPacketTimeOutError,     // 发送数据超时
-        RyanSocketFailedError,              // 套接字 FD 失败
-        RyanMqttSocketConnectFailError,     // MQTT socket连接失败
-        RyanMqttSendPacketError,            // MQTT 发送数据包错误
-        RyanMqttSerializePacketError,       // 序列化报文失败
-        RyanMqttDeserializePacketError,     // 解析报文失败
-        RyanMqttNoRescourceError,           // 没有资源
-        RyanMqttHaveRescourceError,         // 资源已存在
-        RyanMqttNotConnectError,            // MQTT 没有连接
-        RyanMqttConnectError,               // MQTT 已连接
-        RyanMqttRecvBufToShortError,        // MQTT 缓冲区太短
-        RyanMqttSendBufToShortError,        // MQTT 缓冲区太短
-        RyanMqttNotEnoughMemError,          // MQTT 内存不足
-        RyanMqttFailedError,                // 失败
-        RyanMqttSuccessError = 0x0000,      // 成功
-        RyanMqttErrorForceInt32 = INT32_MAX // 强制编译器使用int32_t类型
-    } RyanMqttError_e;
-
-    typedef enum
-    {
-        // mqtt标准定义
-        RyanMqttConnectAccepted = 0,               // 连接已被服务端接受
-        RyanMqttConnectRefusedProtocolVersion = 1, // 服务端不支持客户端请求的 MQTT 协议级别
-        RyanMqttConnectRefusedIdentifier = 2,      // 不合格的客户端标识符
-        RyanMqttConnectRefusedServer = 3,          // 服务端不可用
-        RyanMqttConnectRefusedUsernamePass = 4,    // 无效的用户名或密码
-        RyanMqttConnectRefusedNotAuthorized = 5,   // 连接已拒绝,未授权
-
-        // mqtt非标准定义
-        RyanMqttConnectClientInvalid = 200,         // 客户端处于无效状态
-        RyanMqttConnectNetWorkFail,                 // 网络错误
-        RyanMqttConnectDisconnected,                // mqtt客户端断开连接
-        RyanMqttKeepaliveTimeout,                   // 心跳超时断开连接
-        RyanMqttConnectUserDisconnected,            // 用户手动断开连接
-        RyanMqttConnectTimeout,                     // 超时断开
-        RyanMqttConnectStatusForceInt32 = INT32_MAX // 强制编译器使用int32_t类型
-    } RyanMqttConnectStatus_e;
-
-    // 定义结构体类型
-
-    /* extern variables-----------------------------------------------------------*/
-
-    extern const char *RyanMqttStrError(int32_t state);
-#define RyanMqttCheckCodeNoReturn(EX, ErrorCode, Ryanlevel, code) \
-    if (!(EX))                                                    \
-    {                                                             \
-                                                                  \
-        Ryanlevel("ErrorCode: %d, strError: %s",                  \
-                  ErrorCode, RyanMqttStrError(ErrorCode));        \
-        {code};                                                   \
-    }
-
-#define RyanMqttCheckCode(EX, ErrorCode, level, code) RyanMqttCheckCodeNoReturn(EX, ErrorCode, level, { {code}; return ErrorCode; });
+// 允许的mqtt paketid最大值,协议标准为个非零的 16 位数
+#define RyanMqttMaxPacketId   (UINT16_MAX - 1U)
+// 允许的mqtt可变报头和有效载荷最长长度。默认值为协议标准
+#define RyanMqttMaxPayloadLen (268435455UL)
+
+#define RyanMqttMsgInvalidPacketId (UINT16_MAX)
+
+// 定义枚举类型
+typedef enum
+{
+	// RyanMqttBit31 = 0x80000000,
+	RyanMqttBit30 = 0x40000000,
+	RyanMqttBit29 = 0x20000000,
+	RyanMqttBit28 = 0x10000000,
+	RyanMqttBit27 = 0x08000000,
+	RyanMqttBit26 = 0x04000000,
+	RyanMqttBit25 = 0x02000000,
+	RyanMqttBit24 = 0x01000000,
+	RyanMqttBit23 = 0x00800000,
+	RyanMqttBit22 = 0x00400000,
+	RyanMqttBit21 = 0x00200000,
+	RyanMqttBit20 = 0x00100000,
+	RyanMqttBit19 = 0x00080000,
+	RyanMqttBit18 = 0x00040000,
+	RyanMqttBit17 = 0x00020000,
+	RyanMqttBit16 = 0x00010000,
+	RyanMqttBit15 = 0x00008000,
+	RyanMqttBit14 = 0x00004000,
+	RyanMqttBit13 = 0x00002000,
+	RyanMqttBit12 = 0x00001000,
+	RyanMqttBit11 = 0x00000800,
+	RyanMqttBit10 = 0x00000400,
+	RyanMqttBit9 = 0x00000200,
+	RyanMqttBit8 = 0x00000100,
+	RyanMqttBit7 = 0x00000080,
+	RyanMqttBit6 = 0x00000040,
+	RyanMqttBit5 = 0x00000020,
+	RyanMqttBit4 = 0x00000010,
+	RyanMqttBit3 = 0x00000008,
+	RyanMqttBit2 = 0x00000004,
+	RyanMqttBit1 = 0x00000002,
+	RyanMqttBit0 = 0x00000001,
+} RyanMqttBit_e;
+
+typedef enum
+{
+	RyanMqttFalse = 0,
+	RyanMqttTrue = 1
+} RyanMqttBool_e;
+
+typedef enum
+{
+	RyanMqttQos0 = 0x00,
+	RyanMqttQos1 = 0x01,
+	RyanMqttQos2 = 0x02,
+	RyanMqttSubFail = 0x80
+} RyanMqttQos_e;
+
+typedef enum
+{
+	RyanMqttInvalidState = -1, // 无效状态
+	RyanMqttInitState = 0,     // 初始化状态
+	RyanMqttStartState,        // 开始状态
+	RyanMqttConnectState,      // 连接状态
+	RyanMqttDisconnectState,   // 断开连接状态
+	RyanMqttReconnectState,    // 重新连接状态
+} RyanMqttState_e;
+
+typedef enum
+{
+	/**
+	 * @brief 保留事件
+	 * @eventData NULL
+	 */
+	RyanMqttEventError = RyanMqttBit0,
+	/**
+	 * @brief 连接成功
+	 * @eventData 正数为RyanMqttConnectStatus_e*, 负数为RyanMqttError_e*
+	 */
+	RyanMqttEventConnected = RyanMqttBit1,
+	/**
+	 * @brief 可能由用户触发,断开连接
+	 * @eventData 正数为RyanMqttConnectStatus_e*, 负数为RyanMqttError_e*
+	 */
+	RyanMqttEventDisconnected = RyanMqttBit2,
+	/**
+	 * @brief 订阅成功事件,服务端可以授予比订阅者要求的低的QoS等级
+	 * @eventData RyanMqttMsgHandler_t*
+	 */
+	RyanMqttEventSubscribed = RyanMqttBit3,
+	/**
+	 * @brief 订阅失败事件,超时 / 服务器返回订阅失败
+	 * @eventData RyanMqttMsgHandler_t*
+	 */
+	RyanMqttEventSubscribedFaile = RyanMqttBit4,
+	/**
+	 * @brief 取消订阅事件
+	 * @eventData RyanMqttMsgHandler_t*
+	 */
+	RyanMqttEventUnSubscribed = RyanMqttBit5,
+	/**
+	 * @brief 取消订阅失败事件,超时
+	 * @eventData RyanMqttMsgHandler_t*
+	 */
+	RyanMqttEventUnSubscribedFaile = RyanMqttBit6,
+	/**
+	 * @brief qos1 / qos2发送成功事件。发送没有失败,只会重发或者用户手动丢弃
+	 * @eventData RyanMqttAckHandler_t*
+	 */
+	RyanMqttEventPublished = RyanMqttBit7,
+	/**
+	 * @brief qos1 / qos2数据(或者ack)重发回调函数
+	 * @eventData RyanMqttAckHandler_t*
+	 */
+	RyanMqttEventRepeatPublishPacket = RyanMqttBit8,
+	/**
+	 * @brief ack重发次数超过警戒值
+	 * @eventData RyanMqttAckHandler_t*
+	 */
+	RyanMqttEventAckRepeatCountWarning = RyanMqttBit9,
+	/**
+	 * @brief ack记数值超过警戒值
+	 * @eventData uint16_t* ackHandlerCount;  等待ack的记录个数
+	 */
+	RyanMqttEventAckCountWarning = RyanMqttBit10,
+	/**
+	 * @brief 用户触发,ack句柄丢弃事件,由用户手动调用RyanMqttDestroyAckHandler函数触发
+	 * 可能是发送qos1 / qos2消息丢弃、ack丢弃,也可能是publish报文的ack丢弃
+	 *
+	 * @eventData RyanMqttAckHandler_t*
+	 */
+	RyanMqttEventAckHandlerdiscard = RyanMqttBit11,
+	/**
+	 * @brief 重连前事件,用户可以在此时更改connect信息
+	 * @eventData NULL
+	 */
+	RyanMqttEventReconnectBefore = RyanMqttBit12,
+	/**
+	 * @brief 用户触发,销毁客户端前回调
+	 * @eventData NULL
+	 */
+	RyanMqttEventDestoryBefore = RyanMqttBit13,
+	/**
+	 * @brief 接收到订阅主题数据事件,支持通配符识别,返回的主题信息是报文主题
+	 * @eventData RyanMqttMsgData_t*
+	 */
+	RyanMqttEventData = RyanMqttBit14,
+
+	RyanMqttEventAnyId = UINT32_MAX,
+} RyanMqttEventId_e;
+
+// 定义枚举类型
+typedef enum
+{
+	RyanMqttParamInvalidError = -0x100, // 参数无效
+	RyanMqttRecvPacketTimeOutError,     // 读取数据超时
+	RyanMqttSendPacketTimeOutError,     // 发送数据超时
+	RyanSocketFailedError,              // 套接字 FD 失败
+	RyanMqttSocketConnectFailError,     // MQTT socket连接失败
+	RyanMqttSendPacketError,            // MQTT 发送数据包错误
+	RyanMqttSerializePacketError,       // 序列化报文失败
+	RyanMqttDeserializePacketError,     // 解析报文失败
+	RyanMqttNoRescourceError,           // 没有资源
+	RyanMqttHaveRescourceError,         // 资源已存在
+	RyanMqttNotConnectError,            // MQTT 没有连接
+	RyanMqttConnectError,               // MQTT 已连接
+	RyanMqttRecvBufToShortError,        // MQTT 缓冲区太短
+	RyanMqttSendBufToShortError,        // MQTT 缓冲区太短
+	RyanMqttNotEnoughMemError,          // MQTT 内存不足
+	RyanMqttFailedError,                // 失败
+	RyanMqttSuccessError = 0x0000,      // 成功
+	RyanMqttErrorForceInt32 = INT32_MAX // 强制编译器使用int32_t类型
+} RyanMqttError_e;
+
+typedef enum
+{
+	// mqtt标准定义
+	RyanMqttConnectAccepted = 0,               // 连接已被服务端接受
+	RyanMqttConnectRefusedProtocolVersion = 1, // 服务端不支持客户端请求的 MQTT 协议级别
+	RyanMqttConnectRefusedIdentifier = 2,      // 不合格的客户端标识符
+	RyanMqttConnectRefusedServer = 3,          // 服务端不可用
+	RyanMqttConnectRefusedUsernamePass = 4,    // 无效的用户名或密码
+	RyanMqttConnectRefusedNotAuthorized = 5,   // 连接已拒绝,未授权
+
+	// mqtt非标准定义
+	RyanMqttConnectClientInvalid = 200,         // 客户端处于无效状态
+	RyanMqttConnectNetWorkFail,                 // 网络错误
+	RyanMqttConnectDisconnected,                // mqtt客户端断开连接
+	RyanMqttKeepaliveTimeout,                   // 心跳超时断开连接
+	RyanMqttConnectUserDisconnected,            // 用户手动断开连接
+	RyanMqttConnectTimeout,                     // 超时断开
+	RyanMqttConnectStatusForceInt32 = INT32_MAX // 强制编译器使用int32_t类型
+} RyanMqttConnectStatus_e;
+
+// 定义结构体类型
+
+/* extern variables-----------------------------------------------------------*/
+typedef struct
+{
+	uint32_t time;
+	uint32_t timeOut;
+} RyanMqttTimer_t;
+
+extern void RyanMqttTimerCutdown(RyanMqttTimer_t *platformTimer, uint32_t timeout);
+extern uint32_t RyanMqttTimerRemain(RyanMqttTimer_t *platformTimer);
+
+extern const char *RyanMqttStrError(int32_t state);
+#define RyanMqttCheckCodeNoReturn(EX, ErrorCode, Ryanlevel, code)                                                      \
+	if (!(EX))                                                                                                     \
+	{                                                                                                              \
+                                                                                                                       \
+		Ryanlevel("ErrorCode: %d, strError: %s", ErrorCode, RyanMqttStrError(ErrorCode));                      \
+		{code};                                                                                                \
+	}
+
+#define RyanMqttCheckCode(EX, ErrorCode, level, code)                                                                  \
+	RyanMqttCheckCodeNoReturn(EX, ErrorCode, level, {                                                              \
+		{code};                                                                                                \
+		return ErrorCode;                                                                                      \
+	});
 
 #define RyanMqttCheckNoReturn(EX, ErrorCode, level) RyanMqttCheckCodeNoReturn(EX, ErrorCode, level, {})
-#define RyanMqttCheck(EX, ErrorCode, level) RyanMqttCheckCode(EX, ErrorCode, level, {})
-#define RyanMqttCheckAssert(EX, ErrorCode, level) RyanMqttCheckCodeNoReturn(EX, ErrorCode, level, { assert(NULL); })
+#define RyanMqttCheck(EX, ErrorCode, level)         RyanMqttCheckCode(EX, ErrorCode, level, {})
+#define RyanMqttCheckAssert(EX, ErrorCode, level)   RyanMqttCheckCodeNoReturn(EX, ErrorCode, level, { assert(NULL); })
 #ifdef __cplusplus
 }
 #endif

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 666 - 545
mqttclient/RyanMqttThread.c


+ 7 - 10
mqttclient/RyanMqttThread.h

@@ -2,22 +2,19 @@
 #define __RyanMqttThread__
 
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif
 
-#include "RyanMqttLog.h"
-#include "RyanMqttUtile.h"
 #include "RyanMqttClient.h"
 
-    // 定义枚举类型
+// 定义枚举类型
 
-    // 定义结构体类型
+// 定义结构体类型
 
-    /* extern variables-----------------------------------------------------------*/
-    extern void RyanMqttThread(void *argument);
-    extern void RyanMqttEventMachine(RyanMqttClient_t *client, RyanMqttEventId_e eventId, void *eventData);
-    extern void RyanMqttRefreshKeepaliveTime(RyanMqttClient_t *client);
+/* extern variables-----------------------------------------------------------*/
+extern void RyanMqttThread(void *argument);
+extern void RyanMqttEventMachine(RyanMqttClient_t *client, RyanMqttEventId_e eventId, void *eventData);
+extern void RyanMqttRefreshKeepaliveTime(RyanMqttClient_t *client);
 
 #ifdef __cplusplus
 }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 555 - 351
mqttclient/RyanMqttUtile.c


+ 46 - 29
mqttclient/RyanMqttUtile.h

@@ -1,47 +1,64 @@
-
 #ifndef __RyanMqttUtile__
 #define __RyanMqttUtile__
 
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif
 
-#include "RyanMqttLog.h"
 #include "RyanMqttClient.h"
-#include "RyanMqttThread.h"
-
-    // 定义枚举类型
+#include "core_mqtt_config_defaults.h"
 
-    // 定义结构体类型
+#ifdef PKG_USING_RYANMQTT_IS_ENABLE_ASSERT
+#define RyanMqttAssert(EX) platformAssert(EX)
+#else
+#define RyanMqttAssert(EX)
+#endif
 
-    /* extern variables-----------------------------------------------------------*/
+// 定义枚举类型
 
-    extern void RyanMqttSetClientState(RyanMqttClient_t *client, RyanMqttState_e state);
-    extern RyanMqttState_e RyanMqttGetClientState(RyanMqttClient_t *client);
-    extern RyanMqttError_e RyanMqttIsConnected(RyanMqttClient_t *client);
+// 定义结构体类型
+struct NetworkContext
+{
+	RyanMqttClient_t *client;
+};
+int32_t coreMqttTransportRecv(NetworkContext_t *pNetworkContext, void *pBuffer, size_t bytesToRecv);
 
-    extern RyanMqttError_e RyanMqttSendPacket(RyanMqttClient_t *client, char *buf, int32_t length);
-    extern RyanMqttError_e RyanMqttRecvPacket(RyanMqttClient_t *client, char *buf, int32_t length);
+/* extern variables-----------------------------------------------------------*/
 
-    extern RyanMqttError_e RyanMqttMsgHandlerCreate(RyanMqttClient_t *client, char *topic, uint16_t topicLen, RyanMqttQos_e qos, RyanMqttMsgHandler_t **pMsgHandler);
-    extern void RyanMqttMsgHandlerDestory(RyanMqttClient_t *client, RyanMqttMsgHandler_t *msgHandler);
-    extern RyanMqttError_e RyanMqttMsgHandlerFind(RyanMqttClient_t *client, char *topic, uint16_t topicLen, RyanMqttBool_e topicMatchedFlag, RyanMqttMsgHandler_t **pMsgHandler);
-    extern RyanMqttError_e RyanMqttMsgHandlerAddToMsgList(RyanMqttClient_t *client, RyanMqttMsgHandler_t *msgHandler);
-    extern RyanMqttError_e RyanMqttMsgHandlerRemoveToMsgList(RyanMqttClient_t *client, RyanMqttMsgHandler_t *msgHandler);
+extern void RyanMqttSetClientState(RyanMqttClient_t *client, RyanMqttState_e state);
+extern RyanMqttState_e RyanMqttGetClientState(RyanMqttClient_t *client);
+extern RyanMqttError_e RyanMqttStringCopy(char **dest, char *rest, uint32_t strLen);
+extern void RyanMqttCleanSession(RyanMqttClient_t *client);
 
-    extern RyanMqttError_e RyanMqttAckHandlerCreate(RyanMqttClient_t *client, enum msgTypes packetType, uint16_t packetId, uint16_t packetLen, char *packet, RyanMqttMsgHandler_t *msgHandler, RyanMqttAckHandler_t **pAckHandler);
-    extern void RyanMqttAckHandlerDestroy(RyanMqttClient_t *client, RyanMqttAckHandler_t *ackHandler);
-    extern RyanMqttError_e RyanMqttAckListNodeFind(RyanMqttClient_t *client, enum msgTypes packetType, uint16_t packetId, RyanMqttAckHandler_t **pAckHandler);
-    extern RyanMqttError_e RyanMqttAckListAddToAckList(RyanMqttClient_t *client, RyanMqttAckHandler_t *ackHandler);
-    extern RyanMqttError_e RyanMqttAckListRemoveToAckList(RyanMqttClient_t *client, RyanMqttAckHandler_t *ackHandler);
-    extern RyanMqttError_e RyanMqttAckListAddToUserAckList(RyanMqttClient_t *client, RyanMqttAckHandler_t *ackHandler);
-    extern RyanMqttError_e RyanMqttAckListRemoveToUserAckList(RyanMqttClient_t *client, RyanMqttAckHandler_t *ackHandler);
+extern RyanMqttError_e RyanMqttSendPacket(RyanMqttClient_t *client, uint8_t *buf, uint32_t length);
+extern RyanMqttError_e RyanMqttRecvPacket(RyanMqttClient_t *client, uint8_t *buf, uint32_t length);
 
-    extern RyanMqttError_e RyanMqttStringCopy(char **dest, char *rest, uint32_t strLen);
-    extern RyanMqttError_e RyanMqttSetPublishDup(char *headerBuf, uint8_t dup);
+extern RyanMqttBool_e RyanMqttMsgIsMatch(RyanMqttMsgHandler_t *msgHandler, const char *topic, uint16_t topicLen,
+					 RyanMqttBool_e topicMatchedFlag);
+extern RyanMqttError_e RyanMqttMsgHandlerCreate(RyanMqttClient_t *client, const char *topic, uint16_t topicLen,
+						uint16_t packetId, RyanMqttQos_e qos,
+						RyanMqttMsgHandler_t **pMsgHandler);
+extern void RyanMqttMsgHandlerDestory(RyanMqttClient_t *client, RyanMqttMsgHandler_t *msgHandler);
+extern RyanMqttError_e RyanMqttMsgHandlerFind(RyanMqttClient_t *client, const char *topic, uint16_t topicLen,
+					      RyanMqttBool_e topicMatchedFlag, RyanMqttMsgHandler_t **pMsgHandler);
+extern void RyanMqttMsgHandlerFindByPackId(RyanMqttClient_t *client, const char *topic, uint16_t topicLen,
+					   uint16_t packetId, RyanMqttBool_e isPacketIdEqual);
+extern RyanMqttError_e RyanMqttMsgHandlerAddToMsgList(RyanMqttClient_t *client, RyanMqttMsgHandler_t *msgHandler);
+extern RyanMqttError_e RyanMqttMsgHandlerRemoveToMsgList(RyanMqttClient_t *client, RyanMqttMsgHandler_t *msgHandler);
 
-    extern void RyanMqttCleanSession(RyanMqttClient_t *client);
+extern RyanMqttError_e RyanMqttAckHandlerCreate(RyanMqttClient_t *client, uint8_t packetType, uint16_t packetId,
+						uint16_t packetLen, uint8_t *packet, RyanMqttMsgHandler_t *msgHandler,
+						RyanMqttAckHandler_t **pAckHandler,
+						RyanMqttBool_e isPreallocatedPacket);
+extern void RyanMqttAckHandlerDestroy(RyanMqttClient_t *client, RyanMqttAckHandler_t *ackHandler);
+extern RyanMqttError_e RyanMqttAckListNodeFind(RyanMqttClient_t *client, uint8_t packetType, uint16_t packetId,
+					       RyanMqttAckHandler_t **pAckHandler);
+extern RyanMqttError_e RyanMqttAckListAddToAckList(RyanMqttClient_t *client, RyanMqttAckHandler_t *ackHandler);
+extern RyanMqttError_e RyanMqttAckListRemoveToAckList(RyanMqttClient_t *client, RyanMqttAckHandler_t *ackHandler);
+extern RyanMqttError_e RyanMqttAckListNodeFindByUserAckList(RyanMqttClient_t *client, uint8_t packetType,
+							    uint16_t packetId, RyanMqttAckHandler_t **pAckHandler);
+extern RyanMqttError_e RyanMqttAckListAddToUserAckList(RyanMqttClient_t *client, RyanMqttAckHandler_t *ackHandler);
+extern RyanMqttError_e RyanMqttAckListRemoveToUserAckList(RyanMqttClient_t *client, RyanMqttAckHandler_t *ackHandler);
 
 #ifdef __cplusplus
 }

+ 0 - 148
pahoMqtt/MQTTConnect.h

@@ -1,148 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014, 2017 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *    Ian Craggs - add connack return code definitions 
- *    Xiang Rong - 442039 Add makefile to Embedded C client
- *    Ian Craggs - fix for issue #64, bit order in connack response
- *******************************************************************************/
-
-#ifndef MQTTCONNECT_H_
-#define MQTTCONNECT_H_
-
-enum connack_return_codes
-{
-    MQTT_CONNECTION_ACCEPTED = 0,
-    MQTT_UNNACCEPTABLE_PROTOCOL = 1,
-    MQTT_CLIENTID_REJECTED = 2,
-    MQTT_SERVER_UNAVAILABLE = 3,
-    MQTT_BAD_USERNAME_OR_PASSWORD = 4,
-    MQTT_NOT_AUTHORIZED = 5,
-};
-
-#if !defined(DLLImport)
-  #define DLLImport
-#endif
-#if !defined(DLLExport)
-  #define DLLExport
-#endif
-
-
-typedef union
-{
-	unsigned char all;	/**< all connect flags */
-#if defined(REVERSED)
-	struct
-	{
-		unsigned int username : 1;			/**< 3.1 user name */
-		unsigned int password : 1; 			/**< 3.1 password */
-		unsigned int willRetain : 1;		/**< will retain setting */
-		unsigned int willQoS : 2;				/**< will QoS value */
-		unsigned int will : 1;			    /**< will flag */
-		unsigned int cleansession : 1;	  /**< clean session flag */
-		unsigned int : 1;	  	          /**< unused */
-	} bits;
-#else
-	struct
-	{
-		unsigned int : 1;	     					/**< unused */
-		unsigned int cleansession : 1;	  /**< cleansession flag */
-		unsigned int will : 1;			    /**< will flag */
-		unsigned int willQoS : 2;				/**< will QoS value */
-		unsigned int willRetain : 1;		/**< will retain setting */
-		unsigned int password : 1; 			/**< 3.1 password */
-		unsigned int username : 1;			/**< 3.1 user name */
-	} bits;
-#endif
-} MQTTConnectFlags;	/**< connect flags byte */
-
-
-
-/**
- * Defines the MQTT "Last Will and Testament" (LWT) settings for
- * the connect packet.
- */
-typedef struct
-{
-	/** The eyecatcher for this structure.  must be MQTW. */
-	char struct_id[4];
-	/** The version number of this structure.  Must be 0 */
-	int struct_version;
-	/** The LWT topic to which the LWT message will be published. */
-	MQTTString topicName;
-	/** The LWT payload. */
-	MQTTString message;
-	/**
-      * The retained flag for the LWT message (see MQTTAsync_message.retained).
-      */
-	unsigned char retained;
-	/**
-      * The quality of service setting for the LWT message (see
-      * MQTTAsync_message.qos and @ref qos).
-      */
-	char qos;
-} MQTTPacket_willOptions;
-
-
-#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 }
-
-
-typedef struct
-{
-	/** The eyecatcher for this structure.  must be MQTC. */
-	char struct_id[4];
-	/** The version number of this structure.  Must be 0 */
-	int struct_version;
-	/** Version of MQTT to be used.  3 = 3.1 4 = 3.1.1
-	  */
-	unsigned char MQTTVersion;
-	MQTTString clientID;
-	unsigned short keepAliveInterval;
-	unsigned char cleansession;
-	unsigned char willFlag;
-	MQTTPacket_willOptions will;
-	MQTTString username;
-	MQTTString password;
-} MQTTPacket_connectData;
-
-typedef union
-{
-	unsigned char all;	/**< all connack flags */
-#if defined(REVERSED)
-	struct
-	{
-    unsigned int reserved : 7;	  	    /**< unused */
-		unsigned int sessionpresent : 1;    /**< session present flag */
-	} bits;
-#else
-	struct
-	{
-		unsigned int sessionpresent : 1;    /**< session present flag */
-    unsigned int reserved: 7;	     			/**< unused */
-	} bits;
-#endif
-} MQTTConnackFlags;	/**< connack flags byte */
-
-#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \
-		MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }
-
-DLLExport int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options);
-DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len);
-
-DLLExport int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent);
-DLLExport int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen);
-
-DLLExport int MQTTSerialize_disconnect(unsigned char* buf, int buflen);
-DLLExport int MQTTSerialize_pingreq(unsigned char* buf, int buflen);
-
-#endif /* MQTTCONNECT_H_ */

+ 0 - 214
pahoMqtt/MQTTConnectClient.c

@@ -1,214 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *******************************************************************************/
-
-#include "MQTTPacket.h"
-#include "StackTrace.h"
-
-#include <string.h>
-
-/**
-  * Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
-  * @param options the options to be used to build the connect packet
-  * @return the length of buffer needed to contain the serialized version of the packet
-  */
-int MQTTSerialize_connectLength(MQTTPacket_connectData* options)
-{
-	int len = 0;
-
-	FUNC_ENTRY;
-
-	if (options->MQTTVersion == 3)
-		len = 12; /* variable depending on MQTT or MQIsdp */
-	else if (options->MQTTVersion == 4)
-		len = 10;
-
-	len += MQTTstrlen(options->clientID)+2;
-	if (options->willFlag)
-		len += MQTTstrlen(options->will.topicName)+2 + MQTTstrlen(options->will.message)+2;
-	if (options->username.cstring || options->username.lenstring.data)
-		len += MQTTstrlen(options->username)+2;
-	if (options->password.cstring || options->password.lenstring.data)
-		len += MQTTstrlen(options->password)+2;
-
-	FUNC_EXIT_RC(len);
-	return len;
-}
-
-
-/**
-  * Serializes the connect options into the buffer.
-  * @param buf the buffer into which the packet will be serialized
-  * @param len the length in bytes of the supplied buffer
-  * @param options the options to be used to build the connect packet
-  * @return serialized length, or error if 0
-  */
-int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options)
-{
-	unsigned char *ptr = buf;
-	MQTTHeader header = {0};
-	MQTTConnectFlags flags = {0};
-	int len = 0;
-	int rc = -1;
-
-	FUNC_ENTRY;
-	if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen)
-	{
-		rc = MQTTPACKET_BUFFER_TOO_SHORT;
-		goto exit;
-	}
-
-	header.byte = 0;
-	header.bits.type = CONNECT;
-	writeChar(&ptr, header.byte); /* write header */
-
-	ptr += MQTTPacket_encode(ptr, len); /* write remaining length */
-
-	if (options->MQTTVersion == 4)
-	{
-		writeCString(&ptr, "MQTT");
-		writeChar(&ptr, (char) 4);
-	}
-	else
-	{
-		writeCString(&ptr, "MQIsdp");
-		writeChar(&ptr, (char) 3);
-	}
-
-	flags.all = 0;
-	flags.bits.cleansession = options->cleansession;
-	flags.bits.will = (options->willFlag) ? 1 : 0;
-	if (flags.bits.will)
-	{
-		flags.bits.willQoS = options->will.qos;
-		flags.bits.willRetain = options->will.retained;
-	}
-
-	if (options->username.cstring || options->username.lenstring.data)
-		flags.bits.username = 1;
-	if (options->password.cstring || options->password.lenstring.data)
-		flags.bits.password = 1;
-
-	writeChar(&ptr, flags.all);
-	writeInt(&ptr, options->keepAliveInterval);
-	writeMQTTString(&ptr, options->clientID);
-	if (options->willFlag)
-	{
-		writeMQTTString(&ptr, options->will.topicName);
-		writeMQTTString(&ptr, options->will.message);
-	}
-	if (flags.bits.username)
-		writeMQTTString(&ptr, options->username);
-	if (flags.bits.password)
-		writeMQTTString(&ptr, options->password);
-
-	rc = ptr - buf;
-
-	exit: FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-
-/**
-  * Deserializes the supplied (wire) buffer into connack data - return code
-  * @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
-  * @param connack_rc returned integer value of the connack return code
-  * @param buf the raw buffer data, of the correct length determined by the remaining length field
-  * @param len the length in bytes of the data in the supplied buffer
-  * @return error code.  1 is success, 0 is failure
-  */
-int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen)
-{
-	MQTTHeader header = {0};
-	unsigned char* curdata = buf;
-	unsigned char* enddata = NULL;
-	int rc = 0;
-	int mylen;
-	MQTTConnackFlags flags = {0};
-
-	FUNC_ENTRY;
-	header.byte = readChar(&curdata);
-	if (header.bits.type != CONNACK)
-		goto exit;
-
-	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
-	enddata = curdata + mylen;
-	if (enddata - curdata < 2)
-		goto exit;
-
-	flags.all = readChar(&curdata);
-	*sessionPresent = flags.bits.sessionpresent;
-	*connack_rc = readChar(&curdata);
-
-	rc = 1;
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-
-/**
-  * Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
-  * @param buf the buffer into which the packet will be serialized
-  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
-  * @param packettype the message type
-  * @return serialized length, or error if 0
-  */
-int MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype)
-{
-	MQTTHeader header = {0};
-	int rc = -1;
-	unsigned char *ptr = buf;
-
-	FUNC_ENTRY;
-	if (buflen < 2)
-	{
-		rc = MQTTPACKET_BUFFER_TOO_SHORT;
-		goto exit;
-	}
-	header.byte = 0;
-	header.bits.type = packettype;
-	writeChar(&ptr, header.byte); /* write header */
-
-	ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */
-	rc = ptr - buf;
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-
-/**
-  * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
-  * @param buf the buffer into which the packet will be serialized
-  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
-  * @return serialized length, or error if 0
-  */
-int MQTTSerialize_disconnect(unsigned char* buf, int buflen)
-{
-	return MQTTSerialize_zero(buf, buflen, DISCONNECT);
-}
-
-
-/**
-  * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
-  * @param buf the buffer into which the packet will be serialized
-  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
-  * @return serialized length, or error if 0
-  */
-int MQTTSerialize_pingreq(unsigned char* buf, int buflen)
-{
-	return MQTTSerialize_zero(buf, buflen, PINGREQ);
-}

+ 0 - 148
pahoMqtt/MQTTConnectServer.c

@@ -1,148 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *******************************************************************************/
-
-#include "StackTrace.h"
-#include "MQTTPacket.h"
-#include <string.h>
-
-#define min(a, b) ((a < b) ? a : b)
-
-
-/**
-  * Validates MQTT protocol name and version combinations
-  * @param protocol the MQTT protocol name as an MQTTString
-  * @param version the MQTT protocol version number, as in the connect packet
-  * @return correct MQTT combination?  1 is true, 0 is false
-  */
-int MQTTPacket_checkVersion(MQTTString* protocol, int version)
-{
-	int rc = 0;
-
-	if (version == 3 && memcmp(protocol->lenstring.data, "MQIsdp",
-			min(6, protocol->lenstring.len)) == 0)
-		rc = 1;
-	else if (version == 4 && memcmp(protocol->lenstring.data, "MQTT",
-			min(4, protocol->lenstring.len)) == 0)
-		rc = 1;
-	return rc;
-}
-
-
-/**
-  * Deserializes the supplied (wire) buffer into connect data structure
-  * @param data the connect data structure to be filled out
-  * @param buf the raw buffer data, of the correct length determined by the remaining length field
-  * @param len the length in bytes of the data in the supplied buffer
-  * @return error code.  1 is success, 0 is failure
-  */
-int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len)
-{
-	MQTTHeader header = {0};
-	MQTTConnectFlags flags = {0};
-	unsigned char* curdata = buf;
-	unsigned char* enddata = &buf[len];
-	int rc = 0;
-	MQTTString Protocol;
-	int version;
-	int mylen = 0;
-
-	FUNC_ENTRY;
-	header.byte = readChar(&curdata);
-	if (header.bits.type != CONNECT)
-		goto exit;
-
-	curdata += MQTTPacket_decodeBuf(curdata, &mylen); /* read remaining length */
-
-	if (!readMQTTLenString(&Protocol, &curdata, enddata) ||
-		enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
-		goto exit;
-
-	version = (int)readChar(&curdata); /* Protocol version */
-	/* If we don't recognize the protocol version, we don't parse the connect packet on the
-	 * basis that we don't know what the format will be.
-	 */
-	if (MQTTPacket_checkVersion(&Protocol, version))
-	{
-		flags.all = readChar(&curdata);
-		data->cleansession = flags.bits.cleansession;
-		data->keepAliveInterval = readInt(&curdata);
-		if (!readMQTTLenString(&data->clientID, &curdata, enddata))
-			goto exit;
-		data->willFlag = flags.bits.will;
-		if (flags.bits.will)
-		{
-			data->will.qos = flags.bits.willQoS;
-			data->will.retained = flags.bits.willRetain;
-			if (!readMQTTLenString(&data->will.topicName, &curdata, enddata) ||
-				  !readMQTTLenString(&data->will.message, &curdata, enddata))
-				goto exit;
-		}
-		if (flags.bits.username)
-		{
-			if (enddata - curdata < 3 || !readMQTTLenString(&data->username, &curdata, enddata))
-				goto exit; /* username flag set, but no username supplied - invalid */
-			if (flags.bits.password &&
-				(enddata - curdata < 3 || !readMQTTLenString(&data->password, &curdata, enddata)))
-				goto exit; /* password flag set, but no password supplied - invalid */
-		}
-		else if (flags.bits.password)
-			goto exit; /* password flag set without username - invalid */
-		rc = 1;
-	}
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-
-/**
-  * Serializes the connack packet into the supplied buffer.
-  * @param buf the buffer into which the packet will be serialized
-  * @param buflen the length in bytes of the supplied buffer
-  * @param connack_rc the integer connack return code to be used 
-  * @param sessionPresent the MQTT 3.1.1 sessionPresent flag
-  * @return serialized length, or error if 0
-  */
-int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent)
-{
-	MQTTHeader header = {0};
-	int rc = 0;
-	unsigned char *ptr = buf;
-	MQTTConnackFlags flags = {0};
-
-	FUNC_ENTRY;
-	if (buflen < 2)
-	{
-		rc = MQTTPACKET_BUFFER_TOO_SHORT;
-		goto exit;
-	}
-	header.byte = 0;
-	header.bits.type = CONNACK;
-	writeChar(&ptr, header.byte); /* write header */
-
-	ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
-
-	flags.all = 0;
-	flags.bits.sessionpresent = sessionPresent;
-	writeChar(&ptr, flags.all); 
-	writeChar(&ptr, connack_rc);
-
-	rc = ptr - buf;
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-

+ 0 - 107
pahoMqtt/MQTTDeserializePublish.c

@@ -1,107 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *******************************************************************************/
-
-#include "StackTrace.h"
-#include "MQTTPacket.h"
-#include <string.h>
-
-#define min(a, b) ((a < b) ? 1 : 0)
-
-/**
-  * Deserializes the supplied (wire) buffer into publish data
-  * @param dup returned integer - the MQTT dup flag
-  * @param qos returned integer - the MQTT QoS value
-  * @param retained returned integer - the MQTT retained flag
-  * @param packetid returned integer - the MQTT packet identifier
-  * @param topicName returned MQTTString - the MQTT topic in the publish
-  * @param payload returned byte buffer - the MQTT publish payload
-  * @param payloadlen returned integer - the length of the MQTT payload
-  * @param buf the raw buffer data, of the correct length determined by the remaining length field
-  * @param buflen the length in bytes of the data in the supplied buffer
-  * @return error code.  1 is success
-  */
-int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
-		unsigned char** payload, int* payloadlen, unsigned char* buf, int buflen)
-{
-	MQTTHeader header = {0};
-	unsigned char* curdata = buf;
-	unsigned char* enddata = NULL;
-	int rc = 0;
-	int mylen = 0;
-
-	FUNC_ENTRY;
-	header.byte = readChar(&curdata);
-	if (header.bits.type != PUBLISH)
-		goto exit;
-	*dup = header.bits.dup;
-	*qos = header.bits.qos;
-	*retained = header.bits.retain;
-
-	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
-	enddata = curdata + mylen;
-
-	if (!readMQTTLenString(topicName, &curdata, enddata) ||
-		enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
-		goto exit;
-
-	if (*qos > 0)
-		*packetid = readInt(&curdata);
-
-	*payloadlen = enddata - curdata;
-	*payload = curdata;
-	rc = 1;
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-
-
-/**
-  * Deserializes the supplied (wire) buffer into an ack
-  * @param packettype returned integer - the MQTT packet type
-  * @param dup returned integer - the MQTT dup flag
-  * @param packetid returned integer - the MQTT packet identifier
-  * @param buf the raw buffer data, of the correct length determined by the remaining length field
-  * @param buflen the length in bytes of the data in the supplied buffer
-  * @return error code.  1 is success, 0 is failure
-  */
-int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen)
-{
-	MQTTHeader header = {0};
-	unsigned char* curdata = buf;
-	unsigned char* enddata = NULL;
-	int rc = 0;
-	int mylen;
-
-	FUNC_ENTRY;
-	header.byte = readChar(&curdata);
-	*dup = header.bits.dup;
-	*packettype = header.bits.type;
-
-	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
-	enddata = curdata + mylen;
-
-	if (enddata - curdata < 2)
-		goto exit;
-	*packetid = readInt(&curdata);
-
-	rc = 1;
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-

+ 0 - 262
pahoMqtt/MQTTFormat.c

@@ -1,262 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *******************************************************************************/
-
-#include "StackTrace.h"
-#include "MQTTPacket.h"
-
-#include <string.h>
-
-
-const char* MQTTPacket_names[] =
-{
-	"RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL",
-	"PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK",
-	"PINGREQ", "PINGRESP", "DISCONNECT"
-};
-
-
-const char* MQTTPacket_getName(unsigned short packetid)
-{
-	return MQTTPacket_names[packetid];
-}
-
-
-int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data)
-{
-	int strindex = 0;
-
-	strindex = snprintf(strbuf, strbuflen,
-			"CONNECT MQTT version %d, client id %.*s, clean session %d, keep alive %d",
-			(int)data->MQTTVersion, data->clientID.lenstring.len, data->clientID.lenstring.data,
-			(int)data->cleansession, data->keepAliveInterval);
-	if (data->willFlag)
-		strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
-				", will QoS %d, will retain %d, will topic %.*s, will message %.*s",
-				data->will.qos, data->will.retained,
-				data->will.topicName.lenstring.len, data->will.topicName.lenstring.data,
-				data->will.message.lenstring.len, data->will.message.lenstring.data);
-	if (data->username.lenstring.data && data->username.lenstring.len > 0)
-		strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
-				", user name %.*s", data->username.lenstring.len, data->username.lenstring.data);
-	if (data->password.lenstring.data && data->password.lenstring.len > 0)
-		strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
-				", password %.*s", data->password.lenstring.len, data->password.lenstring.data);
-	return strindex;
-}
-
-
-int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent)
-{
-	int strindex = snprintf(strbuf, strbuflen, "CONNACK session present %d, rc %d", sessionPresent, connack_rc);
-	return strindex;
-}
-
-
-int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
-		unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen)
-{
-	int strindex = snprintf(strbuf, strbuflen,
-				"PUBLISH dup %d, QoS %d, retained %d, packet id %d, topic %.*s, payload length %d, payload %.*s",
-				dup, qos, retained, packetid,
-				(topicName.lenstring.len < 20) ? topicName.lenstring.len : 20, topicName.lenstring.data,
-				payloadlen, (payloadlen < 20) ? payloadlen : 20, payload);
-	return strindex;
-}
-
-
-int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
-{
-	int strindex = snprintf(strbuf, strbuflen, "%s, packet id %d", MQTTPacket_names[packettype], packetid);
-	if (dup)
-		strindex += snprintf(strbuf + strindex, strbuflen - strindex, ", dup %d", dup);
-	return strindex;
-}
-
-
-int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
-		MQTTString topicFilters[], int requestedQoSs[])
-{
-	return snprintf(strbuf, strbuflen,
-		"SUBSCRIBE dup %d, packet id %d count %d topic %.*s qos %d",
-		dup, packetid, count,
-		topicFilters[0].lenstring.len, topicFilters[0].lenstring.data,
-		requestedQoSs[0]);
-}
-
-
-int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs)
-{
-	return snprintf(strbuf, strbuflen,
-		"SUBACK packet id %d count %d granted qos %d", packetid, count, grantedQoSs[0]);
-}
-
-
-int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
-		int count, MQTTString topicFilters[])
-{
-	return snprintf(strbuf, strbuflen,
-					"UNSUBSCRIBE dup %d, packet id %d count %d topic %.*s",
-					dup, packetid, count,
-					topicFilters[0].lenstring.len, topicFilters[0].lenstring.data);
-}
-
-
-#if defined(MQTT_CLIENT)
-char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
-{
-	int index = 0;
-	int rem_length = 0;
-	MQTTHeader header = {0};
-	int strindex = 0;
-
-	header.byte = buf[index++];
-	index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
-
-	switch (header.bits.type)
-	{
-
-	case CONNACK:
-	{
-		unsigned char sessionPresent, connack_rc;
-		if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) == 1)
-			strindex = MQTTStringFormat_connack(strbuf, strbuflen, connack_rc, sessionPresent);
-	}
-	break;
-	case PUBLISH:
-	{
-		unsigned char dup, retained, *payload;
-		unsigned short packetid;
-		int qos, payloadlen;
-		MQTTString topicName = MQTTString_initializer;
-		if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
-				&payload, &payloadlen, buf, buflen) == 1)
-			strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
-					topicName, payload, payloadlen);
-	}
-	break;
-	case PUBACK:
-	case PUBREC:
-	case PUBREL:
-	case PUBCOMP:
-	{
-		unsigned char packettype, dup;
-		unsigned short packetid;
-		if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
-			strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
-	}
-	break;
-	case SUBACK:
-	{
-		unsigned short packetid;
-		int maxcount = 1, count = 0;
-		int grantedQoSs[1];
-		if (MQTTDeserialize_suback(&packetid, maxcount, &count, grantedQoSs, buf, buflen) == 1)
-			strindex = MQTTStringFormat_suback(strbuf, strbuflen, packetid, count, grantedQoSs);
-	}
-	break;
-	case UNSUBACK:
-	{
-		unsigned short packetid;
-		if (MQTTDeserialize_unsuback(&packetid, buf, buflen) == 1)
-			strindex = MQTTStringFormat_ack(strbuf, strbuflen, UNSUBACK, 0, packetid);
-	}
-	break;
-	case PINGREQ:
-	case PINGRESP:
-	case DISCONNECT:
-		strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
-		break;
-	}
-	return strbuf;
-}
-#endif
-
-#if defined(MQTT_SERVER)
-char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
-{
-	int index = 0;
-	int rem_length = 0;
-	MQTTHeader header = {0};
-	int strindex = 0;
-
-	header.byte = buf[index++];
-	index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
-
-	switch (header.bits.type)
-	{
-	case CONNECT:
-	{
-		MQTTPacket_connectData data;
-		int rc;
-		if ((rc = MQTTDeserialize_connect(&data, buf, buflen)) == 1)
-			strindex = MQTTStringFormat_connect(strbuf, strbuflen, &data);
-	}
-	break;
-	case PUBLISH:
-	{
-		unsigned char dup, retained, *payload;
-		unsigned short packetid;
-		int qos, payloadlen;
-		MQTTString topicName = MQTTString_initializer;
-		if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
-				&payload, &payloadlen, buf, buflen) == 1)
-			strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
-					topicName, payload, payloadlen);
-	}
-	break;
-	case PUBACK:
-	case PUBREC:
-	case PUBREL:
-	case PUBCOMP:
-	{
-		unsigned char packettype, dup;
-		unsigned short packetid;
-		if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
-			strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
-	}
-	break;
-	case SUBSCRIBE:
-	{
-		unsigned char dup;
-		unsigned short packetid;
-		int maxcount = 1, count = 0;
-		MQTTString topicFilters[1];
-		int requestedQoSs[1];
-		if (MQTTDeserialize_subscribe(&dup, &packetid, maxcount, &count,
-				topicFilters, requestedQoSs, buf, buflen) == 1)
-			strindex = MQTTStringFormat_subscribe(strbuf, strbuflen, dup, packetid, count, topicFilters, requestedQoSs);;
-	}
-	break;
-	case UNSUBSCRIBE:
-	{
-		unsigned char dup;
-		unsigned short packetid;
-		int maxcount = 1, count = 0;
-		MQTTString topicFilters[1];
-		if (MQTTDeserialize_unsubscribe(&dup, &packetid, maxcount, &count, topicFilters, buf, buflen) == 1)
-			strindex =  MQTTStringFormat_unsubscribe(strbuf, strbuflen, dup, packetid, count, topicFilters);
-	}
-	break;
-	case PINGREQ:
-	case PINGRESP:
-	case DISCONNECT:
-		strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
-		break;
-	}
-	strbuf[strbuflen] = '\0';
-	return strbuf;
-}
-#endif

+ 0 - 37
pahoMqtt/MQTTFormat.h

@@ -1,37 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *******************************************************************************/
-
-#if !defined(MQTTFORMAT_H)
-#define MQTTFORMAT_H
-
-#include "StackTrace.h"
-#include "MQTTPacket.h"
-
-const char* MQTTPacket_getName(unsigned short packetid);
-int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data);
-int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent);
-int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
-		unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen);
-int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid);
-int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
-		MQTTString topicFilters[], int requestedQoSs[]);
-int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs);
-int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
-		int count, MQTTString topicFilters[]);
-char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
-char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
-
-#endif

+ 0 - 413
pahoMqtt/MQTTPacket.c

@@ -1,413 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *    Sergio R. Caprile - non-blocking packet read functions for stream transport
- *******************************************************************************/
-
-#include "StackTrace.h"
-#include "MQTTPacket.h"
-
-#include <string.h>
-
-/**
- * Encodes the message length according to the MQTT algorithm
- * @param buf the buffer into which the encoded data is written
- * @param length the length to be encoded
- * @return the number of bytes written to buffer
- */
-int MQTTPacket_encode(unsigned char* buf, int length)
-{
-	int rc = 0;
-
-	FUNC_ENTRY;
-	do
-	{
-		char d = length % 128;
-		length /= 128;
-		/* if there are more digits to encode, set the top bit of this digit */
-		if (length > 0)
-			d |= 0x80;
-		buf[rc++] = d;
-	} while (length > 0);
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-
-/**
- * Decodes the message length according to the MQTT algorithm
- * @param getcharfn pointer to function to read the next character from the data source
- * @param value the decoded length returned
- * @return the number of bytes read from the socket
- */
-int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value)
-{
-	unsigned char c;
-	int multiplier = 1;
-	int len = 0;
-#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
-
-	FUNC_ENTRY;
-	*value = 0;
-	do
-	{
-		int rc = MQTTPACKET_READ_ERROR;
-
-		if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
-		{
-			rc = MQTTPACKET_READ_ERROR;	/* bad data */
-			goto exit;
-		}
-		rc = (*getcharfn)(&c, 1);
-		if (rc != 1)
-			goto exit;
-		*value += (c & 127) * multiplier;
-		multiplier *= 128;
-	} while ((c & 128) != 0);
-exit:
-	FUNC_EXIT_RC(len);
-	return len;
-}
-
-
-int MQTTPacket_len(int rem_len)
-{
-	/* now remaining_length field */
-	if (rem_len < 128)
-		rem_len += 1;
-	else if (rem_len < 16384)
-		rem_len += 2;
-	else if (rem_len < 2097151)
-		rem_len += 3;
-	else
-		rem_len += 4;
-
-    /* @F涛T rt-thread社区成员 长度计算问题修复 */
-    rem_len += 1; /* header byte */
-	return rem_len;
-}
-
-
-static unsigned char* bufptr;
-
-int bufchar(unsigned char* c, int count)
-{
-	int i;
-
-	for (i = 0; i < count; ++i)
-		*c = *bufptr++;
-	return count;
-}
-
-
-int MQTTPacket_decodeBuf(unsigned char* buf, int* value)
-{
-	bufptr = buf;
-	return MQTTPacket_decode(bufchar, value);
-}
-
-
-/**
- * Calculates an integer from two bytes read from the input buffer
- * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
- * @return the integer value calculated
- */
-int readInt(unsigned char** pptr)
-{
-	unsigned char* ptr = *pptr;
-	int len = 256*(*ptr) + (*(ptr+1));
-	*pptr += 2;
-	return len;
-}
-
-
-/**
- * Reads one character from the input buffer.
- * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
- * @return the character read
- */
-char readChar(unsigned char** pptr)
-{
-	char c = **pptr;
-	(*pptr)++;
-	return c;
-}
-
-
-/**
- * Writes one character to an output buffer.
- * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
- * @param c the character to write
- */
-void writeChar(unsigned char** pptr, char c)
-{
-	**pptr = c;
-	(*pptr)++;
-}
-
-
-/**
- * Writes an integer as 2 bytes to an output buffer.
- * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
- * @param anInt the integer to write
- */
-void writeInt(unsigned char** pptr, int anInt)
-{
-	**pptr = (unsigned char)(anInt / 256);
-	(*pptr)++;
-	**pptr = (unsigned char)(anInt % 256);
-	(*pptr)++;
-}
-
-
-/**
- * Writes a "UTF" string to an output buffer.  Converts C string to length-delimited.
- * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
- * @param string the C string to write
- */
-void writeCString(unsigned char** pptr, const char* string)
-{
-	int len = strlen(string);
-	writeInt(pptr, len);
-	memcpy(*pptr, string, len);
-	*pptr += len;
-}
-
-
-int getLenStringLen(char* ptr)
-{
-	int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
-	return len;
-}
-
-
-void writeMQTTString(unsigned char** pptr, MQTTString mqttstring)
-{
-	if (mqttstring.lenstring.len > 0)
-	{
-		writeInt(pptr, mqttstring.lenstring.len);
-		memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len);
-		*pptr += mqttstring.lenstring.len;
-	}
-	else if (mqttstring.cstring)
-		writeCString(pptr, mqttstring.cstring);
-	else
-		writeInt(pptr, 0);
-}
-
-
-/**
- * @param mqttstring the MQTTString structure into which the data is to be read
- * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
- * @param enddata pointer to the end of the data: do not read beyond
- * @return 1 if successful, 0 if not
- */
-int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata)
-{
-	int rc = 0;
-
-	FUNC_ENTRY;
-	/* the first two bytes are the length of the string */
-	if (enddata - (*pptr) > 1) /* enough length to read the integer? */
-	{
-		mqttstring->lenstring.len = readInt(pptr); /* increments pptr to point past length */
-		if (&(*pptr)[mqttstring->lenstring.len] <= enddata)
-		{
-			mqttstring->lenstring.data = (char*)*pptr;
-			*pptr += mqttstring->lenstring.len;
-			rc = 1;
-		}
-	}
-	mqttstring->cstring = NULL;
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-
-/**
- * Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string
- * @param mqttstring the string to return the length of
- * @return the length of the string
- */
-int MQTTstrlen(MQTTString mqttstring)
-{
-	int rc = 0;
-
-	if (mqttstring.cstring)
-		rc = strlen(mqttstring.cstring);
-	else
-		rc = mqttstring.lenstring.len;
-	return rc;
-}
-
-
-/**
- * Compares an MQTTString to a C string
- * @param a the MQTTString to compare
- * @param bptr the C string to compare
- * @return boolean - equal or not
- */
-int MQTTPacket_equals(MQTTString* a, char* bptr)
-{
-	int alen = 0,
-		blen = 0;
-	char *aptr;
-
-	if (a->cstring)
-	{
-		aptr = a->cstring;
-		alen = strlen(a->cstring);
-	}
-	else
-	{
-		aptr = a->lenstring.data;
-		alen = a->lenstring.len;
-	}
-	blen = strlen(bptr);
-
-	return (alen == blen) && (strncmp(aptr, bptr, alen) == 0);
-}
-
-
-/**
- * Helper function to read packet data from some source into a buffer
- * @param buf the buffer into which the packet will be serialized
- * @param buflen the length in bytes of the supplied buffer
- * @param getfn pointer to a function which will read any number of bytes from the needed source
- * @return integer MQTT packet type, or -1 on error
- * @note  the whole message must fit into the caller's buffer
- */
-int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int))
-{
-	int rc = -1;
-	MQTTHeader header = {0};
-	int len = 0;
-	int rem_len = 0;
-
-	/* 1. read the header byte.  This has the packet type in it */
-	if ((*getfn)(buf, 1) != 1)
-		goto exit;
-
-	len = 1;
-	/* 2. read the remaining length.  This is variable in itself */
-	MQTTPacket_decode(getfn, &rem_len);
-	len += MQTTPacket_encode(buf + 1, rem_len); /* put the original remaining length back into the buffer */
-
-	/* 3. read the rest of the buffer using a callback to supply the rest of the data */
-	if((rem_len + len) > buflen)
-		goto exit;
-	if (rem_len && ((*getfn)(buf + len, rem_len) != rem_len))
-		goto exit;
-
-	header.byte = buf[0];
-	rc = header.bits.type;
-exit:
-	return rc;
-}
-
-/**
- * Decodes the message length according to the MQTT algorithm, non-blocking
- * @param trp pointer to a transport structure holding what is needed to solve getting data from it
- * @param value the decoded length returned
- * @return integer the number of bytes read from the socket, 0 for call again, or -1 on error
- */
-static int MQTTPacket_decodenb(MQTTTransport *trp)
-{
-	unsigned char c;
-	int rc = MQTTPACKET_READ_ERROR;
-
-	FUNC_ENTRY;
-	if(trp->len == 0){		/* initialize on first call */
-		trp->multiplier = 1;
-		trp->rem_len = 0;
-	}
-	do {
-		int frc;
-		if (trp->len >= MAX_NO_OF_REMAINING_LENGTH_BYTES)
-			goto exit;
-		if ((frc=(*trp->getfn)(trp->sck, &c, 1)) == -1)
-			goto exit;
-		if (frc == 0){
-			rc = 0;
-			goto exit;
-		}
-		++(trp->len);
-		trp->rem_len += (c & 127) * trp->multiplier;
-		trp->multiplier *= 128;
-	} while ((c & 128) != 0);
-	rc = trp->len;
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-/**
- * Helper function to read packet data from some source into a buffer, non-blocking
- * @param buf the buffer into which the packet will be serialized
- * @param buflen the length in bytes of the supplied buffer
- * @param trp pointer to a transport structure holding what is needed to solve getting data from it
- * @return integer MQTT packet type, 0 for call again, or -1 on error
- * @note  the whole message must fit into the caller's buffer
- */
-int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp)
-{
-	int rc = -1, frc;
-	MQTTHeader header = {0};
-
-	switch(trp->state){
-	default:
-		trp->state = 0;
-		/*FALLTHROUGH*/
-	case 0:
-		/* read the header byte.  This has the packet type in it */
-		if ((frc=(*trp->getfn)(trp->sck, buf, 1)) == -1)
-			goto exit;
-		if (frc == 0)
-			return 0;
-		trp->len = 0;
-		++trp->state;
-		/*FALLTHROUGH*/
-		/* read the remaining length.  This is variable in itself */
-	case 1:
-		if((frc=MQTTPacket_decodenb(trp)) == MQTTPACKET_READ_ERROR)
-			goto exit;
-		if(frc == 0)
-			return 0;
-		trp->len = 1 + MQTTPacket_encode(buf + 1, trp->rem_len); /* put the original remaining length back into the buffer */
-		if((trp->rem_len + trp->len) > buflen)
-			goto exit;
-		++trp->state;
-		/*FALLTHROUGH*/
-	case 2:
-		if(trp->rem_len){
-			/* read the rest of the buffer using a callback to supply the rest of the data */
-			if ((frc=(*trp->getfn)(trp->sck, buf + trp->len, trp->rem_len)) == -1)
-				goto exit;
-			if (frc == 0)
-				return 0;
-			trp->rem_len -= frc;
-			trp->len += frc;
-			if(trp->rem_len)
-				return 0;
-		}
-		header.byte = buf[0];
-		rc = header.bits.type;
-		break;
-	}
-
-exit:
-	trp->state = 0;
-	return rc;
-}
-

+ 0 - 133
pahoMqtt/MQTTPacket.h

@@ -1,133 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *    Xiang Rong - 442039 Add makefile to Embedded C client
- *******************************************************************************/
-
-#ifndef MQTTPACKET_H_
-#define MQTTPACKET_H_
-
-#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
-extern "C" {
-#endif
-
-#if defined(WIN32_DLL) || defined(WIN64_DLL)
-  #define DLLImport __declspec(dllimport)
-  #define DLLExport __declspec(dllexport)
-#elif defined(LINUX_SO)
-  #define DLLImport extern
-  #define DLLExport  __attribute__ ((visibility ("default")))
-#else
-  #define DLLImport
-  #define DLLExport  
-#endif
-
-enum errors
-{
-	MQTTPACKET_BUFFER_TOO_SHORT = -2,
-	MQTTPACKET_READ_ERROR = -1,
-	MQTTPACKET_READ_COMPLETE
-};
-
-enum msgTypes
-{
-	CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,
-	PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,
-	PINGREQ, PINGRESP, DISCONNECT
-};
-
-/**
- * Bitfields for the MQTT header byte.
- */
-typedef union
-{
-	unsigned char byte;	                /**< the whole byte */
-#if defined(REVERSED)
-	struct
-	{
-		unsigned int type : 4;			/**< message type nibble */
-		unsigned int dup : 1;				/**< DUP flag bit */
-		unsigned int qos : 2;				/**< QoS value, 0, 1 or 2 */
-		unsigned int retain : 1;		/**< retained flag bit */
-	} bits;
-#else
-	struct
-	{
-		unsigned int retain : 1;		/**< retained flag bit */
-		unsigned int qos : 2;				/**< QoS value, 0, 1 or 2 */
-		unsigned int dup : 1;				/**< DUP flag bit */
-		unsigned int type : 4;			/**< message type nibble */
-	} bits;
-#endif
-} MQTTHeader;
-
-typedef struct
-{
-	int len;
-	char* data;
-} MQTTLenString;
-
-typedef struct
-{
-	char* cstring;
-	MQTTLenString lenstring;
-} MQTTString;
-
-#define MQTTString_initializer {NULL, {0, NULL}}
-
-int MQTTstrlen(MQTTString mqttstring);
-
-#include "MQTTConnect.h"
-#include "MQTTPublish.h"
-#include "MQTTSubscribe.h"
-#include "MQTTUnsubscribe.h"
-#include "MQTTFormat.h"
-
-DLLExport int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char type, unsigned char dup, unsigned short packetid);
-DLLExport int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen);
-
-int MQTTPacket_len(int rem_len);
-DLLExport int MQTTPacket_equals(MQTTString* a, char* b);
-
-DLLExport int MQTTPacket_encode(unsigned char* buf, int length);
-int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value);
-int MQTTPacket_decodeBuf(unsigned char* buf, int* value);
-
-int readInt(unsigned char** pptr);
-char readChar(unsigned char** pptr);
-void writeChar(unsigned char** pptr, char c);
-void writeInt(unsigned char** pptr, int anInt);
-int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata);
-void writeCString(unsigned char** pptr, const char* string);
-void writeMQTTString(unsigned char** pptr, MQTTString mqttstring);
-
-DLLExport int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int));
-
-typedef struct {
-	int (*getfn)(void *, unsigned char*, int); /* must return -1 for error, 0 for call again, or the number of bytes read */
-	void *sck;	/* pointer to whatever the system may use to identify the transport */
-	int multiplier;
-	int rem_len;
-	int len;
-	char state;
-}MQTTTransport;
-
-int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp);
-
-#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
-}
-#endif
-
-
-#endif /* MQTTPACKET_H_ */

+ 0 - 38
pahoMqtt/MQTTPublish.h

@@ -1,38 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *    Xiang Rong - 442039 Add makefile to Embedded C client
- *******************************************************************************/
-
-#ifndef MQTTPUBLISH_H_
-#define MQTTPUBLISH_H_
-
-#if !defined(DLLImport)
-  #define DLLImport 
-#endif
-#if !defined(DLLExport)
-  #define DLLExport
-#endif
-
-DLLExport int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
-		MQTTString topicName, unsigned char* payload, int payloadlen);
-
-DLLExport int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
-		unsigned char** payload, int* payloadlen, unsigned char* buf, int len);
-
-DLLExport int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid);
-DLLExport int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid);
-DLLExport int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid);
-
-#endif /* MQTTPUBLISH_H_ */

+ 0 - 169
pahoMqtt/MQTTSerializePublish.c

@@ -1,169 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *    Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144
- *******************************************************************************/
-
-#include "MQTTPacket.h"
-#include "StackTrace.h"
-
-#include <string.h>
-
-
-/**
-  * Determines the length of the MQTT publish packet that would be produced using the supplied parameters
-  * @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)
-  * @param topicName the topic name to be used in the publish  
-  * @param payloadlen the length of the payload to be sent
-  * @return the length of buffer needed to contain the serialized version of the packet
-  */
-int MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen)
-{
-	int len = 0;
-
-	len += 2 + MQTTstrlen(topicName) + payloadlen;
-	if (qos > 0)
-		len += 2; /* packetid */
-	return len;
-}
-
-
-/**
-  * Serializes the supplied publish data into the supplied buffer, ready for sending
-  * @param buf the buffer into which the packet will be serialized
-  * @param buflen the length in bytes of the supplied buffer
-  * @param dup integer - the MQTT dup flag
-  * @param qos integer - the MQTT QoS value
-  * @param retained integer - the MQTT retained flag
-  * @param packetid integer - the MQTT packet identifier
-  * @param topicName MQTTString - the MQTT topic in the publish
-  * @param payload byte buffer - the MQTT publish payload
-  * @param payloadlen integer - the length of the MQTT payload
-  * @return the length of the serialized data.  <= 0 indicates error
-  */
-int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
-		MQTTString topicName, unsigned char* payload, int payloadlen)
-{
-	unsigned char *ptr = buf;
-	MQTTHeader header = {0};
-	int rem_len = 0;
-	int rc = 0;
-
-	FUNC_ENTRY;
-	if (MQTTPacket_len(rem_len = MQTTSerialize_publishLength(qos, topicName, payloadlen)) > buflen)
-	{
-		rc = MQTTPACKET_BUFFER_TOO_SHORT;
-		goto exit;
-	}
-
-	header.bits.type = PUBLISH;
-	header.bits.dup = dup;
-	header.bits.qos = qos;
-	header.bits.retain = retained;
-	writeChar(&ptr, header.byte); /* write header */
-
-	ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
-
-	writeMQTTString(&ptr, topicName);
-
-	if (qos > 0)
-		writeInt(&ptr, packetid);
-
-	memcpy(ptr, payload, payloadlen);
-	ptr += payloadlen;
-
-	rc = ptr - buf;
-
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-
-
-/**
-  * Serializes the ack packet into the supplied buffer.
-  * @param buf the buffer into which the packet will be serialized
-  * @param buflen the length in bytes of the supplied buffer
-  * @param type the MQTT packet type
-  * @param dup the MQTT dup flag
-  * @param packetid the MQTT packet identifier
-  * @return serialized length, or error if 0
-  */
-int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
-{
-	MQTTHeader header = {0};
-	int rc = 0;
-	unsigned char *ptr = buf;
-
-	FUNC_ENTRY;
-	if (buflen < 4)
-	{
-		rc = MQTTPACKET_BUFFER_TOO_SHORT;
-		goto exit;
-	}
-	header.bits.type = packettype;
-	header.bits.dup = dup;
-	header.bits.qos = (packettype == PUBREL) ? 1 : 0;
-	writeChar(&ptr, header.byte); /* write header */
-
-	ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
-	writeInt(&ptr, packetid);
-	rc = ptr - buf;
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-
-/**
-  * Serializes a puback packet into the supplied buffer.
-  * @param buf the buffer into which the packet will be serialized
-  * @param buflen the length in bytes of the supplied buffer
-  * @param packetid integer - the MQTT packet identifier
-  * @return serialized length, or error if 0
-  */
-int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid)
-{
-	return MQTTSerialize_ack(buf, buflen, PUBACK, 0, packetid);
-}
-
-
-/**
-  * Serializes a pubrel packet into the supplied buffer.
-  * @param buf the buffer into which the packet will be serialized
-  * @param buflen the length in bytes of the supplied buffer
-  * @param dup integer - the MQTT dup flag
-  * @param packetid integer - the MQTT packet identifier
-  * @return serialized length, or error if 0
-  */
-int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid)
-{
-	return MQTTSerialize_ack(buf, buflen, PUBREL, dup, packetid);
-}
-
-
-/**
-  * Serializes a pubrel packet into the supplied buffer.
-  * @param buf the buffer into which the packet will be serialized
-  * @param buflen the length in bytes of the supplied buffer
-  * @param packetid integer - the MQTT packet identifier
-  * @return serialized length, or error if 0
-  */
-int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid)
-{
-	return MQTTSerialize_ack(buf, buflen, PUBCOMP, 0, packetid);
-}
-
-

+ 0 - 39
pahoMqtt/MQTTSubscribe.h

@@ -1,39 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *    Xiang Rong - 442039 Add makefile to Embedded C client
- *******************************************************************************/
-
-#ifndef MQTTSUBSCRIBE_H_
-#define MQTTSUBSCRIBE_H_
-
-#if !defined(DLLImport)
-  #define DLLImport 
-#endif
-#if !defined(DLLExport)
-  #define DLLExport
-#endif
-
-DLLExport int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
-		int count, MQTTString topicFilters[], int requestedQoSs[]);
-
-DLLExport int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid,
-		int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, int len);
-
-DLLExport int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs);
-
-DLLExport int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int len);
-
-
-#endif /* MQTTSUBSCRIBE_H_ */

+ 0 - 137
pahoMqtt/MQTTSubscribeClient.c

@@ -1,137 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *******************************************************************************/
-
-#include "MQTTPacket.h"
-#include "StackTrace.h"
-
-#include <string.h>
-
-/**
-  * Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters
-  * @param count the number of topic filter strings in topicFilters
-  * @param topicFilters the array of topic filter strings to be used in the publish
-  * @return the length of buffer needed to contain the serialized version of the packet
-  */
-int MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[])
-{
-	int i;
-	int len = 2; /* packetid */
-
-	for (i = 0; i < count; ++i)
-		len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */
-	return len;
-}
-
-
-/**
-  * Serializes the supplied subscribe data into the supplied buffer, ready for sending
-  * @param buf the buffer into which the packet will be serialized
-  * @param buflen the length in bytes of the supplied bufferr
-  * @param dup integer - the MQTT dup flag
-  * @param packetid integer - the MQTT packet identifier
-  * @param count - number of members in the topicFilters and reqQos arrays
-  * @param topicFilters - array of topic filter names
-  * @param requestedQoSs - array of requested QoS
-  * @return the length of the serialized data.  <= 0 indicates error
-  */
-int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, int count,
-		MQTTString topicFilters[], int requestedQoSs[])
-{
-	unsigned char *ptr = buf;
-	MQTTHeader header = {0};
-	int rem_len = 0;
-	int rc = 0;
-	int i = 0;
-
-	FUNC_ENTRY;
-	if (MQTTPacket_len(rem_len = MQTTSerialize_subscribeLength(count, topicFilters)) > buflen)
-	{
-		rc = MQTTPACKET_BUFFER_TOO_SHORT;
-		goto exit;
-	}
-
-	header.byte = 0;
-	header.bits.type = SUBSCRIBE;
-	header.bits.dup = dup;
-	header.bits.qos = 1;
-	writeChar(&ptr, header.byte); /* write header */
-
-	ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
-
-	writeInt(&ptr, packetid);
-
-	for (i = 0; i < count; ++i)
-	{
-		writeMQTTString(&ptr, topicFilters[i]);
-		writeChar(&ptr, requestedQoSs[i]);
-	}
-
-	rc = ptr - buf;
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-
-
-/**
-  * Deserializes the supplied (wire) buffer into suback data
-  * @param packetid returned integer - the MQTT packet identifier
-  * @param maxcount - the maximum number of members allowed in the grantedQoSs array
-  * @param count returned integer - number of members in the grantedQoSs array
-  * @param grantedQoSs returned array of integers - the granted qualities of service
-  * @param buf the raw buffer data, of the correct length determined by the remaining length field
-  * @param buflen the length in bytes of the data in the supplied buffer
-  * @return error code.  1 is success, 0 is failure
-  */
-int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int buflen)
-{
-	MQTTHeader header = {0};
-	unsigned char* curdata = buf;
-	unsigned char* enddata = NULL;
-	int rc = 0;
-	int mylen;
-
-	FUNC_ENTRY;
-	header.byte = readChar(&curdata);
-	if (header.bits.type != SUBACK)
-		goto exit;
-
-	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
-	enddata = curdata + mylen;
-	if (enddata - curdata < 2)
-		goto exit;
-
-	*packetid = readInt(&curdata);
-
-	*count = 0;
-	while (curdata < enddata)
-	{
-		if (*count > maxcount)
-		{
-			rc = -1;
-			goto exit;
-		}
-		grantedQoSs[(*count)++] = readChar(&curdata);
-	}
-
-	rc = 1;
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-

+ 0 - 117
pahoMqtt/MQTTSubscribeServer.c

@@ -1,117 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014, 2023 IBM Corp., Ian Craggs
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *******************************************************************************/
-
-#include "MQTTPacket.h"
-#include "StackTrace.h"
-
-#include <string.h>
-
-
-/**
-  * Deserializes the supplied (wire) buffer into subscribe data
-  * @param dup integer returned - the MQTT dup flag
-  * @param packetid integer returned - the MQTT packet identifier
-  * @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
-  * @param count - number of members in the topicFilters and requestedQoSs arrays
-  * @param topicFilters - array of topic filter names
-  * @param requestedQoSs - array of requested QoS
-  * @param buf the raw buffer data, of the correct length determined by the remaining length field
-  * @param buflen the length in bytes of the data in the supplied buffer
-  * @return the length of the serialized data.  <= 0 indicates error
-  */
-int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
-	int requestedQoSs[], unsigned char* buf, int buflen)
-{
-	MQTTHeader header = {0};
-	unsigned char* curdata = buf;
-	unsigned char* enddata = NULL;
-	int rc = MQTTPACKET_READ_ERROR;
-	int mylen = 0;
-
-	FUNC_ENTRY;
-	header.byte = readChar(&curdata);
-	if (header.bits.type != SUBSCRIBE)
-		goto exit;
-	*dup = header.bits.dup;
-
-	rc = MQTTPacket_decodeBuf(curdata, &mylen); /* read remaining length */
-	if (rc <= 0)
-		goto exit;
-	curdata += rc;
-	rc = MQTTPACKET_READ_ERROR;
-	enddata = curdata + mylen;
-
-	*packetid = readInt(&curdata);
-
-	*count = 0;
-	while (curdata < enddata)
-	{
-		if (*count == maxcount)
-			goto exit;
-		if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
-			goto exit;
-		if (curdata >= enddata) /* do we have enough data to read the req_qos version byte? */
-			goto exit;
-		requestedQoSs[*count] = readChar(&curdata);
-		(*count)++;
-	}
-
-	rc = 1;
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-
-/**
-  * Serializes the supplied suback data into the supplied buffer, ready for sending
-  * @param buf the buffer into which the packet will be serialized
-  * @param buflen the length in bytes of the supplied buffer
-  * @param packetid integer - the MQTT packet identifier
-  * @param count - number of members in the grantedQoSs array
-  * @param grantedQoSs - array of granted QoS
-  * @return the length of the serialized data.  <= 0 indicates error
-  */
-int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs)
-{
-	MQTTHeader header = {0};
-	int rc = -1;
-	unsigned char *ptr = buf;
-	int i;
-
-	FUNC_ENTRY;
-	if (buflen < 2 + count)
-	{
-		rc = MQTTPACKET_BUFFER_TOO_SHORT;
-		goto exit;
-	}
-	header.byte = 0;
-	header.bits.type = SUBACK;
-	writeChar(&ptr, header.byte); /* write header */
-
-	ptr += MQTTPacket_encode(ptr, 2 + count); /* write remaining length */
-
-	writeInt(&ptr, packetid);
-
-	for (i = 0; i < count; ++i)
-		writeChar(&ptr, grantedQoSs[i]);
-
-	rc = ptr - buf;
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-

+ 0 - 38
pahoMqtt/MQTTUnsubscribe.h

@@ -1,38 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *    Xiang Rong - 442039 Add makefile to Embedded C client
- *******************************************************************************/
-
-#ifndef MQTTUNSUBSCRIBE_H_
-#define MQTTUNSUBSCRIBE_H_
-
-#if !defined(DLLImport)
-  #define DLLImport 
-#endif
-#if !defined(DLLExport)
-  #define DLLExport
-#endif
-
-DLLExport int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
-		int count, MQTTString topicFilters[]);
-
-DLLExport int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int max_count, int* count, MQTTString topicFilters[],
-		unsigned char* buf, int len);
-
-DLLExport int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid);
-
-DLLExport int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int len);
-
-#endif /* MQTTUNSUBSCRIBE_H_ */

+ 0 - 106
pahoMqtt/MQTTUnsubscribeClient.c

@@ -1,106 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *******************************************************************************/
-
-#include "MQTTPacket.h"
-#include "StackTrace.h"
-
-#include <string.h>
-
-/**
-  * Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters
-  * @param count the number of topic filter strings in topicFilters
-  * @param topicFilters the array of topic filter strings to be used in the publish
-  * @return the length of buffer needed to contain the serialized version of the packet
-  */
-int MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[])
-{
-	int i;
-	int len = 2; /* packetid */
-
-	for (i = 0; i < count; ++i)
-		len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/
-	return len;
-}
-
-
-/**
-  * Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
-  * @param buf the raw buffer data, of the correct length determined by the remaining length field
-  * @param buflen the length in bytes of the data in the supplied buffer
-  * @param dup integer - the MQTT dup flag
-  * @param packetid integer - the MQTT packet identifier
-  * @param count - number of members in the topicFilters array
-  * @param topicFilters - array of topic filter names
-  * @return the length of the serialized data.  <= 0 indicates error
-  */
-int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
-		int count, MQTTString topicFilters[])
-{
-	unsigned char *ptr = buf;
-	MQTTHeader header = {0};
-	int rem_len = 0;
-	int rc = -1;
-	int i = 0;
-
-	FUNC_ENTRY;
-	if (MQTTPacket_len(rem_len = MQTTSerialize_unsubscribeLength(count, topicFilters)) > buflen)
-	{
-		rc = MQTTPACKET_BUFFER_TOO_SHORT;
-		goto exit;
-	}
-
-	header.byte = 0;
-	header.bits.type = UNSUBSCRIBE;
-	header.bits.dup = dup;
-	header.bits.qos = 1;
-	writeChar(&ptr, header.byte); /* write header */
-
-	ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
-
-	writeInt(&ptr, packetid);
-
-	for (i = 0; i < count; ++i)
-		writeMQTTString(&ptr, topicFilters[i]);
-
-	rc = ptr - buf;
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-
-/**
-  * Deserializes the supplied (wire) buffer into unsuback data
-  * @param packetid returned integer - the MQTT packet identifier
-  * @param buf the raw buffer data, of the correct length determined by the remaining length field
-  * @param buflen the length in bytes of the data in the supplied buffer
-  * @return error code.  1 is success, 0 is failure
-  */
-int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int buflen)
-{
-	unsigned char type = 0;
-	unsigned char dup = 0;
-	int rc = 0;
-
-	FUNC_ENTRY;
-	rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen);
-	if (type == UNSUBACK)
-		rc = 1;
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-

+ 0 - 102
pahoMqtt/MQTTUnsubscribeServer.c

@@ -1,102 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *******************************************************************************/
-
-#include "MQTTPacket.h"
-#include "StackTrace.h"
-
-#include <string.h>
-
-
-/**
-  * Deserializes the supplied (wire) buffer into unsubscribe data
-  * @param dup integer returned - the MQTT dup flag
-  * @param packetid integer returned - the MQTT packet identifier
-  * @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
-  * @param count - number of members in the topicFilters and requestedQoSs arrays
-  * @param topicFilters - array of topic filter names
-  * @param buf the raw buffer data, of the correct length determined by the remaining length field
-  * @param buflen the length in bytes of the data in the supplied buffer
-  * @return the length of the serialized data.  <= 0 indicates error
-  */
-int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
-		unsigned char* buf, int len)
-{
-	MQTTHeader header = {0};
-	unsigned char* curdata = buf;
-	unsigned char* enddata = NULL;
-	int rc = 0;
-	int mylen = 0;
-
-	FUNC_ENTRY;
-	header.byte = readChar(&curdata);
-	if (header.bits.type != UNSUBSCRIBE)
-		goto exit;
-	*dup = header.bits.dup;
-
-	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
-	enddata = curdata + mylen;
-
-	*packetid = readInt(&curdata);
-
-	*count = 0;
-	while (curdata < enddata)
-	{
-		if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
-			goto exit;
-		(*count)++;
-	}
-
-	rc = 1;
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-
-/**
-  * Serializes the supplied unsuback data into the supplied buffer, ready for sending
-  * @param buf the buffer into which the packet will be serialized
-  * @param buflen the length in bytes of the supplied buffer
-  * @param packetid integer - the MQTT packet identifier
-  * @return the length of the serialized data.  <= 0 indicates error
-  */
-int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid)
-{
-	MQTTHeader header = {0};
-	int rc = 0;
-	unsigned char *ptr = buf;
-
-	FUNC_ENTRY;
-	if (buflen < 2)
-	{
-		rc = MQTTPACKET_BUFFER_TOO_SHORT;
-		goto exit;
-	}
-	header.byte = 0;
-	header.bits.type = UNSUBACK;
-	writeChar(&ptr, header.byte); /* write header */
-
-	ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
-
-	writeInt(&ptr, packetid);
-
-	rc = ptr - buf;
-exit:
-	FUNC_EXIT_RC(rc);
-	return rc;
-}
-
-

+ 0 - 78
pahoMqtt/StackTrace.h

@@ -1,78 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
- *
- * The Eclipse Public License is available at
- *    http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- *   http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *    Ian Craggs - initial API and implementation and/or initial documentation
- *    Ian Craggs - fix for bug #434081
- *******************************************************************************/
-
-#ifndef STACKTRACE_H_
-#define STACKTRACE_H_
-
-#include <stdio.h>
-#define NOSTACKTRACE 1
-
-#if defined(NOSTACKTRACE)
-#define FUNC_ENTRY
-#define FUNC_ENTRY_NOLOG
-#define FUNC_ENTRY_MED
-#define FUNC_ENTRY_MAX
-#define FUNC_EXIT
-#define FUNC_EXIT_NOLOG
-#define FUNC_EXIT_MED
-#define FUNC_EXIT_MAX
-#define FUNC_EXIT_RC(x)
-#define FUNC_EXIT_MED_RC(x)
-#define FUNC_EXIT_MAX_RC(x)
-
-#else
-
-#if defined(WIN32)
-#define inline __inline
-#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM)
-#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1)
-#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM)
-#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM)
-#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM)
-#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1)
-#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM)
-#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM)
-#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM)
-#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM)
-#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM)
-#else
-#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM)
-#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1)
-#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM)
-#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM)
-#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM)
-#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1)
-#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM)
-#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM)
-#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM)
-#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM)
-#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM)
-
-void StackTrace_entry(const char* name, int line, int trace);
-void StackTrace_exit(const char* name, int line, void* return_value, int trace);
-
-void StackTrace_printStack(FILE* dest);
-char* StackTrace_get(unsigned long);
-
-#endif
-
-#endif
-
-
-
-
-#endif /* STACKTRACE_H_ */

+ 172 - 271
platform/linux/platformNetwork.c

@@ -1,7 +1,4 @@
-// #define rlogEnable               // 是否使能日志
-#define rlogColorEnable            // 是否使能日志颜色
-#define rlogLevel (rlogLvlWarning) // 日志打印等级
-#define rlogTag "RyanMqttNet"      // 日志tag
+#define rlogLevel (rlogLvlDebug) // 日志打印等级
 
 #include "platformNetwork.h"
 #include "RyanMqttLog.h"
@@ -15,8 +12,8 @@
  */
 RyanMqttError_e platformNetworkInit(void *userData, platformNetwork_t *platformNetwork)
 {
-    platformNetwork->socket = -1;
-    return RyanMqttSuccessError;
+	platformNetwork->socket = -1;
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -28,8 +25,8 @@ RyanMqttError_e platformNetworkInit(void *userData, platformNetwork_t *platformN
  */
 RyanMqttError_e platformNetworkDestroy(void *userData, platformNetwork_t *platformNetwork)
 {
-    platformNetwork->socket = -1;
-    return RyanMqttSuccessError;
+	platformNetwork->socket = -1;
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -42,74 +39,83 @@ RyanMqttError_e platformNetworkDestroy(void *userData, platformNetwork_t *platfo
  * @return RyanMqttError_e
  * 成功返回RyanMqttSuccessError, 失败返回错误信息
  */
-RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host, uint16_t port)
+RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host,
+				       uint16_t port)
 {
-    RyanMqttError_e result = RyanMqttSuccessError;
-
-    // ?线程安全版本,有些设备没有实现,默认不启用。如果涉及多个客户端解析域名请使用线程安全版本
-    char buf[256];
-    int ret;
-    struct hostent hostinfo, *phost;
-
-    if (0 != gethostbyname_r(host, &hostinfo, buf, sizeof(buf), &phost, &ret))
-    {
-        result = RyanSocketFailedError;
-        goto exit;
-    }
-
-    platformNetwork->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
-    if (platformNetwork->socket < 0)
-    {
-        result = RyanSocketFailedError;
-        goto exit;
-    }
-
-    struct sockaddr_in server_addr;
-    memset(&server_addr, 0, sizeof(server_addr));
-    server_addr.sin_family = AF_INET;
-    server_addr.sin_port = htons(port); // 指定端口号,这里使用HTTP默认端口80
-    server_addr.sin_addr = *((struct in_addr *)hostinfo.h_addr_list[0]);
-
-    // 绑定套接字到主机地址和端口号
-    if (connect(platformNetwork->socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0)
-    {
-        platformNetworkClose(userData, platformNetwork);
-        result = RyanMqttSocketConnectFailError;
-        goto exit;
-    }
-
-    // 非线程安全版本,请根据实际情况选择使用
-    // struct hostent *hostinfo;
-    // hostinfo = gethostbyname(host);
-    // if (NULL == hostinfo)
-    // {
-    //     result = RyanSocketFailedError;
-    //     goto exit;
-    // }
-
-    // platformNetwork->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
-    // if (platformNetwork->socket < 0)
-    // {
-    //     result = RyanSocketFailedError;
-    //     goto exit;
-    // }
-
-    // struct sockaddr_in server_addr;
-    // memset(&server_addr, 0, sizeof(server_addr));
-    // server_addr.sin_family = AF_INET;
-    // server_addr.sin_port = htons(port); // 指定端口号,这里使用HTTP默认端口80
-    // server_addr.sin_addr = *((struct in_addr *)hostinfo->h_addr_list[0]);
-
-    // // 绑定套接字到主机地址和端口号
-    // if (connect(platformNetwork->socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0)
-    // {
-    //     platformNetworkClose(userData, platformNetwork);
-    //     result = RyanMqttSocketConnectFailError;
-    //     goto exit;
-    // }
-
-exit:
-    return result;
+	RyanMqttError_e result = RyanMqttSuccessError;
+	char *buf = NULL;
+	struct sockaddr_in server_addr = {
+		.sin_family = AF_INET,
+		.sin_port = htons(port), // 指定端口号
+	};
+
+	// 传递的是ip地址,不用进行dns解析,某些情况下调用dns解析反而会错误
+	if (INADDR_NONE != inet_addr(host))
+	{
+		rlog_d("host: %s, 不用dns解析", host);
+		server_addr.sin_addr.s_addr = inet_addr(host);
+	}
+	// 解析域名信息
+	else
+	{
+#define dnsBufferSize (384)
+		rlog_d("host: %s, 需要dns解析", host);
+		int h_errnop;
+		struct hostent *phost;
+		struct hostent hostinfo = {0};
+
+		buf = (char *)platformMemoryMalloc(dnsBufferSize);
+		if (NULL == buf)
+		{
+			result = RyanMqttNoRescourceError;
+			goto __exit;
+		}
+
+		if (0 != gethostbyname_r(host, &hostinfo, buf, dnsBufferSize, &phost, &h_errnop))
+		{
+			rlog_w("平台可能不支持 gethostbyname_r 函数, 再次尝试使用 gethostbyname 获取域名信息");
+
+			// 非线程安全版本,请根据实际情况选择使用
+			// NOLINTNEXTLINE(concurrency-mt-unsafe)
+			struct hostent *phostinfo = gethostbyname(host);
+			if (NULL == phostinfo)
+			{
+				result = RyanMqttNoRescourceError;
+				goto __exit;
+			}
+
+			hostinfo = *phostinfo;
+		}
+
+		server_addr.sin_addr = *((struct in_addr *)hostinfo.h_addr_list[0]);
+	}
+
+	platformNetwork->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+	if (platformNetwork->socket < 0)
+	{
+		result = RyanSocketFailedError;
+		goto __exit;
+	}
+
+	// 绑定套接字到主机地址和端口号
+	if (connect(platformNetwork->socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0)
+	{
+		platformNetworkClose(userData, platformNetwork);
+		result = RyanMqttSocketConnectFailError;
+		goto __exit;
+	}
+
+__exit:
+	if (NULL != buf)
+	{
+		platformMemoryFree(buf);
+	}
+
+	if (RyanMqttSuccessError != result)
+	{
+		rlog_e("socket连接失败: %d", result);
+	}
+	return result;
 }
 
 /**
@@ -125,144 +131,49 @@ exit:
  * 接收超时或者接收数据长度不等于期待数据接受长度 RyanMqttRecvPacketTimeOutError
  * 接收成功 RyanMqttSuccessError
  */
-RyanMqttError_e platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf, int recvLen, int timeout)
+int32_t platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf, size_t recvLen,
+				 int32_t timeout)
 {
-
-    // int32_t recvResult = 0;
-    // int32_t offset = 0;
-    // int32_t timeOut2 = timeout;
-    // struct timeval tv = {0};
-    // platformTimer_t timer = {0};
-
-    // if (-1 == platformNetwork->socket)
-    //     return RyanSocketFailedError;
-
-    // platformTimerCutdown(&timer, timeout);
-
-    // while ((offset < recvLen) && (0 != timeOut2))
-    // {
-
-    //     tv.tv_sec = timeOut2 / 1000;
-    //     tv.tv_usec = timeOut2 % 1000 * 1000;
-
-    //     if (tv.tv_sec <= 0 && tv.tv_usec <= 100)
-    //     {
-    //         tv.tv_sec = 0;
-    //         tv.tv_usec = 100;
-    //     }
-
-    //     setsockopt(platformNetwork->socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); // 设置错做模式为非阻塞
-
-    //     recvResult = recv(platformNetwork->socket, recvBuf + offset, recvLen - offset, 0);
-    //     if (0 == recvResult)
-    //     {
-    //         rlog_d("对端关闭socket连接");
-    //         return RyanSocketFailedError;
-    //     }
-    //     else if (recvResult < 0) // 小于零,表示错误,个别错误不代表socket错误
-    //     {
-    //         int32_t err = errno;
-    //         // 下列3种表示没问题,但需要推出发送
-    //         if (err == EAGAIN ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
-    //             err == EWOULDBLOCK || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
-    //             err == EINTR)         // 操作被信号中断
-    //             break;
-
-    //         return RyanSocketFailedError;
-    //     }
-
-    //     offset += recvResult;
-    //     timeOut2 = platformTimerRemain(&timer);
-    // }
-
-    // if (offset != recvLen)
-    //     return RyanMqttRecvPacketTimeOutError;
-
-    // return RyanMqttSuccessError;
-
-    int32_t recvResult = 0;
-    int32_t offset = 0;
-    int32_t timeOut2 = timeout;
-    struct timeval tv = {0};
-    platformTimer_t timer = {0};
-
-    if (-1 == platformNetwork->socket)
-        return RyanSocketFailedError;
-
-    platformTimerCutdown(&timer, timeout);
-
-    while ((offset < recvLen) && (0 != timeOut2))
-    {
-
-        tv.tv_sec = timeOut2 / 1000;
-        tv.tv_usec = timeOut2 % 1000 * 1000;
-
-        if (tv.tv_sec <= 0 && tv.tv_usec <= 100)
-        {
-            tv.tv_sec = 0;
-            tv.tv_usec = 100;
-        }
-
-        fd_set readset;
-        fd_set exceptset;
-        int i;
-
-        /* 清空可读事件描述符列表 */
-        FD_ZERO(&readset);
-        FD_ZERO(&exceptset);
-
-        FD_SET(platformNetwork->socket, &readset);   // 监听可读事件
-        FD_SET(platformNetwork->socket, &exceptset); // 监听异常事件
-
-        /* 等待设定的网络描述符有事件发生 */
-        i = select(platformNetwork->socket + 1, &readset, NULL, &exceptset, &tv);
-        if (i < 0)
-        {
-            int32_t err = errno;
-
-            // 下列3种表示没问题,但需要退出接收
-            if (err == EAGAIN ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
-                err == EWOULDBLOCK || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
-                err == EINTR)         // 操作被信号中断
-                break;
-
-            return RyanSocketFailedError;
-        }
-        /* 查看 sock 描述符上有没有发生可读事件 */
-        else if (i > 0)
-        {
-            if (FD_ISSET(platformNetwork->socket, &readset))
-            {
-                recvResult = recv(platformNetwork->socket, recvBuf + offset, recvLen - offset, 0);
-
-                if (recvResult <= 0) // 小于零,表示错误,个别错误不代表socket错误
-                {
-                    int32_t err = errno;
-                    // 下列3种表示没问题,但需要退出接收
-                    if (err == EAGAIN ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
-                        err == EWOULDBLOCK || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
-                        err == EINTR)         // 操作被信号中断
-                        break;
-
-                    return RyanSocketFailedError;
-                }
-
-                offset += recvResult;
-            }
-
-            if (FD_ISSET(platformNetwork->socket, &exceptset))
-            {
-                return RyanSocketFailedError;
-            }
-        }
-
-        timeOut2 = platformTimerRemain(&timer);
-    }
-
-    if (offset != recvLen)
-        return RyanMqttRecvPacketTimeOutError;
-
-    return RyanMqttSuccessError;
+	ssize_t recvResult = 0;
+	struct timeval tv = {
+		.tv_sec = timeout / 1000,
+		.tv_usec = 1000 * timeout % 1000,
+	};
+
+	if (-1 == platformNetwork->socket)
+	{
+		rlog_e("对端关闭socket连接");
+		return -1;
+	}
+
+	setsockopt(platformNetwork->socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
+		   sizeof(struct timeval)); // 设置操作模式为非阻塞
+
+	recvResult = recv(platformNetwork->socket, recvBuf, recvLen, 0);
+	if (0 == recvResult)
+	{
+		rlog_e("对端关闭socket连接");
+		return -1;
+	}
+
+	if (recvResult < 0) // 小于零,表示错误,个别错误不代表socket错误
+	{
+		int32_t rt_errno = errno; // 似乎RT 5.0.0以上版本需要使用 rt_get_errno
+		// 下列表示没问题,但需要退出接收
+		if (EAGAIN == rt_errno ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
+		    EWOULDBLOCK == rt_errno || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
+		    EINTR == rt_errno ||       // 操作被信号中断
+		    ETIME == rt_errno)         // 计时器过期
+		{
+			return 0;
+		}
+
+		// NOLINTNEXTLINE(concurrency-mt-unsafe)
+		rlog_e("recvResult: %d, errno: %d  str: %s", recvResult, rt_errno, strerror(rt_errno));
+		return -1;
+	}
+
+	return (int32_t)recvResult;
 }
 
 /**
@@ -278,60 +189,49 @@ RyanMqttError_e platformNetworkRecvAsync(void *userData, platformNetwork_t *plat
  * 接收超时或者接收数据长度不等于期待数据接受长度 RyanMqttRecvPacketTimeOutError
  * 接收成功 RyanMqttSuccessError
  */
-RyanMqttError_e platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf, int sendLen, int timeout)
+int32_t platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf, size_t sendLen,
+				 int32_t timeout)
 {
-
-    int32_t sendResult = 0;
-    int32_t offset = 0;
-    int32_t timeOut2 = timeout;
-    struct timeval tv = {0};
-    platformTimer_t timer = {0};
-
-    if (-1 == platformNetwork->socket)
-        return RyanSocketFailedError;
-
-    platformTimerCutdown(&timer, timeout);
-
-    while ((offset < sendLen) && (0 != timeOut2))
-    {
-
-        tv.tv_sec = timeOut2 / 1000;
-        tv.tv_usec = timeOut2 % 1000 * 1000;
-
-        if (tv.tv_sec <= 0 && tv.tv_usec <= 100)
-        {
-            tv.tv_sec = 0;
-            tv.tv_usec = 100;
-        }
-
-        setsockopt(platformNetwork->socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); // 设置错做模式为非阻塞
-
-        sendResult = send(platformNetwork->socket, sendBuf + offset, sendLen - offset, 0);
-        if (0 == sendResult)
-        {
-            rlog_d("对端关闭socket连接");
-            return RyanSocketFailedError;
-        }
-        else if (sendResult < 0) // 小于零,表示错误,个别错误不代表socket错误
-        {
-            int32_t err = errno;
-            // 下列3种表示没问题,但需要退出发送
-            if (err == EAGAIN ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
-                err == EWOULDBLOCK || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
-                err == EINTR)         // 操作被信号中断
-                break;
-
-            return RyanSocketFailedError;
-        }
-
-        offset += sendResult;
-        timeOut2 = platformTimerRemain(&timer);
-    }
-
-    if (offset != sendLen)
-        return RyanMqttSendPacketTimeOutError;
-
-    return RyanMqttSuccessError;
+	ssize_t sendResult = 0;
+	struct timeval tv = {
+		.tv_sec = timeout / 1000,
+		.tv_usec = 1000 * timeout % 1000,
+	};
+
+	if (-1 == platformNetwork->socket)
+	{
+		rlog_e("对端关闭socket连接");
+		return -1;
+	}
+
+	setsockopt(platformNetwork->socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv,
+		   sizeof(struct timeval)); // 设置操作模式为非阻塞
+
+	sendResult = send(platformNetwork->socket, sendBuf, sendLen, 0);
+	if (0 == sendResult)
+	{
+		rlog_e("对端关闭socket连接");
+		return -1;
+	}
+
+	if (sendResult < 0) // 小于零,表示错误,个别错误不代表socket错误
+	{
+		int32_t rt_errno = errno;      // 似乎5.0.0以上版本需要使用 rt_get_errno
+					       // 下列表示没问题,但需要退出发送
+		if (EAGAIN == rt_errno ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
+		    EWOULDBLOCK == rt_errno || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
+		    EINTR == rt_errno ||       // 操作被信号中断
+		    ETIME == rt_errno)         // 计时器过期
+		{
+			return 0;
+		}
+
+		// NOLINTNEXTLINE(concurrency-mt-unsafe)
+		rlog_e("sendResult: %d, errno: %d str: %s", sendResult, rt_errno, strerror(rt_errno));
+		return -1;
+	}
+
+	return (int32_t)sendResult;
 }
 
 /**
@@ -344,11 +244,12 @@ RyanMqttError_e platformNetworkSendAsync(void *userData, platformNetwork_t *plat
 RyanMqttError_e platformNetworkClose(void *userData, platformNetwork_t *platformNetwork)
 {
 
-    if (platformNetwork->socket >= 0)
-    {
-        close(platformNetwork->socket);
-        platformNetwork->socket = -1;
-    }
+	if (platformNetwork->socket >= 0)
+	{
+		close(platformNetwork->socket);
+		rlog_w("platformNetworkClose socket close %d", platformNetwork->socket);
+		platformNetwork->socket = -1;
+	}
 
-    return RyanMqttSuccessError;
+	return RyanMqttSuccessError;
 }

+ 22 - 18
platform/linux/platformNetwork.h

@@ -2,10 +2,15 @@
 #define __platformNetwork__
 
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif
 
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/param.h>
@@ -15,28 +20,27 @@ extern "C"
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
 #include <netdb.h>
-#include <stdio.h>
 #include <unistd.h>
-#include <errno.h>
 #include <fcntl.h>
-
-#include <stdlib.h>
-#include <string.h>
 #include <signal.h>
-#include "platformTimer.h"
+
 #include "RyanMqttPublic.h"
+#include "platformSystem.h"
 
-    typedef struct
-    {
-        int socket;
-    } platformNetwork_t;
+typedef struct
+{
+	int socket;
+} platformNetwork_t;
 
-    extern RyanMqttError_e platformNetworkInit(void *userData, platformNetwork_t *platformNetwork);
-    extern RyanMqttError_e platformNetworkDestroy(void *userData, platformNetwork_t *platformNetwork);
-    extern RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host, uint16_t port);
-    extern RyanMqttError_e platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf, int recvLen, int timeout);
-    extern RyanMqttError_e platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf, int sendLen, int timeout);
-    extern RyanMqttError_e platformNetworkClose(void *userData, platformNetwork_t *platformNetwork);
+extern RyanMqttError_e platformNetworkInit(void *userData, platformNetwork_t *platformNetwork);
+extern RyanMqttError_e platformNetworkDestroy(void *userData, platformNetwork_t *platformNetwork);
+extern RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host,
+					      uint16_t port);
+extern int32_t platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf,
+					size_t recvLen, int32_t timeout);
+extern int32_t platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf,
+					size_t sendLen, int32_t timeout);
+extern RyanMqttError_e platformNetworkClose(void *userData, platformNetwork_t *platformNetwork);
 
 #ifdef __cplusplus
 }

+ 57 - 50
platform/linux/platformSystem.c

@@ -9,7 +9,7 @@
  */
 inline void *platformMemoryMalloc(size_t size)
 {
-    return malloc(size);
+	return malloc(size);
 }
 
 /**
@@ -19,7 +19,7 @@ inline void *platformMemoryMalloc(size_t size)
  */
 inline void platformMemoryFree(void *ptr)
 {
-    free(ptr);
+	free(ptr);
 }
 
 /**
@@ -29,7 +29,17 @@ inline void platformMemoryFree(void *ptr)
  */
 inline void platformDelay(uint32_t ms)
 {
-    usleep(ms * 1000);
+	usleep(ms * 1000);
+}
+
+uint32_t platformUptimeMs(void)
+{
+	struct timespec ts;
+	if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
+	{
+		return 0;
+	}
+	return (uint32_t)(ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
 }
 
 /**
@@ -40,7 +50,7 @@ inline void platformDelay(uint32_t ms)
  */
 inline void platformPrint(char *str, uint16_t strLen)
 {
-    printf("%.*s", strLen, str);
+	printf("%.*s", strLen, str);
 }
 
 /**
@@ -55,28 +65,25 @@ inline void platformPrint(char *str, uint16_t strLen)
  * @param priority
  * @return RyanMqttError_e
  */
-RyanMqttError_e platformThreadInit(void *userData,
-                                   platformThread_t *platformThread,
-                                   const char *name,
-                                   void (*entry)(void *),
-                                   void *const param,
-                                   uint32_t stackSize,
-                                   uint32_t priority)
+RyanMqttError_e platformThreadInit(void *userData, platformThread_t *platformThread, const char *name,
+				   void (*entry)(void *), void *const param, uint32_t stackSize, uint32_t priority)
 {
 
-    pthread_attr_t attr = {0};
-    pthread_attr_init(&attr);
-    pthread_attr_setstacksize(&attr, stackSize);
-    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // 设置为分离状态
+	pthread_attr_t attr = {0};
+	pthread_attr_init(&attr);
+	pthread_attr_setstacksize(&attr, stackSize);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // 设置为分离状态
 
-    int ret = pthread_create(&platformThread->thread, &attr, (void *)entry, param);
-    if (0 != ret)
-        return RyanMqttNoRescourceError;
+	int ret = pthread_create(&platformThread->thread, &attr, (void *)entry, param);
+	if (0 != ret)
+	{
+		return RyanMqttNoRescourceError;
+	}
 
-    pthread_mutex_init(&platformThread->mutex, NULL);
-    pthread_cond_init(&platformThread->cond, NULL);
+	pthread_mutex_init(&platformThread->mutex, NULL);
+	pthread_cond_init(&platformThread->cond, NULL);
 
-    return RyanMqttSuccessError;
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -88,8 +95,8 @@ RyanMqttError_e platformThreadInit(void *userData,
  */
 RyanMqttError_e platformThreadDestroy(void *userData, platformThread_t *platformThread)
 {
-    pthread_exit(NULL);
-    return RyanMqttSuccessError;
+	pthread_exit(NULL);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -101,10 +108,10 @@ RyanMqttError_e platformThreadDestroy(void *userData, platformThread_t *platform
  */
 RyanMqttError_e platformThreadStart(void *userData, platformThread_t *platformThread)
 {
-    pthread_mutex_lock(&platformThread->mutex);
-    pthread_cond_signal(&platformThread->cond);
-    pthread_mutex_unlock(&platformThread->mutex);
-    return RyanMqttSuccessError;
+	pthread_mutex_lock(&platformThread->mutex);
+	pthread_cond_signal(&platformThread->cond);
+	pthread_mutex_unlock(&platformThread->mutex);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -116,10 +123,10 @@ RyanMqttError_e platformThreadStart(void *userData, platformThread_t *platformTh
  */
 RyanMqttError_e platformThreadStop(void *userData, platformThread_t *platformThread)
 {
-    pthread_mutex_lock(&platformThread->mutex);
-    pthread_cond_wait(&platformThread->cond, &platformThread->mutex);
-    pthread_mutex_unlock(&platformThread->mutex);
-    return RyanMqttSuccessError;
+	pthread_mutex_lock(&platformThread->mutex);
+	pthread_cond_wait(&platformThread->cond, &platformThread->mutex);
+	pthread_mutex_unlock(&platformThread->mutex);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -131,11 +138,11 @@ RyanMqttError_e platformThreadStop(void *userData, platformThread_t *platformThr
  */
 RyanMqttError_e platformMutexInit(void *userData, platformMutex_t *platformMutex)
 {
-    pthread_mutexattr_t attr;
-    pthread_mutexattr_init(&attr);
-    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
-    pthread_mutex_init(&platformMutex->mutex, &attr);
-    return RyanMqttSuccessError;
+	pthread_mutexattr_t attr;
+	pthread_mutexattr_init(&attr);
+	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+	pthread_mutex_init(&platformMutex->mutex, &attr);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -147,8 +154,8 @@ RyanMqttError_e platformMutexInit(void *userData, platformMutex_t *platformMutex
  */
 RyanMqttError_e platformMutexDestroy(void *userData, platformMutex_t *platformMutex)
 {
-    pthread_mutex_destroy(&platformMutex->mutex);
-    return RyanMqttSuccessError;
+	pthread_mutex_destroy(&platformMutex->mutex);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -160,8 +167,8 @@ RyanMqttError_e platformMutexDestroy(void *userData, platformMutex_t *platformMu
  */
 RyanMqttError_e platformMutexLock(void *userData, platformMutex_t *platformMutex)
 {
-    pthread_mutex_lock(&platformMutex->mutex); // 互斥锁上锁
-    return RyanMqttSuccessError;
+	pthread_mutex_lock(&platformMutex->mutex); // 互斥锁上锁
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -173,8 +180,8 @@ RyanMqttError_e platformMutexLock(void *userData, platformMutex_t *platformMutex
  */
 RyanMqttError_e platformMutexUnLock(void *userData, platformMutex_t *platformMutex)
 {
-    pthread_mutex_unlock(&platformMutex->mutex); // 互斥锁解锁
-    return RyanMqttSuccessError;
+	pthread_mutex_unlock(&platformMutex->mutex); // 互斥锁解锁
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -186,8 +193,8 @@ RyanMqttError_e platformMutexUnLock(void *userData, platformMutex_t *platformMut
  */
 RyanMqttError_e platformCriticalInit(void *userData, platformCritical_t *platformCritical)
 {
-    pthread_spin_init(&platformCritical->spin, PTHREAD_PROCESS_PRIVATE);
-    return RyanMqttSuccessError;
+	pthread_spin_init(&platformCritical->spin, PTHREAD_PROCESS_PRIVATE);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -199,8 +206,8 @@ RyanMqttError_e platformCriticalInit(void *userData, platformCritical_t *platfor
  */
 RyanMqttError_e platformCriticalDestroy(void *userData, platformCritical_t *platformCritical)
 {
-    pthread_spin_destroy(&platformCritical->spin);
-    return RyanMqttSuccessError;
+	pthread_spin_destroy(&platformCritical->spin);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -212,8 +219,8 @@ RyanMqttError_e platformCriticalDestroy(void *userData, platformCritical_t *plat
  */
 inline RyanMqttError_e platformCriticalEnter(void *userData, platformCritical_t *platformCritical)
 {
-    pthread_spin_lock(&platformCritical->spin);
-    return RyanMqttSuccessError;
+	pthread_spin_lock(&platformCritical->spin);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -225,6 +232,6 @@ inline RyanMqttError_e platformCriticalEnter(void *userData, platformCritical_t
  */
 inline RyanMqttError_e platformCriticalExit(void *userData, platformCritical_t *platformCritical)
 {
-    pthread_spin_unlock(&platformCritical->spin);
-    return RyanMqttSuccessError;
+	pthread_spin_unlock(&platformCritical->spin);
+	return RyanMqttSuccessError;
 }

+ 37 - 39
platform/linux/platformSystem.h

@@ -2,8 +2,7 @@
 #define __platformSystem__
 
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif
 
 #include <stdio.h>
@@ -11,54 +10,53 @@ extern "C"
 #include <assert.h>
 #include <pthread.h>
 #include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
 #include "RyanMqttPublic.h"
 #include "valloc.h"
 
-#define RyanMqttAssert(EX) assert(EX)
+#define platformAssert(EX) assert(EX)
 
-    typedef struct
-    {
-        pthread_t thread;
-        pthread_mutex_t mutex;
-        pthread_cond_t cond;
-    } platformThread_t;
+typedef struct
+{
+	pthread_t thread;
+	pthread_mutex_t mutex;
+	pthread_cond_t cond;
+} platformThread_t;
 
-    typedef struct
-    {
-        pthread_mutex_t mutex;
-    } platformMutex_t;
+typedef struct
+{
+	pthread_mutex_t mutex;
+} platformMutex_t;
 
-    typedef struct
-    {
-        pthread_spinlock_t spin;
-    } platformCritical_t;
+typedef struct
+{
+	pthread_spinlock_t spin;
+} platformCritical_t;
 
-    extern void *platformMemoryMalloc(size_t size);
-    extern void platformMemoryFree(void *ptr);
+extern void *platformMemoryMalloc(size_t size);
+extern void platformMemoryFree(void *ptr);
 
-    extern void platformPrint(char *str, uint16_t strLen);
-    extern void platformDelay(uint32_t ms);
+extern void platformPrint(char *str, uint16_t strLen);
+extern void platformDelay(uint32_t ms);
+extern uint32_t platformUptimeMs(void);
 
-    extern RyanMqttError_e platformThreadInit(void *userData,
-                                              platformThread_t *platformThread,
-                                              const char *name,
-                                              void (*entry)(void *),
-                                              void *const param,
-                                              uint32_t stackSize,
-                                              uint32_t priority);
-    extern RyanMqttError_e platformThreadDestroy(void *userData, platformThread_t *platformThread);
-    extern RyanMqttError_e platformThreadStart(void *userData, platformThread_t *platformThread);
-    extern RyanMqttError_e platformThreadStop(void *userData, platformThread_t *platformThread);
+extern RyanMqttError_e platformThreadInit(void *userData, platformThread_t *platformThread, const char *name,
+					  void (*entry)(void *), void *const param, uint32_t stackSize,
+					  uint32_t priority);
+extern RyanMqttError_e platformThreadDestroy(void *userData, platformThread_t *platformThread);
+extern RyanMqttError_e platformThreadStart(void *userData, platformThread_t *platformThread);
+extern RyanMqttError_e platformThreadStop(void *userData, platformThread_t *platformThread);
 
-    extern RyanMqttError_e platformMutexInit(void *userData, platformMutex_t *platformMutex);
-    extern RyanMqttError_e platformMutexDestroy(void *userData, platformMutex_t *platformMutex);
-    extern RyanMqttError_e platformMutexLock(void *userData, platformMutex_t *platformMutex);
-    extern RyanMqttError_e platformMutexUnLock(void *userData, platformMutex_t *platformMutex);
+extern RyanMqttError_e platformMutexInit(void *userData, platformMutex_t *platformMutex);
+extern RyanMqttError_e platformMutexDestroy(void *userData, platformMutex_t *platformMutex);
+extern RyanMqttError_e platformMutexLock(void *userData, platformMutex_t *platformMutex);
+extern RyanMqttError_e platformMutexUnLock(void *userData, platformMutex_t *platformMutex);
 
-    extern RyanMqttError_e platformCriticalInit(void *userData, platformCritical_t *platformCritical);
-    extern RyanMqttError_e platformCriticalDestroy(void *userData, platformCritical_t *platformCritical);
-    extern RyanMqttError_e platformCriticalEnter(void *userData, platformCritical_t *platformCritical);
-    extern RyanMqttError_e platformCriticalExit(void *userData, platformCritical_t *platformCritical);
+extern RyanMqttError_e platformCriticalInit(void *userData, platformCritical_t *platformCritical);
+extern RyanMqttError_e platformCriticalDestroy(void *userData, platformCritical_t *platformCritical);
+extern RyanMqttError_e platformCriticalEnter(void *userData, platformCritical_t *platformCritical);
+extern RyanMqttError_e platformCriticalExit(void *userData, platformCritical_t *platformCritical);
 
 #ifdef __cplusplus
 }

+ 0 - 42
platform/linux/platformTimer.c

@@ -1,42 +0,0 @@
-
-
-#include "platformTimer.h"
-
-/**
- * @brief 初始化定时器
- *
- * @param platformTimer
- */
-void platformTimerInit(platformTimer_t *platformTimer)
-{
-    platformTimer->time.tv_sec = 0;
-    platformTimer->time.tv_usec = 0;
-}
-
-/**
- * @brief 添加计数时间
- *
- * @param platformTimer
- * @param timeout
- */
-void platformTimerCutdown(platformTimer_t *platformTimer, uint32_t timeout)
-{
-    struct timeval now = {0};
-    gettimeofday(&now, NULL);
-    struct timeval interval = {timeout / 1000, (timeout % 1000) * 1000};
-    timeradd(&now, &interval, &platformTimer->time);
-}
-
-/**
- * @brief 计算time还有多长时间超时,考虑了32位溢出判断
- *
- * @param platformTimer
- * @return uint32_t 返回剩余时间,超时返回0
- */
-uint32_t platformTimerRemain(platformTimer_t *platformTimer)
-{
-    struct timeval now = {0}, res = {0};
-    gettimeofday(&now, NULL);
-    timersub(&platformTimer->time, &now, &res);
-    return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000;
-}

+ 0 - 24
platform/linux/platformTimer.h

@@ -1,24 +0,0 @@
-#ifndef __platformTimer__
-#define __platformTimer__
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-#include <stdint.h>
-#include <stddef.h>
-#include <sys/time.h>
-
-    typedef struct
-    {
-        struct timeval time;
-    } platformTimer_t;
-
-    extern void platformTimerInit(platformTimer_t *platformTimer);
-    extern void platformTimerCutdown(platformTimer_t *platformTimer, uint32_t timeout);
-    extern uint32_t platformTimerRemain(platformTimer_t *platformTimer);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif

+ 70 - 56
platform/linux/valloc/valloc.c

@@ -10,88 +10,102 @@ static int use = 0;
 
 void *v_malloc(size_t size)
 {
-    void *p;
-    p = malloc(size ? size + sizeof(int) : 0);
-    if (!p)
-        return NULL;
+	void *p;
+	p = malloc(size ? size + sizeof(int) : 0);
+	if (!p)
+	{
+		return NULL;
+	}
 
-    pthread_mutex_lock(&mutex); // 互斥锁上锁
-    count++;
-    *(int *)p = size;
-    use += size;
-    pthread_mutex_unlock(&mutex); // 互斥锁解锁
-    return (void *)((char *)p + sizeof(int));
+	pthread_mutex_lock(&mutex); // 互斥锁上锁
+	count++;
+	*(int *)p = size;
+	use += size;
+	pthread_mutex_unlock(&mutex); // 互斥锁解锁
+	return (void *)((char *)p + sizeof(int));
 }
 
 void *v_calloc(size_t num, size_t size)
 {
-    void *p;
-    p = v_malloc(num * size);
-    if (!p)
-        return NULL;
-    memset(p, 0, num * size);
-    return p;
+	void *p;
+	p = v_malloc(num * size);
+	if (!p)
+	{
+		return NULL;
+	}
+	memset(p, 0, num * size);
+	return p;
 }
 
 void v_free(void *block)
 {
-    void *p;
-    if (!block)
-        return;
-    p = (void *)((char *)block - sizeof(int));
+	void *p;
+	if (!block)
+	{
+		return;
+	}
+	p = (void *)((char *)block - sizeof(int));
 
-    pthread_mutex_lock(&mutex); // 互斥锁上锁
-    use -= *(int *)p;
-    count--;
-    pthread_mutex_unlock(&mutex); // 互斥锁解锁
+	pthread_mutex_lock(&mutex); // 互斥锁上锁
+	use -= *(int *)p;
+	count--;
+	pthread_mutex_unlock(&mutex); // 互斥锁解锁
 
-    free(p);
+	free(p);
 }
 
 void *v_realloc(void *block, size_t size)
 {
-    void *p;
-    int s = 0;
-    if (block)
-    {
-        block = (void *)((char *)block - sizeof(int));
-        s = *(int *)block;
-    }
-    p = realloc(block, size ? size + sizeof(int) : 0);
-    if (!p)
-        return NULL;
+	void *p;
+	int s = 0;
+	if (block)
+	{
+		block = (void *)((char *)block - sizeof(int));
+		s = *(int *)block;
+	}
+	p = realloc(block, size ? size + sizeof(int) : 0);
+	if (!p)
+	{
+		return NULL;
+	}
 
-    pthread_mutex_lock(&mutex); // 互斥锁上锁
-    if (!block)
-        count++;
-    *(int *)p = size;
-    use += (size - s);
-    pthread_mutex_unlock(&mutex); // 互斥锁解锁
+	pthread_mutex_lock(&mutex); // 互斥锁上锁
+	if (!block)
+	{
+		count++;
+	}
+	*(int *)p = size;
+	use += (size - s);
+	pthread_mutex_unlock(&mutex); // 互斥锁解锁
 
-    return (void *)((char *)p + sizeof(int));
+	return (void *)((char *)p + sizeof(int));
 }
 
 int v_mcheck(int *_count, int *_use)
 {
-    pthread_mutex_lock(&mutex); // 互斥锁上锁
-    if (_count)
-        *_count = count;
-    if (_use)
-        *_use = use;
-    pthread_mutex_unlock(&mutex); // 互斥锁解锁
+	pthread_mutex_lock(&mutex); // 互斥锁上锁
+	if (_count)
+	{
+		*_count = count;
+	}
+	if (_use)
+	{
+		*_use = use;
+	}
+	pthread_mutex_unlock(&mutex); // 互斥锁解锁
 
-    return 0;
+	return 0;
 }
 
-void displayMem()
+void displayMem(void)
 {
-    int area = 0, use = 0;
-    v_mcheck(&area, &use);
-    printf("|||----------->>> area = %d, size = %d\r\n", area, use);
+	int area = 0, use = 0;
+	v_mcheck(&area, &use);
+	printf("|||----------->>> area = %d, size = %d\r\n", area, use);
 }
 
-void vallocInit()
+void vallocInit(void)
 {
-    /* 初始化互斥锁 */
-    pthread_mutex_init(&mutex, NULL);
+	/* 初始化互斥锁 */
+	pthread_mutex_init(&mutex, NULL);
 }

+ 2 - 2
platform/linux/valloc/valloc.h

@@ -23,8 +23,8 @@ extern "C"
     void v_free(void *block);
     void *v_realloc(void *block, size_t size);
     int v_mcheck(int *_count, int *_use);
-    void displayMem();
-    void vallocInit();
+    void displayMem(void);
+    void vallocInit(void);
 
 #define malloc v_malloc
 #define calloc v_calloc

+ 169 - 175
platform/openLuat/platformNetwork.c

@@ -1,7 +1,4 @@
-#define rlogEnable               // 是否使能日志
-#define rlogColorEnable          // 是否使能日志颜色
 #define rlogLevel (rlogLvlDebug) // 日志打印等级
-#define rlogTag "RyanMqttNet"    // 日志tag
 
 #include "platformNetwork.h"
 #include "RyanMqttLog.h"
@@ -15,8 +12,8 @@
  */
 RyanMqttError_e platformNetworkInit(void *userData, platformNetwork_t *platformNetwork)
 {
-    platformNetwork->socket = -1;
-    return RyanMqttSuccessError;
+	platformNetwork->socket = -1;
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -28,8 +25,8 @@ RyanMqttError_e platformNetworkInit(void *userData, platformNetwork_t *platformN
  */
 RyanMqttError_e platformNetworkDestroy(void *userData, platformNetwork_t *platformNetwork)
 {
-    platformNetwork->socket = -1;
-    return RyanMqttSuccessError;
+	platformNetwork->socket = -1;
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -42,60 +39,83 @@ RyanMqttError_e platformNetworkDestroy(void *userData, platformNetwork_t *platfo
  * @return RyanMqttError_e
  * 成功返回RyanMqttSuccessError, 失败返回错误信息
  */
-RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host, uint16_t port)
+RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host,
+				       uint16_t port)
 {
-    RyanMqttError_e result = RyanMqttSuccessError;
-
-    struct hostent hostinfo = {0};
-
-    // 解析域名信息
-    {
-        char buf[512];
-        int h_errnop;
-        struct hostent *phost;
-
-        if (0 != gethostbyname_r(host, &hostinfo, buf, sizeof(buf), &phost, &h_errnop))
-        {
-            rlog_w("平台可能不支持 gethostbyname_r 函数, 再次尝试使用 gethostbyname 获取域名信息");
-
-            // 非线程安全版本,请根据实际情况选择使用
-            // NOLINTNEXTLINE(concurrency-mt-unsafe)
-            struct hostent *phostinfo = gethostbyname(host);
-            if (NULL == phostinfo)
-            {
-                result = RyanMqttNoRescourceError;
-                goto __exit;
-            }
-
-            hostinfo = *phostinfo;
-        }
-    }
-
-    platformNetwork->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
-    if (platformNetwork->socket < 0)
-    {
-        result = RyanSocketFailedError;
-        goto __exit;
-    }
-
-    struct sockaddr_in server_addr = {
-        .sin_family = AF_INET,
-        .sin_port = htons(port), // 指定端口号
-        .sin_addr = *((struct in_addr *)hostinfo.h_addr_list[0]),
-    };
-
-    // 绑定套接字到主机地址和端口号
-    if (connect(platformNetwork->socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0)
-    {
-        platformNetworkClose(userData, platformNetwork);
-        result = RyanMqttSocketConnectFailError;
-        goto __exit;
-    }
+	RyanMqttError_e result = RyanMqttSuccessError;
+	char *buf = NULL;
+	struct sockaddr_in server_addr = {
+		.sin_family = AF_INET,
+		.sin_port = htons(port), // 指定端口号
+	};
+
+	// 传递的是ip地址,不用进行dns解析,某些情况下调用dns解析反而会错误
+	if (INADDR_NONE != inet_addr(host))
+	{
+		rlog_d("host: %s, 不用dns解析", host);
+		server_addr.sin_addr.s_addr = inet_addr(host);
+	}
+	// 解析域名信息
+	else
+	{
+#define dnsBufferSize (384)
+		rlog_d("host: %s, 需要dns解析", host);
+		int h_errnop;
+		struct hostent *phost;
+		struct hostent hostinfo = {0};
+
+		buf = (char *)platformMemoryMalloc(dnsBufferSize);
+		if (NULL == buf)
+		{
+			result = RyanMqttNoRescourceError;
+			goto __exit;
+		}
+
+		if (0 != gethostbyname_r(host, &hostinfo, buf, dnsBufferSize, &phost, &h_errnop))
+		{
+			rlog_w("平台可能不支持 gethostbyname_r 函数, 再次尝试使用 gethostbyname 获取域名信息");
+
+			// 非线程安全版本,请根据实际情况选择使用
+			// NOLINTNEXTLINE(concurrency-mt-unsafe)
+			struct hostent *phostinfo = gethostbyname(host);
+			if (NULL == phostinfo)
+			{
+				result = RyanMqttNoRescourceError;
+				goto __exit;
+			}
+
+			hostinfo = *phostinfo;
+		}
+
+		server_addr.sin_addr = *((struct in_addr *)hostinfo.h_addr_list[0]);
+	}
+
+	platformNetwork->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+	if (platformNetwork->socket < 0)
+	{
+		result = RyanSocketFailedError;
+		goto __exit;
+	}
+
+	// 绑定套接字到主机地址和端口号
+	if (connect(platformNetwork->socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0)
+	{
+		platformNetworkClose(userData, platformNetwork);
+		result = RyanMqttSocketConnectFailError;
+		goto __exit;
+	}
 
 __exit:
-    if (RyanMqttSuccessError != result)
-        rlog_e("socket连接失败: %d", result);
-    return result;
+	if (NULL != buf)
+	{
+		platformMemoryFree(buf);
+	}
+
+	if (RyanMqttSuccessError != result)
+	{
+		rlog_e("socket连接失败: %d", result);
+	}
+	return result;
 }
 
 /**
@@ -111,62 +131,49 @@ __exit:
  * 接收超时或者接收数据长度不等于期待数据接受长度 RyanMqttRecvPacketTimeOutError
  * 接收成功 RyanMqttSuccessError
  */
-RyanMqttError_e platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf, int recvLen, int timeout)
+int32_t platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf, size_t recvLen,
+				 int32_t timeout)
 {
-
-    int32_t recvResult = 0;
-    int32_t offset = 0;
-    int32_t timeOut2 = timeout;
-    struct timeval tv = {0};
-    platformTimer_t timer = {0};
-
-    if (-1 == platformNetwork->socket)
-    {
-        rlog_e("对端关闭socket连接");
-        return RyanMqttNoRescourceError;
-    }
-
-    platformTimerCutdown(&timer, timeout);
-
-    while ((offset < recvLen) && (0 != timeOut2))
-    {
-        tv.tv_sec = timeOut2 / 1000;
-        tv.tv_usec = timeOut2 % 1000 * 1000;
-
-        setsockopt(platformNetwork->socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); // 设置错做模式为非阻塞
-
-        recvResult = recv(platformNetwork->socket, recvBuf + offset, recvLen - offset, 0);
-        if (0 == recvResult)
-        {
-            rlog_e("对端关闭socket连接");
-            return RyanMqttNoRescourceError;
-        }
-        else if (recvResult < 0) // 小于零,表示错误,个别错误不代表socket错误
-        {
-            int32_t rt_errno = errno; // 似乎5.0.0以上版本需要使用 rt_get_errno
-
-            // 下列表示没问题,但需要退出接收
-            if (EAGAIN == rt_errno ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
-                EWOULDBLOCK == rt_errno || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
-                EINTR == rt_errno ||       // 操作被信号中断
-                ETIME == rt_errno)         // 计时器过期
-            {
-                break;
-            }
-
-            // NOLINTNEXTLINE(concurrency-mt-unsafe)
-            rlog_e("recvResult: %d, errno: %d  str: %s", recvResult, rt_errno, strerror(rt_errno));
-            return RyanSocketFailedError;
-        }
-
-        offset += recvResult;
-        timeOut2 = platformTimerRemain(&timer);
-    }
-
-    if (offset != recvLen)
-        return RyanMqttRecvPacketTimeOutError;
-
-    return RyanMqttSuccessError;
+	ssize_t recvResult = 0;
+	struct timeval tv = {
+		.tv_sec = timeout / 1000,
+		.tv_usec = 1000 * timeout % 1000,
+	};
+
+	if (-1 == platformNetwork->socket)
+	{
+		rlog_e("对端关闭socket连接");
+		return -1;
+	}
+
+	setsockopt(platformNetwork->socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
+		   sizeof(struct timeval)); // 设置操作模式为非阻塞
+
+	recvResult = recv(platformNetwork->socket, recvBuf, recvLen, 0);
+	if (0 == recvResult)
+	{
+		rlog_e("对端关闭socket连接");
+		return -1;
+	}
+
+	if (recvResult < 0) // 小于零,表示错误,个别错误不代表socket错误
+	{
+		int32_t rt_errno = errno; // 似乎RT 5.0.0以上版本需要使用 rt_get_errno
+		// 下列表示没问题,但需要退出接收
+		if (EAGAIN == rt_errno ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
+		    EWOULDBLOCK == rt_errno || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
+		    EINTR == rt_errno ||       // 操作被信号中断
+		    ETIME == rt_errno)         // 计时器过期
+		{
+			return 0;
+		}
+
+		// NOLINTNEXTLINE(concurrency-mt-unsafe)
+		rlog_e("recvResult: %d, errno: %d  str: %s", recvResult, rt_errno, strerror(rt_errno));
+		return -1;
+	}
+
+	return (int32_t)recvResult;
 }
 
 /**
@@ -182,62 +189,49 @@ RyanMqttError_e platformNetworkRecvAsync(void *userData, platformNetwork_t *plat
  * 接收超时或者接收数据长度不等于期待数据接受长度 RyanMqttRecvPacketTimeOutError
  * 接收成功 RyanMqttSuccessError
  */
-RyanMqttError_e platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf, int sendLen, int timeout)
+int32_t platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf, size_t sendLen,
+				 int32_t timeout)
 {
-
-    int32_t sendResult = 0;
-    int32_t offset = 0;
-    int32_t timeOut2 = timeout;
-    struct timeval tv = {0};
-    platformTimer_t timer = {0};
-
-    if (-1 == platformNetwork->socket)
-    {
-        rlog_e("对端关闭socket连接");
-        return RyanMqttNoRescourceError;
-    }
-
-    platformTimerCutdown(&timer, timeout);
-
-    while ((offset < sendLen) && (0 != timeOut2))
-    {
-        tv.tv_sec = timeOut2 / 1000;
-        tv.tv_usec = timeOut2 % 1000 * 1000;
-
-        setsockopt(platformNetwork->socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); // 设置错做模式为非阻塞
-
-        sendResult = send(platformNetwork->socket, sendBuf + offset, sendLen - offset, 0);
-        if (0 == sendResult)
-        {
-            rlog_e("对端关闭socket连接");
-            return RyanMqttNoRescourceError;
-        }
-        else if (sendResult < 0) // 小于零,表示错误,个别错误不代表socket错误
-        {
-            int32_t rt_errno = errno; // 似乎5.0.0以上版本需要使用 rt_get_errno
-
-            // 下列表示没问题,但需要退出发送
-            if (EAGAIN == rt_errno ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
-                EWOULDBLOCK == rt_errno || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
-                EINTR == rt_errno ||       // 操作被信号中断
-                ETIME == rt_errno)         // 计时器过期
-            {
-                break;
-            }
-
-            // NOLINTNEXTLINE(concurrency-mt-unsafe)
-            rlog_e("sendResult: %d, errno: %d str: %s", sendResult, rt_errno, strerror(rt_errno));
-            return RyanSocketFailedError;
-        }
-
-        offset += sendResult;
-        timeOut2 = platformTimerRemain(&timer);
-    }
-
-    if (offset != sendLen)
-        return RyanMqttSendPacketTimeOutError;
-
-    return RyanMqttSuccessError;
+	ssize_t sendResult = 0;
+	struct timeval tv = {
+		.tv_sec = timeout / 1000,
+		.tv_usec = 1000 * timeout % 1000,
+	};
+
+	if (-1 == platformNetwork->socket)
+	{
+		rlog_e("对端关闭socket连接");
+		return -1;
+	}
+
+	setsockopt(platformNetwork->socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv,
+		   sizeof(struct timeval)); // 设置操作模式为非阻塞
+
+	sendResult = send(platformNetwork->socket, sendBuf, sendLen, 0);
+	if (0 == sendResult)
+	{
+		rlog_e("对端关闭socket连接");
+		return -1;
+	}
+
+	if (sendResult < 0) // 小于零,表示错误,个别错误不代表socket错误
+	{
+		int32_t rt_errno = errno;      // 似乎5.0.0以上版本需要使用 rt_get_errno
+					       // 下列表示没问题,但需要退出发送
+		if (EAGAIN == rt_errno ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
+		    EWOULDBLOCK == rt_errno || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
+		    EINTR == rt_errno ||       // 操作被信号中断
+		    ETIME == rt_errno)         // 计时器过期
+		{
+			return 0;
+		}
+
+		// NOLINTNEXTLINE(concurrency-mt-unsafe)
+		rlog_e("sendResult: %d, errno: %d str: %s", sendResult, rt_errno, strerror(rt_errno));
+		return -1;
+	}
+
+	return (int32_t)sendResult;
 }
 
 /**
@@ -250,12 +244,12 @@ RyanMqttError_e platformNetworkSendAsync(void *userData, platformNetwork_t *plat
 RyanMqttError_e platformNetworkClose(void *userData, platformNetwork_t *platformNetwork)
 {
 
-    if (platformNetwork->socket >= 0)
-    {
-        closesocket(platformNetwork->socket);
-        rlog_w("platformNetworkClose socket close %d", platformNetwork->socket);
-        platformNetwork->socket = -1;
-    }
+	if (platformNetwork->socket >= 0)
+	{
+		close(platformNetwork->socket);
+		rlog_w("platformNetworkClose socket close %d", platformNetwork->socket);
+		platformNetwork->socket = -1;
+	}
 
-    return RyanMqttSuccessError;
+	return RyanMqttSuccessError;
 }

+ 14 - 12
platform/openLuat/platformNetwork.h

@@ -2,8 +2,7 @@
 #define __platformNetwork__
 
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif
 
 #include <stdio.h>
@@ -21,17 +20,20 @@ extern "C"
 #include "lwip/sockets.h"
 #include "lwip/netdb.h"
 
-    typedef struct
-    {
-        int socket;
-    } platformNetwork_t;
+typedef struct
+{
+	int socket;
+} platformNetwork_t;
 
-    extern RyanMqttError_e platformNetworkInit(void *userData, platformNetwork_t *platformNetwork);
-    extern RyanMqttError_e platformNetworkDestroy(void *userData, platformNetwork_t *platformNetwork);
-    extern RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host, uint16_t port);
-    extern RyanMqttError_e platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf, int recvLen, int timeout);
-    extern RyanMqttError_e platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf, int sendLen, int timeout);
-    extern RyanMqttError_e platformNetworkClose(void *userData, platformNetwork_t *platformNetwork);
+extern RyanMqttError_e platformNetworkInit(void *userData, platformNetwork_t *platformNetwork);
+extern RyanMqttError_e platformNetworkDestroy(void *userData, platformNetwork_t *platformNetwork);
+extern RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host,
+					      uint16_t port);
+extern int32_t platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf,
+					size_t recvLen, int32_t timeout);
+extern int32_t platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf,
+					size_t sendLen, int32_t timeout);
+extern RyanMqttError_e platformNetworkClose(void *userData, platformNetwork_t *platformNetwork);
 
 #ifdef __cplusplus
 }

+ 51 - 42
platform/openLuat/platformSystem.c

@@ -9,7 +9,7 @@
  */
 inline void *platformMemoryMalloc(size_t size)
 {
-    return luat_heap_malloc(size);
+	return luat_heap_malloc(size);
 }
 
 /**
@@ -19,7 +19,7 @@ inline void *platformMemoryMalloc(size_t size)
  */
 inline void platformMemoryFree(void *ptr)
 {
-    luat_heap_free(ptr);
+	luat_heap_free(ptr);
 }
 
 /**
@@ -29,7 +29,19 @@ inline void platformMemoryFree(void *ptr)
  */
 inline void platformDelay(uint32_t ms)
 {
-    luat_rtos_task_sleep(luat_rtos_ms2tick(ms));
+	luat_rtos_task_sleep(luat_rtos_ms2tick(ms));
+}
+
+uint32_t platformUptimeMs(void)
+{
+	if (1000 == luat_mcu_hz())
+	{
+		return (uint32_t)luat_mcu_ticks();
+	}
+
+	// 已经不能提供精准的ms了
+	uint32_t tick = luat_mcu_ticks();
+	return (uint32_t)((tick * 1000 + luat_mcu_hz() - 1) / luat_mcu_hz());
 }
 
 /**
@@ -40,7 +52,7 @@ inline void platformDelay(uint32_t ms)
  */
 inline void platformPrint(char *str, uint16_t strLen)
 {
-    luat_debug_print("%.*s", strLen, str);
+	luat_debug_print("%.*s", strLen, str);
 }
 
 /**
@@ -55,27 +67,24 @@ inline void platformPrint(char *str, uint16_t strLen)
  * @param priority
  * @return RyanMqttError_e
  */
-RyanMqttError_e platformThreadInit(void *userData,
-                                   platformThread_t *platformThread,
-                                   const char *name,
-                                   void (*entry)(void *),
-                                   void *const param,
-                                   uint32_t stackSize,
-                                   uint32_t priority)
+RyanMqttError_e platformThreadInit(void *userData, platformThread_t *platformThread, const char *name,
+				   void (*entry)(void *), void *const param, uint32_t stackSize, uint32_t priority)
 {
-    // 36 减
-    int32_t result = luat_rtos_task_create(&platformThread->thread, // 线程句柄
-                                           stackSize,               // 线程栈大小
-                                           priority,                // 线程优先级
-                                           name,                    // 线程name
-                                           entry,                   // 线程入口函数
-                                           param,                   // 线程入口函数参数
-                                           priority);
+	// 36 减
+	int32_t result = luat_rtos_task_create(&platformThread->thread, // 线程句柄
+					       stackSize,               // 线程栈大小
+					       priority,                // 线程优先级
+					       name,                    // 线程name
+					       entry,                   // 线程入口函数
+					       param,                   // 线程入口函数参数
+					       priority);
 
-    if (0 != result)
-        return RyanMqttNoRescourceError;
+	if (0 != result)
+	{
+		return RyanMqttNoRescourceError;
+	}
 
-    return RyanMqttSuccessError;
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -87,8 +96,8 @@ RyanMqttError_e platformThreadInit(void *userData,
  */
 RyanMqttError_e platformThreadDestroy(void *userData, platformThread_t *platformThread)
 {
-    luat_rtos_task_delete(platformThread->thread);
-    return RyanMqttSuccessError;
+	luat_rtos_task_delete(platformThread->thread);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -101,8 +110,8 @@ RyanMqttError_e platformThreadDestroy(void *userData, platformThread_t *platform
 RyanMqttError_e platformThreadStart(void *userData, platformThread_t *platformThread)
 {
 
-    luat_rtos_task_resume(platformThread->thread);
-    return RyanMqttSuccessError;
+	luat_rtos_task_resume(platformThread->thread);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -114,8 +123,8 @@ RyanMqttError_e platformThreadStart(void *userData, platformThread_t *platformTh
  */
 RyanMqttError_e platformThreadStop(void *userData, platformThread_t *platformThread)
 {
-    luat_rtos_task_suspend(platformThread->thread);
-    return RyanMqttSuccessError;
+	luat_rtos_task_suspend(platformThread->thread);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -127,8 +136,8 @@ RyanMqttError_e platformThreadStop(void *userData, platformThread_t *platformThr
  */
 RyanMqttError_e platformMutexInit(void *userData, platformMutex_t *platformMutex)
 {
-    luat_rtos_mutex_create(&platformMutex->mutex);
-    return RyanMqttSuccessError;
+	luat_rtos_mutex_create(&platformMutex->mutex);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -140,8 +149,8 @@ RyanMqttError_e platformMutexInit(void *userData, platformMutex_t *platformMutex
  */
 RyanMqttError_e platformMutexDestroy(void *userData, platformMutex_t *platformMutex)
 {
-    luat_rtos_mutex_delete(platformMutex->mutex);
-    return RyanMqttSuccessError;
+	luat_rtos_mutex_delete(platformMutex->mutex);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -153,8 +162,8 @@ RyanMqttError_e platformMutexDestroy(void *userData, platformMutex_t *platformMu
  */
 RyanMqttError_e platformMutexLock(void *userData, platformMutex_t *platformMutex)
 {
-    luat_rtos_mutex_lock(platformMutex->mutex, LUAT_WAIT_FOREVER);
-    return RyanMqttSuccessError;
+	luat_rtos_mutex_lock(platformMutex->mutex, LUAT_WAIT_FOREVER);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -166,8 +175,8 @@ RyanMqttError_e platformMutexLock(void *userData, platformMutex_t *platformMutex
  */
 RyanMqttError_e platformMutexUnLock(void *userData, platformMutex_t *platformMutex)
 {
-    luat_rtos_mutex_unlock(platformMutex->mutex);
-    return RyanMqttSuccessError;
+	luat_rtos_mutex_unlock(platformMutex->mutex);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -179,7 +188,7 @@ RyanMqttError_e platformMutexUnLock(void *userData, platformMutex_t *platformMut
  */
 RyanMqttError_e platformCriticalInit(void *userData, platformCritical_t *platformCritical)
 {
-    return RyanMqttSuccessError;
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -191,7 +200,7 @@ RyanMqttError_e platformCriticalInit(void *userData, platformCritical_t *platfor
  */
 RyanMqttError_e platformCriticalDestroy(void *userData, platformCritical_t *platformCritical)
 {
-    return RyanMqttSuccessError;
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -203,8 +212,8 @@ RyanMqttError_e platformCriticalDestroy(void *userData, platformCritical_t *plat
  */
 inline RyanMqttError_e platformCriticalEnter(void *userData, platformCritical_t *platformCritical)
 {
-    platformCritical->level = luat_rtos_entry_critical();
-    return RyanMqttSuccessError;
+	platformCritical->level = luat_rtos_entry_critical();
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -216,6 +225,6 @@ inline RyanMqttError_e platformCriticalEnter(void *userData, platformCritical_t
  */
 inline RyanMqttError_e platformCriticalExit(void *userData, platformCritical_t *platformCritical)
 {
-    luat_rtos_exit_critical(platformCritical->level);
-    return RyanMqttSuccessError;
+	luat_rtos_exit_critical(platformCritical->level);
+	return RyanMqttSuccessError;
 }

+ 38 - 42
platform/openLuat/platformSystem.h

@@ -2,8 +2,7 @@
 #define __platformSystem__
 
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif
 
 #include <stdio.h>
@@ -14,49 +13,46 @@ extern "C"
 #include "luat_malloc.h"
 #include "luat_rtos.h"
 
-#define RyanMqttAssert(EX) assert(EX)
-
-    typedef struct
-    {
-        luat_rtos_task_handle thread;
-    } platformThread_t;
-
-    typedef struct
-    {
-        luat_rtos_mutex_t mutex;
-    } platformMutex_t;
-
-    typedef struct
-    {
-        uint32_t level;
-    } platformCritical_t;
-
-    extern void *platformMemoryMalloc(size_t size);
-    extern void platformMemoryFree(void *ptr);
+#define platformAssert(EX) assert(EX)
 
-    extern void platformPrint(char *str, uint16_t strLen);
-    extern void platformDelay(uint32_t ms);
-
-    extern RyanMqttError_e platformThreadInit(void *userData,
-                                              platformThread_t *platformThread,
-                                              const char *name,
-                                              void (*entry)(void *),
-                                              void *const param,
-                                              uint32_t stackSize,
-                                              uint32_t priority);
-    extern RyanMqttError_e platformThreadDestroy(void *userData, platformThread_t *platformThread);
-    extern RyanMqttError_e platformThreadStart(void *userData, platformThread_t *platformThread);
-    extern RyanMqttError_e platformThreadStop(void *userData, platformThread_t *platformThread);
+typedef struct
+{
+	luat_rtos_task_handle thread;
+} platformThread_t;
 
-    extern RyanMqttError_e platformMutexInit(void *userData, platformMutex_t *platformMutex);
-    extern RyanMqttError_e platformMutexDestroy(void *userData, platformMutex_t *platformMutex);
-    extern RyanMqttError_e platformMutexLock(void *userData, platformMutex_t *platformMutex);
-    extern RyanMqttError_e platformMutexUnLock(void *userData, platformMutex_t *platformMutex);
+typedef struct
+{
+	luat_rtos_mutex_t mutex;
+} platformMutex_t;
 
-    extern RyanMqttError_e platformCriticalInit(void *userData, platformCritical_t *platformCritical);
-    extern RyanMqttError_e platformCriticalDestroy(void *userData, platformCritical_t *platformCritical);
-    extern RyanMqttError_e platformCriticalEnter(void *userData, platformCritical_t *platformCritical);
-    extern RyanMqttError_e platformCriticalExit(void *userData, platformCritical_t *platformCritical);
+typedef struct
+{
+	uint32_t level;
+} platformCritical_t;
+
+extern void *platformMemoryMalloc(size_t size);
+extern void platformMemoryFree(void *ptr);
+
+extern void platformPrint(char *str, uint16_t strLen);
+extern void platformDelay(uint32_t ms);
+extern uint32_t platformUptimeMs(void);
+
+extern RyanMqttError_e platformThreadInit(void *userData, platformThread_t *platformThread, const char *name,
+					  void (*entry)(void *), void *const param, uint32_t stackSize,
+					  uint32_t priority);
+extern RyanMqttError_e platformThreadDestroy(void *userData, platformThread_t *platformThread);
+extern RyanMqttError_e platformThreadStart(void *userData, platformThread_t *platformThread);
+extern RyanMqttError_e platformThreadStop(void *userData, platformThread_t *platformThread);
+
+extern RyanMqttError_e platformMutexInit(void *userData, platformMutex_t *platformMutex);
+extern RyanMqttError_e platformMutexDestroy(void *userData, platformMutex_t *platformMutex);
+extern RyanMqttError_e platformMutexLock(void *userData, platformMutex_t *platformMutex);
+extern RyanMqttError_e platformMutexUnLock(void *userData, platformMutex_t *platformMutex);
+
+extern RyanMqttError_e platformCriticalInit(void *userData, platformCritical_t *platformCritical);
+extern RyanMqttError_e platformCriticalDestroy(void *userData, platformCritical_t *platformCritical);
+extern RyanMqttError_e platformCriticalEnter(void *userData, platformCritical_t *platformCritical);
+extern RyanMqttError_e platformCriticalExit(void *userData, platformCritical_t *platformCritical);
 
 #ifdef __cplusplus
 }

+ 0 - 66
platform/openLuat/platformTimer.c

@@ -1,66 +0,0 @@
-
-
-#include "platformTimer.h"
-
-uint32_t platformUptimeMs(void)
-{
-    if (1000 == luat_mcu_hz())
-        return (uint32_t)luat_mcu_ticks();
-
-    uint32_t tick = 0;
-    tick = luat_mcu_ticks() * 1000;
-    return (uint32_t)((tick + luat_mcu_ticks() - 1) / luat_mcu_ticks());
-}
-
-/**
- * @brief 初始化定时器
- *
- * @param platformTimer
- */
-void platformTimerInit(platformTimer_t *platformTimer)
-{
-    platformTimer->time = 0;
-    platformTimer->timeOut = 0;
-}
-
-/**
- * @brief 添加计数时间
- *
- * @param platformTimer
- * @param timeout
- */
-void platformTimerCutdown(platformTimer_t *platformTimer, uint32_t timeout)
-{
-    platformTimer->timeOut = timeout;
-    platformTimer->time = platformUptimeMs();
-}
-
-/**
- * @brief 计算time还有多长时间超时,考虑了32位溢出判断
- *
- * @param platformTimer
- * @return uint32_t 返回剩余时间,超时返回0
- */
-uint32_t platformTimerRemain(platformTimer_t *platformTimer)
-{
-    uint32_t tnow = platformUptimeMs();
-    uint32_t overTime = platformTimer->time + platformTimer->timeOut;
-    // uint32_t 没有溢出
-    if (overTime >= platformTimer->time)
-    {
-        // tnow溢出,不存在时间超时可能性
-        if (tnow < platformTimer->time)
-            return (UINT32_MAX - overTime + tnow + 1);
-
-        // tnow没有溢出
-        return tnow >= overTime ? 0 : (overTime - tnow);
-    }
-
-    // uint32_t 溢出了
-    // tnow 溢出了
-    if (tnow < platformTimer->time)
-        return tnow >= overTime ? 0 : (overTime - tnow + 1);
-
-    // tnow 没有溢出
-    return UINT32_MAX - tnow + overTime + 1;
-}

+ 0 - 25
platform/openLuat/platformTimer.h

@@ -1,25 +0,0 @@
-#ifndef __platformTimer__
-#define __platformTimer__
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-#include <stdint.h>
-#include "luat_mcu.h"
-
-    typedef struct
-    {
-        uint32_t time;
-        uint32_t timeOut;
-    } platformTimer_t;
-
-    extern uint32_t platformUptimeMs(void);
-    extern void platformTimerInit(platformTimer_t *platformTimer);
-    extern void platformTimerCutdown(platformTimer_t *platformTimer, uint32_t timeout);
-    extern uint32_t platformTimerRemain(platformTimer_t *platformTimer);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif

+ 0 - 318
platform/quecOpen/platformNetwork.c

@@ -1,318 +0,0 @@
-/**
- * 注意!此接口仅提供思路示例,具体请根据实际进行修改
- *
- */
-
-// #define rlogEnable               // 是否使能日志
-#define rlogColorEnable          // 是否使能日志颜色
-#define rlogLevel (rlogLvlWarning) // 日志打印等级
-#define rlogTag "RyanMqttNet"      // 日志tag
-
-#include "platformNetwork.h"
-#include "RyanMqttLog.h"
-
-#define tcpConnect (RyanMqttBit1)
-#define tcpSend (RyanMqttBit2)
-#define tcpClose (RyanMqttBit3)
-#define tcpRecv (RyanMqttBit4)
-
-static char g_resolveIp[64] = {0};
-static osMutexId_t mutex = NULL;
-static osSemaphoreId_t sem = NULL;
-
-static void callback_socket_GetIPByHostName(u8 contexId, s32 errCode, u32 ipAddrCnt, u8 *ipAddr)
-{
-    if (errCode == SOC_SUCCESS_OK)
-    {
-        memset(g_resolveIp, 0, sizeof(g_resolveIp));
-        for (int i = 0; i < ipAddrCnt; i++)
-        {
-            strcpy((char *)g_resolveIp, (char *)ipAddr);
-            rlog_i("socket 获取ip成功: num_entry=%d, resolve_ip:[%s]", i, (u8 *)g_resolveIp);
-        }
-        osSemaphoreRelease(sem);
-    }
-    else
-    {
-        rlog_e("socket 获取ip失败: %d", errCode);
-    }
-}
-
-static void callback_socket_connect(s32 socketId, s32 errCode, void *customParam)
-{
-    platformNetwork_t *platformNetwork = (platformNetwork_t *)customParam;
-    if (errCode == SOC_SUCCESS_OK && platformNetwork->socket == socketId)
-    {
-        rlog_i("socket 连接成功: %d", socketId);
-        osEventFlagsSet(platformNetwork.mqttNetEventHandle, tcpConnect);
-    }
-}
-
-static void callback_socket_close(s32 socketId, s32 errCode, void *customParam)
-{
-    if (errCode == SOC_SUCCESS_OK)
-    {
-        rlog_w("关闭socket成功: %d", socketId);
-    }
-    else
-    {
-        rlog_e("关闭socket失败 socketId=%d,error_cause=%d", socketId, errCode);
-    }
-}
-
-static void callback_socket_read(s32 socketId, s32 errCode, void *customParam)
-{
-    platformNetwork_t *platformNetwork = (platformNetwork_t *)customParam;
-    if (SOC_SUCCESS_OK == errCode && platformNetwork->socket == socketId)
-    {
-        rlog_w("socket接收到数据: %d", socketId);
-        osEventFlagsSet(platformNetwork.mqttNetEventHandle, tcpRecv);
-    }
-}
-
-static void callback_socket_accept(s32 listenSocketId, s32 errCode, void *customParam)
-{
-}
-
-static ST_SOC_Callback callback_soc_func =
-    {
-        callback_socket_connect,
-        callback_socket_close,
-        callback_socket_accept,
-        callback_socket_read,
-};
-
-/**
- * @brief 连接mqtt服务器
- *
- * @param userData
- * @param platformNetwork
- * @param host
- * @param port
- * @return RyanMqttError_e
- * 成功返回RyanMqttSuccessError, 失败返回错误信息
- */
-RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host, uint16_t port)
-{
-    RyanMqttError_e result = RyanMqttSuccessError;
-    u8 nw_state = 0;
-    int32_t eventId;
-    char resolveIp[64] = {0};
-
-    // 如果第一次connect就创建事件标志组,否则情况事件标志组标志位
-    if (NULL == mutex)
-    {
-        const osMutexAttr_t myMutex01_attributes = {
-            .attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust};
-        mutex = osMutexNew(&myMutex01_attributes);
-    }
-    if (NULL == sem)
-    {
-        sem = osSemaphoreNew(1, 0, NULL);
-    }
-
-    // 如果第一次connect就创建事件标志组,否则情况事件标志组标志位
-    if (NULL == platformNetwork.mqttNetEventHandle)
-        platformNetwork.mqttNetEventHandle = osEventFlagsNew(NULL);
-
-    Ql_SOC_Register(callback_soc_func, platformNetwork); // 注册socket回调函数
-
-    // 获取网络连接状态
-    Ql_GetCeregState(&nw_state);
-    if ((1 != nw_state) && (5 != nw_state))
-    {
-        result = RyanMqttSocketConnectFailError;
-        goto __exit;
-    }
-
-    osMutexAcquire(mutex, osWaitForever);
-    // 清除接收标志位
-    osSemaphoreAcquire(sem, 0);
-    // 解析域名
-    s32 getHostIpResult = Ql_IpHelper_GetIPByHostName(0,
-                                                      (u8 *)host,
-                                                      callback_socket_GetIPByHostName);
-    if (SOC_SUCCESS_OK != getHostIpResult && SOC_NONBLOCK != getHostIpResult)
-    {
-        result = RyanMqttSocketConnectFailError;
-        osMutexRelease(mutex);
-        goto __exit;
-    }
-
-    if (osOK != osSemaphoreAcquire(sem, 10 * 1000))
-    {
-        result = RyanMqttSocketConnectFailError;
-        osMutexRelease(mutex);
-        goto __exit;
-    }
-    memcpy(resolveIp, g_resolveIp, sizeof(resolveIp));
-    osMutexRelease(mutex);
-
-    // 创建socket
-    platformNetwork->socket = Ql_SOC_Create(0, SOC_TYPE_TCP);
-    if (platformNetwork->socket < 0)
-    {
-        result = RyanSocketFailedError;
-        goto __exit;
-    }
-
-    // 等待连接成功
-    s32 connectResult = Ql_SOC_Connect(platformNetwork->socket, (u8 *)resolveIp, port);
-    if (SOC_SUCCESS_OK != connectResult && SOC_NONBLOCK != connectResult)
-    {
-        platformNetworkClose(userData, platformNetwork);
-        result = RyanMqttSocketConnectFailError;
-        goto __exit;
-    }
-
-    eventId = osEventFlagsWait(mqttNetEventHandle, tcpConnect, osFlagsWaitAny, 10000);
-    if (tcpConnect != eventId)
-    {
-        platformNetworkClose(userData, platformNetwork);
-        result = RyanMqttSocketConnectFailError;
-        goto __exit;
-    }
-
-__exit:
-    return result;
-}
-
-/**
- * @brief 非阻塞接收数据
- *
- * @param userData
- * @param platformNetwork
- * @param recvBuf
- * @param recvLen
- * @param timeout
- * @return RyanMqttError_e
- * socket错误返回 RyanSocketFailedError
- * 接收超时或者接收数据长度不等于期待数据接受长度 RyanMqttRecvPacketTimeOutError
- * 接收成功 RyanMqttSuccessError
- */
-RyanMqttError_e platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf, int recvLen, int timeout)
-{
-
-    int32_t recvResult = 0;
-    int32_t offset = 0;
-    int32_t timeOut2 = timeout;
-    int32_t eventId;
-    platformTimer_t timer = {0};
-
-    if (-1 == platformNetwork->socket)
-        return RyanSocketFailedError;
-
-    platformTimerCutdown(&timer, timeout);
-    while ((offset < recvLen) && (0 != timeOut2))
-    {
-
-        recvResult = Ql_SOC_Recv(platformNetwork->socket, (u8 *)(recvBuf + offset), recvLen - offset);
-        if (recvResult > 0)
-        {
-            offset += recvResult;
-        }
-        else
-        {
-            eventId = osEventFlagsWait(mqttNetEventHandle, tcpRecv, osFlagsWaitAny, timeOut2);
-            if (tcpRecv == eventId)
-            {
-                recvResult = Ql_SOC_Recv(platformNetwork->socket, (u8 *)(recvBuf + offset), recvLen - offset);
-                if (recvResult < 0) // 小于零,表示错误,个别错误不代表socket错误
-                {
-                    if (recvResult != SOC_NONBLOCK &&
-                        recvResult != SOC_ERROR_TIMEOUT)
-                    {
-                        rlog_e("recv失败 result: %d, recvLen: %d, eventId: %d", recvResult, recvLen, eventId);
-                        return RyanSocketFailedError;
-                    }
-
-                    break;
-                }
-
-                offset += recvResult;
-            }
-        }
-
-        timeOut2 = platformTimerRemain(&timer);
-    }
-
-    if (offset != recvLen)
-        return RyanMqttRecvPacketTimeOutError;
-
-    return RyanMqttSuccessError;
-}
-
-/**
- * @brief 非阻塞发送数据
- *
- * @param userData
- * @param platformNetwork
- * @param sendBuf
- * @param sendLen
- * @param timeout
- * @return RyanMqttError_e
- * socket错误返回 RyanSocketFailedError
- * 接收超时或者接收数据长度不等于期待数据接受长度 RyanMqttRecvPacketTimeOutError
- * 接收成功 RyanMqttSuccessError
- */
-RyanMqttError_e platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf, int sendLen, int timeout)
-{
-
-    int32_t sendResult = 0;
-    int32_t offset = 0;
-    int32_t timeOut2 = timeout;
-    int32_t eventId;
-    platformTimer_t timer = {0};
-
-    if (-1 == platformNetwork->socket)
-        return RyanSocketFailedError;
-
-    platformTimerCutdown(&timer, timeout);
-
-    while ((offset < sendLen) && (0 != timeOut2))
-    {
-
-        sendResult = Ql_SOC_Send(platformNetwork->socket, (u8 *)(sendBuf + offset), sendLen - offset);
-        if (sendResult < 0) // 小于零,表示错误,个别错误不代表socket错误
-        {
-            if (sendResult != SOC_NONBLOCK &&
-                sendResult != SOC_ERROR_TIMEOUT)
-                return RyanSocketFailedError;
-        }
-        offset += sendResult;
-        timeOut2 = platformTimerRemain(&timer);
-    }
-
-    // osDelay(1000);
-
-    if (offset != sendLen)
-        return RyanMqttSendPacketTimeOutError;
-
-    return RyanMqttSuccessError;
-}
-
-/**
- * @brief 断开mqtt服务器连接
- *
- * @param userData
- * @param platformNetwork
- * @return RyanMqttError_e
- */
-RyanMqttError_e platformNetworkClose(void *userData, platformNetwork_t *platformNetwork)
-{
-
-    if (platformNetwork->socket >= 0)
-    {
-        Ql_SOC_Close(platformNetwork->socket);
-        platformNetwork->socket = -1;
-
-        // todo 这里还是推荐在close的时候把时间标志组删除,否则没有别的地方可以调用删除函数。
-        if (platformNetwork.mqttNetEventHandle)
-        {
-            osEventFlagsDelete(platformNetwork.mqttNetEventHandle);
-            platformNetwork.mqttNetEventHandle = NULL;
-        }
-    }
-
-    return RyanMqttSuccessError;
-}

+ 0 - 37
platform/quecOpen/platformNetwork.h

@@ -1,37 +0,0 @@
-#ifndef __platformNetwork__
-#define __platformNetwork__
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include "RyanMqttPublic.h"
-#include "platformTimer.h"
-
-#include "cmsis_os2.h"
-#include "ril.h"
-#include "ril_util.h "
-#include "ql_ps.h"
-#include "ql_socket.h"
-#include "ql_urc_register.h"
-
-    typedef struct
-    {
-        int socket;
-        osEventFlagsId_t mqttNetEventHandle;
-    } platformNetwork_t;
-
-    extern RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host, uint16_t port);
-    extern RyanMqttError_e platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf, int recvLen, int timeout);
-    extern RyanMqttError_e platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf, int sendLen, int timeout);
-    extern RyanMqttError_e platformNetworkClose(void *userData, platformNetwork_t *platformNetwork);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif

+ 0 - 224
platform/quecOpen/platformSystem.c

@@ -1,224 +0,0 @@
-
-#include "platformSystem.h"
-
-/**
- * @brief 申请内存
- *
- * @param size
- * @return void*
- */
-inline void *platformMemoryMalloc(size_t size)
-{
-    return malloc(size);
-}
-
-/**
- * @brief 释放内存
- *
- * @param ptr
- */
-inline void platformMemoryFree(void *ptr)
-{
-    free(ptr);
-}
-
-/**
- * @brief ms延时
- *
- * @param ms
- */
-inline void platformDelay(uint32_t ms)
-{
-    osDelay(ms);
-}
-
-/**
- * @brief 打印字符串函数,可通过串口打印出去
- *
- * @param str
- * @param strLen
- */
-inline void platformPrint(char *str, uint16_t strLen)
-{
-    Ql_UART_Write((Enum_SerialPort)(UART_PORT0), (u8 *)(str), strLen);
-}
-
-/**
- * @brief 初始化并运行线程
- *
- * @param userData
- * @param platformThread
- * @param name
- * @param entry
- * @param param
- * @param stackSize
- * @param priority
- * @return RyanMqttError_e
- */
-RyanMqttError_e platformThreadInit(void *userData,
-                                   platformThread_t *platformThread,
-                                   const char *name,
-                                   void (*entry)(void *),
-                                   void *const param,
-                                   uint32_t stackSize,
-                                   uint32_t priority)
-{
-
-    const osThreadAttr_t myTask02_attributes = {
-        .name = name,
-        .stack_size = stackSize,
-        .priority = (osPriority_t)priority,
-    };
-
-    platformThread->thread = osThreadNew(entry, param, &myTask02_attributes);
-
-    if (NULL == platformThread->thread)
-        return RyanMqttNoRescourceError;
-
-    return RyanMqttSuccessError;
-}
-
-/**
- * @brief 销毁自身线程
- *
- * @param userData
- * @param platformThread
- * @return RyanMqttError_e
- */
-RyanMqttError_e platformThreadDestroy(void *userData, platformThread_t *platformThread)
-{
-    osThreadExit();
-    return RyanMqttSuccessError;
-}
-
-/**
- * @brief 开启线程
- *
- * @param userData
- * @param platformThread
- * @return RyanMqttError_e
- */
-RyanMqttError_e platformThreadStart(void *userData, platformThread_t *platformThread)
-{
-    osThreadResume(platformThread->thread);
-    return RyanMqttSuccessError;
-}
-
-/**
- * @brief 挂起线程
- *
- * @param userData
- * @param platformThread
- * @return RyanMqttError_e
- */
-RyanMqttError_e platformThreadStop(void *userData, platformThread_t *platformThread)
-{
-    osThreadSuspend(platformThread->thread);
-    return RyanMqttSuccessError;
-}
-
-/**
- * @brief 互斥锁初始化
- *
- * @param userData
- * @param platformMutex
- * @return RyanMqttError_e
- */
-RyanMqttError_e platformMutexInit(void *userData, platformMutex_t *platformMutex)
-{
-
-    const osMutexAttr_t myMutex01_attributes = {
-        .name = "mqttMutex", .attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust};
-
-    platformMutex->mutex = osMutexNew(&myMutex01_attributes);
-    return RyanMqttSuccessError;
-}
-
-/**
- * @brief 销毁互斥锁
- *
- * @param userData
- * @param platformMutex
- * @return RyanMqttError_e
- */
-RyanMqttError_e platformMutexDestroy(void *userData, platformMutex_t *platformMutex)
-{
-    osMutexDelete(platformMutex->mutex);
-    return RyanMqttSuccessError;
-}
-
-/**
- * @brief 阻塞获取互斥锁
- *
- * @param userData
- * @param platformMutex
- * @return RyanMqttError_e
- */
-RyanMqttError_e platformMutexLock(void *userData, platformMutex_t *platformMutex)
-{
-    osMutexAcquire(platformMutex->mutex, osWaitForever);
-    return RyanMqttSuccessError;
-}
-
-/**
- * @brief 释放互斥锁
- *
- * @param userData
- * @param platformMutex
- * @return RyanMqttError_e
- */
-RyanMqttError_e platformMutexUnLock(void *userData, platformMutex_t *platformMutex)
-{
-    osMutexRelease(platformMutex->mutex);
-    return RyanMqttSuccessError;
-}
-
-/**
- * @brief 临界区初始化
- *
- * @param userData
- * @param platformCritical
- * @return RyanMqttError_e
- */
-RyanMqttError_e platformCriticalInit(void *userData, platformCritical_t *platformCritical)
-{
-    return RyanMqttSuccessError;
-}
-
-/**
- * @brief 销毁临界区
- *
- * @param userData
- * @param platformCritical
- * @return RyanMqttError_e
- */
-RyanMqttError_e platformCriticalDestroy(void *userData, platformCritical_t *platformCritical)
-{
-    return RyanMqttSuccessError;
-}
-
-/**
- * @brief 进入临界区
- *
- * @param userData
- * @param platformCritical
- * @return RyanMqttError_e
- */
-inline RyanMqttError_e platformCriticalEnter(void *userData, platformCritical_t *platformCritical)
-{
-    osKernelLock();
-    return RyanMqttSuccessError;
-}
-
-/**
- * @brief 退出临界区
- *
- * @param userData
- * @param platformCritical
- * @return RyanMqttError_e
- */
-inline RyanMqttError_e platformCriticalExit(void *userData, platformCritical_t *platformCritical)
-{
-    osKernelUnlock();
-    return RyanMqttSuccessError;
-}

+ 0 - 64
platform/quecOpen/platformSystem.h

@@ -1,64 +0,0 @@
-#ifndef __platformSystem__
-#define __platformSystem__
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-#include <stdio.h>
-#include <stdint.h>
-#include <assert.h>
-#include "cmsis_os2.h"
-#include "ql_uart.h"
-#include "RyanMqttPublic.h"
-
-#define RyanMqttAssert(EX) assert(EX)
-
-    typedef struct
-    {
-        osThreadId_t thread;
-    } platformThread_t;
-
-    typedef struct
-    {
-        osMutexId_t mutex;
-    } platformMutex_t;
-
-    typedef struct
-    {
-        uint8_t invalid; // 不使用,避免报错
-    } platformCritical_t;
-
-    extern void *platformMemoryMalloc(size_t size);
-    extern void platformMemoryFree(void *ptr);
-
-    extern void platformPrint(char *str, uint16_t strLen);
-    extern void platformDelay(uint32_t ms);
-
-    extern RyanMqttError_e platformThreadInit(void *userData,
-                                              platformThread_t *platformThread,
-                                              const char *name,
-                                              void (*entry)(void *),
-                                              void *const param,
-                                              uint32_t stackSize,
-                                              uint32_t priority);
-    extern RyanMqttError_e platformThreadDestroy(void *userData, platformThread_t *platformThread);
-    extern RyanMqttError_e platformThreadStart(void *userData, platformThread_t *platformThread);
-    extern RyanMqttError_e platformThreadStop(void *userData, platformThread_t *platformThread);
-
-    extern RyanMqttError_e platformMutexInit(void *userData, platformMutex_t *platformMutex);
-    extern RyanMqttError_e platformMutexDestroy(void *userData, platformMutex_t *platformMutex);
-    extern RyanMqttError_e platformMutexLock(void *userData, platformMutex_t *platformMutex);
-    extern RyanMqttError_e platformMutexUnLock(void *userData, platformMutex_t *platformMutex);
-
-    extern RyanMqttError_e platformCriticalInit(void *userData, platformCritical_t *platformCritical);
-    extern RyanMqttError_e platformCriticalDestroy(void *userData, platformCritical_t *platformCritical);
-    extern RyanMqttError_e platformCriticalEnter(void *userData, platformCritical_t *platformCritical);
-    extern RyanMqttError_e platformCriticalExit(void *userData, platformCritical_t *platformCritical);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif

+ 0 - 69
platform/quecOpen/platformTimer.c

@@ -1,69 +0,0 @@
-
-
-#include "platformTimer.h"
-
-uint32_t platformUptimeMs(void)
-{
-    if (1000 == osKernelGetTickFreq())
-        return (uint32_t)osKernelGetTickCount();
-    else
-    {
-        uint32_t tick = 0;
-        tick = osKernelGetTickCount() * 1000;
-        return (uint32_t)((tick + osKernelGetTickCount() - 1) / osKernelGetTickCount());
-    }
-}
-
-/**
- * @brief 初始化定时器
- *
- * @param platformTimer
- */
-void platformTimerInit(platformTimer_t *platformTimer)
-{
-    platformTimer->time = 0;
-    platformTimer->timeOut = 0;
-}
-
-/**
- * @brief 添加计数时间
- *
- * @param platformTimer
- * @param timeout
- */
-void platformTimerCutdown(platformTimer_t *platformTimer, uint32_t timeout)
-{
-    platformTimer->timeOut = timeout;
-    platformTimer->time = platformUptimeMs();
-}
-
-/**
- * @brief 计算time还有多长时间超时,考虑了32位溢出判断
- *
- * @param platformTimer
- * @return uint32_t 返回剩余时间,超时返回0
- */
-uint32_t platformTimerRemain(platformTimer_t *platformTimer)
-{
-    uint32_t tnow = platformUptimeMs();
-    uint32_t overTime = platformTimer->time + platformTimer->timeOut;
-    // uint32_t 没有溢出
-    if (overTime >= platformTimer->time)
-    {
-        // tnow溢出,时间必然已经超时
-        if (tnow < platformTimer->time)
-            // return (UINT32_MAX - overTime + tnow + 1);
-            return 0;
-
-        // tnow没有溢出
-        return tnow >= overTime ? 0 : (overTime - tnow);
-    }
-
-    // uint32_t 溢出了
-    // tnow 溢出了
-    if (tnow < platformTimer->time)
-        return tnow >= overTime ? 0 : (overTime - tnow + 1);
-
-    // tnow 没有溢出
-    return UINT32_MAX - tnow + overTime + 1;
-}

+ 0 - 24
platform/quecOpen/platformTimer.h

@@ -1,24 +0,0 @@
-#ifndef __platformTimer__
-#define __platformTimer__
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-#include <stdint.h>
-
-    typedef struct
-    {
-        uint32_t time;
-        uint32_t timeOut;
-    } platformTimer_t;
-
-    extern uint32_t platformUptimeMs(void);
-    extern void platformTimerInit(platformTimer_t *platformTimer);
-    extern void platformTimerCutdown(platformTimer_t *platformTimer, uint32_t timeout);
-    extern uint32_t platformTimerRemain(platformTimer_t *platformTimer);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif

+ 179 - 179
platform/rtthread/platformNetwork.c

@@ -1,7 +1,4 @@
-#define rlogEnable               // 是否使能日志
-#define rlogColorEnable          // 是否使能日志颜色
 #define rlogLevel (rlogLvlDebug) // 日志打印等级
-#define rlogTag "RyanMqttNet"    // 日志tag
 
 #include "platformNetwork.h"
 #include "RyanMqttLog.h"
@@ -15,8 +12,8 @@
  */
 RyanMqttError_e platformNetworkInit(void *userData, platformNetwork_t *platformNetwork)
 {
-    platformNetwork->socket = -1;
-    return RyanMqttSuccessError;
+	platformNetwork->socket = -1;
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -28,8 +25,8 @@ RyanMqttError_e platformNetworkInit(void *userData, platformNetwork_t *platformN
  */
 RyanMqttError_e platformNetworkDestroy(void *userData, platformNetwork_t *platformNetwork)
 {
-    platformNetwork->socket = -1;
-    return RyanMqttSuccessError;
+	platformNetwork->socket = -1;
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -42,60 +39,83 @@ RyanMqttError_e platformNetworkDestroy(void *userData, platformNetwork_t *platfo
  * @return RyanMqttError_e
  * 成功返回RyanMqttSuccessError, 失败返回错误信息
  */
-RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host, uint16_t port)
+RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host,
+				       uint16_t port)
 {
-    RyanMqttError_e result = RyanMqttSuccessError;
-
-    struct hostent hostinfo = {0};
-
-    // 解析域名信息
-    {
-        char buf[256];
-        int h_errnop;
-        struct hostent *phost;
-
-        if (0 != gethostbyname_r(host, &hostinfo, buf, sizeof(buf), &phost, &h_errnop))
-        {
-            rlog_w("平台可能不支持 gethostbyname_r 函数, 再次尝试使用 gethostbyname 获取域名信息");
-
-            // 非线程安全版本,请根据实际情况选择使用
-            // NOLINTNEXTLINE(concurrency-mt-unsafe)
-            struct hostent *phostinfo = gethostbyname(host);
-            if (NULL == phostinfo)
-            {
-                result = RyanMqttNoRescourceError;
-                goto __exit;
-            }
-
-            hostinfo = *phostinfo;
-        }
-    }
-
-    platformNetwork->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
-    if (platformNetwork->socket < 0)
-    {
-        result = RyanSocketFailedError;
-        goto __exit;
-    }
-
-    struct sockaddr_in server_addr = {
-        .sin_family = AF_INET,
-        .sin_port = htons(port), // 指定端口号
-        .sin_addr = *((struct in_addr *)hostinfo.h_addr_list[0]),
-    };
-
-    // 绑定套接字到主机地址和端口号
-    if (connect(platformNetwork->socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0)
-    {
-        platformNetworkClose(userData, platformNetwork);
-        result = RyanMqttSocketConnectFailError;
-        goto __exit;
-    }
+	RyanMqttError_e result = RyanMqttSuccessError;
+	char *buf = NULL;
+	struct sockaddr_in server_addr = {
+		.sin_family = AF_INET,
+		.sin_port = htons(port), // 指定端口号
+	};
+
+	// 传递的是ip地址,不用进行dns解析,某些情况下调用dns解析反而会错误
+	if (INADDR_NONE != inet_addr(host))
+	{
+		rlog_d("host: %s, 不用dns解析", host);
+		server_addr.sin_addr.s_addr = inet_addr(host);
+	}
+	// 解析域名信息
+	else
+	{
+#define dnsBufferSize (384)
+		rlog_d("host: %s, 需要dns解析", host);
+		int h_errnop;
+		struct hostent *phost;
+		struct hostent hostinfo = {0};
+
+		buf = (char *)platformMemoryMalloc(dnsBufferSize);
+		if (NULL == buf)
+		{
+			result = RyanMqttNoRescourceError;
+			goto __exit;
+		}
+
+		if (0 != gethostbyname_r(host, &hostinfo, buf, dnsBufferSize, &phost, &h_errnop))
+		{
+			rlog_w("平台可能不支持 gethostbyname_r 函数, 再次尝试使用 gethostbyname 获取域名信息");
+
+			// 非线程安全版本,请根据实际情况选择使用
+			// NOLINTNEXTLINE(concurrency-mt-unsafe)
+			struct hostent *phostinfo = gethostbyname(host);
+			if (NULL == phostinfo)
+			{
+				result = RyanMqttNoRescourceError;
+				goto __exit;
+			}
+
+			hostinfo = *phostinfo;
+		}
+
+		server_addr.sin_addr = *((struct in_addr *)hostinfo.h_addr_list[0]);
+	}
+
+	platformNetwork->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+	if (platformNetwork->socket < 0)
+	{
+		result = RyanSocketFailedError;
+		goto __exit;
+	}
+
+	// 绑定套接字到主机地址和端口号
+	if (connect(platformNetwork->socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0)
+	{
+		platformNetworkClose(userData, platformNetwork);
+		result = RyanMqttSocketConnectFailError;
+		goto __exit;
+	}
 
 __exit:
-    if (RyanMqttSuccessError != result)
-        rlog_e("socket连接失败: %d", result);
-    return result;
+	if (NULL != buf)
+	{
+		platformMemoryFree(buf);
+	}
+
+	if (RyanMqttSuccessError != result)
+	{
+		rlog_e("socket连接失败: %d", result);
+	}
+	return result;
 }
 
 /**
@@ -111,64 +131,54 @@ __exit:
  * 接收超时或者接收数据长度不等于期待数据接受长度 RyanMqttRecvPacketTimeOutError
  * 接收成功 RyanMqttSuccessError
  */
-RyanMqttError_e platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf, int recvLen, int timeout)
+int32_t platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf, size_t recvLen,
+				 int32_t timeout)
 {
-
-    int32_t recvResult = 0;
-    int32_t offset = 0;
-    int32_t timeOut2 = timeout;
-    struct timeval tv = {0};
-    platformTimer_t timer = {0};
-
-    if (-1 == platformNetwork->socket)
-    {
-        rlog_e("对端关闭socket连接");
-        return RyanMqttNoRescourceError;
-    }
-
-    platformTimerCutdown(&timer, timeout);
-
-    while ((offset < recvLen) && (0 != timeOut2))
-    {
-        tv.tv_sec = timeOut2 / 1000;
-        tv.tv_usec = timeOut2 % 1000 * 1000;
-
-        setsockopt(platformNetwork->socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); // 设置错做模式为非阻塞
-
-        recvResult = recv(platformNetwork->socket, recvBuf + offset, recvLen - offset, 0);
-        if (0 == recvResult)
-        {
-            rlog_e("对端关闭socket连接");
-            return RyanMqttNoRescourceError;
-        }
-        else if (recvResult < 0) // 小于零,表示错误,个别错误不代表socket错误
-        {
-            int32_t rt_errno = errno; // 似乎5.0.0以上版本需要使用 rt_get_errno
-            if (0 == rt_errno)
-                rt_errno = rt_get_errno();
-
-            // 下列表示没问题,但需要退出接收
-            if (EAGAIN == rt_errno ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
-                EWOULDBLOCK == rt_errno || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
-                EINTR == rt_errno ||       // 操作被信号中断
-                ETIME == rt_errno)         // 计时器过期
-            {
-                break;
-            }
-
-            // NOLINTNEXTLINE(concurrency-mt-unsafe)
-            rlog_e("recvResult: %d, errno: %d  str: %s", recvResult, rt_errno, strerror(rt_errno));
-            return RyanSocketFailedError;
-        }
-
-        offset += recvResult;
-        timeOut2 = platformTimerRemain(&timer);
-    }
-
-    if (offset != recvLen)
-        return RyanMqttRecvPacketTimeOutError;
-
-    return RyanMqttSuccessError;
+	ssize_t recvResult = 0;
+	struct timeval tv = {
+		.tv_sec = timeout / 1000,
+		.tv_usec = 1000 * timeout % 1000,
+	};
+
+	if (-1 == platformNetwork->socket)
+	{
+		rlog_e("对端关闭socket连接");
+		return -1;
+	}
+
+	setsockopt(platformNetwork->socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
+		   sizeof(struct timeval)); // 设置操作模式为非阻塞
+
+	recvResult = recv(platformNetwork->socket, recvBuf, recvLen, 0);
+	if (0 == recvResult)
+	{
+		rlog_e("对端关闭socket连接");
+		return -1;
+	}
+
+	if (recvResult < 0) // 小于零,表示错误,个别错误不代表socket错误
+	{
+		int32_t rt_errno = errno; // 似乎RT 5.0.0以上版本需要使用 rt_get_errno
+		if (0 == rt_errno)
+		{
+			rt_errno = rt_get_errno();
+		}
+
+		// 下列表示没问题,但需要退出接收
+		if (EAGAIN == rt_errno ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
+		    EWOULDBLOCK == rt_errno || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
+		    EINTR == rt_errno ||       // 操作被信号中断
+		    ETIME == rt_errno)         // 计时器过期
+		{
+			return 0;
+		}
+
+		// NOLINTNEXTLINE(concurrency-mt-unsafe)
+		rlog_e("recvResult: %d, errno: %d  str: %s", recvResult, rt_errno, strerror(rt_errno));
+		return -1;
+	}
+
+	return (int32_t)recvResult;
 }
 
 /**
@@ -184,64 +194,54 @@ RyanMqttError_e platformNetworkRecvAsync(void *userData, platformNetwork_t *plat
  * 接收超时或者接收数据长度不等于期待数据接受长度 RyanMqttRecvPacketTimeOutError
  * 接收成功 RyanMqttSuccessError
  */
-RyanMqttError_e platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf, int sendLen, int timeout)
+int32_t platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf, size_t sendLen,
+				 int32_t timeout)
 {
-
-    int32_t sendResult = 0;
-    int32_t offset = 0;
-    int32_t timeOut2 = timeout;
-    struct timeval tv = {0};
-    platformTimer_t timer = {0};
-
-    if (-1 == platformNetwork->socket)
-    {
-        rlog_e("对端关闭socket连接");
-        return RyanMqttNoRescourceError;
-    }
-
-    platformTimerCutdown(&timer, timeout);
-
-    while ((offset < sendLen) && (0 != timeOut2))
-    {
-        tv.tv_sec = timeOut2 / 1000;
-        tv.tv_usec = timeOut2 % 1000 * 1000;
-
-        setsockopt(platformNetwork->socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); // 设置错做模式为非阻塞
-
-        sendResult = send(platformNetwork->socket, sendBuf + offset, sendLen - offset, 0);
-        if (0 == sendResult)
-        {
-            rlog_e("对端关闭socket连接");
-            return RyanMqttNoRescourceError;
-        }
-        else if (sendResult < 0) // 小于零,表示错误,个别错误不代表socket错误
-        {
-            int32_t rt_errno = errno; // 似乎5.0.0以上版本需要使用 rt_get_errno
-            if (0 == rt_errno)
-                rt_errno = rt_get_errno();
-
-            // 下列表示没问题,但需要退出发送
-            if (EAGAIN == rt_errno ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
-                EWOULDBLOCK == rt_errno || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
-                EINTR == rt_errno ||       // 操作被信号中断
-                ETIME == rt_errno)         // 计时器过期
-            {
-                break;
-            }
-
-            // NOLINTNEXTLINE(concurrency-mt-unsafe)
-            rlog_e("sendResult: %d, errno: %d str: %s", sendResult, rt_errno, strerror(rt_errno));
-            return RyanSocketFailedError;
-        }
-
-        offset += sendResult;
-        timeOut2 = platformTimerRemain(&timer);
-    }
-
-    if (offset != sendLen)
-        return RyanMqttSendPacketTimeOutError;
-
-    return RyanMqttSuccessError;
+	ssize_t sendResult = 0;
+	struct timeval tv = {
+		.tv_sec = timeout / 1000,
+		.tv_usec = 1000 * timeout % 1000,
+	};
+
+	if (-1 == platformNetwork->socket)
+	{
+		rlog_e("对端关闭socket连接");
+		return -1;
+	}
+
+	setsockopt(platformNetwork->socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv,
+		   sizeof(struct timeval)); // 设置操作模式为非阻塞
+
+	sendResult = send(platformNetwork->socket, sendBuf, sendLen, 0);
+	if (0 == sendResult)
+	{
+		rlog_e("对端关闭socket连接");
+		return -1;
+	}
+
+	if (sendResult < 0) // 小于零,表示错误,个别错误不代表socket错误
+	{
+		int32_t rt_errno = errno; // 似乎5.0.0以上版本需要使用 rt_get_errno
+		if (0 == rt_errno)
+		{
+			rt_errno = rt_get_errno();
+		}
+
+		// 下列表示没问题,但需要退出发送
+		if (EAGAIN == rt_errno ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
+		    EWOULDBLOCK == rt_errno || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
+		    EINTR == rt_errno ||       // 操作被信号中断
+		    ETIME == rt_errno)         // 计时器过期
+		{
+			return 0;
+		}
+
+		// NOLINTNEXTLINE(concurrency-mt-unsafe)
+		rlog_e("sendResult: %d, errno: %d str: %s", sendResult, rt_errno, strerror(rt_errno));
+		return -1;
+	}
+
+	return (int32_t)sendResult;
 }
 
 /**
@@ -254,12 +254,12 @@ RyanMqttError_e platformNetworkSendAsync(void *userData, platformNetwork_t *plat
 RyanMqttError_e platformNetworkClose(void *userData, platformNetwork_t *platformNetwork)
 {
 
-    if (platformNetwork->socket >= 0)
-    {
-        closesocket(platformNetwork->socket);
-        rlog_w("platformNetworkClose socket close %d", platformNetwork->socket);
-        platformNetwork->socket = -1;
-    }
+	if (platformNetwork->socket >= 0)
+	{
+		closesocket(platformNetwork->socket);
+		rlog_w("platformNetworkClose socket close %d", platformNetwork->socket);
+		platformNetwork->socket = -1;
+	}
 
-    return RyanMqttSuccessError;
+	return RyanMqttSuccessError;
 }

+ 14 - 12
platform/rtthread/platformNetwork.h

@@ -2,8 +2,7 @@
 #define __platformNetwork__
 
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif
 
 #include <stdio.h>
@@ -17,17 +16,20 @@ extern "C"
 #include <sys/time.h>
 #include <netdb.h>
 
-    typedef struct
-    {
-        int socket;
-    } platformNetwork_t;
+typedef struct
+{
+	int socket;
+} platformNetwork_t;
 
-    extern RyanMqttError_e platformNetworkInit(void *userData, platformNetwork_t *platformNetwork);
-    extern RyanMqttError_e platformNetworkDestroy(void *userData, platformNetwork_t *platformNetwork);
-    extern RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host, uint16_t port);
-    extern RyanMqttError_e platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf, int recvLen, int timeout);
-    extern RyanMqttError_e platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf, int sendLen, int timeout);
-    extern RyanMqttError_e platformNetworkClose(void *userData, platformNetwork_t *platformNetwork);
+extern RyanMqttError_e platformNetworkInit(void *userData, platformNetwork_t *platformNetwork);
+extern RyanMqttError_e platformNetworkDestroy(void *userData, platformNetwork_t *platformNetwork);
+extern RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host,
+					      uint16_t port);
+extern int32_t platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf,
+					size_t recvLen, int32_t timeout);
+extern int32_t platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf,
+					size_t sendLen, int32_t timeout);
+extern RyanMqttError_e platformNetworkClose(void *userData, platformNetwork_t *platformNetwork);
 
 #ifdef __cplusplus
 }

+ 52 - 44
platform/rtthread/platformSystem.c

@@ -9,7 +9,7 @@
  */
 inline void *platformMemoryMalloc(size_t size)
 {
-    return rt_malloc(size);
+	return rt_malloc(size);
 }
 
 /**
@@ -19,7 +19,7 @@ inline void *platformMemoryMalloc(size_t size)
  */
 inline void platformMemoryFree(void *ptr)
 {
-    rt_free(ptr);
+	rt_free(ptr);
 }
 
 /**
@@ -29,7 +29,18 @@ inline void platformMemoryFree(void *ptr)
  */
 inline void platformDelay(uint32_t ms)
 {
-    rt_thread_mdelay(ms);
+	rt_thread_mdelay(ms);
+}
+
+uint32_t platformUptimeMs(void)
+{
+#if (RT_TICK_PER_SECOND == 1000)
+	return (uint32_t)rt_tick_get();
+#else
+	// 已经不能提供精准的ms了
+	rt_tick_t tick = rt_tick_get();
+	return (uint32_t)((tick * 1000 + RT_TICK_PER_SECOND - 1) / RT_TICK_PER_SECOND);
+#endif
 }
 
 /**
@@ -40,7 +51,7 @@ inline void platformDelay(uint32_t ms)
  */
 inline void platformPrint(char *str, uint16_t strLen)
 {
-    rt_kputs(str);
+	rt_kputs(str);
 }
 
 /**
@@ -55,26 +66,23 @@ inline void platformPrint(char *str, uint16_t strLen)
  * @param priority
  * @return RyanMqttError_e
  */
-RyanMqttError_e platformThreadInit(void *userData,
-                                   platformThread_t *platformThread,
-                                   const char *name,
-                                   void (*entry)(void *),
-                                   void *const param,
-                                   uint32_t stackSize,
-                                   uint32_t priority)
+RyanMqttError_e platformThreadInit(void *userData, platformThread_t *platformThread, const char *name,
+				   void (*entry)(void *), void *const param, uint32_t stackSize, uint32_t priority)
 {
-    platformThread->thread = rt_thread_create(name,      // 线程name
-                                              entry,     // 线程入口函数
-                                              param,     // 线程入口函数参数
-                                              stackSize, // 线程栈大小
-                                              priority,  // 线程优先级
-                                              10);       // 线程时间片
+	platformThread->thread = rt_thread_create(name,      // 线程name
+						  entry,     // 线程入口函数
+						  param,     // 线程入口函数参数
+						  stackSize, // 线程栈大小
+						  priority,  // 线程优先级
+						  10);       // 线程时间片
 
-    if (NULL == platformThread->thread)
-        return RyanMqttNoRescourceError;
+	if (NULL == platformThread->thread)
+	{
+		return RyanMqttNoRescourceError;
+	}
 
-    rt_thread_startup(platformThread->thread);
-    return RyanMqttSuccessError;
+	rt_thread_startup(platformThread->thread);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -86,9 +94,9 @@ RyanMqttError_e platformThreadInit(void *userData,
  */
 RyanMqttError_e platformThreadDestroy(void *userData, platformThread_t *platformThread)
 {
-    rt_thread_delete(platformThread->thread);
-    rt_schedule();
-    return RyanMqttSuccessError;
+	rt_thread_delete(platformThread->thread);
+	rt_schedule();
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -100,9 +108,9 @@ RyanMqttError_e platformThreadDestroy(void *userData, platformThread_t *platform
  */
 RyanMqttError_e platformThreadStart(void *userData, platformThread_t *platformThread)
 {
-    rt_thread_resume(platformThread->thread);
-    rt_schedule();
-    return RyanMqttSuccessError;
+	rt_thread_resume(platformThread->thread);
+	rt_schedule();
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -114,9 +122,9 @@ RyanMqttError_e platformThreadStart(void *userData, platformThread_t *platformTh
  */
 RyanMqttError_e platformThreadStop(void *userData, platformThread_t *platformThread)
 {
-    rt_thread_suspend(platformThread->thread);
-    rt_schedule(); // rtthread挂起线程后应立即调用线程上下文切换函数
-    return RyanMqttSuccessError;
+	rt_thread_suspend(platformThread->thread);
+	rt_schedule(); // rtthread挂起线程后应立即调用线程上下文切换函数
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -128,8 +136,8 @@ RyanMqttError_e platformThreadStop(void *userData, platformThread_t *platformThr
  */
 RyanMqttError_e platformMutexInit(void *userData, platformMutex_t *platformMutex)
 {
-    platformMutex->mutex = rt_mutex_create("mqttMutex", RT_IPC_FLAG_PRIO);
-    return RyanMqttSuccessError;
+	platformMutex->mutex = rt_mutex_create("mqttMutex", RT_IPC_FLAG_PRIO);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -141,8 +149,8 @@ RyanMqttError_e platformMutexInit(void *userData, platformMutex_t *platformMutex
  */
 RyanMqttError_e platformMutexDestroy(void *userData, platformMutex_t *platformMutex)
 {
-    rt_mutex_delete(platformMutex->mutex);
-    return RyanMqttSuccessError;
+	rt_mutex_delete(platformMutex->mutex);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -154,8 +162,8 @@ RyanMqttError_e platformMutexDestroy(void *userData, platformMutex_t *platformMu
  */
 RyanMqttError_e platformMutexLock(void *userData, platformMutex_t *platformMutex)
 {
-    rt_mutex_take(platformMutex->mutex, RT_WAITING_FOREVER);
-    return RyanMqttSuccessError;
+	rt_mutex_take(platformMutex->mutex, RT_WAITING_FOREVER);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -167,8 +175,8 @@ RyanMqttError_e platformMutexLock(void *userData, platformMutex_t *platformMutex
  */
 RyanMqttError_e platformMutexUnLock(void *userData, platformMutex_t *platformMutex)
 {
-    rt_mutex_release(platformMutex->mutex);
-    return RyanMqttSuccessError;
+	rt_mutex_release(platformMutex->mutex);
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -180,7 +188,7 @@ RyanMqttError_e platformMutexUnLock(void *userData, platformMutex_t *platformMut
  */
 RyanMqttError_e platformCriticalInit(void *userData, platformCritical_t *platformCritical)
 {
-    return RyanMqttSuccessError;
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -192,7 +200,7 @@ RyanMqttError_e platformCriticalInit(void *userData, platformCritical_t *platfor
  */
 RyanMqttError_e platformCriticalDestroy(void *userData, platformCritical_t *platformCritical)
 {
-    return RyanMqttSuccessError;
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -204,8 +212,8 @@ RyanMqttError_e platformCriticalDestroy(void *userData, platformCritical_t *plat
  */
 inline RyanMqttError_e platformCriticalEnter(void *userData, platformCritical_t *platformCritical)
 {
-    rt_enter_critical();
-    return RyanMqttSuccessError;
+	platformCritical->level = rt_hw_interrupt_disable();
+	return RyanMqttSuccessError;
 }
 
 /**
@@ -217,6 +225,6 @@ inline RyanMqttError_e platformCriticalEnter(void *userData, platformCritical_t
  */
 inline RyanMqttError_e platformCriticalExit(void *userData, platformCritical_t *platformCritical)
 {
-    rt_exit_critical();
-    return RyanMqttSuccessError;
+	rt_hw_interrupt_enable(platformCritical->level);
+	return RyanMqttSuccessError;
 }

+ 39 - 43
platform/rtthread/platformSystem.h

@@ -2,8 +2,7 @@
 #define __platformSystem__
 
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif
 
 #include <stdio.h>
@@ -13,52 +12,49 @@ extern "C"
 
 #include <rtthread.h>
 #ifdef RT_ASSERT
-#define RyanMqttAssert(EX) RT_ASSERT(EX)
+#define platformAssert(EX) RT_ASSERT(EX)
 #else
-#define RyanMqttAssert(EX) assert(EX)
+#define platformAssert(EX) assert(EX)
 #endif
 
-    typedef struct
-    {
-        rt_thread_t thread;
-    } platformThread_t;
-
-    typedef struct
-    {
-        rt_mutex_t mutex;
-    } platformMutex_t;
-
-    typedef struct
-    {
-        uint8_t invalid; // 不使用,避免报错
-    } platformCritical_t;
-
-    extern void *platformMemoryMalloc(size_t size);
-    extern void platformMemoryFree(void *ptr);
-
-    extern void platformPrint(char *str, uint16_t strLen);
-    extern void platformDelay(uint32_t ms);
-
-    extern RyanMqttError_e platformThreadInit(void *userData,
-                                              platformThread_t *platformThread,
-                                              const char *name,
-                                              void (*entry)(void *),
-                                              void *const param,
-                                              uint32_t stackSize,
-                                              uint32_t priority);
-    extern RyanMqttError_e platformThreadDestroy(void *userData, platformThread_t *platformThread);
-    extern RyanMqttError_e platformThreadStart(void *userData, platformThread_t *platformThread);
-    extern RyanMqttError_e platformThreadStop(void *userData, platformThread_t *platformThread);
+typedef struct
+{
+	rt_thread_t thread;
+} platformThread_t;
 
-    extern RyanMqttError_e platformMutexInit(void *userData, platformMutex_t *platformMutex);
-    extern RyanMqttError_e platformMutexDestroy(void *userData, platformMutex_t *platformMutex);
-    extern RyanMqttError_e platformMutexLock(void *userData, platformMutex_t *platformMutex);
-    extern RyanMqttError_e platformMutexUnLock(void *userData, platformMutex_t *platformMutex);
+typedef struct
+{
+	rt_mutex_t mutex;
+} platformMutex_t;
 
-    extern RyanMqttError_e platformCriticalInit(void *userData, platformCritical_t *platformCritical);
-    extern RyanMqttError_e platformCriticalDestroy(void *userData, platformCritical_t *platformCritical);
-    extern RyanMqttError_e platformCriticalEnter(void *userData, platformCritical_t *platformCritical);
-    extern RyanMqttError_e platformCriticalExit(void *userData, platformCritical_t *platformCritical);
+typedef struct
+{
+	rt_base_t level;
+} platformCritical_t;
+
+extern void *platformMemoryMalloc(size_t size);
+extern void platformMemoryFree(void *ptr);
+
+extern void platformPrint(char *str, uint16_t strLen);
+extern void platformDelay(uint32_t ms);
+extern uint32_t platformUptimeMs(void);
+
+extern RyanMqttError_e platformThreadInit(void *userData, platformThread_t *platformThread, const char *name,
+					  void (*entry)(void *), void *const param, uint32_t stackSize,
+					  uint32_t priority);
+extern RyanMqttError_e platformThreadDestroy(void *userData, platformThread_t *platformThread);
+extern RyanMqttError_e platformThreadStart(void *userData, platformThread_t *platformThread);
+extern RyanMqttError_e platformThreadStop(void *userData, platformThread_t *platformThread);
+
+extern RyanMqttError_e platformMutexInit(void *userData, platformMutex_t *platformMutex);
+extern RyanMqttError_e platformMutexDestroy(void *userData, platformMutex_t *platformMutex);
+extern RyanMqttError_e platformMutexLock(void *userData, platformMutex_t *platformMutex);
+extern RyanMqttError_e platformMutexUnLock(void *userData, platformMutex_t *platformMutex);
+
+extern RyanMqttError_e platformCriticalInit(void *userData, platformCritical_t *platformCritical);
+extern RyanMqttError_e platformCriticalDestroy(void *userData, platformCritical_t *platformCritical);
+extern RyanMqttError_e platformCriticalEnter(void *userData, platformCritical_t *platformCritical);
+extern RyanMqttError_e platformCriticalExit(void *userData, platformCritical_t *platformCritical);
 
 #ifdef __cplusplus
 }

+ 0 - 69
platform/rtthread/platformTimer.c

@@ -1,69 +0,0 @@
-
-
-#include "platformTimer.h"
-
-uint32_t platformUptimeMs(void)
-{
-#if (RT_TICK_PER_SECOND == 1000)
-    return (uint32_t)rt_tick_get();
-#else
-    rt_tick_t tick = 0u;
-
-    tick = rt_tick_get() * 1000;
-    return (uint32_t)((tick + RT_TICK_PER_SECOND - 1) / RT_TICK_PER_SECOND);
-#endif
-}
-
-/**
- * @brief 初始化定时器
- *
- * @param platformTimer
- */
-void platformTimerInit(platformTimer_t *platformTimer)
-{
-    platformTimer->time = 0;
-    platformTimer->timeOut = 0;
-}
-
-/**
- * @brief 添加计数时间
- *
- * @param platformTimer
- * @param timeout
- */
-void platformTimerCutdown(platformTimer_t *platformTimer, uint32_t timeout)
-{
-    platformTimer->timeOut = timeout;
-    platformTimer->time = platformUptimeMs();
-}
-
-/**
- * @brief 计算time还有多长时间超时,考虑了32位溢出判断
- *
- * @param platformTimer
- * @return uint32_t 返回剩余时间,超时返回0
- */
-uint32_t platformTimerRemain(platformTimer_t *platformTimer)
-{
-    uint32_t tnow = platformUptimeMs();
-    uint32_t overTime = platformTimer->time + platformTimer->timeOut;
-    // uint32_t 没有溢出
-    if (overTime >= platformTimer->time)
-    {
-        // tnow溢出,时间必然已经超时
-        if (tnow < platformTimer->time)
-            // return (UINT32_MAX - overTime + tnow + 1);
-            return 0;
-
-        // tnow没有溢出
-        return tnow >= overTime ? 0 : (overTime - tnow);
-    }
-
-    // uint32_t 溢出了
-    // tnow 溢出了
-    if (tnow < platformTimer->time)
-        return tnow >= overTime ? 0 : (overTime - tnow + 1);
-
-    // tnow 没有溢出
-    return UINT32_MAX - tnow + overTime + 1;
-}

+ 0 - 25
platform/rtthread/platformTimer.h

@@ -1,25 +0,0 @@
-#ifndef __platformTimer__
-#define __platformTimer__
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-#include <stdint.h>
-#include <rtthread.h>
-
-    typedef struct
-    {
-        uint32_t time;
-        uint32_t timeOut;
-    } platformTimer_t;
-
-    extern uint32_t platformUptimeMs(void);
-    extern void platformTimerInit(platformTimer_t *platformTimer);
-    extern void platformTimerCutdown(platformTimer_t *platformTimer, uint32_t timeout);
-    extern uint32_t platformTimerRemain(platformTimer_t *platformTimer);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif

+ 52 - 0
test/RyanMqttDestoryTest.c

@@ -0,0 +1,52 @@
+#include "RyanMqttTest.h"
+
+static RyanMqttError_e RyanMqttConnectDestory(uint32_t count, uint32_t delayms)
+{
+	for (uint32_t i = 0; i < count; i++)
+	{
+
+		RyanMqttClient_t *client;
+
+		RyanMqttInitSync(&client, i == count - 1 ? RyanMqttTrue : RyanMqttFalse, RyanMqttTrue, 120, NULL);
+
+		RyanMqttSubscribe(client, "testlinux/pub1", RyanMqttQos0);
+		RyanMqttSubscribe(client, "testlinux/pub2", RyanMqttQos1);
+		RyanMqttSubscribe(client, "testlinux/pub3", RyanMqttQos2);
+		RyanMqttPublish(client, "testlinux/pub1", "helloworld", strlen("helloworld"), RyanMqttQos0,
+				RyanMqttFalse);
+		RyanMqttPublish(client, "testlinux/pub2", "helloworld", strlen("helloworld"), RyanMqttQos1,
+				RyanMqttFalse);
+		RyanMqttPublish(client, "testlinux/pub3", "helloworld", strlen("helloworld"), RyanMqttQos2,
+				RyanMqttFalse);
+
+		if (delayms)
+		{
+			delay(delayms);
+		}
+
+		if (i == count - 1) // 最后一次同步释放
+		{
+			RyanMqttDestorySync(client);
+			delay(100);
+		}
+		else
+		{
+			RyanMqttDestroy(client);
+		}
+	}
+
+	return RyanMqttSuccessError;
+}
+
+RyanMqttError_e RyanMqttDestoryTest(void)
+{
+	RyanMqttError_e result = RyanMqttSuccessError;
+	result = RyanMqttConnectDestory(100, 0);
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+	checkMemory;
+
+	return RyanMqttSuccessError;
+
+__exit:
+	return RyanMqttFailedError;
+}

+ 49 - 0
test/RyanMqttKeepAliveTest.c

@@ -0,0 +1,49 @@
+#include "RyanMqttTest.h"
+
+static RyanMqttError_e keepAliveTest(void)
+{
+	RyanMqttClient_t *client;
+	RyanMqttError_e result = RyanMqttSuccessError;
+
+	RyanMqttInitSync(&client, RyanMqttTrue, RyanMqttTrue, 20, NULL);
+
+	while (RyanMqttConnectState != RyanMqttGetState(client))
+	{
+		delay(100);
+	}
+
+	uint32_t keepAliveRemain = 0;
+	for (uint32_t i = 0; i < 90; i++)
+	{
+		if (RyanMqttConnectState != RyanMqttGetState(client))
+		{
+			rlog_e("mqtt断连了");
+			return RyanMqttFailedError;
+		}
+
+		RyanMqttGetKeepAliveRemain(client, &keepAliveRemain);
+
+		rlog_w("心跳倒计时: %d", keepAliveRemain);
+		if (0 == keepAliveRemain)
+		{
+			result = RyanMqttFailedError;
+			break;
+		}
+		delay(1000);
+	}
+
+	RyanMqttDestorySync(client);
+
+	return result;
+}
+
+RyanMqttError_e RyanMqttKeepAliveTest(void)
+{
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == keepAliveTest(), RyanMqttFailedError, rlog_e,
+				  { goto __exit; });
+
+	return RyanMqttSuccessError;
+
+__exit:
+	return RyanMqttFailedError;
+}

+ 270 - 0
test/RyanMqttPubTest.c

@@ -0,0 +1,270 @@
+#include "RyanMqttTest.h"
+
+static int32_t pubTestPublishedEventCount = 0;
+static int32_t pubTestDataEventCount = 0;
+static char *pubStr = NULL;
+static int32_t pubStrLen = 0;
+static RyanMqttQos_e exportQos = RyanMqttSubFail;
+
+static int32_t pubTestDataEventCountNotQos0 = 0;
+
+static void RyanMqttPublishEventHandle(void *pclient, RyanMqttEventId_e event, const void *eventData)
+{
+	RyanMqttClient_t *client = (RyanMqttClient_t *)pclient;
+	switch (event)
+	{
+	case RyanMqttEventPublished: {
+		RyanMqttMsgHandler_t *msgHandler = ((RyanMqttAckHandler_t *)eventData)->msgHandler;
+		rlog_w("qos1 / qos2发送成功事件回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		pubTestPublishedEventCount++;
+		break;
+	}
+
+	case RyanMqttEventData: {
+		RyanMqttMsgData_t *msgData = (RyanMqttMsgData_t *)eventData;
+		// rlog_i("接收到mqtt消息事件回调 topic: %.*s, packetId: %d, payload len: %d, qos: %d",
+		//        msgData->topicLen, msgData->topic, msgData->packetId, msgData->payloadLen, msgData->qos);
+		if (RyanMqttSubFail != exportQos && exportQos != msgData->qos)
+		{
+			rlog_e("pub测试收到qos等级不一致 exportQos: %d, msgQos: %d", exportQos, msgData->qos);
+			RyanMqttDestroy(client);
+		}
+
+		if (0 == strncmp(msgData->payload, pubStr, pubStrLen))
+		{
+			pubTestDataEventCount++;
+
+			if (RyanMqttQos0 != msgData->qos)
+			{
+				pubTestDataEventCountNotQos0++;
+			}
+		}
+		else
+		{
+			rlog_e("pub测试收到数据不一致 %.*s", msgData->payloadLen, msgData->payload);
+			RyanMqttDestroy(client);
+		}
+
+		break;
+	}
+
+	default: mqttEventBaseHandle(pclient, event, eventData); break;
+	}
+}
+
+static RyanMqttError_e RyanMqttPublishTest(RyanMqttQos_e qos, int32_t count, uint32_t delayms)
+{
+	RyanMqttError_e result = RyanMqttSuccessError;
+	RyanMqttClient_t *client;
+	time_t timeStampNow = 0;
+
+	RyanMqttInitSync(&client, RyanMqttTrue, RyanMqttTrue, 120, RyanMqttPublishEventHandle);
+
+	RyanMqttSubscribe(client, "testlinux/pub", qos);
+	delay(100);
+
+	exportQos = qos;
+
+	// 生成随机的数据包大小
+	{
+		// NOLINTNEXTLINE(cert-err33-c)
+		time(&timeStampNow);
+
+		pubStr = (char *)malloc(2048);
+		if (NULL == pubStr)
+		{
+			rlog_e("内存不足");
+			return RyanMqttNotEnoughMemError;
+		}
+		memset(pubStr, 0, 2048);
+
+		// NOLINTNEXTLINE(cert-msc32-c,cert-msc51-cpp)
+		srand(timeStampNow);
+		// NOLINTNEXTLINE(concurrency-mt-unsafe,cert-msc30-c,cert-msc50-cpp)
+		for (int32_t i = 0; i < rand() % 250 + 1 + 100; i++)
+		{
+			// NOLINTNEXTLINE(concurrency-mt-unsafe,cert-msc30-c,cert-msc50-cpp)
+			snprintf(pubStr + 4 * i, 2048 - 4 * i, "%04d", rand());
+		}
+		pubStrLen = (int32_t)strlen(pubStr);
+	}
+
+	pubTestPublishedEventCount = 0;
+	pubTestDataEventCount = 0;
+	for (int32_t i = 0; i < count; i++)
+	{
+		RyanMqttError_e pubResult =
+			RyanMqttPublish(client, "testlinux/pub", pubStr, pubStrLen, qos, RyanMqttFalse);
+		if (RyanMqttSuccessError != pubResult)
+		{
+			rlog_e("QOS发布错误 Qos: %d, result: %d", qos, pubResult);
+			result = RyanMqttFailedError;
+			goto __exit;
+		}
+
+		if (delayms)
+		{
+			delay(delayms);
+		}
+	}
+
+	// 检查收到的数据是否正确
+	for (int32_t i = 0;; i++)
+	{
+		if (RyanMqttQos0 == qos)
+		{
+			if (count == pubTestDataEventCount)
+			{
+				break;
+			}
+		}
+		else if (pubTestPublishedEventCount == count && pubTestPublishedEventCount == pubTestDataEventCount)
+		{
+			break;
+		}
+
+		if (i > 300)
+		{
+			rlog_e("QOS测试失败 Qos: %d, PublishedEventCount: %d, dataEventCount: %d", qos,
+			       pubTestPublishedEventCount, pubTestDataEventCount);
+			result = RyanMqttFailedError;
+			goto __exit;
+		}
+
+		delay(100);
+	}
+
+	RyanMqttUnSubscribe(client, "testlinux/pub");
+
+	result = checkAckList(client);
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+__exit:
+	free(pubStr);
+	pubStr = NULL;
+	rlog_i("mqtt 发布测试,销毁mqtt客户端");
+	RyanMqttDestorySync(client);
+	return result;
+}
+
+static RyanMqttError_e RyanMqttPublishHybridTest(int32_t count, uint32_t delayms)
+{
+	RyanMqttError_e result = RyanMqttSuccessError;
+	RyanMqttClient_t *client;
+	time_t timeStampNow = 0;
+	int32_t sendNeedAckCount = 0;
+
+	RyanMqttInitSync(&client, RyanMqttTrue, RyanMqttTrue, 120, RyanMqttPublishEventHandle);
+
+	RyanMqttSubscribe(client, "testlinux/pub", RyanMqttQos2);
+	delay(100);
+
+	exportQos = RyanMqttSubFail;
+
+	// 生成随机的数据包大小
+	{
+		// NOLINTNEXTLINE(cert-err33-c)
+		time(&timeStampNow);
+
+		pubStr = (char *)malloc(2048);
+		if (NULL == pubStr)
+		{
+			rlog_e("内存不足");
+			return RyanMqttNotEnoughMemError;
+		}
+		memset(pubStr, 0, 2048);
+
+		// NOLINTNEXTLINE(cert-msc32-c,cert-msc51-cpp)
+		srand(timeStampNow);
+		// NOLINTNEXTLINE(concurrency-mt-unsafe,cert-msc30-c,cert-msc50-cpp)
+		for (int32_t i = 0; i < rand() % 250 + 1 + 100; i++)
+		{
+			// NOLINTNEXTLINE(concurrency-mt-unsafe,cert-msc30-c,cert-msc50-cpp)
+			snprintf(pubStr + 4 * i, 2048 - 4 * i, "%04d", rand());
+		}
+		pubStrLen = (int32_t)strlen(pubStr);
+	}
+
+	pubTestPublishedEventCount = 0;
+	pubTestDataEventCount = 0;
+	pubTestDataEventCountNotQos0 = 0;
+	for (int32_t i = 0; i < count; i++)
+	{
+		RyanMqttError_e pubResult =
+			RyanMqttPublish(client, "testlinux/pub", pubStr, pubStrLen, i % 3, RyanMqttFalse);
+		if (RyanMqttSuccessError != pubResult)
+		{
+			rlog_e("QOS发布错误 Qos: %d, result: %d", i % 3, pubResult);
+			result = RyanMqttFailedError;
+			goto __exit;
+		}
+
+		if (RyanMqttQos0 != i % 3)
+		{
+			sendNeedAckCount++;
+		}
+
+		if (delayms)
+		{
+			delay(delayms);
+		}
+	}
+
+	// 检查收到的数据是否正确
+	for (int32_t i = 0;; i++)
+	{
+
+		if (pubTestPublishedEventCount == sendNeedAckCount &&
+		    pubTestPublishedEventCount == pubTestDataEventCountNotQos0)
+		{
+			break;
+		}
+
+		if (i > 300)
+		{
+			rlog_e("QOS测试失败, PublishedEventCount: %d, pubTestDataEventCountNotQos0: %d",
+			       pubTestPublishedEventCount, pubTestDataEventCountNotQos0);
+			result = RyanMqttFailedError;
+			goto __exit;
+		}
+
+		delay(100);
+	}
+
+	RyanMqttUnSubscribe(client, "testlinux/pub");
+
+	result = checkAckList(client);
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+__exit:
+	free(pubStr);
+	pubStr = NULL;
+	rlog_i("mqtt 发布测试,销毁mqtt客户端");
+	RyanMqttDestorySync(client);
+	return result;
+}
+
+RyanMqttError_e RyanMqttPubTest(void)
+{
+	RyanMqttError_e result = RyanMqttSuccessError;
+
+	// 发布 & 订阅 qos 测试
+	result = RyanMqttPublishTest(RyanMqttQos0, 1000, 0);
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+	checkMemory;
+
+	result = RyanMqttPublishTest(RyanMqttQos1, 1000, 2);
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+	checkMemory;
+
+	result = RyanMqttPublishTest(RyanMqttQos2, 1000, 5);
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+	checkMemory;
+
+	result = RyanMqttPublishHybridTest(1000, 5);
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+	checkMemory;
+
+	return RyanMqttSuccessError;
+
+__exit:
+	return RyanMqttFailedError;
+}

+ 44 - 0
test/RyanMqttReconnectTest.c

@@ -0,0 +1,44 @@
+#include "RyanMqttTest.h"
+
+// todo 增加 RyanMqttReconnect 测试
+static RyanMqttError_e reconnectTest(uint32_t count, uint32_t delayms)
+{
+	RyanMqttClient_t *client;
+	RyanMqttInitSync(&client, RyanMqttTrue, RyanMqttTrue, 120, NULL);
+	for (uint32_t i = 0; i < count; i++)
+	{
+		RyanMqttDisconnect(client, i % 2 == 0);
+
+		// 测试手动连接
+		// if (0 == i % 5)
+		// {
+		//     RyanMqttReconnect();
+		// }
+
+		while (RyanMqttConnectState != RyanMqttGetState(client))
+		{
+			delay(1);
+		}
+
+		if (delayms)
+		{
+			delay(delayms);
+		}
+	}
+
+	RyanMqttDestorySync(client);
+	return RyanMqttSuccessError;
+}
+
+RyanMqttError_e RyanMqttReconnectTest(void)
+{
+	RyanMqttError_e result = RyanMqttSuccessError;
+	result = reconnectTest(3, 0);
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+	checkMemory;
+
+	return RyanMqttSuccessError;
+
+__exit:
+	return RyanMqttFailedError;
+}

+ 301 - 0
test/RyanMqttSubTest.c

@@ -0,0 +1,301 @@
+#include "RyanMqttTest.h"
+
+static RyanMqttSubscribeData_t *subscribeManyData = NULL;
+static int32_t subTestCount = 0;
+
+static RyanMqttSubscribeData_t *topicIsSubscribeArr(char *topic)
+{
+	for (int32_t i = 0; i < subTestCount; i++)
+	{
+		if (0 == strcmp(topic, subscribeManyData[i].topic))
+		{
+			return &subscribeManyData[i];
+		}
+	}
+
+	return NULL;
+}
+
+static void RyanMqttSubEventHandle(void *pclient, RyanMqttEventId_e event, const void *eventData)
+{
+	RyanMqttClient_t *client = (RyanMqttClient_t *)pclient;
+	switch (event)
+	{
+
+	case RyanMqttEventSubscribed: {
+		RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
+		rlog_i("mqtt订阅成功回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		RyanMqttSubscribeData_t *subscribeData = topicIsSubscribeArr(msgHandler->topic);
+		if (NULL == subscribeData)
+		{
+			rlog_e("mqtt 订阅主题非法 topic: %s", msgHandler->topic);
+			RyanMqttDestroy(client);
+		}
+
+		if (subscribeData->qos != msgHandler->qos)
+		{
+			rlog_e("mqtt 订阅主题降级 topic: %s, exportQos: %d, qos: %d", msgHandler->topic,
+			       subscribeData->qos, msgHandler->qos);
+			RyanMqttDestroy(client);
+		}
+
+		break;
+	}
+
+	case RyanMqttEventSubscribedFaile: {
+		RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
+		rlog_i("mqtt订阅失败回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		break;
+	}
+
+	case RyanMqttEventUnSubscribed: {
+		RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
+		rlog_i("mqtt取消订阅成功回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		RyanMqttSubscribeData_t *subscribeData = topicIsSubscribeArr(msgHandler->topic);
+		if (NULL == subscribeData)
+		{
+			rlog_e("mqtt 订阅主题非法 topic: %s", msgHandler->topic);
+		}
+		if (subscribeData->qos != msgHandler->qos)
+		{
+			rlog_e("mqtt 取消订阅主题信息不对 topic: %s, exportQos: %d, qos: %d", msgHandler->topic,
+			       subscribeData->qos, msgHandler->qos);
+			RyanMqttDestroy(client);
+		}
+
+		break;
+	}
+
+	case RyanMqttEventUnSubscribedFaile: {
+		RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
+		rlog_w("mqtt取消订阅失败回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		break;
+	}
+
+	default: mqttEventBaseHandle(pclient, event, eventData); break;
+	}
+}
+
+static RyanMqttError_e RyanMqttSubscribeCheckMsgHandle(RyanMqttClient_t *client)
+{
+	RyanMqttError_e result = RyanMqttSuccessError;
+	int32_t subscribeNum = 0;
+	RyanMqttMsgHandler_t *msgHandles = NULL;
+	delay(100);
+	for (int32_t i = 0; i < 600; i++)
+	{
+
+		result = RyanMqttGetSubscribeSafe(client, &msgHandles, &subscribeNum);
+		if (RyanMqttSuccessError != result)
+		{
+			if (RyanMqttNoRescourceError == result)
+			{
+				rlog_w("没有订阅的主题");
+			}
+			else
+			{
+				rlog_e("获取订阅主题数失败!!!");
+			}
+		}
+		else
+		{
+			rlog_i("mqtt客户端已订阅的主题数: %d, 应该订阅主题数: %d", subscribeNum, subTestCount);
+			// for (int32_t i = 0; i < subscribeNum; i++)
+			//     rlog_i("已经订阅主题: %d, topic: %s, QOS: %d", i, msgHandles[i].topic,
+			//     msgHandles[i].qos);
+			int32_t subscribeTotalCount = 0;
+			RyanMqttGetSubscribeTotalCount(client, &subscribeTotalCount);
+
+			if (subscribeNum == subTestCount && subscribeTotalCount == subTestCount)
+			{
+				break;
+			}
+		}
+
+		if (i > 500)
+		{
+			result = RyanMqttFailedError;
+			goto __exit;
+		}
+
+		RyanMqttSafeFreeSubscribeResources(msgHandles, subscribeNum);
+		msgHandles = NULL;
+		delay(100);
+	}
+
+	// 检查订阅主题是否正确
+	for (int32_t i = 0; i < subscribeNum; i++)
+	{
+		if (NULL == topicIsSubscribeArr(msgHandles[i].topic))
+		{
+			rlog_e("主题不匹配或者qos不对, topic: %s, qos: %d", msgHandles[i].topic, msgHandles[i].qos);
+			result = RyanMqttFailedError;
+			goto __exit;
+		}
+	}
+
+__exit:
+	if (NULL != msgHandles)
+	{
+		RyanMqttSafeFreeSubscribeResources(msgHandles, subscribeNum);
+	}
+	return result;
+}
+
+static RyanMqttError_e RyanMqttSubscribeTest(int32_t count)
+{
+	RyanMqttError_e result = RyanMqttSuccessError;
+	RyanMqttClient_t *client;
+	RyanMqttUnSubscribeData_t *unSubscribeManyData = NULL;
+	subTestCount = count;
+
+	RyanMqttInitSync(&client, RyanMqttTrue, RyanMqttTrue, 120, RyanMqttSubEventHandle);
+
+	subscribeManyData = (RyanMqttSubscribeData_t *)malloc(sizeof(RyanMqttSubscribeData_t) * count);
+	if (NULL == subscribeManyData)
+	{
+		rlog_e("内存不足");
+		return RyanMqttNotEnoughMemError;
+	}
+
+	for (int32_t i = 0; i < count; i++)
+	{
+		subscribeManyData[i].qos = i % 3;
+		char *topic = (char *)malloc(64);
+		if (NULL == topic)
+		{
+			rlog_e("内存不足");
+			return RyanMqttNotEnoughMemError;
+		}
+		snprintf(topic, 64, "test/subscribe/%d", i);
+		subscribeManyData[i].topic = topic;
+		subscribeManyData[i].topicLen = strlen(topic);
+	}
+
+	// 订阅全部主题
+	RyanMqttSubscribeMany(client, count - 1, subscribeManyData);
+	RyanMqttSubscribe(client, subscribeManyData[count - 1].topic, subscribeManyData[count - 1].qos);
+	result = RyanMqttSubscribeCheckMsgHandle(client);
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+
+	// 测试重复订阅,不修改qos等级
+	RyanMqttSubscribeMany(client, count / 2, subscribeManyData);
+	result = RyanMqttSubscribeCheckMsgHandle(client);
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+
+	// 测试重复订阅并且修改qos等级
+	for (int32_t i = count; i > 0; i--)
+	{
+		subscribeManyData[count - i].qos = i % 3;
+	}
+	RyanMqttSubscribeMany(client, count, subscribeManyData);
+	result = RyanMqttSubscribeCheckMsgHandle(client);
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+
+	// 测试取消所有订阅消息
+	unSubscribeManyData = malloc(sizeof(RyanMqttUnSubscribeData_t) * count);
+	if (NULL == unSubscribeManyData)
+	{
+		rlog_e("内存不足");
+		return RyanMqttNotEnoughMemError;
+	}
+	for (int32_t i = 0; i < count; i++)
+	{
+		char *topic = (char *)malloc(64);
+		if (NULL == topic)
+		{
+			rlog_e("内存不足");
+			return RyanMqttNotEnoughMemError;
+		}
+		snprintf(topic, 64, "test/subscribe/%d", i);
+		unSubscribeManyData[i].topic = topic;
+		unSubscribeManyData[i].topicLen = strlen(topic);
+	}
+	RyanMqttUnSubscribeMany(client, count - 1, unSubscribeManyData);
+	RyanMqttUnSubscribe(client, unSubscribeManyData[count - 1].topic);
+
+	// 重复取消订阅主题
+	RyanMqttUnSubscribeMany(client, count / 2, unSubscribeManyData);
+
+	delay(100);
+	for (int32_t i = 0; i < 600; i++)
+	{
+		RyanMqttMsgHandler_t *msgHandles = NULL;
+		int32_t subscribeNum = 0;
+		result = RyanMqttGetSubscribeSafe(client, &msgHandles, &subscribeNum);
+		if (RyanMqttSuccessError != result)
+		{
+			if (RyanMqttNoRescourceError == result)
+			{
+				rlog_w("没有订阅的主题");
+			}
+			else
+			{
+				rlog_e("获取订阅主题数失败!!!");
+			}
+		}
+		RyanMqttSafeFreeSubscribeResources(msgHandles, subscribeNum);
+
+		// result = RyanMqttGetSubscribe(client, msgHandles, count, &subscribeNum);
+		// if (RyanMqttNoRescourceError == result)
+		// {
+		// 	rlog_w("订阅主题数超过缓冲区%d个,已截断,请修改msgHandles缓冲区", count);
+		// }
+
+		if (0 == subscribeNum)
+		{
+			break;
+		}
+
+		if (i > 500)
+		{
+			result = RyanMqttFailedError;
+			goto __exit;
+		}
+
+		delay(100);
+	}
+
+	result = checkAckList(client);
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+
+__exit:
+
+	// 删除
+	for (int32_t i = 0; i < count; i++)
+	{
+		if (NULL != subscribeManyData)
+		{
+			free(subscribeManyData[i].topic);
+		}
+		if (NULL != unSubscribeManyData)
+		{
+			free(unSubscribeManyData[i].topic);
+		}
+	}
+	if (NULL != subscribeManyData)
+	{
+		free(subscribeManyData);
+	}
+	if (NULL != unSubscribeManyData)
+	{
+		free(unSubscribeManyData);
+	}
+
+	rlog_i("mqtt 订阅测试,销毁mqtt客户端");
+	RyanMqttDestorySync(client);
+	return result;
+}
+
+RyanMqttError_e RyanMqttSubTest(void)
+{
+	RyanMqttError_e result = RyanMqttSuccessError;
+	result = RyanMqttSubscribeTest(1000);
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+	checkMemory;
+
+	return RyanMqttSuccessError;
+
+__exit:
+	return RyanMqttFailedError;
+}

+ 291 - 0
test/RyanMqttTest.c

@@ -0,0 +1,291 @@
+#include "RyanMqttTest.h"
+
+static pthread_spinlock_t spin = {0};
+
+/**
+ * @brief mqtt事件回调处理函数
+ * 事件的详细定义可以查看枚举定义
+ *
+ * @param pclient
+ * @param event
+ * @param eventData 查看事件枚举,后面有说明eventData是什么类型
+ */
+void mqttEventBaseHandle(void *pclient, RyanMqttEventId_e event, const void *eventData)
+{
+	RyanMqttClient_t *client = (RyanMqttClient_t *)pclient;
+
+	switch (event)
+	{
+	case RyanMqttEventError: break;
+
+	case RyanMqttEventConnected: // 不管有没有使能clearSession,都非常推荐在连接成功回调函数中订阅主题
+		rlog_i("mqtt连接成功回调 %d", *(int32_t *)eventData);
+		break;
+
+	case RyanMqttEventDisconnected: rlog_w("mqtt断开连接回调 %d", *(int32_t *)eventData); break;
+
+	case RyanMqttEventSubscribed: {
+		RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
+		rlog_w("mqtt订阅成功回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		break;
+	}
+
+	case RyanMqttEventSubscribedFaile: {
+		RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
+		rlog_w("mqtt订阅失败回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		break;
+	}
+
+	case RyanMqttEventUnSubscribed: {
+		RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
+		rlog_w("mqtt取消订阅成功回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		break;
+	}
+
+	case RyanMqttEventUnSubscribedFaile: {
+		RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
+		rlog_w("mqtt取消订阅失败回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		break;
+	}
+
+	case RyanMqttEventPublished: {
+		RyanMqttMsgHandler_t *msgHandler = ((RyanMqttAckHandler_t *)eventData)->msgHandler;
+		rlog_w("qos1 / qos2发送成功事件回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
+		break;
+	}
+
+	case RyanMqttEventData: {
+		RyanMqttMsgData_t *msgData = (RyanMqttMsgData_t *)eventData;
+		rlog_i("接收到mqtt消息事件回调 topic: %.*s, packetId: %d, payload len: %d, qos: %d", msgData->topicLen,
+		       msgData->topic, msgData->packetId, msgData->payloadLen, msgData->qos);
+
+		rlog_i("%.*s", msgData->payloadLen, msgData->payload);
+		break;
+	}
+
+	case RyanMqttEventRepeatPublishPacket: // qos2 / qos1重发事件回调
+	{
+		RyanMqttAckHandler_t *ackHandler = (RyanMqttAckHandler_t *)eventData;
+		rlog_w("发布消息进行重发了,packetType: %d, packetId: %d, topic: %s, qos: %d", ackHandler->packetType,
+		       ackHandler->packetId, ackHandler->msgHandler->topic, ackHandler->msgHandler->qos);
+
+		printfArrStr(ackHandler->packet, ackHandler->packetLen, "重发数据: ");
+		break;
+	}
+
+	case RyanMqttEventReconnectBefore:
+		// 如果每次connect都需要修改连接信息,这里是最好的选择。 否则需要注意资源互斥
+		rlog_i("重连前事件回调");
+		break;
+
+	case RyanMqttEventAckCountWarning: // qos2 / qos1的ack链表超过警戒值,不进行释放会一直重发,占用额外内存
+	{
+		// 根据实际情况清除ack, 这里等待每个ack重发次数到达警戒值后清除。
+		// 在资源有限的单片机中也不应频繁发送qos2 / qos1消息
+		uint16_t ackHandlerCount = *(uint16_t *)eventData;
+		rlog_i("ack记数值超过警戒值回调: %d", ackHandlerCount);
+		break;
+	}
+
+	case RyanMqttEventAckRepeatCountWarning: // 重发次数到达警戒值事件
+	{
+		// 这里选择直接丢弃该消息
+		RyanMqttAckHandler_t *ackHandler = (RyanMqttAckHandler_t *)eventData;
+		rlog_w("ack重发次数超过警戒值回调 packetType: %d, packetId: %d, topic: %s, qos: %d",
+		       ackHandler->packetType, ackHandler->packetId, ackHandler->msgHandler->topic,
+		       ackHandler->msgHandler->qos);
+		RyanMqttDiscardAckHandler(client, ackHandler->packetType, ackHandler->packetId);
+		break;
+	}
+
+	case RyanMqttEventAckHandlerdiscard: {
+		RyanMqttAckHandler_t *ackHandler = (RyanMqttAckHandler_t *)eventData;
+		rlog_i("ack丢弃回调: packetType: %d, packetId: %d, topic: %s, qos: %d", ackHandler->packetType,
+		       ackHandler->packetId, ackHandler->msgHandler->topic, ackHandler->msgHandler->qos);
+		break;
+	}
+
+	case RyanMqttEventDestoryBefore:
+		rlog_e("销毁mqtt客户端前回调");
+		if (client->config.userData)
+		{
+			sem_post((sem_t *)client->config.userData);
+		}
+		break;
+
+	default: break;
+	}
+}
+
+// todo 增加多线程测试用例
+RyanMqttError_e RyanMqttInitSync(RyanMqttClient_t **client, RyanMqttBool_e syncFlag, RyanMqttBool_e autoReconnectFlag,
+				 uint16_t keepaliveTimeoutS, RyanMqttEventHandle mqttEventCallback)
+{
+	// 手动避免count的资源竞争了
+	static uint32_t count = 0;
+	char aaa[64];
+
+	pthread_spin_lock(&spin);
+	count++;
+	pthread_spin_unlock(&spin);
+
+	snprintf(aaa, sizeof(aaa), "%s%d", RyanMqttClientId, count);
+
+	sem_t *sem = NULL;
+	if (syncFlag == RyanMqttTrue)
+	{
+		sem = (sem_t *)malloc(sizeof(sem_t));
+		if (sem)
+		{
+			sem_init(sem, 0, 0);
+		}
+		else
+		{
+			rlog_e("内存不足");
+			return RyanMqttNotEnoughMemError;
+		}
+	}
+
+	RyanMqttError_e result = RyanMqttSuccessError;
+	RyanMqttClientConfig_t mqttConfig = {.clientId = aaa,
+					     .userName = RyanMqttUserName,
+					     .password = RyanMqttPassword,
+					     .host = RyanMqttHost,
+					     .port = RyanMqttPort,
+					     .taskName = "mqttThread",
+					     .taskPrio = 16,
+					     .taskStack = 4096,
+					     .mqttVersion = 4,
+					     .ackHandlerRepeatCountWarning = 6,
+					     .ackHandlerCountWarning = 200,
+					     .autoReconnectFlag = autoReconnectFlag,
+					     .cleanSessionFlag = RyanMqttTrue,
+					     .reconnectTimeout = 3000,
+					     .recvTimeout = 3000,
+					     .sendTimeout = 2000,
+					     .ackTimeout = 10000,
+					     .keepaliveTimeoutS = keepaliveTimeoutS,
+					     .mqttEventHandle =
+						     mqttEventCallback ? mqttEventCallback : mqttEventBaseHandle,
+					     .userData = sem};
+
+	// 初始化mqtt客户端
+	result = RyanMqttInit(client);
+	RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_e);
+
+	// 注册需要的事件回调
+	result = RyanMqttRegisterEventId(*client, RyanMqttEventAnyId);
+	RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_e);
+
+	// 设置mqtt客户端config
+	result = RyanMqttSetConfig(*client, &mqttConfig);
+	RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_e);
+
+	// // 设置遗嘱消息
+	// result = RyanMqttSetLwt(*client, "pub/test", "this is will", strlen("this is will"), RyanMqttQos0, 0);
+	// RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_e);
+
+	// 启动mqtt客户端线程
+	result = RyanMqttStart(*client);
+	RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_e);
+
+	while (RyanMqttConnectState != RyanMqttGetState(*client))
+	{
+		delay(100);
+	}
+
+	return RyanMqttSuccessError;
+}
+
+RyanMqttError_e RyanMqttDestorySync(RyanMqttClient_t *client)
+{
+	sem_t *sem = (sem_t *)client->config.userData;
+	// 启动mqtt客户端线程
+	RyanMqttDestroy(client);
+
+	sem_wait(sem);
+	sem_destroy(sem);
+	free(sem);
+	delay(3);
+	return RyanMqttSuccessError;
+}
+
+RyanMqttError_e checkAckList(RyanMqttClient_t *client)
+{
+	rlog_w("等待检查ack链表,等待 recvTime: %d", client->config.recvTimeout);
+	delay(client->config.recvTimeout + 500);
+
+	if (!RyanListIsEmpty(&client->ackHandlerList))
+	{
+		rlog_e("mqtt空间 ack链表不为空");
+		return RyanMqttFailedError;
+	}
+
+	if (!RyanListIsEmpty(&client->userAckHandlerList))
+	{
+		rlog_e("用户空间 ack链表不为空");
+		return RyanMqttFailedError;
+	}
+
+	if (!RyanListIsEmpty(&client->msgHandlerList))
+	{
+		rlog_e("mqtt空间 msg链表不为空");
+		return RyanMqttFailedError;
+	}
+
+	return RyanMqttSuccessError;
+}
+
+void printfArrStr(uint8_t *buf, uint32_t len, char *userData)
+{
+	rlog_raw("%s", userData);
+	for (uint32_t i = 0; i < len; i++)
+	{
+		rlog_raw("%x", buf[i]);
+	}
+
+	rlog_raw("\r\n");
+}
+
+// !当测试程序出错时,并不会回收内存。交由父进程进行回收
+int main(void)
+{
+	RyanMqttError_e result = RyanMqttSuccessError;
+	vallocInit();
+
+	pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE);
+
+	result = RyanMqttSubTest();
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+
+	result = RyanMqttPubTest();
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+
+	result = RyanMqttDestoryTest();
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+
+	result = RyanMqttReconnectTest();
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+
+	result = RyanMqttKeepAliveTest();
+	RyanMqttCheckCodeNoReturn(RyanMqttSuccessError == result, RyanMqttFailedError, rlog_e, { goto __exit; });
+
+__exit:
+	pthread_spin_destroy(&spin);
+
+	if (RyanMqttSuccessError == result)
+	{
+		rlog_i("测试成功---------------------------");
+	}
+	else
+	{
+		rlog_e("测试失败---------------------------");
+	}
+
+	for (uint32_t i = 0; i < 5; i++)
+	{
+		displayMem();
+		delay(10 * 1000);
+	}
+	return 0;
+}

+ 72 - 0
test/RyanMqttTest.h

@@ -0,0 +1,72 @@
+#ifndef __RyanMqttTest__
+#define __RyanMqttTest__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <semaphore.h>
+#include <pthread.h>
+
+#define rlogLevel (rlogLvlDebug) // 日志打印等级
+
+#include "RyanMqttLog.h"
+#include "RyanMqttClient.h"
+
+#define RyanMqttClientId ("RyanMqttTest888") // 填写mqtt客户端id,要求唯一
+// #define RyanMqttHost ("127.0.0.1")           // 填写你的mqtt服务器ip
+#define RyanMqttHost     ("localhost") // 填写你的mqtt服务器ip
+#define RyanMqttPort     (1883)        // mqtt服务器端口
+#define RyanMqttUserName ("test")      // 填写你的用户名,没有填NULL
+#define RyanMqttPassword ("test")      // 填写你的密码,没有填NULL
+
+#define delay(ms)         usleep((ms) * 1000)
+#define getArraySize(arr) ((int32_t)(sizeof(arr) / sizeof((arr)[0])))
+#define checkMemory                                                                                                    \
+	do                                                                                                             \
+	{                                                                                                              \
+		int area = 0, use = 0;                                                                                 \
+		v_mcheck(&area, &use);                                                                                 \
+		if (area != 0 || use != 0)                                                                             \
+		{                                                                                                      \
+			rlog_e("内存泄漏");                                                                            \
+			while (1)                                                                                      \
+			{                                                                                              \
+				int area = 0, use = 0;                                                                 \
+				v_mcheck(&area, &use);                                                                 \
+				rlog_w("|||----------->>> area = %d, size = %d", area, use);                           \
+				delay(3000);                                                                           \
+			}                                                                                              \
+		}                                                                                                      \
+	} while (0)
+
+// 定义枚举类型
+
+// 定义结构体类型
+
+/* extern variables-----------------------------------------------------------*/
+
+extern RyanMqttError_e RyanMqttInitSync(RyanMqttClient_t **client, RyanMqttBool_e syncFlag,
+					RyanMqttBool_e autoReconnectFlag, uint16_t keepaliveTimeoutS,
+					RyanMqttEventHandle mqttEventCallback);
+extern RyanMqttError_e RyanMqttDestorySync(RyanMqttClient_t *client);
+extern void mqttEventBaseHandle(void *pclient, RyanMqttEventId_e event, const void *eventData);
+extern RyanMqttError_e checkAckList(RyanMqttClient_t *client);
+extern void printfArrStr(uint8_t *buf, uint32_t len, char *userData);
+
+extern RyanMqttError_e RyanMqttDestoryTest(void);
+extern RyanMqttError_e RyanMqttKeepAliveTest(void);
+extern RyanMqttError_e RyanMqttPubTest(void);
+extern RyanMqttError_e RyanMqttReconnectTest(void);
+extern RyanMqttError_e RyanMqttSubTest(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 0 - 648
test/RyanMqttTestLinux.c

@@ -1,648 +0,0 @@
-
-#define RyanMqttClientId ("RyanMqttTest888") // 填写mqtt客户端id,要求唯一
-#define RyanMqttHost ("127.0.0.1")           // 填写你的mqtt服务器ip
-#define RyanMqttPort (1883)                  // mqtt服务器端口
-#define RyanMqttUserName ("test")            // 填写你的用户名,没有填NULL
-#define RyanMqttPassword ("test")            // 填写你的密码,没有填NULL
-
-#define rlogEnable               // 是否使能日志
-#define rlogColorEnable          // 是否使能日志颜色
-#define rlogLevel (rlogLvlDebug) // 日志打印等级
-#define rlogTag "RyanMqttTest"   // 日志tag
-
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <semaphore.h>
-
-#include "RyanMqttLog.h"
-#include "RyanMqttClient.h"
-
-#define delay(ms) usleep(ms * 1000)
-
-#define checkMemory                                                          \
-    do                                                                       \
-    {                                                                        \
-        int area = 0, use = 0;                                               \
-        v_mcheck(&area, &use);                                               \
-        if (area != 0 || use != 0)                                           \
-        {                                                                    \
-            rlog_e("内存泄漏");                                              \
-            while (1)                                                        \
-            {                                                                \
-                int area = 0, use = 0;                                       \
-                v_mcheck(&area, &use);                                       \
-                rlog_w("|||----------->>> area = %d, size = %d", area, use); \
-                delay(3000);                                                 \
-            }                                                                \
-        }                                                                    \
-    } while (0)
-
-static uint32_t mqttTest[10] = {0};
-#define dataEventCount (0)      // 接收到数据次数统计
-#define PublishedEventCount (1) // qos1和qos2发布成功的次数统计
-
-static void printfArrStr(char *buf, uint32_t len, char *userData)
-{
-    rlog_raw("%s", userData);
-    for (uint32_t i = 0; i < len; i++)
-        rlog_raw("%x", buf[i]);
-
-    rlog_raw("\r\n");
-}
-
-/**
- * @brief mqtt事件回调处理函数
- * 事件的详细定义可以查看枚举定义
- *
- * @param pclient
- * @param event
- * @param eventData 查看事件枚举,后面有说明eventData是什么类型
- */
-static void mqttEventHandle(void *pclient, RyanMqttEventId_e event, const void *eventData)
-{
-    RyanMqttClient_t *client = (RyanMqttClient_t *)pclient;
-
-    switch (event)
-    {
-    case RyanMqttEventError:
-        break;
-
-    case RyanMqttEventConnected: // 不管有没有使能clearSession,都非常推荐在连接成功回调函数中订阅主题
-        rlog_i("mqtt连接成功回调 %d", *(int32_t *)eventData);
-
-        break;
-
-    case RyanMqttEventDisconnected:
-        rlog_w("mqtt断开连接回调 %d", *(int32_t *)eventData);
-        break;
-
-    case RyanMqttEventSubscribed:
-    {
-        RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
-        rlog_w("mqtt订阅成功回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
-        break;
-    }
-
-    case RyanMqttEventSubscribedFaile:
-    {
-        RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
-        rlog_w("mqtt订阅失败回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
-        break;
-    }
-
-    case RyanMqttEventUnSubscribed:
-    {
-        RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
-        rlog_w("mqtt取消订阅成功回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
-        break;
-    }
-
-    case RyanMqttEventUnSubscribedFaile:
-    {
-        RyanMqttMsgHandler_t *msgHandler = (RyanMqttMsgHandler_t *)eventData;
-        rlog_w("mqtt取消订阅失败回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
-        break;
-    }
-
-    case RyanMqttEventPublished:
-    {
-        RyanMqttMsgHandler_t *msgHandler = ((RyanMqttAckHandler_t *)eventData)->msgHandler;
-        rlog_w("qos1 / qos2发送成功事件回调 topic: %s, qos: %d", msgHandler->topic, msgHandler->qos);
-        mqttTest[PublishedEventCount]++;
-        break;
-    }
-
-    case RyanMqttEventData:
-    {
-        RyanMqttMsgData_t *msgData = (RyanMqttMsgData_t *)eventData;
-        rlog_i("接收到mqtt消息事件回调 topic: %.*s, packetId: %d, payload len: %d",
-               msgData->topicLen, msgData->topic, msgData->packetId, msgData->payloadLen);
-
-        rlog_i("%.*s", msgData->payloadLen, msgData->payload);
-        mqttTest[dataEventCount]++;
-        break;
-    }
-
-    case RyanMqttEventRepeatPublishPacket: // qos2 / qos1重发事件回调
-    {
-        RyanMqttAckHandler_t *ackHandler = (RyanMqttAckHandler_t *)eventData;
-        rlog_w("发布消息进行重发了,packetType: %d, packetId: %d, topic: %s, qos: %d",
-               ackHandler->packetType, ackHandler->packetId, ackHandler->msgHandler->topic, ackHandler->msgHandler->qos);
-
-        printfArrStr(ackHandler->packet, ackHandler->packetLen, "重发数据: ");
-        break;
-    }
-
-    case RyanMqttEventReconnectBefore:
-        // 如果每次connect都需要修改连接信息,这里是最好的选择。 否则需要注意资源互斥
-        rlog_i("重连前事件回调");
-        break;
-
-    case RyanMqttEventAckCountWarning: // qos2 / qos1的ack链表超过警戒值,不进行释放会一直重发,占用额外内存
-    {
-        // 根据实际情况清除ack, 这里等待每个ack重发次数到达警戒值后清除。
-        // 在资源有限的单片机中也不应频繁发送qos2 / qos1消息
-        uint16_t ackHandlerCount = *(uint16_t *)eventData;
-        rlog_i("ack记数值超过警戒值回调: %d", ackHandlerCount);
-        break;
-    }
-
-    case RyanMqttEventAckRepeatCountWarning: // 重发次数到达警戒值事件
-    {
-        // 这里选择直接丢弃该消息
-        RyanMqttAckHandler_t *ackHandler = (RyanMqttAckHandler_t *)eventData;
-        rlog_w("ack重发次数超过警戒值回调 packetType: %d, packetId: %d, topic: %s, qos: %d", ackHandler->packetType, ackHandler->packetId, ackHandler->msgHandler->topic, ackHandler->msgHandler->qos);
-        RyanMqttDiscardAckHandler(client, ackHandler->packetType, ackHandler->packetId);
-        break;
-    }
-
-    case RyanMqttEventAckHandlerdiscard:
-    {
-        RyanMqttAckHandler_t *ackHandler = (RyanMqttAckHandler_t *)eventData;
-        rlog_i("ack丢弃回调: packetType: %d, packetId: %d, topic: %s, qos: %d",
-               ackHandler->packetType, ackHandler->packetId, ackHandler->msgHandler->topic, ackHandler->msgHandler->qos);
-        break;
-    }
-
-    case RyanMqttEventDestoryBefore:
-        rlog_i("销毁mqtt客户端前回调");
-        free(client->config.sendBuffer);
-        free(client->config.recvBuffer);
-        if (client->config.userData)
-            sem_post((sem_t *)client->config.userData);
-        break;
-
-    default:
-        break;
-    }
-}
-
-static int32_t RyanMqttInitSync(RyanMqttClient_t **client, RyanMqttBool_e syncFlag)
-{
-
-    char aaa[64];
-
-    // 手动避免count的资源竞争了
-    static uint32_t count = 0;
-    snprintf(aaa, sizeof(aaa), "%s%d", RyanMqttClientId, count);
-    count++;
-
-    sem_t *sem = NULL;
-    if (syncFlag == RyanMqttTrue)
-    {
-        sem = (sem_t *)malloc(sizeof(sem_t));
-        sem_init(sem, 0, 0);
-    }
-
-    RyanMqttError_e result = RyanMqttSuccessError;
-    RyanMqttClientConfig_t mqttConfig = {
-        .clientId = aaa,
-        .userName = RyanMqttUserName,
-        .password = RyanMqttPassword,
-        .host = RyanMqttHost,
-        .port = RyanMqttPort,
-        .taskName = "mqttThread",
-        .taskPrio = 16,
-        .taskStack = 4096,
-        .recvBufferSize = 1024,
-        .sendBufferSize = 1024,
-        .recvBuffer = malloc(1024),
-        .sendBuffer = malloc(1024),
-        .mqttVersion = 4,
-        .ackHandlerRepeatCountWarning = 6,
-        .ackHandlerCountWarning = 20,
-        .autoReconnectFlag = RyanMqttTrue,
-        .cleanSessionFlag = RyanMqttTrue,
-        .reconnectTimeout = 3000,
-        .recvTimeout = 5000,
-        .sendTimeout = 2000,
-        .ackTimeout = 10000,
-        .keepaliveTimeoutS = 120,
-        .mqttEventHandle = mqttEventHandle,
-        .userData = sem};
-
-    // 初始化mqtt客户端
-    result = RyanMqttInit(client);
-    RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_e);
-
-    // 注册需要的事件回调
-    result = RyanMqttRegisterEventId(*client, RyanMqttEventAnyId);
-    RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_e);
-
-    // 设置mqtt客户端config
-    result = RyanMqttSetConfig(*client, &mqttConfig);
-    RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_e);
-
-    // 设置遗嘱消息
-    result = RyanMqttSetLwt(*client, "pub/test", "this is will", strlen("this is will"), RyanMqttQos0, 0);
-    RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_e);
-
-    // 启动mqtt客户端线程
-    result = RyanMqttStart(*client);
-    RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_e);
-
-    while (RyanMqttConnectState != RyanMqttGetState(*client))
-    {
-        delay(100);
-    }
-
-    return 0;
-}
-
-static void RyanMqttDestorySync(RyanMqttClient_t *client)
-{
-    sem_t *sem = (sem_t *)client->config.userData;
-    // 启动mqtt客户端线程
-    RyanMqttDestroy(client);
-
-    sem_wait(sem);
-    sem_destroy(sem);
-    free(sem);
-    delay(3);
-}
-
-static RyanMqttError_e RyanMqttSubscribeTest(RyanMqttQos_e qos)
-{
-
-#define getArraySize(arr) (sizeof(arr) / sizeof((arr)[0]))
-
-    RyanMqttClient_t *client;
-    RyanMqttInitSync(&client, RyanMqttTrue);
-
-    char *subscribeArr[] = {
-        "testlinux/pub",
-        "testlinux/pub2",
-        "testlinux/pub3",
-        "testlinux/pub4",
-        "testlinux/pub5",
-    };
-
-    for (uint8_t i = 0; i < getArraySize(subscribeArr); i++)
-        RyanMqttSubscribe(client, subscribeArr[i], qos);
-
-    RyanMqttMsgHandler_t msgHandles[10] = {0};
-    int32_t subscribeNum = 0;
-    int32_t result = RyanMqttSuccessError;
-
-    delay(100);
-    for (int32_t i = 0; i < 600; i++)
-    {
-        result = RyanMqttGetSubscribe(client, msgHandles, getArraySize(msgHandles), &subscribeNum);
-        if (result == RyanMqttNoRescourceError)
-            rlog_w("订阅主题数超过缓冲区%d个,已截断,请修改msgHandles缓冲区", getArraySize(msgHandles));
-
-        if (subscribeNum == getArraySize(subscribeArr))
-            break;
-
-        rlog_i("mqtt客户端已订阅的主题数: %d, 应该订阅主题数: %d", subscribeNum, getArraySize(subscribeArr));
-        for (int32_t i = 0; i < subscribeNum; i++)
-            rlog_i("已经订阅主题: %d, topic: %s, QOS: %d", i, msgHandles[i].topic, msgHandles[i].qos);
-
-        if (i > 500)
-            return RyanMqttFailedError;
-
-        delay(100);
-    }
-
-    for (int32_t i = 0; i < subscribeNum; i++)
-    {
-        uint8_t flag = 0;
-        for (uint8_t j = 0; j < getArraySize(subscribeArr); j++)
-        {
-            if (0 == strcmp(msgHandles[i].topic, subscribeArr[j]))
-                flag = 1;
-        }
-
-        if (flag != 1)
-        {
-            rlog_i("主题不匹配: %d", msgHandles[i].topic);
-            return RyanMqttFailedError;
-        }
-    }
-
-    for (uint8_t i = 0; i < getArraySize(subscribeArr); i++)
-        RyanMqttUnSubscribe(client, subscribeArr[i]);
-
-    for (int32_t i = 0; i < 600; i++)
-    {
-        result = RyanMqttGetSubscribe(client, msgHandles, getArraySize(msgHandles), &subscribeNum);
-        if (result == RyanMqttNoRescourceError)
-            rlog_w("订阅主题数超过缓冲区%d个,已截断,请修改msgHandles缓冲区", getArraySize(msgHandles));
-
-        if (0 == subscribeNum)
-            break;
-
-        if (i > 500)
-            return RyanMqttFailedError;
-
-        delay(100);
-    }
-
-    RyanMqttDestorySync(client);
-
-    return RyanMqttSuccessError;
-}
-
-static RyanMqttError_e RyanMqttUnSubscribeTest(RyanMqttQos_e qos)
-{
-
-    int count = 2;
-
-#define getArraySize(arr) (sizeof(arr) / sizeof((arr)[0]))
-
-    RyanMqttClient_t *client;
-    RyanMqttInitSync(&client, RyanMqttTrue);
-
-    char *subscribeArr[] = {
-        "testlinux/pub",
-        "testlinux/pub2",
-        "testlinux/pub3",
-        "testlinux/pub4",
-        "testlinux/pub5",
-    };
-
-    for (uint8_t i = 0; i < getArraySize(subscribeArr); i++)
-        RyanMqttSubscribe(client, subscribeArr[i], qos);
-
-    RyanMqttMsgHandler_t msgHandles[10] = {0};
-    int32_t subscribeNum = 0;
-    int32_t result = RyanMqttSuccessError;
-
-    delay(100);
-    for (int32_t i = 0; i < 600; i++)
-    {
-        result = RyanMqttGetSubscribe(client, msgHandles, getArraySize(msgHandles), &subscribeNum);
-        if (result == RyanMqttNoRescourceError)
-            rlog_w("订阅主题数超过缓冲区%d个,已截断,请修改msgHandles缓冲区", getArraySize(msgHandles));
-
-        if (subscribeNum == getArraySize(subscribeArr))
-            break;
-
-        rlog_i("mqtt客户端已订阅的主题数: %d, 应该订阅主题数: %d", subscribeNum, getArraySize(subscribeArr));
-
-        if (i > 500)
-            return RyanMqttFailedError;
-
-        delay(100);
-    }
-
-    // 取消订阅指定的数值
-    for (uint8_t i = 0; i < getArraySize(subscribeArr) - count - 1; i++)
-        RyanMqttUnSubscribe(client, subscribeArr[i]);
-
-    delay(100);
-    for (int32_t i = 0; i < 600; i++)
-    {
-        result = RyanMqttGetSubscribe(client, msgHandles, getArraySize(msgHandles), &subscribeNum);
-        if (result == RyanMqttNoRescourceError)
-            rlog_w("订阅主题数超过缓冲区%d个,已截断,请修改msgHandles缓冲区", getArraySize(msgHandles));
-
-        if (subscribeNum == getArraySize(subscribeArr) - count)
-            break;
-
-        rlog_i("mqtt客户端已订阅的主题数: %d, 应该订阅主题数: %d", subscribeNum, getArraySize(subscribeArr) - count);
-
-        if (i > 500)
-            return RyanMqttFailedError;
-
-        delay(100);
-    }
-
-    for (int32_t i = 0; i < subscribeNum; i++)
-    {
-        uint8_t flag = 0;
-        for (uint8_t j = count - 1; j < getArraySize(subscribeArr); j++)
-        {
-            if (0 == strcmp(msgHandles[i].topic, subscribeArr[j]))
-                flag = 1;
-        }
-
-        if (flag != 1)
-        {
-            rlog_i("主题不匹配: %d", msgHandles[i].topic);
-            return RyanMqttFailedError;
-        }
-    }
-
-    RyanMqttDestorySync(client);
-
-    return RyanMqttSuccessError;
-}
-
-static int RyanMqttPublishTest(RyanMqttQos_e qos, uint32_t count, uint32_t delayms)
-{
-    RyanMqttClient_t *client;
-    RyanMqttInitSync(&client, RyanMqttTrue);
-
-    RyanMqttSubscribe(client, "testlinux/pub", qos);
-    mqttTest[PublishedEventCount] = 0;
-    mqttTest[dataEventCount] = 0;
-    for (uint32_t i = 0; i < count; i++)
-    {
-        RyanMqttError_e result = RyanMqttPublish(client, "testlinux/pub", "helloworld", strlen("helloworld"), qos, RyanMqttFalse);
-        if (RyanMqttSuccessError != result)
-        {
-            rlog_e("QOS发布错误 Qos: %d, result: %d", qos, result);
-            return -1;
-        }
-
-        if (delayms)
-            delay(delayms);
-    }
-
-    for (uint32_t i = 0; i < 60; i++)
-    {
-        delay(1000);
-
-        uint8_t result = 0;
-        if (RyanMqttQos0 == qos)
-        {
-            if (count == mqttTest[dataEventCount])
-                result = 1;
-        }
-        else if (mqttTest[PublishedEventCount] == count && mqttTest[PublishedEventCount] == mqttTest[dataEventCount])
-            result = 1;
-
-        if (!result)
-        {
-            rlog_e("QOS测试失败 Qos: %d, PublishedEventCount: %d, dataEventCount: %d", qos, mqttTest[PublishedEventCount], mqttTest[dataEventCount]);
-            return -1;
-        }
-        else
-        {
-            rlog_i("QOS测试成功 Qos: %d", qos);
-            break;
-        }
-    }
-
-    RyanMqttUnSubscribe(client, "testlinux/pub");
-
-    RyanMqttDestorySync(client);
-    return 0;
-}
-
-static void RyanMqttConnectDestory(uint32_t count, uint32_t delayms)
-{
-    for (uint32_t i = 0; i < count; i++)
-    {
-
-        RyanMqttClient_t *client;
-
-        RyanMqttInitSync(&client, i == count - 1 ? RyanMqttTrue : RyanMqttFalse);
-
-        RyanMqttPublish(client, "testlinux/pub", "helloworld", strlen("helloworld"), RyanMqttQos0, RyanMqttFalse);
-
-        if (delayms)
-            delay(delayms);
-
-        if (i == count - 1) // 最后一次同步释放
-        {
-            RyanMqttDestorySync(client);
-            delay(1000);
-        }
-        else
-            RyanMqttDestroy(client);
-    }
-}
-
-static void RyanMqttReconnectTest(uint32_t count, uint32_t delayms)
-{
-    RyanMqttClient_t *client;
-    RyanMqttInitSync(&client, RyanMqttTrue);
-    for (uint32_t i = 0; i < count; i++)
-    {
-        RyanMqttDisconnect(client, i % 2 == 0);
-        while (RyanMqttConnectState != RyanMqttGetState(client))
-        {
-            delay(1);
-        }
-
-        if (delayms)
-            delay(delayms);
-    }
-
-    RyanMqttDestorySync(client);
-}
-
-static RyanMqttError_e RyanMqttKeepAliveTest()
-{
-    RyanMqttClient_t *client;
-    RyanMqttError_e result = RyanMqttSuccessError;
-
-    sem_t *sem = (sem_t *)malloc(sizeof(sem_t));
-    sem_init(sem, 0, 0);
-    RyanMqttClientConfig_t mqttConfig = {
-        .clientId = "dfawerwdfgaeruyfku",
-        .userName = RyanMqttUserName,
-        .password = RyanMqttPassword,
-        .host = RyanMqttHost,
-        .port = RyanMqttPort,
-        .taskName = "mqttThread",
-        .taskPrio = 16,
-        .taskStack = 4096,
-        .recvBufferSize = 1024,
-        .sendBufferSize = 1024,
-        .recvBuffer = malloc(1024),
-        .sendBuffer = malloc(1024),
-        .mqttVersion = 4,
-        .ackHandlerRepeatCountWarning = 6,
-        .ackHandlerCountWarning = 20,
-        .autoReconnectFlag = RyanMqttTrue,
-        .cleanSessionFlag = RyanMqttTrue,
-        .reconnectTimeout = 3000,
-        .recvTimeout = 5000,
-        .sendTimeout = 2000,
-        .ackTimeout = 10000,
-        .keepaliveTimeoutS = 30,
-        .mqttEventHandle = mqttEventHandle,
-        .userData = sem};
-
-    // 初始化mqtt客户端
-    result = RyanMqttInit(&client);
-    RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_e);
-
-    // 注册需要的事件回调
-    result = RyanMqttRegisterEventId(client, RyanMqttEventAnyId);
-    RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_e);
-
-    // 设置mqtt客户端config
-    result = RyanMqttSetConfig(client, &mqttConfig);
-    RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_e);
-
-    // 启动mqtt客户端线程
-    result = RyanMqttStart(client);
-    RyanMqttCheck(RyanMqttSuccessError == result, result, rlog_e);
-
-    while (RyanMqttConnectState != RyanMqttGetState(client))
-    {
-        delay(100);
-    }
-
-    // recvTimeout = 5000,每过 5000 ms检查一次心跳周期,如果超过 3 / 4 时间就会进行心跳保活
-    for (uint32_t i = 0; i < 90; i++)
-    {
-        if (RyanMqttConnectState != RyanMqttGetState(client))
-        {
-            rlog_e("mqtt断连了");
-            return RyanMqttFailedError;
-        }
-
-        rlog_w("心跳倒计时: %d", platformTimerRemain(&client->keepaliveTimer));
-        delay(1000);
-    }
-
-    RyanMqttDestorySync(client);
-
-    return RyanMqttSuccessError;
-}
-
-// !当测试程序出错时,并不会回收内存。交由父进程进行回收
-int main()
-{
-    vallocInit();
-    int result = 0;
-
-    RyanMqttCheckCode(RyanMqttSuccessError == RyanMqttSubscribeTest(RyanMqttQos0), RyanMqttFailedError, rlog_e, { goto __exit; });
-    RyanMqttCheckCode(RyanMqttSuccessError == RyanMqttSubscribeTest(RyanMqttQos1), RyanMqttFailedError, rlog_e, { goto __exit; });
-    RyanMqttCheckCode(RyanMqttSuccessError == RyanMqttSubscribeTest(RyanMqttQos2), RyanMqttFailedError, rlog_e, { goto __exit; });
-
-    RyanMqttCheckCode(RyanMqttSuccessError == RyanMqttUnSubscribeTest(RyanMqttQos0), RyanMqttFailedError, rlog_e, { goto __exit; });
-    RyanMqttCheckCode(RyanMqttSuccessError == RyanMqttUnSubscribeTest(RyanMqttQos1), RyanMqttFailedError, rlog_e, { goto __exit; });
-    RyanMqttCheckCode(RyanMqttSuccessError == RyanMqttUnSubscribeTest(RyanMqttQos2), RyanMqttFailedError, rlog_e, { goto __exit; });
-
-    // 发布 & 订阅 qos 测试
-    result = RyanMqttPublishTest(RyanMqttQos0, 1000, 0);
-    if (result != 0)
-        goto __exit;
-    checkMemory;
-
-    result = RyanMqttPublishTest(RyanMqttQos1, 1000, 1);
-    if (result != 0)
-        goto __exit;
-    checkMemory;
-
-    result = RyanMqttPublishTest(RyanMqttQos2, 1000, 1);
-    if (result != 0)
-        goto __exit;
-    checkMemory;
-
-    RyanMqttConnectDestory(100, 0);
-    checkMemory;
-
-    RyanMqttReconnectTest(3, 0);
-    checkMemory;
-
-    RyanMqttCheckCode(RyanMqttSuccessError == RyanMqttKeepAliveTest(), RyanMqttFailedError, rlog_e, { goto __exit; });
-
-__exit:
-    while (1)
-    {
-        displayMem();
-        delay(10 * 1000);
-    }
-
-    return 0;
-}

+ 34 - 6
xmake.lua

@@ -1,16 +1,44 @@
+add_rules("plugin.compile_commands.autoupdate", {outputdir = ".vscode"})
 target("RyanMqtt",function()
-    set_kind("static")
+    set_kind("binary")
+
+    add_syslinks("pthread")
+    set_toolchains("gcc")  -- 确保使用 GCC
+    -- set_toolchains("clang-20")  -- 确保使用 GCC
+    set_languages("gnu99") -- 关键!启用 GNU 扩展
+    set_warnings("everything") -- 启用全部警告 -Wall -Wextra -Weffc++ / -Weverything
+
+    -- set_optimize("smallest") -- -Os
+    -- set_optimize("faster") -- -O2
+    set_optimize("fastest") -- -O3
+
+    add_defines("PKG_USING_RYANMQTT_IS_ENABLE_ASSERT") -- 开启assert
+
+    add_cxflags(
+                "-pedantic",  
+                "-Wall",
+                "-Wextra",
+                "-Wno-unused-parameter",
+                -- clang的
+                -- "-Wno-gnu-zero-variadic-macro-arguments",
+                -- "-Wno-c23-extensions",
+                {force=true})
+    
 
-    description_csdk()
 
     --加入代码和头文件
     add_includedirs('./common', {public = true})
-    add_includedirs('./pahoMqtt', {public = true})
+    add_includedirs('./coreMqtt', {public = true})
     add_includedirs('./mqttclient', {public = true})
-    add_includedirs('./platform/openLuat', {public = true})
+    add_includedirs('./platform/linux', {public = true})
+    add_includedirs('./platform/linux/valloc', {public = true})
 
+    add_files('./test/*.c', {public = true})
     add_files('./common/*.c', {public = true})
-    add_files('./pahoMqtt/*.c', {public = true})
+    add_files('./coreMqtt/*.c', {public = true})
     add_files('./mqttclient/*.c', {public = true})
-    add_files('./platform/openLuat/*.c', {public = true})
+    add_files('./platform/linux/*.c', {public = true})
+    add_files('./platform/linux/valloc/*.c', {public = true})
+
+          add_ldflags("-Wl,-Map=$(buildir)/RyanMqtt.map") 
 end)

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است