
IoTSharp/mqttclient 移植笔记
一、移植流程概述
先使用上述网址将代码下载下来。

需要移植的主要文件如下:

- memory:内存相关
- mutex:互斥量相关
- net_socket:网络相关
- thread:线程相关
- timer:定时器相关

定时器部分已完成。

线程部分也已创建。

网络部分需要我们实现,因需通过串口发送AT命令给ESP8266,需自行编写。

还需处理数据接收,考虑如何读取数据。

发送数据也需要相应的函数实现。

互斥量部分已完成。

接下来是内存函数。

因此,只需修改这三个函数即可。

.c文件编译后会变为.o文件,这一过程称为编译。

.o文件转为.hex文件的过程为链接。编译时可发现如头文件等错误。

如图所示:
假设在main.c中定义了led_init2,但led.c只提供了led_init,则会报链接错误,提示未定义函数。

需要新建一个文件夹。

需要移植的内容如下:

建立五个分组。

common文件夹内有很多文件,需判断是否用得到。

先添加这两个文件。

mqtt文件夹内包含各种解包等功能文件,需全部添加。

添加mqtt核心线程文件。

网络部分只需加入这两个文件。mbedtls为加密相关,暂不处理。

平台部分只需移植FreeRTOS即可。
二、错误解决方案
(1)大范围错误

从第一个错误开始逐步解决。

无法找到头文件。

这是1的头文件需查找位置。

需复制缺失文件的路径。

通过魔术棒(c和c++设置),粘贴路径。

再次编译,仍有5个错误,逐一修正后再次编译,提示缺少头文件。

发现缺少一个文件夹。

定位到该文件。

尝试先注释掉。

还有一个文件夹需处理。

找到目标文件。

上方有宏定义,指MQTT网络不使用TLS(传输层安全)。

目前采用最简单方式,强制定义宏后不会包含下方头文件。

重新编译,定位到新错误文件。

错误信息:期望括号。

跳转注释后,修改为1000,检查类型是否未定义。

错误消失,说明ticktype_t类型未被包含。

可将#if改为普通if。

需包含该类型的头文件。

需在文件中自行包含头文件。

但编译后出现77个错误。

查看错误,编译到freertos.c时出现宏未定义。

freertos第180行用到该宏。

可在a.c包含a.h,也可在a.h包含b.h,编译.c文件需确保.c文件包含.h文件。

回到文件,将宏定义撤销。

直接修改为1000,暂不使用该类型。

再次编译发现缺少lwip文件。lwip为联网相关,当前使用AT命令操作ESP8266,故不使用该文件。

直接去掉相关引用。

再次编译,错误增多,需继续修改。

查看tcp.c编译错误,size_t类型未定义。

在报错文件夹内处理。

先自定义类型,确保编译通过。

剩余错误如下。

socklen_t未定义。

还有其他错误。

最终发现已有定义。

就在当前文件夹内。

编译文件时先调用上方文件,size_t类型在下方文件定义,需调整头文件引用顺序。

stdio.h已包含。

文件调用顺序如下。

应先调用log.h。

在该文件夹内。

需删除自定义的两个类型。

又出现未定义问题。

定位到该文件。

跳转到错误位置,发现引用了socket.h头文件,并用到size_t类型。

该类型在此定义,可直接包含log头文件。

引用头文件。

仍有错误。

提示socklen未定义。

自定义类型。

剩余错误多为结构体未包含。因不使用部分函数,头文件未包含,需自定义收发函数。

将这些函数均写成return 0,后续自行完善收发功能。

目前仅剩一个错误。
(2)GNU扩展问题

需解决弱定义错误,因函数被定义两次,不加__weak,keil编译器会报错。

在文件夹内添加以下代码,解决strnlen未定义问题。strnlen是Linux的扩展函数,非标准C语言函数,不是单片机库函数。

也可加入此代码骗过编译器。

编译后不会再报错。
keil使用armcc编译器,其他平台用gnu编译器,语法略有不同。

有时需让宏展开,判断走哪一路。

可在宏后故意加错误,若错误增多则证明走该分支。

编译后未新增错误,说明宏未影响,未使用c90文件。

在keil5:魔术棒->c/c++可勾选相关选项,测试不勾选是否可正常编译。

keil官方解释如下。

涉及匿名结构体,即结构体中嵌套无名结构体。

展开宏后得到如下内容。

添加错误代码后编译,发现宏未起作用。

继续实验。

确实存在问题。

再次测试。

均在当前文件夹进行。

错误减少,说明有效。

去掉相关内容后不报错,说明问题所在。

故意加错误,判断宏走哪个分支。

在此加错误,错误变为24个,说明走该分支。

此处走下方分支,若需走上方分支,则需定义POOL_CFG宏。

宏在此定义,但为c++代码。

先在上方定义,测试编译。

发现问题可解决。需进一步理解宏含义。

逐层展开宏,结构体内容应走上方__VA_ARGS__分支,但实际走下方。

下方分支为结构体嵌套匿名结构体,属于GNU语法。keil5未勾选GNU支持时会报错。

该宏为配置项,含义如下:
- REMOVR:移除
- MEMORY:内存
- LAYOUT:布局
- BOUNDARY:边界
使用该宏时需格外小心。