[嵌入式开发模块]Coap开源库libnyoci移植及简单使用(基于wiz/W5500官方io库)

ゞ 浴缸里的玫瑰 2021-12-05 01:43 695阅读 0赞

文章目录

  • 前言
  • 工程环境配置
    • 配置文件
      • config.h
      • nyoci-config.h
  • 平台移植
    • nyoci-plat-net.h
    • nyoci-plat-net-internal.h
    • nyoci-plat-net.c
    • 简要说明
  • 使用示例
    • 示例代码
    • 简要说明
    • 测试
  • 总结

前言

最近研究了下实现coap协议,几个纯C开源库看下来感觉还是libnyoci移植起来靠谱点,其他库要不然对POSIX的API强耦合,要不反正就是不知道怎么搞。

折腾好久起码现在能够实现一个正常的Coap服务器了,发上来供需要的人参考。

因为这个库依赖了大量相对高级版本的标准库函数以及(如果要完整移植的话)要求实现很多应用层网络功能,如DNS、TSL什么的,所以着实折腾了好久才成功编译。

这里只讲到要实现一个基于UDP的Coap服务器所需要移植的部分。

工程环境配置

首先,先去全球最大的同性交友网站下载好libnyoci的源文件,完不成的话点击下右上角的×

然后libnyoci\src\libnyoci中的.c和.h文件全扔进工程中,基本都会用到。
libnyoci\src\libnyociextra中的文件则根据需要放进工程中,取决于你使用这个库的方法。

然后我们需要加入配置文件,在这之前先打开编译器选项,加入宏定义HAVE_CONFIG_H=1

在我的CodeWarrior上是这样子实现的:
watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpbl9zdHJvbmc_size_16_color_FFFFFF_t_70
不同的IDE找各自的方法。

配置文件

这样子nyoci就知道了你会包含一个叫做config.h的配置文件;以及默认会有的nyoci-config.h配置文件。这两个文件如下:

