移植MQTT到STM32

IoTSharp/mqttclient 移植笔记

GitHub - IoTSharp/mqttclient:一款高性能、高稳定性、跨平台的MQTT客户端,基于套接字API开发,可应用于嵌入式设备(FreeRTOS / LiteOS / RT-Thread / TencentOS tiny)、Linux、Windows、Mac,且API接口以极少资源实现QOS2的服务质量,并无缝连接mbedtls加密库。·GitHub

一、移植流程概述

先使用上述网址将代码下载下来。

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

  1. memory:内存相关
  2. mutex:互斥量相关
  3. net_socket:网络相关
  4. thread:线程相关
  5. 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支持时会报错。

该宏为配置项,含义如下:

  1. REMOVR:移除
  2. MEMORY:内存
  3. LAYOUT:布局
  4. BOUNDARY:边界

使用该宏时需格外小心。

相关推荐
高翔·权衡之境7 小时前
主题10:实时性——硬实时与软实时
服务器·网络·驱动开发·信息与通信·智能硬件
不怕犯错,就怕不做12 小时前
ARM设备异常断电容易造成数据损坏,硬件如何设计
linux·驱动开发·嵌入式硬件
枳实-叶14 小时前
【Linux驱动开发】第10天:设备树零基础入门——DTS/DTB/DTC全解+编译流程
linux·运维·驱动开发
枳实-叶14 小时前
【Linux驱动开发】第11天:设备树(Device Tree)超详细全解:从诞生背景到工作原理
linux·运维·驱动开发
沃普天科技15 小时前
USB显示器驱动板触摸收款机显示器收银机点菜机广告机
驱动开发·游戏·计算机外设·电脑·ar·音视频·硬件工程
小此方16 小时前
Re:Linux系统篇(十九)进程篇·四:内核托底与生死交错 ,深度硬核剖析“僵尸”与“孤儿”进程
linux·运维·驱动开发
charlie1145141911 天前
嵌入式Linux驱动开发pinctrl篇(1)——从寄存器到子系统:驱动演进之路
linux·运维·驱动开发
猫猫的小茶馆1 天前
【Python】函数与模块化编程
linux·开发语言·arm开发·驱动开发·python·stm32
高翔·权衡之境2 天前
主题9:DMA与零拷贝——让CPU从数据搬运中解放
驱动开发·安全·缓存·系统安全·信息与通信
小此方2 天前
Re:Linux系统篇(十七)进程篇·二:深入浅出 [进程概念与进程父子关系]:从底层原理到实战应用
linux·运维·驱动开发