config.h

  1. /* src/config.h. Generated from config.h.in by configure. */
  2. /* src/config.h.in. Generated from configure.ac by autoheader. */
  3. /* rl_completion_entry_function has the wrong return type */
  4. #define HAS_LIBEDIT_COMPLETION_ENTRY_BUG 1
  5. /* Define to 1 if you have the `alloca' function. */
  6. /* #undef HAVE_ALLOCA */
  7. /* Define to 1 if you have the <alloca.h> header file. */
  8. #define HAVE_ALLOCA_H 0
  9. /* Define to 1 if you have the <dlfcn.h> header file. */
  10. #define HAVE_DLFCN_H 0
  11. /* Define to 1 if you have the <errno.h> header file. */
  12. #define HAVE_ERRNO_H 1
  13. /* Define to 1 if you have the `fprintf' function. */
  14. #define HAVE_FPRINTF 0
  15. /* Define to 1 if the system has the `deprecated' function attribute */
  16. #define HAVE_FUNC_ATTRIBUTE_DEPRECATED 0
  17. /* Define to 1 if the system has the `pure' function attribute */
  18. #define HAVE_FUNC_ATTRIBUTE_PURE 0
  19. /* Define to 1 if you have the `getline' function. */
  20. #define HAVE_GETLINE 0
  21. /* Define to 1 if you have the `getloadavg' function. */
  22. #define HAVE_GETLOADAVG 0
  23. /* Define to 1 if you have the `gettimeofday' function. */
  24. #define HAVE_GETTIMEOFDAY 0
  25. /* Define to 1 if you have the <inttypes.h> header file. */
  26. #define HAVE_INTTYPES_H 0
  27. /* Define to 1 if you have the `readline' library (-lreadline). */
  28. #define HAVE_LIBREADLINE 0
  29. /* Define to 1 if you have the `malloc' function. */
  30. #define HAVE_MALLOC 1
  31. /* Define to 1 if you have the `memcmp' function. */
  32. #define HAVE_MEMCMP 1
  33. /* Define to 1 if you have the <memory.h> header file. */
  34. #define HAVE_MEMORY_H 0
  35. /* Define to 1 if you have the `memset' function. */
  36. #define HAVE_MEMSET 1
  37. /* Set if OpenSSL is present */
  38. /* #undef HAVE_OPENSSL */
  39. /* Set if OpenSSL has DTLSv1_method() */
  40. /* #undef HAVE_OPENSSL_DTLSV1_METHOD */
  41. /* Set if OpenSSL has DTLS_method() */
  42. /* #undef HAVE_OPENSSL_DTLS_METHOD */
  43. /* Set if OpenSSL has SSL_CONF_CTX_new() */
  44. /* #undef HAVE_OPENSSL_SSL_CONF_CTX_NEW */
  45. /* Set if OpenSSL has SSL_CONF_finish() */
  46. /* #undef HAVE_OPENSSL_SSL_CONF_FINISH */
  47. /* Define to 1 if you have the `printf' function. */
  48. #define HAVE_PRINTF 1
  49. /* Define if you have POSIX threads libraries and header files. */
  50. #define HAVE_PTHREAD 0
  51. /* Have PTHREAD_PRIO_INHERIT. */
  52. #define HAVE_PTHREAD_PRIO_INHERIT 0
  53. /* Define to 1 if you have the `rl_set_prompt' function. */
  54. #define HAVE_RL_SET_PROMPT 0
  55. /* Define to 1 if you have the `setenv' function. */
  56. #define HAVE_SETENV 0
  57. /* Define to 1 if you have the `snprintf' function. */
  58. #define HAVE_SNPRINTF 1
  59. /* Define to 1 if you have the `sprintf' function. */
  60. #define HAVE_SPRINTF 1
  61. /* Define to 1 if you have the <stdarg.h> header file. */
  62. #define HAVE_STDARG_H 1
  63. /* Define to 1 if you have the <stdbool.h> header file. */
  64. #define HAVE_STDBOOL_H 1
  65. /* Define to 1 if you have the <stddef.h> header file. */
  66. #define HAVE_STDDEF_H 1
  67. /* Define to 1 if you have the <stdint.h> header file. */
  68. #define HAVE_STDINT_H 1
  69. /* Define to 1 if you have the <stdio.h> header file. */
  70. #define HAVE_STDIO_H 1
  71. /* Define to 1 if you have the <stdlib.h> header file. */
  72. #define HAVE_STDLIB_H 1
  73. /* Define to 1 if you have the `stpncpy' function. */
  74. #define HAVE_STPNCPY 1
  75. /* Define to 1 if you have the `strchr' function. */
  76. #define HAVE_STRCHR 1
  77. /* Define to 1 if you have the `strdup' function. */
  78. #define HAVE_STRDUP 0
  79. #define HAVE_STRSEP 0
  80. /* Define to 1 if you have the `strerror' function. */
  81. #define HAVE_STRERROR 0
  82. /* Define to 1 if you have the <strings.h> header file. */
  83. #define HAVE_STRINGS_H 0
  84. /* Define to 1 if you have the <string.h> header file. */
  85. #define HAVE_STRING_H 1
  86. /* Define to 1 if you have the `strlcat' function. */
  87. #define HAVE_STRLCAT 1
  88. /* Define to 1 if you have the `strlcpy' function. */
  89. #define HAVE_STRLCPY 0
  90. /* Define to 1 if you have the `strndup' function. */
  91. #define HAVE_STRNDUP 0
  92. /* Define to 1 if you have the `strstr' function. */
  93. #define HAVE_STRSTR 1
  94. /* Define to 1 if you have the `strtol' function. */
  95. #define HAVE_STRTOL 1
  96. /* Define to 1 if you have the <sys/stat.h> header file. */
  97. #define HAVE_SYS_STAT_H 0
  98. /* Define to 1 if you have the <sys/types.h> header file. */
  99. #define HAVE_SYS_TYPES_H 0
  100. /* Define to 1 if you have the <unistd.h> header file. */
  101. #define HAVE_UNISTD_H 0
  102. /* Define to 1 if you have the `vsnprintf' function. */
  103. #define HAVE_VSNPRINTF 0
  104. /* Define to 1 if you have the `vsprintf' function. */
  105. #define HAVE_VSPRINTF 0
  106. #define HAVE_C99_VLA 0
  107. /* Define to the sub-directory where libtool stores uninstalled libraries. */
  108. //#define LT_OBJDIR ".libs/"
  109. /* . */
  110. //#define NYOCI_API_EXTERN extern
  111. /* . */
  112. /* #undef NYOCI_AVOID_MALLOC */
  113. /* . */
  114. /* #undef NYOCI_AVOID_PRINTF */
  115. /* . */
  116. /* #undef NYOCI_CONF_NODE_ROUTER */
  117. /* . */
  118. /* #undef NYOCI_CONF_TRANS_ENABLE_BLOCK2 */
  119. /* . */
  120. /* #undef NYOCI_CONF_TRANS_ENABLE_OBSERVING */
  121. /* . */
  122. /* #undef NYOCI_EMBEDDED */
  123. /* . */
  124. //#define NYOCI_INTERNAL_EXTERN extern
  125. /* . */
  126. /* #undef NYOCI_MAX_OBSERVERS */
  127. /* . */
  128. /* #undef NYOCI_MAX_VHOSTS */
  129. /* LibNyoci network abstraction */
  130. //#define NYOCI_PLAT_NET posix
  131. /* . */
  132. /* #undef NYOCI_PLAT_NET_POSIX_FAMILY */
  133. /* LibNyoci TLS abstraction */
  134. /* #undef NYOCI_PLAT_TLS */
  135. /* . */
  136. /* #undef NYOCI_SINGLETON */
  137. /* . */
  138. /* #undef NYOCI_USE_CASCADE_COUNT */
  139. /* Name of package */
  140. #define PACKAGE "libnyoci"
  141. /* Define to the address where bug reports for this package should be sent. */
  142. #define PACKAGE_BUGREPORT "https://github.com/darconeous/libnyoci/"
  143. /* Define to the full name of this package. */
  144. #define PACKAGE_NAME "LibNyoci"
  145. /* Define to the full name and version of this package. */
  146. #define PACKAGE_STRING "LibNyoci 0.07.00rc1"
  147. /* Define to the one symbol short name of this package. */
  148. #define PACKAGE_TARNAME "libnyoci"
  149. /* Define to the home page for this package. */
  150. #define PACKAGE_URL "http://libnyoci.org/"
  151. /* Define to the version of this package. */
  152. #define PACKAGE_VERSION "0.07.00rc1"
  153. /* Define to necessary symbol if this constant uses a non-standard name on
  154. your system. */
  155. /* #undef PTHREAD_CREATE_JOINABLE */
  156. /* Source version */
  157. #define SOURCE_VERSION "0.07.00rc1-6-g5ad1f3d"
  158. /* Define to 1 if you have the ANSI C header files. */
  159. #define STDC_HEADERS 1
  160. /* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
  161. #define TIME_WITH_SYS_TIME 0
  162. /* Enable extensions on AIX 3, Interix. */
  163. //#ifndef _ALL_SOURCE
  164. // #define _ALL_SOURCE 1
  165. //#endif
  166. /* Enable GNU extensions on systems that have them. */
  167. //#ifndef _GNU_SOURCE
  168. //# define _GNU_SOURCE 1
  169. //#endif
  170. /* Enable threading extensions on Solaris. */
  171. //#ifndef _POSIX_PTHREAD_SEMANTICS
  172. //# define _POSIX_PTHREAD_SEMANTICS 1
  173. //#endif
  174. /* Enable extensions on HP NonStop. */
  175. //#ifndef _TANDEM_SOURCE
  176. //# define _TANDEM_SOURCE 1
  177. //#endif
  178. /* Enable general extensions on Solaris. */
  179. //#ifndef __EXTENSIONS__
  180. //# define __EXTENSIONS__ 1
  181. //#endif
  182. #define DEBUG 1
  183. #define VERBOSE_DEBUG 1
  184. #define __ORDER_BIG_ENDIAN__ 1
  185. #define __BYTE_ORDER__ 0
  186. /* Version number of package */
  187. #define VERSION "0.07.00rc1"
  188. /* Define to 1 if on MINIX. */
  189. /* #undef _MINIX */
  190. /* Define to 2 if the system does not provide POSIX.1 features except with
  191. this defined. */
  192. /* #undef _POSIX_1_SOURCE */
  193. /* Define to 1 if you need to in order for `stat' and other things to work. */
  194. /* #undef _POSIX_SOURCE */
  195. /* Define to empty if `const' does not conform to ANSI C. */
  196. /* #undef const */
  197. /* Define to `__inline__' or `__inline' if that's what the C compiler
  198. calls it, or to nothing if 'inline' is not supported under any name. */
  199. #ifndef __cplusplus
  200. /* #undef inline */
  201. #endif
  202. /* Define to `unsigned int' if <sys/types.h> does not define. */
  203. /* #undef size_t */
  204. /* Define to `int' if <sys/types.h> does not define. */
  205. /* #undef ssize_t */
  206. /* Define to empty if the keyword `volatile' does not work. Warning: valid
  207. code using `volatile' can become incorrect without. Disable with care. */
  208. /* #undef volatile */

这个文件主要是用于告知nyoci你的开发环境有没有包含某个函数以配置代码,上面是我目前的配置。请参照自己的开发环境按注释配置好其中未注释掉的部分,以减少编译链接时一堆报警。。

要注意的是

  1. #define __ORDER_BIG_ENDIAN__ 1
  2. #define __BYTE_ORDER__ 0

这里两个其实并不是让你回答机器是大端还是小端的。它的功能就是帮助nyoci确定位序以确定:

  1. struct coap_header_s {
  2. #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
  3. uint8_t
  4. version:2,
  5. tt:2,
  6. token_len:4;
  7. #else
  8. uint8_t
  9. token_len:4,
  10. tt:2,
  11. version:2;
  12. #endif
  13. ……
  14. };

这个结构体中到底应该按什么顺序排这三个字段。这个可能和单片机与编译器都有关,不见得大端字节序的就一定大端位序。反正就是两个值相等和两个值不等的都试一下,用成功通讯的那个就好。

nyoci-config.h

  1. /*! @file nyoci-config.h
  2. ** @author Robert Quattlebaum <darco@deepdarc.com>
  3. ** @brief LibNyoci Build Options
  4. **
  5. ** Copyright (C) 2017 Robert Quattlebaum
  6. **
  7. ** Permission is hereby granted, free of charge, to any person
  8. ** obtaining a copy of this software and associated
  9. ** documentation files (the "Software"), to deal in the
  10. ** Software without restriction, including without limitation
  11. ** the rights to use, copy, modify, merge, publish, distribute,
  12. ** sublicense, and/or sell copies of the Software, and to
  13. ** permit persons to whom the Software is furnished to do so,
  14. ** subject to the following conditions:
  15. **
  16. ** The above copyright notice and this permission notice shall
  17. ** be included in all copies or substantial portions of the
  18. ** Software.
  19. **
  20. ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
  21. ** KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  22. ** WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  23. ** PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
  24. ** OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  25. ** OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  26. ** OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  27. ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. */
  29. // 1/0
  30. #define NYOCI_EMBEDDED 1
  31. // 1/0
  32. #define NYOCI_SINGLETON 0
  33. #undef NYOCI_PLAT_NET_POSIX_FAMILY
  34. #undef NYOCI_PLAT_NET
  35. // define/undef
  36. #undef NYOCI_PLAT_TLS
  37. #undef NYOCI_AVOID_MALLOC
  38. #undef NYOCI_AVOID_PRINTF
  39. #undef NYOCI_DEFAULT_PORT
  40. #undef NYOCI_CONF_DUPE_BUFFER_SIZE
  41. #undef NYOCI_CONF_ENABLE_VHOSTS
  42. #define NYOCI_CONF_MAX_ALLOCED_NODES 2
  43. #undef NYOCI_CONF_MAX_GROUPS
  44. #undef NYOCI_CONF_MAX_OBSERVERS
  45. #undef NYOCI_CONF_MAX_PAIRINGS
  46. #undef NYOCI_CONF_MAX_TIMEOUT
  47. #define NYOCI_CONF_NODE_ROUTER
  48. #undef NYOCI_CONF_TRANS_ENABLE_BLOCK2
  49. #undef NYOCI_CONF_TRANS_ENABLE_OBSERVING
  50. // 0/1
  51. #define NYOCI_CONF_USE_DNS 0
  52. #undef NYOCI_ADD_NEWLINES_TO_LIST_OUTPUT
  53. #undef NYOCI_ASYNC_RESPONSE_MAX_LENGTH 50
  54. #undef NYOCI_DEBUG_INBOUND_DROP_PERCENT
  55. #undef NYOCI_DEBUG_OUTBOUND_DROP_PERCENT
  56. #undef NYOCI_MAX_CASCADE_COUNT
  57. #define NYOCI_MAX_CONTENT_LENGTH 50
  58. #undef NYOCI_MAX_OBSERVERS
  59. #undef NYOCI_MAX_PACKET_LENGTH
  60. #undef NYOCI_MAX_PATH_LENGTH
  61. #undef NYOCI_MAX_URI_LENGTH
  62. #undef NYOCI_MAX_VHOSTS
  63. #undef NYOCI_TRANSACTION_BURST_COUNT
  64. #undef NYOCI_TRANSACTION_BURST_TIMEOUT_MAX
  65. #undef NYOCI_TRANSACTION_BURST_TIMEOUT_MIN
  66. #undef NYOCI_THREAD_SAFE
  67. #undef NYOCI_NODE_ROUTER_USE_BTREE
  68. #undef NYOCI_OBSERVATION_DEFAULT_MAX_AGE
  69. #undef NYOCI_OBSERVATION_KEEPALIVE_INTERVAL
  70. #undef NYOCI_OBSERVER_CON_EVENT_EXPIRATION
  71. #undef NYOCI_OBSERVER_NON_EVENT_EXPIRATION
  72. #undef NYOCI_TRANSACTIONS_USE_BTREE
  73. #undef NYOCI_TRANSACTION_BURST_COUNT
  74. #undef NYOCI_TRANSACTION_POOL_SIZE
  75. #undef NYOCI_USE_CASCADE_COUNT
  76. #undef NYOCI_VARIABLE_MAX_KEY_LENGTH
  77. #undef NYOCI_VARIABLE_MAX_VALUE_LENGTH
  78. #undef NYOCI_INTERNAL_EXTERN
  79. #undef NYOCI_API_EXTERN
  80. #undef NYOCI_DEPRECATED

这个配置文件主要用于配置NYOCI本身。反正看名字大概也能猜出大概每个配置变量是干嘛用的,自己瞅一眼大概设设就是。要设置的话就把#undef改成#define然后设置值,不设置的话基本都会在nyoci-defaults.h文件里有默认值。上面也是我目前根据我的环境设的值。

把这两个配置文件创建好后放在自己的工程目录下,然后扔进工程里就好。

平台移植

libnyoci和(网络栈)平台相关的代码被组织在libnyoci\src\plat-net目录下。目前,只支持posix和uip。

我们要为wiz的io库做一个移植,然后因为我用的RTOS是uCOS-II,所以还会有些uCOS-II的相关代码。首先,把uip那个文件夹复制然后黏贴,改个名字叫wiz。就像这样:
watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpbl9zdHJvbmc_size_16_color_FFFFFF_t_70 1watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpbl9zdHJvbmc_size_16_color_FFFFFF_t_70 2
然后我直接给出我目前移植好的文件:

nyoci-plat-net.h

  1. #ifndef NYOCI_nyoci_plat_wiz_h
  2. #define NYOCI_nyoci_plat_wiz_h
  3. #if !defined(NYOCI_INCLUDED_FROM_LIBNYOCI_H) && !defined(BUILDING_LIBNYOCI)
  4. #error "Do not include this header directly, include <libnyoci/libnyoci.h> instead"
  5. #endif
  6. NYOCI_BEGIN_C_DECLS
  7. typedef uint8_t nyoci_addr_t[4];
  8. typedef struct {
  9. nyoci_addr_t nyoci_addr;
  10. uint16_t nyoci_port;
  11. } nyoci_sockaddr_t;
  12. NYOCI_API_EXTERN uint8_t nyoci_plat_get_socketnumber(nyoci_t self);
  13. NYOCI_API_EXTERN void nyoci_plat_set_socketnumber(nyoci_t self, uint8_t sn);
  14. NYOCI_BEGIN_C_DECLS
  15. #include "nyoci-plat-net-func.h"
  16. #endif

nyoci-plat-net-internal.h

  1. #ifndef NYOCI_nyoci_plat_wiz_internal_h
  2. #define NYOCI_nyoci_plat_wiz_internal_h
  3. #ifndef wiz_is_addr_mcast
  4. #define wiz_is_addr_mcast(addrptr) (*(const uint8_t*)(addrptr)==224)
  5. #endif
  6. #ifndef wiz_is_addr_unspecified
  7. #define wiz_is_addr_unspecified(addrptr) (*(addrptr)==0)
  8. #endif
  9. #ifndef wiz_is_addr_loopback
  10. #define wiz_is_addr_loopback(addrptr) (*(const uint8_t*)(addrptr)==127)
  11. #endif
  12. #define NYOCI_IS_ADDR_MULTICAST wiz_is_addr_mcast
  13. #define NYOCI_IS_ADDR_UNSPECIFIED wiz_is_addr_unspecified
  14. #define NYOCI_IS_ADDR_LOOPBACK wiz_is_addr_loopback
  15. NYOCI_BEGIN_C_DECLS
  16. struct nyoci_plat_s {
  17. nyoci_sockaddr_t sockaddr_local;
  18. nyoci_sockaddr_t sockaddr_remote;
  19. nyoci_session_type_t session_type;
  20. uint8_t socketNum;
  21. uint8_t outbound_packet_bytes[NYOCI_MAX_PACKET_LENGTH+1];
  22. uint8_t inbound_packet_bytes[NYOCI_MAX_PACKET_LENGTH+1];
  23. };
  24. NYOCI_END_C_DECLS
  25. #endif

nyoci-plat-net.c

  1. #if HAVE_CONFIG_H
  2. #include <config.h>
  3. #endif
  4. #ifndef VERBOSE_DEBUG
  5. #define VERBOSE_DEBUG 0
  6. #endif
  7. #ifndef DEBUG
  8. #define DEBUG VERBOSE_DEBUG
  9. #endif
  10. #define NYOCI_COAP_MULTICAST_ALLDEVICES_ADDR COAP_MULTICAST_STR_ALLDEVICES
  11. #include <stdio.h>
  12. #include "assert-macros.h"
  13. #include "libnyoci.h"
  14. #include "nyoci-internal.h"
  15. #include "nyoci-logging.h"
  16. #include "lib_lite.h"
  17. #include "Network.h"
  18. #include "ucos_ii.h"
  19. #include "os_cfg.h"
  20. #include "socket.h"
  21. uint8_t nyoci_plat_get_socketnumber(nyoci_t self) {
  22. return self->plat.socketNum;
  23. };
  24. void nyoci_plat_set_socketnumber(nyoci_t self, uint8_t sn){
  25. self->plat.socketNum = sn;
  26. }
  27. nyoci_status_t
  28. nyoci_plat_join_standard_groups(nyoci_t self, int interface)
  29. {
  30. NYOCI_SINGLETON_SELF_HOOK;
  31. // TODO: Implement me!
  32. return NYOCI_STATUS_NOT_IMPLEMENTED;
  33. }
  34. nyoci_t
  35. nyoci_plat_init(nyoci_t self) {
  36. NYOCI_SINGLETON_SELF_HOOK;
  37. self->plat.socketNum = -1;
  38. return self;
  39. }
  40. nyoci_status_t
  41. nyoci_plat_bind_to_port(
  42. nyoci_t self,
  43. nyoci_session_type_t type,
  44. uint16_t port
  45. ) {
  46. nyoci_status_t ret = NYOCI_STATUS_FAILURE;
  47. NYOCI_SINGLETON_SELF_HOOK;
  48. switch(type) {
  49. case NYOCI_SESSION_TYPE_UDP:
  50. //#if NYOCI_DTLS
  51. // case NYOCI_SESSION_TYPE_DTLS:
  52. //#endif
  53. //#if NYOCI_TCP
  54. // case NYOCI_SESSION_TYPE_TCP:
  55. //#endif
  56. //#if NYOCI_TLS
  57. // case NYOCI_SESSION_TYPE_TLS:
  58. //#endif
  59. break;
  60. default:
  61. ret = NYOCI_STATUS_NOT_IMPLEMENTED;
  62. // Unsupported session type.
  63. goto bail;
  64. }
  65. self->plat.session_type = type;
  66. self->plat.sockaddr_local.nyoci_port = port;
  67. ret = NYOCI_STATUS_OK;
  68. bail:
  69. return ret;
  70. }
  71. void
  72. nyoci_plat_finalize(nyoci_t self) {
  73. NYOCI_SINGLETON_SELF_HOOK;
  74. close(self->plat.socketNum);
  75. }
  76. nyoci_status_t
  77. nyoci_plat_set_remote_hostname_and_port(const char* hostname, uint16_t port)
  78. {
  79. nyoci_status_t ret;
  80. NYOCI_NON_RECURSIVE nyoci_sockaddr_t saddr;
  81. DEBUG_PRINTF("Outbound: Dest host [%s]:%d",hostname,port);
  82. #if NYOCI_DTLS
  83. nyoci_plat_tls_set_remote_hostname(hostname);
  84. #endif
  85. // Check to see if this host is a group we know about.
  86. if (strcasecmp(hostname, COAP_MULTICAST_STR_ALLDEVICES) == 0) {
  87. hostname = NYOCI_COAP_MULTICAST_ALLDEVICES_ADDR;
  88. }
  89. ret = nyoci_plat_lookup_hostname(hostname, &saddr, NYOCI_LOOKUP_HOSTNAME_FLAG_DEFAULT);
  90. require_noerr(ret, bail);
  91. saddr.nyoci_port = port;
  92. nyoci_plat_set_remote_sockaddr(&saddr);
  93. bail:
  94. return ret;
  95. }
  96. void
  97. nyoci_plat_set_remote_sockaddr(const nyoci_sockaddr_t* addr)
  98. {
  99. nyoci_t const self = nyoci_get_current_instance();
  100. if (addr) {
  101. self->plat.sockaddr_remote = *addr;
  102. } else {
  103. memset(&self->plat.sockaddr_remote,0,sizeof(self->plat.sockaddr_remote));
  104. }
  105. }
  106. void
  107. nyoci_plat_set_local_sockaddr(const nyoci_sockaddr_t* addr)
  108. {
  109. nyoci_t const self = nyoci_get_current_instance();
  110. if (addr) {
  111. self->plat.sockaddr_local = *addr;
  112. } else {
  113. memset(&self->plat.sockaddr_local,0,sizeof(self->plat.sockaddr_local));
  114. }
  115. }
  116. void
  117. nyoci_plat_set_session_type(nyoci_session_type_t type)
  118. {
  119. nyoci_t const self = nyoci_get_current_instance();
  120. self->plat.session_type = type;
  121. }
  122. const nyoci_sockaddr_t*
  123. nyoci_plat_get_remote_sockaddr(void)
  124. {
  125. return &nyoci_get_current_instance()->plat.sockaddr_remote;
  126. }
  127. const nyoci_sockaddr_t*
  128. nyoci_plat_get_local_sockaddr(void)
  129. {
  130. return &nyoci_get_current_instance()->plat.sockaddr_local;
  131. }
  132. nyoci_session_type_t
  133. nyoci_plat_get_session_type(void)
  134. {
  135. return nyoci_get_current_instance()->plat.session_type;
  136. }
  137. uint16_t
  138. nyoci_plat_get_port(nyoci_t self) {
  139. NYOCI_SINGLETON_SELF_HOOK;
  140. return self->plat.sockaddr_local.nyoci_port;
  141. }
  142. nyoci_status_t
  143. nyoci_plat_outbound_start(nyoci_t self, uint8_t** data_ptr, coap_size_t *data_len)
  144. {
  145. NYOCI_SINGLETON_SELF_HOOK;
  146. if (data_ptr) {
  147. *data_ptr = (uint8_t*)self->plat.outbound_packet_bytes;
  148. }
  149. if (data_len) {
  150. *data_len = sizeof(self->plat.outbound_packet_bytes);
  151. }
  152. self->outbound.packet = (struct coap_header_s*)self->plat.outbound_packet_bytes;
  153. return NYOCI_STATUS_OK;
  154. }
  155. //
  156. nyoci_status_t
  157. nyoci_plat_outbound_finish(nyoci_t self,const uint8_t* data_ptr, coap_size_t data_len, int flags)
  158. {
  159. nyoci_status_t ret = NYOCI_STATUS_FAILURE;
  160. int32_t sent_bytes = -1;
  161. int sn;
  162. NYOCI_SINGLETON_SELF_HOOK;
  163. #if NYOCI_DTLS
  164. if (nyoci_plat_get_session_type() == NYOCI_SESSION_TYPE_DTLS) {
  165. ret = nyoci_plat_tls_outbound_packet_process(self, data_ptr, data_len);
  166. } else
  167. #endif
  168. if (nyoci_plat_get_session_type() == NYOCI_SESSION_TYPE_UDP) {
  169. sn = nyoci_get_current_instance()->plat.socketNum;
  170. assert(sn < 8);
  171. require(data_len > 0, bail);
  172. #if VERBOSE_DEBUG
  173. {
  174. char addr_str[30] = "???";
  175. uint16_t port = nyoci_plat_get_remote_sockaddr()->nyoci_port;
  176. IPToStr(nyoci_plat_get_remote_sockaddr()->nyoci_addr,addr_str);
  177. DEBUG_PRINTF("nyoci(%p): Outbound packet to [%s]:%u", self,addr_str,port);
  178. coap_dump_header(
  179. NYOCI_DEBUG_OUT_FILE,
  180. "Outbound:\t",
  181. (struct coap_header_s*)data_ptr,
  182. (coap_size_t)data_len
  183. );
  184. }
  185. #endif
  186. sent_bytes = sendto(
  187. sn,
  188. data_ptr,
  189. data_len,
  190. self->plat.sockaddr_remote.nyoci_addr,
  191. self->plat.sockaddr_remote.nyoci_port
  192. );
  193. require_action_string(
  194. (sent_bytes >= 0),
  195. bail, ret = NYOCI_STATUS_ERRNO, "sendto() fail"
  196. );
  197. require_action_string(
  198. (sent_bytes == data_len),
  199. bail, ret = NYOCI_STATUS_FAILURE, "sendto() returned less than len"
  200. );
  201. ret = NYOCI_STATUS_OK;
  202. } else {
  203. ret = NYOCI_STATUS_NOT_IMPLEMENTED;
  204. }
  205. bail:
  206. return ret;
  207. }
  208. // MARK: -
  209. nyoci_status_t
  210. nyoci_plat_wait(
  211. nyoci_t self, nyoci_cms_t cms
  212. ) {
  213. #ifdef OS_uCOS_II_H
  214. OSTimeDly(cms * OS_TICKS_PER_SEC / MSEC_PER_SEC);
  215. return NYOCI_STATUS_OK;
  216. #else
  217. return NYOCI_STATUS_NOT_IMPLEMENTED;
  218. #endif
  219. }
  220. nyoci_status_t
  221. nyoci_plat_process(nyoci_t self) {
  222. uint8_t sn;
  223. int32_t bytesCnt;
  224. nyoci_status_t ret = NYOCI_STATUS_FAILURE;
  225. NYOCI_SINGLETON_SELF_HOOK;
  226. require_action(self != NULL, bail, ret = NYOCI_STATUS_INVALID_ARGUMENT);
  227. sn = self->plat.socketNum;
  228. if(!Network_hasReady()){
  229. #ifdef OS_uCOS_II_H
  230. OSTimeDlyHMSM(0, 0, 3, 0);
  231. #endif
  232. goto bail;
  233. }
  234. require(sn < 8,bail);
  235. if(getSn_SR(sn) != SOCK_UDP){
  236. if(socket(sn,Sn_MR_UDP,self->plat.sockaddr_local.nyoci_port,0x00) != sn){
  237. DEBUG_PRINTF("nyoci init fail");
  238. #ifdef OS_uCOS_II_H
  239. OSTimeDlyHMSM(0, 0, 3, 0);
  240. #endif
  241. goto bail;
  242. }else{
  243. DEBUG_PRINTF("nyoci process on socket %d", (int)sn);
  244. }
  245. }
  246. if(getSn_RX_RSR(sn)>0){
  247. bytesCnt = recvfrom(sn, self->plat.inbound_packet_bytes, sizeof(self->plat.inbound_packet_bytes),
  248. self->plat.sockaddr_remote.nyoci_addr, &self->plat.sockaddr_remote.nyoci_port);
  249. #if VERBOSE_DEBUG
  250. {
  251. char addr_str[30] = "???";
  252. uint16_t port = self->plat.sockaddr_remote.nyoci_port;
  253. IPToStr(self->plat.sockaddr_remote.nyoci_addr,addr_str);
  254. DEBUG_PRINTF("nyoci received data from %s:%u len:%d", addr_str, port, (int)bytesCnt);
  255. }
  256. #endif
  257. require(bytesCnt >= 0, bail);
  258. nyoci_plat_set_session_type(NYOCI_SESSION_TYPE_UDP);
  259. nyoci_inbound_packet_process(self, self->plat.inbound_packet_bytes, bytesCnt, 0);
  260. }
  261. nyoci_handle_timers(self);
  262. ret = NYOCI_STATUS_OK;
  263. bail:
  264. nyoci_set_current_instance(NULL);
  265. self->is_responding = false;
  266. return ret;
  267. }
  268. nyoci_status_t
  269. nyoci_plat_lookup_hostname(const char* hostname, nyoci_sockaddr_t* saddr, int flags)
  270. {
  271. /* nyoci_status_t ret;
  272. memset(saddr, 0, sizeof(*saddr));
  273. ret = StrToIP(hostname, (uint8_t *)&saddr->nyoci_addr) ? NYOCI_STATUS_OK : NYOCI_STATUS_HOST_LOOKUP_FAILURE;
  274. #if NYOCI_CONF_USE_DNS
  275. #if CONTIKI
  276. if(ret) {
  277. NYOCI_NON_RECURSIVE uip_ipaddr_t *temp = NULL;
  278. switch(resolv_lookup(hostname,&temp)) {
  279. case RESOLV_STATUS_CACHED:
  280. memcpy(&saddr->nyoci_addr, temp, sizeof(uip_ipaddr_t));
  281. ret = NYOCI_STATUS_OK;
  282. break;
  283. case RESOLV_STATUS_UNCACHED:
  284. case RESOLV_STATUS_EXPIRED:
  285. resolv_query(hostname);
  286. case RESOLV_STATUS_RESOLVING:
  287. ret = NYOCI_STATUS_WAIT_FOR_DNS;
  288. break;
  289. default:
  290. case RESOLV_STATUS_ERROR:
  291. case RESOLV_STATUS_NOT_FOUND:
  292. ret = NYOCI_STATUS_HOST_LOOKUP_FAILURE;
  293. break;
  294. }
  295. }
  296. #else // CONTIKI
  297. #warning NYOCI_CONF_USE_DNS was set, but no DNS lookup mechamism is known!
  298. #endif
  299. #endif // NYOCI_CONF_USE_DNS
  300. require_noerr(ret,bail);
  301. bail:
  302. return ret; //*/
  303. // TODO: Implement me!
  304. return NYOCI_STATUS_NOT_IMPLEMENTED;
  305. }
  306. #if defined(CONTIKI)
  307. nyoci_timestamp_t
  308. nyoci_plat_cms_to_timestamp(
  309. nyoci_cms_t cms
  310. ) {
  311. return clock_time() + cms*CLOCK_SECOND/MSEC_PER_SEC;
  312. }
  313. nyoci_cms_t
  314. nyoci_plat_timestamp_diff(nyoci_timestamp_t lhs, nyoci_timestamp_t rhs) {
  315. return (lhs - rhs)*MSEC_PER_SEC/CLOCK_SECOND;
  316. }
  317. nyoci_cms_t
  318. nyoci_plat_timestamp_to_cms(nyoci_timestamp_t ts) {
  319. return nyoci_plat_timestamp_diff(ts, clock_time());
  320. }
  321. #elif defined(OS_uCOS_II_H)
  322. nyoci_timestamp_t
  323. nyoci_plat_cms_to_timestamp(
  324. nyoci_cms_t cms
  325. ) {
  326. return OSTimeGet() + cms * ((double)OS_TICKS_PER_SEC / MSEC_PER_SEC);
  327. }
  328. nyoci_cms_t
  329. nyoci_plat_timestamp_diff(nyoci_timestamp_t lhs, nyoci_timestamp_t rhs) {
  330. return (lhs - rhs) * ((double)MSEC_PER_SEC / OS_TICKS_PER_SEC);
  331. }
  332. nyoci_cms_t
  333. nyoci_plat_timestamp_to_cms(nyoci_timestamp_t ts) {
  334. return nyoci_plat_timestamp_diff(ts, OSTimeGet());
  335. }
  336. #endif

简要说明

这里大概说一下一些移植会出问题的地方。

首先看一下include
#include “lib_lite.h”
这个文件是我自己加的,用到的里头的函数就一个IPtoStr,在打印调试信息时用到的,不是很重要,自己可以根据需要实现一个或直接不管。
#include “Network.h”
这个也是我自己写的基于W5500的网络管理模块的头文件,主要就是提供nyoci_plat_process这个函数里头的Network_hasReady这一个判断,自己根据需要进行修改即可。
#include “os_cfg.h”
这个文件是uCOS-II的配置文件名,用于引入uCOS-II接口的。

nyoci_plat_set_remote_hostname_and_port和nyoci_plat_lookup_hostname顾名思义,用于通过字符串设置和DNS查询对方主机。这个不是必要的接口,我也没有实现它,主要是io库也没有提供好用的DNS接口,但我保留了实现的框架,如有需要可以照着实现它。

这里头最容易让人困惑的是时间戳里的cms到底是什么鬼。经过我辛苦的钻研,得出结论:这个变量代表的意思是相对时间,单位ms。
nyoci中同时使用平台特定的时间戳和单位为ms的相对时间戳。
nyoci_plat_cms_to_timestamp
就是要你返回相对当前时间cms毫秒(正代表未来,负代表过去)对应的平台时间戳。
nyoci_plat_timestamp_diff
返回两个平台时间戳之间差多少ms。
nyoci_plat_timestamp_to_cms
返回给定平台时间戳与当前时间差多少ms。
nyoci_plat_wait
也就是sleep多少毫秒的意思。

上面我加进去了在uCOS-II下的实现,如果你用的是其他操作系统的话则根据具体OS进行修改。

使用示例

这里只简单示例下这个移植后的代码的其中一种用法,其他用法请参照examples里的几个示例。

示例代码

以下是Coap服务器任务/线程的示例

  1. ……
  2. #include <libnyoci/libnyoci.h>
  3. #include <libnyociextra/nyoci-node-router.h>
  4. ……
  5. #define OBSERVABLE_KEY 35
  6. static nyoci_t CoapInstance = NULL;
  7. static struct nyoci_observable_s observable = {
  8. 0 };
  9. static char sensordata[] = "30.32Cel";
  10. ……
  11. static nyoci_status_t
  12. request_handler(void* context)
  13. {
  14. nyoci_observable_t observable = context;
  15. const uint8_t* opt;
  16. coap_size_t len;
  17. if (!nyoci_inbound_is_fake()) {
  18. printf("Got a request!\n");
  19. }
  20. // Only handle GET requests for now.
  21. if (nyoci_inbound_get_code() != COAP_METHOD_GET) {
  22. return NYOCI_STATUS_NOT_IMPLEMENTED;
  23. }
  24. // Begin describing the response.
  25. nyoci_outbound_begin_response(COAP_RESULT_205_CONTENT);
  26. // This is the key line to making a resource observable.
  27. // It must be placed after nyoci_outbound_begin_response()
  28. // and before nyoci_outbound_send(). When this resource changes,
  29. // a simple call to nyoci_observable_trigger() with the given
  30. // nyoci_observable object and observable key will trigger the
  31. // observers to be updated. Really --- that's it...!
  32. nyoci_observable_update(observable, OBSERVABLE_KEY);
  33. nyoci_outbound_add_option_uint(
  34. COAP_OPTION_CONTENT_TYPE,
  35. COAP_CONTENT_TYPE_TEXT_PLAIN
  36. );
  37. nyoci_outbound_append_content(sensordata, sizeof(sensordata) - 1);
  38. return nyoci_outbound_send();
  39. }
  40. static void CoapTask(void *p_arg){
  41. nyoci_node_t root_node, hello_node;
  42. NYOCI_LIBRARY_VERSION_CHECK();
  43. while(!CoapInstance){
  44. CoapInstance = nyoci_create();
  45. if (!CoapInstance) {
  46. printf("Unable to create LibNyoci instance");
  47. OSTimeDlyHMSM(0, 0, 5, 0);
  48. }
  49. }
  50. nyoci_plat_set_socketnumber(CoapInstance, COAP_SOCKET);
  51. nyoci_plat_bind_to_port(CoapInstance, NYOCI_SESSION_TYPE_UDP, COAP_DEFAULT_PORT);
  52. root_node = nyoci_node_init(NULL, NULL, NULL);
  53. nyoci_set_default_request_handler(
  54. CoapInstance,
  55. &nyoci_node_router_handler,
  56. (void*)root_node
  57. );
  58. hello_node = nyoci_node_init(NULL,root_node,"sData");
  59. hello_node->request_handler = &request_handler;
  60. hello_node->context = &observable;
  61. printf("Listening on port %d\n", nyoci_plat_get_port(CoapInstance));
  62. while (1) {
  63. MyOS_DlyHMSM(0, 0, 0, 30);
  64. //nyoci_plat_wait(CoapInstance, INTERVAL_PER_TICK);
  65. nyoci_plat_process(CoapInstance);
  66. }
  67. nyoci_release(CoapInstance);
  68. }

如果要触发publish的话,则在某处调用nyoci_observable_trigger:

  1. if(++sensordata[1] > '9')
  2. sensordata[1] = '0';
  3. (void)printf("%d observers registered\n", nyoci_observable_observer_count(&observable, OBSERVABLE_KEY));
  4. nyoci_observable_trigger(&observable, OBSERVABLE_KEY ,0);

简要说明

由于我这个示例使用的是多实例,所以一开始要create一个nyoci实例。
然后通过nyoci_plat_set_socketnumber设置其socket号,对应W5500的socket号。
然后用nyoci_plat_bind_to_port绑定这个Coap服务的端口为默认端口号,使用UDP,这个移植也只实现了UDP。

这个代码里头使用了router,这种方式使用链表(可选B树)来管理资源,收到请求时会在所有注册的资源中寻找匹配的资源,如果存在,则调用对应的request_handler,否则404。这里我们添加了一个叫sData的资源,又给他设置了一个observable使其可以被订阅。

然后就开始不断地用nyoci_plat_process驱动服务器实例的运行了,这个方法的含义是进行一次无阻塞的处理。

还有些其他方式,请自行探索,或者等我研究透了再出篇博文来讲。

测试

这里我通过Chrome浏览器插件Copper来进行测试。
http://element-ui.cn/news\_show\_33612.shtml
我目前配置的设备主机名为SIA5300.local,所以资源的地址为:
SIA5300.local/sData
watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpbl9zdHJvbmc_size_16_color_FFFFFF_t_70 3然后我们使用Get方法获取资源:
watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpbl9zdHJvbmc_size_16_color_FFFFFF_t_70 4获取资源成功。
然后来试一下Observe即发布订阅方式:
watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpbl9zdHJvbmc_size_16_color_FFFFFF_t_70 5watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpbl9zdHJvbmc_size_16_color_FFFFFF_t_70 6主动推送消息成功。

总结

这篇文章讲了移植libnyoci到wiz io库以实现一个简单的UDP Coap服务器所需要的主要事项,但是实际移植的时候由于开发环境不同等原因估摸还是会遇到很多问题,语法不支持、缺少库什么的一堆问题。如果实在搞不定,下面留言。

发表评论

表情:
评论列表 (有 0 条评论,695人围观)

还没有评论,来说两句吧...

相关阅读