基于芯科Host-NCP解决方案的Zigbee 3.0 Gateway技术研究(三)-移植到ESP32平台(1)

相关系列文章

基于芯科Host-NCP解决方案的Zigbee 3.0 Gateway技术研究(-)-Z3GatewayHost应用搭建

基于芯科Host-NCP解决方案的Zigbee 3.0 Gateway技术研究(二)-使用gateway-management-ui

基于芯科Host-NCP解决方案的Zigbee 3.0 Gateway技术研究(三)-移植到ESP32平台(1)

基于芯科Host-NCP解决方案的Zigbee 3.0 Gateway技术研究(三)-移植到ESP32平台(2)

基于芯科Host-NCP解决方案的Zigbee 3.0 Gateway技术研究(四)-移植到STM32平台​​​​​​​

概要

前两章节已经简单介绍了芯科的Host-NCP解决方案,对一些相关概念有了初步认识,接下来这个章节将记录一下将Host应用从Ubuntu移植到乐鑫ESP32上的过程和注意事项。在芯科官方的视频教学中,也有关于LCGW网关(低成本网关?)的介绍,可以看出芯科官方也希望Host-NCP解决方案能在更广的范围进行推广,教学视频地址如下(感谢相关文章作者的分享,在此借以引用参考,如有涉及版权问题,请及时联系我)

《Zigbee 3.0 RTOS网关介绍》,如下图所示:https://www.bilibili.com/video/BV1L54y1z7aZ

所以,如果有条件的话,应当尽量使用芯科官方提供的RTOS SDK进行移植。

如果想体验一下将Host移植到不同MCU平台的过程,那下面的内容也许可以给你帮助。

整个移植工作主要分为以下几步:

1.软硬件环境准备工作:ESP32选型、相关的SDK、交叉编译工具链等

2.生成ESP32调用的静态库:Host需要调整的相关文件、交叉编译参数

3.在ESP32工程中使用静态库:在ESP32开发环境中导入和使用静态库,结合ESP32自身的uart、wifi、mqtt、spiffs等实现相关功能的移植

4.移植后的功能验证:zigbee主要功能的验证工作

软硬件环境准备工作

1.硬件环境

Host:ESP32-WROOM-32D  Flash:8MB  SRAM :536KB (备注:采用Flash 4MB的版本也是可以的)

NCP:EFR32MG21A020F768IM32

因为,Host-NCP间是通过uart进行数据传输的,所以对串口稳定性要求想对较高;一开始,我是用杜邦线连接ESP32核心板和EFR32模组进行开发的,但经常会出现各种莫名其妙的通讯问题,所以后来打样了一块ESP32-EFR32开发板,方便测试。

这块开发板主要包括了:esp32模组、efr32模组、ch340、2个功能按键、2个功能指示灯、oled屏接口、大彩触摸屏接口;可以通过usb线进行esp32固件下载。

当然,你也可以用esp32开发板+efr32模组的方式进行开发,如下图所示:

2.软件环境

编译环境:Ubuntu 18.04(建议使用乐鑫的开发虚拟机镜像,里面已经安装交叉编译工具链)

编译工具链:xtensa-esp32-elf-gcc  gcc version 8.2.0 (crosstool-NG esp-2019r2)

软件:Simplicity Studio V4、Eclipse IDE for C/C++ Developers、ESP-IDF Tools(以插件方式在Eclipse中安装)

芯科SDK:EmberZNet SDK 6.7.5.0

备注:如果对ESP32开发不熟悉,请先查看乐鑫ESP-IDF 编程指南文档;和 ESP32 & ESP32S2 平台官方工具链的设置和下载

生成ESP32调用的静态库

将前面章节中在Ubuntu下编译的工程项目,直接复制一份,然后将文件夹修改为esp32,如下图所示:

需要修改的文件主要分为以下几类:

  • 基础配置文件
  • 涉及串口相关操作的
  • 涉及文件操作相关的

具体修改文件列表(为了不影响SDK,所有需要修改的文件,都是原地复制一份;然后在文件名增加"-esp32"后缀,例如“gcc-esp32.h”即代表对原来的“gcc.h”文件)

编号文件名所在路径分类调整备注
1gcc-esp32.hv2.7/platform/base/hal/micro/unix/compiler/gcc配置文件微调 
2linux-serial-esp32.cv2.7/protocol/zigbee/app/util/serial/串口相关操作调整较多 
3ezsp-host-io-esp32.cv2.7/protocol/zigbee/app/ezsp-host/ 
4ezsp-esp32.cv2.7/protocol/zigbee/app/util/ezsp/ezsp协议实现微调有不确定的内存泄露问题
5gateway-relay-mqtt-esp32.cv2.7/protocol/zigbee/app/framework/plugin-host/gateway-relay-mqtt/mqtt插件相关实现微调 
6gateway-support-esp32.cv2.7/protocol/zigbee/app/framework/plugin-host/gateway/感觉很重要,但暂时没弄清楚它的作用微调后续考虑移除
7command-relay-esp32.cv2.7/protocol/zigbee/app/framework/plugin/command-relay/命令行插件相关实现微调 
8device-table-esp32.cv2.7/protocol/zigbee/app/framework/plugin/device-table/device-table插件微调 
9device-table-discovery-esp32.cv2.7/protocol/zigbee/app/framework/plugin/device-table/微调有可能引发异常,具体原因还没找到
10ota-storage-linux-esp32.cv2.7/protocol/zigbee/app/framework/plugin/ota-storage-posix-filesystem/ota插件微调 
11token-esp32.cv2.7/platform/base/hal/micro/unix/host/不清楚要来干嘛 基本把功能都屏蔽了
12backchannel-support-esp32.cv2.7/protocol/zigbee/app/framework/plugin-host/gateway/不清楚要来干嘛 基本把功能都屏蔽了
13Makefile项目根目录编译配置文件调整较多配置esp32编译器、编译文件、编译参数等

移植文件修改:

1)gcc-esp32.h

107行,将原来的“#error endianess not defined”修改为“#define BIGENDIAN_CPU  false”

备注:此处用于指定运行平台CPU为大端模式(big endian)还是小端(little endian)模式;MCU一般都为小端模式


2)linux-serial-esp32.c

改动实在太多,不一一列举,基本上是把各linux串口操作方法具体内容删掉,直接返回success,如下图所示

备注:这个文件的方法主要是用于linux串口的操作,移植到MCU,大部分方法都不适用(更好的做法应该是直接去掉)。但emberSerialPrintfVarArg方法比较重要,用于通过串口打印各种调试信息,是各种调试信息(ezsp、ash、af等)最后调用的底层,所以修改如下;将原来的backchannel打印去掉了:

// Main printing routine.
// Calls into normal C 'vprintf()'
EmberStatus emberSerialPrintfVarArg(uint8_t port, const char * formatString, va_list ap)
{

  EmberStatus stat = EMBER_SERIAL_INVALID_PORT;
  char* newFormatString = transformEmberPrintfToStandardPrintf(formatString,
                                                               true);
  
  vprintf(newFormatString,  ap);
  free(newFormatString);

  return EMBER_SUCCESS;
}

3)ezsp-host-io-esp32.c

替换头文件termios.h的引用

termios.h是用于定义串口操作的一些常量,例如波特率等。因为在esp32的编译链中是没有,所以可以直接在网上找一个,放到目录中引用。如下图所示;

网上找到的termios.h定义

#ifndef _TERMIOS_H
#define _TERMIOS_H
 
#define TTY_BUF_SIZE 1024  //tty缓冲区长度
/*
*0x54只是一个魔数,目的是位来使这些常数唯一
*tty设备的ioctl调用命令集合,iosctl将命令编码在低位字中
*下面TC的含义是tty控制命令
*/
//取相应终端termios结构中的信息
#define TCGETS      0x5401
 
//设置应终端termios结构中的信息
#define TCSETS	    0x5402
//在设置终端termios的信息前,需要先等待输出队列中所有处理完,对于修改参数回影响输出的情况
//就绪要使用这种形式
#define TCSETSW	    0x5403
//在设置termios信息前,需要先等待输出队列中所有数据处理完,并且刷新输入队列
#define TCSETSF	    0x5404
//取相应终端termios对应的信息
#define TCGETA	    0x5405
//设置相应终端termios对应的信息
#define TCSETA	    0x5406
//在设置终端termios的信息前,需要先等待输出队列中所有处理完,对于修改参数回影响输出的情况
//就绪要使用这种形式(参见tcsetattr TCSADRAIN选项)
#define TCSETAW	    0x5407
//在设置termios信息前,需要先等待输出队列中所有数据处理完,并且刷新输入队列
//(参见tcsetattr    TCSAFLUSH)
#define TCSETAF	    0x5408
//等待输出队列处理完毕(空),如果参数值是0,则发送一个brank
#define TCSBRK	    0x5409
 
//开始/停止控制,参数为0则挂起,为1,则重新开启挂起出处,是2则挂起,为3则重新开启挂起的输入
#define TCXONC	    0x540A
 
//刷新已写输出但还没有发送或已收但换没有读数据。参数为0,则刷新输入队列;为1,刷新输出队列
//为2,刷新输入输出队列
#define TCFLSH	    0x540B
 
//下面TIO含义是tty输入输出控制命令
//设置终端串行线路专用模式
#define TIOCEXCL    0x540C
//复位终端串行线路专用模式
#define TIONXCL	    0x540D
//设置tty为控制终端
#define TIOCSCTTY   0x540E
 
//读取指定终端设备进程的组id
#define TIOCGPGRP   0x540F
 
//设置指定终端设备进程的组id
#define TIOCSPGRP   0x5410
//返回输出队列中还未送出的字符数
#define TIOCOUTQ    0x5411
//模拟终端输入,该命令以一个指向字符的指针作为参数,并假装该字符是在终端上键入的,用户必须
//在该控制终端上具有超级用户权限或具有读权限
#define TIOCSTI	    0x5412
//读取终端设备窗口大小信息
#define TIOCGWINSZ  0x5413
//设置终端设备窗口大小信息
#define TIOCSWINSZ  0x5414
 
//返回modem状态控制引线的当前状态比特位标志集
#define TIOCMGET    0x5415
//设置单个modem状态控制引线的状态
#define TIOCMBIS    0x5416
//复位单个modem状态控制引线的状态
#define TIOCMBIX    0x5417 
//设置modem状态引线的状态。如果某一比特位置位,则modem对应的状态引线将置位有效
#define TIOCMSET    0x5418 
/*读取软件载波检测标志(0-关闭,1-开启)。对于本地连接的终端或其他设备,软件载波标志是开启的
*对于使用modem线路的终端或设备则是关闭的。为了能使用这两个ioctl调用,tty线路应该是以
*O_NDELRY方式打开的,这样open就不回等待载波
*/
#define TIOCGSOFTCAR 0x5419
 
//设置软件载波检测标志
#define TIOCSSOFTCAR 0x541A 
 
//返回输入队列还位取走字符的数目
#define TIOCINQ     0X541B
 
struct winsize
{
	unsigned short ws_row;   //窗口字符行数
	unsigned short ws_col;	 //窗口字符列数
	unsigned short ws_xpixel;//窗口宽度,像素值
	unsigned short ws_ypixel;//窗口高度,像素值
};
 
#define NCC    8        //termios结构中控制字符数组的长度
struct termio
{
	unsigned short 	c_iflag;   //输入模式标志 
	unsigned short	c_oflag;   //输出模式标志
	unsigned short	c_cflag;   //控制模式标志
	unsigned short	c_lflag;   //本地模式标志
	unsigned char	c_line ;   //线路规程(速率) 
};	unsigned char	c_cc[NCC]; //控制字符数组
 
 
#define NCCS 17 //termios结构中控制字符数组的长度    
 
struct termios
{
	unsigned long c_iflag;   //输入模式标志
	unsigned long c_oflag;	 //输出模式标志
	unsigned long c_cflag;	 //控制模式标志
	unsigned long c_lflag;	 //本地模式标志
	unsigned char c_line;	 //线路规程(速率)
	unsigned char c_cc[NCCS];//控制字符数组
};
//c_cc数组对应字符索引值
#define VINTR    0  //c_cc[VINTR]=INTR       (^C) \003  中断字符
#define VQUIT	 1  //c_cc[VQUIT]=QUIT	     (^\) \034  退出字符
#define VERASE	 2  //c_cc[VERASE]=ERASE     (^H) \0177 擦除字符
#define VKILL	 3  //c_cc[VKILL]=KILL	     (^U) \025  终止字符
#define VEOF	 4  //c_cc[VEOF]=EOF	     (^D) \004  文件结束字符
#define VTIME	 5  //c_cc[VTIME]=TIME	     (\0) \0    定时器值
#define VMIN	 6  //c_cc[VMIN]= MIN	     (\1) \1    定时器值 
#define VSWTC	 7  //c_cc[VSWTC]= SWTC	     (\0) \0    交换字符
#define VSTART	 8  //c_cc[VSTART]=START     (^Q) \021  开始字符
#define VSTOP	 9  //c_cc[VSTOP]=STOP	     (^S) \023  停止字符
#define VSUSP	 10 //c_cc[VSUSP]=SUSP	     (^Z) \032  挂起字符
#define VEOL	 11 //c_cc[VEOL]=EOL	     (\0) \0    行结束字符
#define VREPRINT 12 //c_cc[VREPRINT]=REPRINT (^R) \022  重显示字符
#define VDISCARD 13 //c_cc[VDISCARD]=DISCARD (^O) \017  丢弃字符
#define VWERASE	 14 //c_cc[VWERASE]=WERASE   (^W) \027  单词擦除字符
#define VLNEXT	 15 //c_cc[VLNEXT]=LNEXT     (^V) \026  下一行字符
#define VEOL2	 16 //c_cc[VEOL2]=EOL2	     (\0) \0    行结束2
//termios结构输入模式字段c_iflag标志符号常数
#define IGNBRK  0000001	 //输入时回略break条件
#define BRKINT	0000002	 //在break时产生sigint信号
#define IGNPAR	0000004	 //胡恶劣奇哦校验出错的字符
#define PARMRK	0000010	 //标记奇哦校验错
#define INPCK	0000020	 //允许输入奇哦校验
#define ISTRIP	0000040	 //屏蔽字符第8位
#define INLCR	0000100	 //输入时将换行符NL映射成回车符CR
#define IGNCR	0000200	 //忽略回车符CR
#define ICRNL	0000400	 //在输入时将回车符CR映射成换行符NL
#define ICULC	0001000	 //在输入时将大写字符转换成小写字符
#define IXON	0002000	 //允许开始/停止输出控制
#define IXANY	0004000	 //允许任何字符重启输出
#define IXOFF	0010000	 //允许开始/停止输入控制
#define IMAXBEL	0020000	 //输入队列满时响铃
//termios结构中输出模式字段c_oflag何种标志
#define OPOST   0000001	  //执行输出处理
#define OLCUC	0000002	  //在输出时将小写字符转换成大写字符
#define ONLCR	0000004	  //在输出时将换行符NL映射成回车换行符CR-NL
#define OCRNL	0000010	  //子输出时将回车符CR映射成换行符NL
#define ONOCR	0000020	  //在0列不输出回车符CR
#define ONLRET	0000040	  //换行符NL在执行回车符的功能
#define OFILL	0000100	  //延迟时使用填充字符而不使用时间延迟
#define OFDEL	0000200	  //填充字符是ASCII码DEL,如果未设置,使用ASCII  NULL
#define NLDLY	0000400	  //选择换行延迟
#define NL0	0000000	  //换行延迟类型0
#define NL1	0000400	  //换行延迟类型1
#define CRDLY	0003000	  //选择回车延迟
#define CR0	0000000	  //回车延迟类型0
#define CR1	0001000	  //回车延迟类型1
#define CR2	0002000	  //回车延迟类型2
#define CR3	0003000	  //回车延迟类型3
#define TABDLY	0014000	  //选择水平制表延迟
#define TAB0	0000000	  //水平制表延迟类型0
#define TAB1	0004000	  //水平制表延迟类型1
#define TAB2	0010000	  //水平制表延迟类型2
#define TAB3	0014000	  //水平制表延迟类型3
#define XTABS	0014000	  //将制表符TAB换成空格,该值表示空格数
#define BSDLY	0020000	  //选择退格延迟
#define BS0	0000000	  //退格延迟类型0
#define BS1	0020000	  //退格延迟类型1
#define VTDLY	0040000	  //纵向制表延迟
#define VT0	0000000	  //纵向制表延迟类型0
#define VT1	0040000	  //纵向制表延迟类型1
#define FFDLY	0040000	  //选择换页延迟
#define FF0	0000000	  //换页延迟类型0
#define FF1	0040000	  //换页延迟类型1
//termios结构中控制模式字段c_cfag符号
#define CBAUD   0000000	 //传输速率屏蔽码
#define B0	0000000	 //挂断线路
#define	B50	0000000	 //波特率50
#define	B75	0000000	 //波特率75
#define	B110	0000000	 //波特率110
#define	B134	0000000	 //波特率134
#define	B150	0000000	 //波特率150
#define	B200	0000000	 //波特率200
#define	B300	0000000	 //波特率300
#define	B600	0000000	 //波特率600
#define	B1200	0000000	 //波特率1200
#define	B1800	0000000	 //波特率1800
#define	B2400	0000000	 //波特率2400
#define	B4800	0000000	 //波特率4800
#define	B9600	0000000	 //波特率9600
#define	B19200	0000000	 //波特率1920
#define	B38400	0000000	 //波特率38400
#define	B57600	0000000	 //波特率38400
#define	B115200	0000000	 //波特率38400
#define	B230400	0000000	 //波特率38400
#define	EXTA B19200      //扩展波特率A 
#define	EXTB B38400      //扩展波特率B 

#define _POSIX_VDISABLE 0
#define CSTART 0
#define CSTOP  0
 
#define	CSIZE    0000060      //字符位宽度屏蔽码
#define	CS5	 0000000      //每字符5比特位
#define	CS6	 0000020      //每字符6比特位
#define	CS7	 0000040      //每字符7比特位
#define	CS8	 0000060      //每字符8比特位
#define	CSTOPB	 0000100      //设置两个停止位
#define	CREAD	 0000200      //允许接收
#define CPARENB	 0000400      //开始输出时产生奇哦位,输入时进行奇哦校验
#define CPARODD	 0001000      //输入/输入校验是奇校验
#define HUPCL	 0002000      //最后进程关闭后挂断
#define CLOCAL	 0004000      //忽略调制解调器
#define CLBAUD	 0360000      //输入波特率被
#define CRTSCTS  02000000000  //流控制
 
#define PARENB CPARENB
#define PARODD CPARODD
//termios结构是哦那个本地模式标志字段c_lflag
#define ISIG      0000001  //当接收到字符INTR,QUIT,SUSP,DSUSP产生相应信号
#define ICANON	  0000002  //开始规范模式
#define XCASE	  0000004  //若设置来ICANON,终端是大写字符
#define ECHO	  0000010  //回显输入字符
#define ECHOE	  0000020  //若设置了ICANON,则erase/werase将擦除前一字符/单词
#define ECHOK	  0000040  //若设置了ICANON,则kill字符旧爱那个擦除当前行
#define ECHONL	  0000100  //若设置了ICANON,则即使咩有ECHO也回显NL字符
#define NOFLSH	  0000200  //当生成SIGINT忽然SIGQUIT信号时不刷新输入输出队列,当
                           //生成SIGSUSP信号后,刷新输入队列
#define TOSTOP	  0000400  //发送SIGTOU信号到后台进程的进程组,该后台进程试图写自己
		           //自己的控制终端
#define ECHOCTL	  0001000  //若设置了ECHO,则除来TAB,NL,START,STOP以外的ASCII
                    //控制信号将被回显成象‘^X’样子,X是控制符+0x40
#define ECHORPT	  0002000  //若设置来IECHO,ICANON则字符在擦除时将显示
#define ECHOKE	  0004000  //若设置了ICANON,则kill通过擦除行上所有字符被回显
#define FLUSHO	  0010000  //输出被刷新,通过键入DISCARD字符,该标志被反转
#define PENDIN	  0040000  //当下一个字符是读时,输入队列中的所有字符将被重显
#define IEXTEN	  0100000  //开启实现时定义的输入处理
//modem线路信号符号常数
#define TIOCM_LE  0x001   //线路允许
#define TIOCM_DTR 0x002	  //数据终端就绪
#define TIOCM_RTS 0x004	  //请求发送
#define TIOCM_ST  0x008	  //串行数据发送
#define TIOCM_SR  0x010	  //串行数据接收
#define TIOCM_CTS 0x020	  //清除发送
#define TIOCM_CAR 0x040	  //载波检测
#define TIOCM_RNG 0x080	  //响玲指示
#define TIOCM_DSR 0x100	  //数据设备就绪
#define TIOCM_CD TIOCM_CAR//
#define TIOCM_R1 TIOCM_RNG//
//tcfow()和TCXONCSHIYONG
#define TCOOFF       0 //挂起输出 	
#define TCOON        1 //重启被挂起的输出	
#define TCIOFF       2 //系统传输一个stop字符,使设备停止向系统传输数据 
#define TCION        3 //系统传输一个start字符,使设备开始向系统传输数据
//tcflush()和TCFLSH使用
#define TCIFLUSH     0 //请接收到的数据但不读
#define TCOFLUSH     1 //清已写的数据但不传送
#define TCIOFLUSH    2 //清接收到的数据但不读,清已写的数据但不传送
//tcsetattr()使用
#define TCSANOW            0 //改变立即发生
#define TCSADRAIN	   1 //改变在所有已写的输出被传输之后发生
#define TCSAFLUSH	   2 //改变在所有已写的输出被传输之后并且在所有接收到
                             //还没有读取的数据被丢弃之后发生
 
typedef int speed_t;  //波特率数值类型
 
//返回termios_p所指termios结构中的接收波特率
extern speed_t cfgetispeed(struct termios *termios_p);
 
//返回termios_p所指termios结构中的发送波特率
extern speed_t cfgetospeed(struct termios *termios_p);
 
//将termios_p所指termios结构中的接收波特率设置为speed
extern int cfsetispeed(struct termios*termios_p,speed_t speed);
 
//将termios_p所指termios结构中的发送波特率设置为speed
extern int cfsetospeed(struct termios *termios_p,speed_t speed);
 
//等待fildes所指对象已写输出数据被传送出去
extern int tcdrain(int fildes);
 
//挂起/重启fildes所指对象数据的接收和发送
extern int tcflow(int fildes,int action);
 
//丢弃fildes指定对象 所有已写但还没传送以及所有已收到但还没有读取的数据
extern int tcflush(int fildes,int queue_selector);
 
//获取与句柄fildes对应对象的参数,并将其保存在termios_p所指的地方
extern int tcgetattr(int fildes,struct termios *termios_p);
 
//如果终端使用异步串行数据传输,则在一定时间内连续传输一系列0值比特位
extern int tcsendbreak(int fildes,int duration);
 
//使用termios结构指针termios_p所指的数据,设置与终相关的参数
extern int tcsetattr(int fildes,int optional_actions,struct termios *termios_p);
 
#endif

修改ezspSetupSerialPort方法实现;

EzspStatus ezspSetupSerialPort(int* serialPortFdReturn,
                               char* errorStringLocation,
                               int maxErrorLength,
                               bool bootloaderMode)
{

	//TODO 使用esp32 串口2;在应用启动时完成串口初始化
	return EZSP_SUCCESS;
  
}

增加外部方法声明(这两个方法,将在esp32中实现):

//串口写入数据
extern int esp32_uart_SerialWriteByte(const char* src, size_t size);

//串口读取数据
extern int16_t esp32_uart_SerialReadByte(uint8_t* buf, uint16_t length);

然后将此文件中(有多处),

bytesRead = read(serialFd, inBuffer, inBlockLen); 替换为 bytesRead = esp32_uart_SerialReadByte( inBuffer, inBlockLen);

count = write(serialFd, outBufRd, outBufWr - outBufRd); 替换为  count = esp32_uart_SerialWriteByte( (const char*) outBufRd, outBufWr - outBufRd);

如下图所示

备注:ezspSerialReadAvailable、ezspSerialWriteFlush这两个方法非常重要,是host和ncp在通讯时,串口的写入和读取;对性能要求很高,不能出现阻塞的情况。特别是ezspSerialReadAvailable,在主程序中每隔20ms会调用一次,用于不断检测ncp是否有数据送到host。


4)ezsp-esp32.c

EzspStatus sendCommand(void)方法、void ezspTick(void)方法中的assert改成打印错误信息(assert在esp32中会引发MCU重启,或者重新定义assert在esp32中的实现,会是更好的解决方案)

 

备注:ezsp协议的主要实现方法都在这里,尽量不要改动里面内容。


5)gateway-relay-mqtt-esp32.c

static void publishMqttZclCommand(uint8_t commandId,
                                  boolean clusterSpecific,
                                  uint16_t clusterId,
                                  boolean mfgSpecific,
                                  uint16_t mfgCode,
                                  uint8_t* buffer,
                                  uint8_t bufLen,
                                  uint8_t payloadStartIndex)

备注:publishMqttZclCommand方法好像会产生内存泄露问题,特别是在OTA的时候,需要向mqtt大量上报OTA状态的时候。每次调用会泄露52字节;因为mqtt是采用esp32自己的api;不是使用芯科的插件,所以可能导致某些资源(例如json对象)没有释放;暂时的解决办法是直接返回,好像功能也正常,相当奇怪;后面再仔细研究。

这个方法的调用链如下:

emAfPreCommandReceived -> emberAfPluginGatewayRelayMqttPreCommandReceivedCallback -> publishMqttZclCommand

emAfPreCommandReceived 位于“znet-bookkeeping.c”文件中;(难道是host收到命令后,如果是zcl命令,又将命令发送到mqtt?这么奇怪)


6)gateway-support-esp32.c

先把assert后面的代码先屏蔽了。

static void ezspSerialPortCallback(EzspSerialPortEvent event, int fileDescriptor)
{
  printf("=================ezspSerialPortCallback=================");
  if (event == EZSP_SERIAL_PORT_CLOSED) {
    printf("EZSP serial port closed.  FD=%d \r\n", fileDescriptor);
    
  } else if (event == EZSP_SERIAL_PORT_OPENED) {
    
    printf("Registered EZSP FD %d \r\n", fileDescriptor);
    
  }

  /**
  assert(fileDescriptor != NULL_FILE_DESCRIPTOR);

  if (event == EZSP_SERIAL_PORT_CLOSED) {
    debugPrint("EZSP serial port closed.  FD=%d", fileDescriptor);
    emberAfPluginFileDescriptorDispatchRemove(fileDescriptor);
  } else if (event == EZSP_SERIAL_PORT_OPENED) {
    EmberAfFileDescriptorDispatchStruct dispatchStruct = {
      ezspFileDescriptorReadyCallback,   // callback
      (void *) fileDescriptor,   // data passed to callback
      EMBER_AF_FILE_DESCRIPTOR_OPERATION_READ,
      fileDescriptor,
    };

    debugPrint("Registered EZSP FD %d", fileDescriptor);
    if (EMBER_SUCCESS != emberAfPluginFileDescriptorDispatchAdd(&dispatchStruct)) {
      emberAfCorePrintln("Error: Gateway Plugin failed to register EZSP FD %d", fileDescriptor);
    }
  }
  **/
}

备注:如果ezsp出现通讯异常,会打印异常错误码,都定义在“ezsp-enum.h”的EzspStatus结构体中;如下图所示。

下面是出现频率最多的错误,先记录一下

 // Operation not yet complete.
  EZSP_ASH_IN_PROGRESS                          = 0x20,
  // Fatal error detected by host.
  EZSP_HOST_FATAL_ERROR                         = 0x21,
  // Fatal error detected by NCP.
  EZSP_ASH_NCP_FATAL_ERROR                      = 0x22,
  // Tried to send DATA frame too long.
  EZSP_DATA_FRAME_TOO_LONG                      = 0x23,
  // Tried to send DATA frame too short.
  EZSP_DATA_FRAME_TOO_SHORT                     = 0x24,
  // No space for tx'ed DATA frame.
  EZSP_NO_TX_SPACE                              = 0x25,
  // No space for rec'd DATA frame.
  EZSP_NO_RX_SPACE                              = 0x26,
  // No receive data available.
  EZSP_NO_RX_DATA                               = 0x27,
  // Not in Connected state.
  EZSP_NOT_CONNECTED                            = 0x28,
  // The NCP received a command before the EZSP version had been set.
  EZSP_ERROR_VERSION_NOT_SET                    = 0x30,
  // The NCP received a command containing an unsupported frame ID.
  EZSP_ERROR_INVALID_FRAME_ID                   = 0x31,

7)command-relay-esp32.c

将emberAfPluginCommandRelaySave、emberAfPluginCommandRelayLoad方法调整如下;将原来的文件操作部分先删除,后面有需要再调整为esp32的文件操作方式。如下图所示

void emberAfPluginCommandRelaySave(void)
{
  //TODO esp32暂时不将配置保存到本地文件
  emberAfPluginCommandRelayChangedCallback();
}
void emberAfPluginCommandRelayLoad(void)
{
  initRelayTable();
  //TODO esp32暂时不将配置保存到本地文件
  emberAfPluginCommandRelayChangedCallback();
}

备注:此文件是命令行处理插件,相关的文件还包括command-interpreter2.h等文件;在command-interpreter2.h有详细的命令行使用方法(类似其他MCU的AT指令操作),可以重点关注,特别是其中的bool emberProcessCommandString(uint8_t *input, uint8_t sizeOrPort) 方法。


8)device-table-esp32.c

和上面类似,将emAfDeviceTableSave、emAfDeviceTableLoad关于文件操作部分先删除。

// Save/Load the devices
void emAfDeviceTableSave(void)
{
	//TODO esp32 不保存device table 文件
	return;

}

void emAfDeviceTableLoad(void)
{
	//TODO esp32 不保存device table 文件
	return;
}

9)device-table-discovery-esp32.c

emAfPluginDeviceTablePreZDOMessageReceived方法最后,调整为return true;如下图所示。

如果是return false;可能引发esp32重启(可能是内存访问越界),具体原因还没找到,先记录一下。


10)ota-storage-linux-esp32.c

修改ota文件保存目录(与后续esp32中的分区表保持一致)、修改相关的存储初始化方法、关闭方法(后续在esp32中做相应处理)。

static char* storageDevice = "/ota-files/";
static bool storageDeviceIsDirectory = true;

EmberAfOtaStorageStatus emAfOtaSetStorageDevice(const void* device)
{
  
  if (initDone) {
    return EMBER_AF_OTA_STORAGE_ERROR;
  }
  
}
EmberAfOtaStorageStatus emberAfOtaStorageInitCallback(void)
{
   
  if (initDone) {
    return EMBER_AF_OTA_STORAGE_SUCCESS;
  }

  EmberAfOtaStorageStatus status;
  status = initImageDirectory();
 
  iterator = NULL; // Must be initialized via
                   // otaStorageIteratorReset()

  if (status == EMBER_AF_OTA_STORAGE_SUCCESS) {
    initDone = true;
  }

  return status;
}

void emAfOtaStorageClose(void)
{
 
  OtaImage* ptr = imageListLast;
  while (ptr != NULL) {
    OtaImage* current = ptr;
    ptr = (OtaImage*)ptr->prev;
	 
    freeOtaImage(current);
  }
  imageListLast = NULL;
  imageListFirst = NULL;
 
  initDone = false;
  imageCount = 0;
}

11)token-esp32.c

不清楚要来干嘛,暂时调整如下:


#define _XOPEN_SOURCE 500

#include PLATFORM_HEADER
#include CONFIGURATION_HEADER
#include EMBER_AF_API_HAL



#ifdef EMBER_AF_API_TOKEN


#define VERSION 1

extern const uint16_t tokenCreators[];
extern const bool tokenIsCnt[];
extern const uint8_t tokenSize[];
extern const uint8_t tokenArraySize[];
extern const void * const tokenDefaults[];

// TODO: Don't include stack tokens on the host.
#define DEFINETOKENS
#define TOKEN_MFG TOKEN_DEF
#define TOKEN_DEF(name, creator, iscnt, isidx, type, arraysize, ...) \
  TOKEN_##name##_ADDRESS,
static const uint16_t addresses[] = {
    #include "stack/config/token-stack.h"
};
#undef TOKEN_DEF
#undef TOKEN_MFG
#undef DEFINETOKENS

static void initializeTokenSystem(void);
static void resetTokenData(void);
static size_t getNvmOffset(uint16_t token, uint8_t index, uint8_t len);

#ifndef EMBER_AF_TOKEN_FILENAME
  #if defined(EMBER_AF_DEVICE_NAME)
    #define EMBER_AF_TOKEN_FILENAME EMBER_AF_DEVICE_NAME ".nvm"
  #elif defined(ZA_PROMPT)
    #define EMBER_AF_TOKEN_FILENAME ZA_PROMPT ".nvm"
  #else
    #error EMBER_AF_TOKEN_FILENAME must be defined.
  #endif
#endif

// #define EMBER_AF_HOST_TOKEN_DEBUG
#ifdef EMBER_AF_HOST_TOKEN_DEBUG
  #define hostTokenDebugPrintf(...) fprintf(stdout, __VA_ARGS__)
#else
  #define hostTokenDebugPrintf(...)
#endif

// mmap(2) returns MAP_FAILED on failure, which is not necessarily defined the
// same as NULL.
static uint8_t *nvm = MAP_FAILED;
#define isInitialized() (nvm != MAP_FAILED)

#define PER_TOKEN_OVERHEAD  \
  (sizeof(tokenCreators[0]) \
   + sizeof(tokenIsCnt[0])  \
   + sizeof(tokenSize[0])   \
   + sizeof(tokenArraySize[0]))
#define TOTAL_SIZE                    \
  (1 /* version overhead */           \
   + TOKEN_COUNT * PER_TOKEN_OVERHEAD \
   + TOKEN_MAXIMUM_SIZE)

typedef struct {
  size_t offset; // offset from start of nvm file
  bool present;  // true if entry is present in nvm file
} nvmCreatorOffsetType;

// keeps track of token offsets in nvm file (helps with rearranged tokens)
// when populating, each index is maintained to be the same as the creator's
// index in tokenCreators[], tokenIsCnt[] etc.
static nvmCreatorOffsetType nvmCreatorOffset[TOKEN_COUNT];

void halInternalGetTokenData(void *data, uint16_t token, uint8_t index, uint8_t len)
{

}

void halInternalSetTokenData(uint16_t token, uint8_t index, void *data, uint8_t len)
{

}

void halInternalSetMfgTokenData(uint16_t token, void *data, uint8_t len)
{

}

// check if token in nvm file is still present in stack/app
// if present, return new index in tokenCreators, else return false
static bool isOldToken(uint16_t tokCreator, size_t* index)
{

  return false;
}

// should we copy nvm values?
// if index is present (was populated) and token structure is same, return true
// else return false, so that we reset values
static bool copyNvm(uint8_t* nvmData,
                    size_t index,
                    size_t* tokOffset)
{

  return false;
}

static void initializeTokenSystem(void)
{

}

static void resetTokenData(void)
{

}

static size_t getNvmOffset(uint16_t token, uint8_t index, uint8_t len)
{

  return 1;
}

#endif // EMBER_AF_API_TOKEN

12)backchannel-support-esp32.c

不清楚要来干嘛,暂时调整如下:

#include PLATFORM_HEADER //compiler/micro specifics, types

#include "stack/include/ember-types.h"
#include "stack/include/error.h"

#include "hal/hal.h"

#include <sys/types.h>



#include "app/framework/plugin-host/gateway/gateway-support.h"

//------------------------------------------------------------------------------
// GLOBALS

const bool backchannelSupported = true;

// The serial port number (0 or 1) plus this offset gives the port that the
// socket server will listen on. By default (to match the InSight Adapter
// behavior):
//    * serial port 0 -> server port 4900
//    * serial port 1 -> server port 4901
int backchannelSerialPortOffset = EMBER_AF_PLUGIN_GATEWAY_TCP_PORT_OFFSET;

#define SERVER_PORT_OFFSET (backchannelSerialPortOffset)

#define INVALID_FD -1

static int socketFd[] = { INVALID_FD, INVALID_FD };
static int clientFd[] = { INVALID_FD, INVALID_FD };

//struct sockaddr_in clientConnections[2];

static bool debugOn = false;
static const char debugString[] = "backchannel";

// These will change
static int LOCAL_STDIN = 0;
static int LOCAL_STDOUT = 1;
static int LOCAL_STDERR = 2;

#define REMOTE_STDIN  0
#define REMOTE_STDOUT 1
#define REMOTE_STDERR 2

#define MAX_STRING_LENGTH 250

// Turned on via command-line options
bool backchannelEnable = false;

static FILE* clientOut[] = { NULL, NULL };

//------------------------------------------------------------------------------
// Forward Declarations

static int willConnectionBlock(bool server, uint8_t port, bool read);

#define willClientConnectionBlock(port) \
  willConnectionBlock(false, (port), false)
#define willServerConnectionBlock(port) \
  willConnectionBlock(true, (port), true)

static bool getNewConnection(uint8_t port);
static void unixError(const char* format, ...);
static void debugPrint(const char* formatString, ...);
static void infoPrint(const char* formatString, ...);
static int myPrintf(int fd, const char* formatString, ...);
static int myVprintf(int fd, const char* formatString, va_list ap);

//------------------------------------------------------------------------------
// API

EmberStatus backchannelStartServer(uint8_t port)
{



  return EMBER_SUCCESS;
}

EmberStatus backchannelClientConnectionCleanup(uint8_t port)
{

  return EMBER_SUCCESS;
}

EmberStatus backchannelStopServer(uint8_t port)
{

  return EMBER_SUCCESS;
}

// Retrieves a single byte from the client connection.  Returns the number
// of bytes read, or -1 on error.  If no client connection currently exists,
// then it will block until one is established.  If an error is returned then
// it means an attempt was made to establish one but it failed.
EmberStatus backchannelReceive(uint8_t port, char* data)
{


  return EMBER_ERR_FATAL;
}

EmberStatus backchannelSend(uint8_t port, uint8_t * data, uint8_t length)
{

  return EMBER_INVALID_CALL;
}

// Checks on the state of the current backchannel connection.
// If one doesn't exist, it can wait for a new connection and return
// the result.
BackchannelState backchannelCheckConnection(uint8_t port,
                                            bool waitForConnection)
{

  return NO_CONNECTION;
}

EmberStatus backchannelServerPrintf(const char* formatString, ...)
{

  return EMBER_SUCCESS ;
}

EmberStatus backchannelClientPrintf(uint8_t port, const char* formatString, ...)
{
	return EMBER_SUCCESS ;
}

EmberStatus backchannelClientVprintf(uint8_t port,
                                     const char* formatString,
                                     va_list ap)
{
	return EMBER_SUCCESS ;
}

// Re-map STDIN, STDOUT, and STDERR to the client connection.
// This allows the software to use normal read() and write() calls to
// to receive and send data to the remote client.
EmberStatus backchannelMapStandardInputOutputToRemoteConnection(int port)
{

  return EMBER_SUCCESS;
}

EmberStatus backchannelCloseConnection(uint8_t port)
{
	return EMBER_SUCCESS ;
}

//------------------------------------------------------------------------------
// Internal Functions

// Returns 0 if a read/write will not block, 1 if it will, and -1 on error.
static int willConnectionBlock(bool server, uint8_t port, bool read)
{

  return  0  ;
}

// Accepts a new TCP connection.  Returns the state of the connection.
static bool getNewConnection(uint8_t port)
{

  return false;
}

//------------------------------------------------------------------------------
// Internal Printing routines

// Print an error message plus the associated 'errno' string
static void unixError(const char* format, ...)
{

}

static void debugPrint(const char* formatString, ...)
{

}

static void infoPrint(const char* formatString, ...)
{

}

// Because we mess around with FDs, we need our own printing routine
// for handling where messages are printed to.

static int myPrintf(int fd, const char* formatString, ...)
{

  return 0;
}

// Returns 0 on success, 1 on error
static int myVprintf(int fd, const char* formatString, va_list ap)
{

  return 0;
}

13)Makefile

    指定以生成静态库方式编译,指定esp32交叉编译命令

 

将前面12个修改的esp32文件名,替换到对应的位置

在编译参数中增加 mlongcalls参数

如果不增加此参数,可以正常编译为静态库;但在esp32中使用时,会出现“call8: call target out of range: malloc”异常,如下图所示

具体异常描述,可查看此贴子:https://www.esp32.com/viewtopic.php?t=1612

最后,将修改后的Makefile内容贴上,仅供参考

# This file was generated by Simplicity Studio from the following template:
#   protocol/zigbee/tool/appbuilder/host-unix-Makefile-afv2
# Please do not edit it directly.

# This Makefile defines how to build a unix host application connected to an
# Ember NCP EZSP device.  This also works for Windows machines running
# Cygwin.

# Variables

# If using a different compiler than GCC, you can create a makefile
# that overrides the following variables.  
#   COMPILER - Compiler binary path
#   LINKER - Linker binary path
#   ARCHIVE - Optional archive tool, only necessary for building a library.
#     Must also set GENERATE_LIBRARY := 1 in your makefile.
#   COMPILER_INCLUDES - Any additional compiler includes each prefixed with -I
#   COMPILER_DEFINES - Any additional compiler defines each prefixed with -D
#   COMPILER_FLAGS - The set of compiler flags (not including dependencies)
#   LINKER_FLAGS - The set of linker flags
#   ARCHIVE_FLAGS - The set of archive tool flags.
#   DEPENDENCY_FLAGS - The set of dependency generation flags used to generate
#     dependencies at the same time compilation is executed.
#   DEPENDENCY_POST_PROCESS - An optional post processing step for massaging
#     generated dependencies.  Only necessary when using a compiler on the 
#     non-native platform (e.g. Windows compiler on Linux)
#   PLATFORM_HEADER_FILE - The header file defining the basic int8u, int32u,
#     and other typedefs and platform elements.
#   ARCHIVE_EXTENSION - The file extension for archives if not using the standard
#     .a file extension.
#
# Then pass the makefile to this one on the command line with:
#   "make -C app/builder/Z3GatewayHost_ESP32 INCLUDE_MAKEFILE=my-custom.mak"
#   or 
#   "cd app/builder/Z3GatewayHost_ESP32; make INCLUDE_MAKEFILE=my-custom.mak"
#

NO_READLINE ?= 1
GENERATE_LIBRARY := 1

ifdef INCLUDE_MAKEFILE
  include $(INCLUDE_MAKEFILE)
endif  

.SUFFIXES:

COMPILER ?= xtensa-esp32-elf-gcc
LINKER   ?= xtensa-esp32-elf-gcc
ARCHIVE  ?= ar
STD      ?= gnu99

ARCHIVE_EXTENSION ?= .a



CC = $(COMPILER)
LD = $(LINKER)
SHELL = /bin/sh

ifneq ($(CURDIR),$(shell dirname '$(abspath $(lastword $(MAKEFILE_LIST)))'))
$(error This makefile should only be invoked under its current directory ($(shell dirname '$(abspath $(lastword $(MAKEFILE_LIST)))')))
endif

COMPILER_INCLUDES ?= 

INCLUDES= -I./ \
  $(COMPILER_INCLUDES) \
  -I./../../../v2.7 \
  -I./../../../v2.7/protocol/zigbee/app/framework \
  -I./../../../v2.7/protocol/zigbee/app/framework/../.. \
  -I./../../../v2.7/protocol/zigbee/app/framework/../../stack \
  -I./../../../v2.7/protocol/zigbee/app/framework/../util \
  -I./../../../v2.7/protocol/zigbee/app/framework/../util/common \
  -I./../../../v2.7/protocol/zigbee/app/framework/../util/ezsp \
  -I./../../../v2.7/protocol/zigbee/app/framework/../util/serial \
  -I./../../../v2.7/protocol/zigbee/app/framework/../util/zigbee-framework \
  -I./../../../v2.7/protocol/zigbee/app/framework/cli \
  -I./../../../v2.7/protocol/zigbee/app/framework/include \
  -I./../../../v2.7/protocol/zigbee/app/framework/security \
  -I./../../../v2.7/protocol/zigbee/app/framework/util \
  -I./Z3GatewayHost_ESP32 \
  -I./../../../v2.7/platform/base/hal \
  -I./../../../v2.7/platform/base/hal/plugin \
  -I./../../../v2.7/platform/base/hal/.. \
  -I./../../../v2.7/platform/base/hal/micro/generic \
  -I./../../../v2.7/platform/base/hal/micro/unix/host \
  -I../../../v2.7/platform/base/hal/micro/unix/host/board \
  -I../../../v2.7/util/plugin/plugin-common/mbedtls \
  -I../../../v2.7/util/third_party/mbedtls \
  -I../../../v2.7/util/third_party/mbedtls/include \
  -I../../../v2.7/util/third_party/mbedtls/include/mbedtls \
  -I../../../v2.7/util/third_party/mbedtls/sl_crypto/include \
 \

APP_BUILDER_OUTPUT_DIRECTORY=.
APP_BUILDER_CONFIG_HEADER=$(APP_BUILDER_OUTPUT_DIRECTORY)/Z3GatewayHost_ESP32.h
APP_BUILDER_STORAGE_FILE=$(APP_BUILDER_OUTPUT_DIRECTORY)/Z3GatewayHost_ESP32_endpoint_config.h

PLATFORM_HEADER_FILE ?= \"../../../v2.7/platform/base/hal/micro/unix/compiler/gcc-esp32.h\"

DEFINES = \
  $(COMPILER_DEFINES) \
  -DUNIX \
  -DUNIX_HOST \
  -DPHY_NULL \
  -DCONFIGURATION_HEADER=\"../../../v2.7/protocol/zigbee/app/framework/util/config.h\" \
  -DEZSP_HOST \
  -DGATEWAY_APP \
  -DZA_GENERATED_HEADER=\"$(APP_BUILDER_CONFIG_HEADER)\" \
  -DATTRIBUTE_STORAGE_CONFIGURATION=\"$(APP_BUILDER_STORAGE_FILE)\" \
  -DPLATFORM_HEADER=$(PLATFORM_HEADER_FILE) \
    -DBOARD_HOST \
  -DBOARD_HEADER=\"Z3GatewayHost_ESP32_board.h\" \
  -DEM_AF_TEST_HARNESS_CODE \
  -DEM_AF_LINK_M \
  -DEM_AF_LINK_PTHREAD \
  -DEMBER_AF_API_EMBER_TYPES=\"stack/include/ember-types.h\" \
  -DEMBER_AF_API_DEBUG_PRINT=\"app/framework/util/print.h\" \
  -DEMBER_AF_API_AF_HEADER=\"app/framework/include/af.h\" \
  -DEMBER_AF_API_AF_SECURITY_HEADER=\"app/framework/security/af-security.h\" \
  -DEMBER_AF_API_NEIGHBOR_HEADER=\"stack/include/stack-info.h\" \
  -DEMBER_STACK_ZIGBEE \
  -DEZSP_ASH \
  -DMBEDTLS_CONFIG_FILE=\"mbedtls-config-generated.h\" \
  -DWITH_POSIX \
  -D_GNU_SOURCE \



COMPILER_FLAGS ?= \
  -Wall \
  -ggdb \
  -O0   \
  -mlongcalls  \
  -std=$(STD)

APPLICATION_FILES= \
  ./znet-bookkeeping.c \
  ./call-command-handler.c \
  ./callback-stub.c \
  ./stack-handler-stub.c \
  ./znet-cli.c \
  ./Z3GatewayHost_ESP32_callbacks.c \
  ../../../v2.7/protocol/zigbee/app/framework/../util/common/library.c \
  ../../../v2.7/protocol/zigbee/app/framework/../util/serial/command-interpreter2.c \
  ../../../v2.7/protocol/zigbee/app/framework/../util/zigbee-framework/zigbee-device-common.c \
  ../../../v2.7/protocol/zigbee/app/framework/../util/zigbee-framework/zigbee-device-host.c \
  ../../../v2.7/protocol/zigbee/app/framework/../../stack/framework/event-control.c \
  ../../../v2.7/platform/base/hal/micro/generic/led-stub.c \
  ../../../v2.7/platform/base/hal/micro/generic/mem-util.c \
  ../../../v2.7/platform/base/hal/plugin/antenna-stub/antenna-stub.c \
  ../../../v2.7/platform/base/hal/plugin/buzzer-stub/buzzer-stub.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/address-table/address-table.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/address-table/address-table-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/basic/basic.c \
  ../../../v2.7/util/third_party/cjson/cJSON.c \
  ../../../v2.7/util/third_party/cjson/cJSON_Utils.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/color-control-server/color-control-server.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/command-relay/command-relay-esp32.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/command-relay/command-relay-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/concentrator/concentrator-support.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/concentrator/concentrator-support-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/counters/counters-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/counters/counters-ota-host.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/counters/counters-host.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/device-table/device-table-esp32.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/device-table/device-table-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/device-table/device-table-discovery-esp32.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/device-table/device-table-tracking.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/ezmode-commissioning/ez-mode.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/ezmode-commissioning/ez-mode-cli.c \
  ../../../v2.7/protocol/zigbee/app/util/ezsp/ezsp-callbacks.c \
  ../../../v2.7/protocol/zigbee/app/util/ezsp/ezsp-enum-decode.c \
  ../../../v2.7/protocol/zigbee/app/util/ezsp/ezsp-frame-utilities.c \
  ../../../v2.7/protocol/zigbee/app/util/ezsp/ezsp-esp32.c \
  ../../../v2.7/protocol/zigbee/app/ezsp-host/ezsp-host-io-esp32.c \
  ../../../v2.7/protocol/zigbee/app/ezsp-host/ezsp-host-queues.c \
  ../../../v2.7/protocol/zigbee/app/ezsp-host/ezsp-host-ui.c \
  ../../../v2.7/protocol/zigbee/app/util/ezsp/serial-interface-uart.c \
  ../../../v2.7/protocol/zigbee/app/ezsp-host/ash/ash-host-ui.c \
  ../../../v2.7/protocol/zigbee/app/ezsp-host/ash/ash-host.c \
  ../../../v2.7/platform/base/hal/micro/generic/ash-common.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin-host/file-descriptor-dispatch/file-descriptor-dispatch.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin-host/gateway/gateway-support-esp32.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin-host/gateway/backchannel-support-esp32.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin-host/gateway/gateway-support-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin-host/gateway-relay-mqtt/gateway-relay-mqtt-esp32.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin-host/gateway-relay-mqtt/gateway-relay-mqtt-commands.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/green-power-client/green-power-client.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/green-power-client/green-power-client-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/green-power-common/green-power-common.c \
  ../../../v2.7/protocol/zigbee/stack/gp/gp-util.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/heartbeat/heartbeat.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/ias-zone-client/ias-zone-client.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/ias-zone-client/ias-zone-client-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/identify/identify.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/identify/identify-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/identify-feedback/identify-feedback.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/level-control/level-control.c \
  ../../../v2.7/util/plugin/plugin-common/linked-list/linked-list.c \
  ../../../v2.7/util/third_party/mbedtls/library/aes.c \
  ../../../v2.7/util/third_party/mbedtls/library/aesni.c \
  ../../../v2.7/util/third_party/mbedtls/library/arc4.c \
  ../../../v2.7/util/third_party/mbedtls/library/asn1parse.c \
  ../../../v2.7/util/third_party/mbedtls/library/asn1write.c \
  ../../../v2.7/util/third_party/mbedtls/library/base64.c \
  ../../../v2.7/util/third_party/mbedtls/library/bignum.c \
  ../../../v2.7/util/third_party/mbedtls/library/blowfish.c \
  ../../../v2.7/util/third_party/mbedtls/library/camellia.c \
  ../../../v2.7/util/third_party/mbedtls/library/ccm.c \
  ../../../v2.7/util/third_party/mbedtls/library/certs.c \
  ../../../v2.7/util/third_party/mbedtls/library/cipher.c \
  ../../../v2.7/util/third_party/mbedtls/library/cipher_wrap.c \
  ../../../v2.7/util/third_party/mbedtls/library/cmac.c \
  ../../../v2.7/util/third_party/mbedtls/library/ctr_drbg.c \
  ../../../v2.7/util/third_party/mbedtls/library/debug.c \
  ../../../v2.7/util/third_party/mbedtls/library/des.c \
  ../../../v2.7/util/third_party/mbedtls/library/dhm.c \
  ../../../v2.7/util/third_party/mbedtls/library/ecdh.c \
  ../../../v2.7/util/third_party/mbedtls/library/ecdsa.c \
  ../../../v2.7/util/third_party/mbedtls/library/ecjpake.c \
  ../../../v2.7/util/third_party/mbedtls/library/ecp.c \
  ../../../v2.7/util/third_party/mbedtls/library/ecp_curves.c \
  ../../../v2.7/util/third_party/mbedtls/library/entropy.c \
  ../../../v2.7/util/third_party/mbedtls/library/entropy_poll.c \
  ../../../v2.7/util/third_party/mbedtls/library/error.c \
  ../../../v2.7/util/third_party/mbedtls/library/gcm.c \
  ../../../v2.7/util/third_party/mbedtls/library/havege.c \
  ../../../v2.7/util/third_party/mbedtls/library/hmac_drbg.c \
  ../../../v2.7/util/third_party/mbedtls/library/md.c \
  ../../../v2.7/util/third_party/mbedtls/library/md2.c \
  ../../../v2.7/util/third_party/mbedtls/library/md4.c \
  ../../../v2.7/util/third_party/mbedtls/library/md5.c \
  ../../../v2.7/util/third_party/mbedtls/library/md_wrap.c \
  ../../../v2.7/util/third_party/mbedtls/library/memory_buffer_alloc.c \
  ../../../v2.7/util/third_party/mbedtls/library/net_sockets.c \
  ../../../v2.7/util/third_party/mbedtls/library/oid.c \
  ../../../v2.7/util/third_party/mbedtls/library/padlock.c \
  ../../../v2.7/util/third_party/mbedtls/library/pem.c \
  ../../../v2.7/util/third_party/mbedtls/library/pk.c \
  ../../../v2.7/util/third_party/mbedtls/library/pk_wrap.c \
  ../../../v2.7/util/third_party/mbedtls/library/pkcs11.c \
  ../../../v2.7/util/third_party/mbedtls/library/pkcs12.c \
  ../../../v2.7/util/third_party/mbedtls/library/pkcs5.c \
  ../../../v2.7/util/third_party/mbedtls/library/pkparse.c \
  ../../../v2.7/util/third_party/mbedtls/library/pkwrite.c \
  ../../../v2.7/util/third_party/mbedtls/library/ripemd160.c \
  ../../../v2.7/util/third_party/mbedtls/library/rsa.c \
  ../../../v2.7/util/third_party/mbedtls/library/rsa_internal.c \
  ../../../v2.7/util/third_party/mbedtls/library/sha1.c \
  ../../../v2.7/util/third_party/mbedtls/library/sha256.c \
  ../../../v2.7/util/third_party/mbedtls/library/sha512.c \
  ../../../v2.7/util/third_party/mbedtls/library/ssl_cache.c \
  ../../../v2.7/util/third_party/mbedtls/library/ssl_ciphersuites.c \
  ../../../v2.7/util/third_party/mbedtls/library/ssl_cli.c \
  ../../../v2.7/util/third_party/mbedtls/library/ssl_cookie.c \
  ../../../v2.7/util/third_party/mbedtls/library/ssl_srv.c \
  ../../../v2.7/util/third_party/mbedtls/library/ssl_ticket.c \
  ../../../v2.7/util/third_party/mbedtls/library/ssl_tls.c \
  ../../../v2.7/util/third_party/mbedtls/library/threading.c \
  ../../../v2.7/util/third_party/mbedtls/library/timing.c \
  ../../../v2.7/util/third_party/mbedtls/library/version.c \
  ../../../v2.7/util/third_party/mbedtls/library/version_features.c \
  ../../../v2.7/util/third_party/mbedtls/library/x509.c \
  ../../../v2.7/util/third_party/mbedtls/library/x509_create.c \
  ../../../v2.7/util/third_party/mbedtls/library/x509_crl.c \
  ../../../v2.7/util/third_party/mbedtls/library/x509_crt.c \
  ../../../v2.7/util/third_party/mbedtls/library/x509_csr.c \
  ../../../v2.7/util/third_party/mbedtls/library/x509write_crt.c \
  ../../../v2.7/util/third_party/mbedtls/library/x509write_csr.c \
  ../../../v2.7/util/third_party/mbedtls/library/xtea.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin-host/ncp-configuration/ncp-configuration.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/network-creator/network-creator.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/network-creator/network-creator-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/network-creator-security/network-creator-security.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/network-creator-security/network-creator-security-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/network-steering/network-steering.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/network-steering/network-steering-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/network-steering/network-steering-v2.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/network-steering/network-steering-host.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/on-off/on-off.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/ota-common/ota-common.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/ota-server/ota-server.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/ota-server/ota-server-page-request.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/ota-server/ota-server-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/ota-server/ota-server-dynamic-block-period.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/ota-server-policy/ota-server-policy.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/ota-storage-common/ota-storage-common.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/ota-storage-common/ota-storage-common-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/ota-storage-posix-filesystem/ota-storage-linux-esp32.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/poll-control-client/poll-control-client.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/poll-control-client/poll-control-client-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/reporting/reporting.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/reporting/reporting-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/reporting/reporting-default-configuration.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/scan-dispatch/scan-dispatch.c \
  ../../../v2.7/protocol/zigbee/app/util/ezsp/secure-ezsp-stub.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/simple-main/simple-main.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/simple-metering-client/simple-metering-client.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/simple-metering-client/simple-metering-client-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/stack-diagnostics/stack-diagnostics.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/test-harness/test-harness.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/test-harness/read-write-attributes.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/test-harness/test-harness-host.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/time-server/time-server.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/trust-center-nwk-key-update-broadcast/trust-center-nwk-key-update-broadcast.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/trust-center-nwk-key-update-periodic/trust-center-nwk-key-update-periodic.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/trust-center-nwk-key-update-unicast/trust-center-nwk-key-update-unicast.c \
  ../../../v2.7/platform/base/hal/micro/generic/crc.c \
  ../../../v2.7/platform/base/hal/micro/generic/endian.c \
  ../../../v2.7/platform/base/hal/micro/generic/random.c \
  ../../../v2.7/platform/base/hal/micro/generic/system-timer.c \
  ../../../v2.7/platform/base/hal/micro/unix/host/micro.c \
  ../../../v2.7/platform/base/hal/micro/unix/host/token-def-unix.c \
  ../../../v2.7/platform/base/hal/micro/unix/host/token-esp32.c \
  ../../../v2.7/protocol/zigbee/app/util/serial/linux-serial-esp32.c \
  ../../../v2.7/platform/base/hal/plugin/serial/ember-printf-convert.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/update-tc-link-key/update-tc-link-key.c \
  ../../../v2.7/protocol/zigbee/app/framework/plugin/update-tc-link-key/update-tc-link-key-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/cli/core-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/cli/network-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/cli/option-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/cli/plugin-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/cli/security-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/cli/zcl-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/cli/zdo-cli.c \
  ../../../v2.7/protocol/zigbee/app/framework/security/af-node.c \
  ../../../v2.7/protocol/zigbee/app/framework/security/af-security-common.c \
  ../../../v2.7/protocol/zigbee/app/framework/security/af-trust-center.c \
  ../../../v2.7/protocol/zigbee/app/framework/security/crypto-state.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/af-event.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/af-main-common.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/attribute-size.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/attribute-storage.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/attribute-table.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/client-api.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/message.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/multi-network.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/print.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/print-formatter.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/process-cluster-message.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/process-global-message.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/service-discovery-common.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/time-util.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/util.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/af-main-host.c \
  ../../../v2.7/protocol/zigbee/app/framework/util/service-discovery-host.c \


LIBRARIES = \
 \


OUTPUT_DIR=$(APP_BUILDER_OUTPUT_DIRECTORY)/build
OUTPUT_DIR_CREATED= $(OUTPUT_DIR)/created
EXE_DIR=$(OUTPUT_DIR)/exe
# Build a list of object files from the source file list, but all objects
# live in the $(OUTPUT_DIR) above.  The list of object files
# created assumes that the file part of the filepath is unique
# (i.e. the bar.c of foo/bar.c is unique across all sub-directories included).
APPLICATION_OBJECTS= $(addprefix $(OUTPUT_DIR)/, $(notdir $(APPLICATION_FILES:.c=.o)))

ifdef GENERATE_LIBRARY
TARGET_FILE= $(EXE_DIR)/Z3GatewayHost_ESP32$(ARCHIVE_EXTENSION)
else
TARGET_FILE= $(EXE_DIR)/Z3GatewayHost_ESP32
endif

# -MMD and -MF generates Makefile dependencies while at the same time compiling.
# -MP notes to add a dummy 'build' rule for each header file.  This 
# prevent a problem where a removed header file will generate an error because a
# dependency references it but it can't be found anymore.
DEPENDENCY_FLAGS ?= -MMD -MP -MF $(@D)/$(@F:.o=.d)

# Dependency post process is a way to massage generated dependencies.
# This is necessary for example when using Make under Cygwin but compiling
# using a native Windows compiler that generates native Windows paths
# that Cygwin will choke on.  Or if compiling on Linux using Wine to run a 
# Windows compiler, a similar problem can occur.  
DEPENDENCY_POST_PROCESS ?=

CPPFLAGS= $(INCLUDES) $(DEFINES) $(COMPILER_FLAGS) $(DEPENDENCY_FLAGS)
LINKER_FLAGS ?=

ifdef NO_READLINE
  CPPFLAGS += -DNO_READLINE
else
  LINKER_FLAGS +=  \
    -lreadline \
    -lncurses 
endif

# Conditionally include the math library if EM_AF_LINK_M is defined.
ifeq ($(findstring -DEM_AF_LINK_M,$(DEFINES)),-DEM_AF_LINK_M)
  LINKER_FLAGS += \
    -lm
endif

# Conditionally include the POSIX threads library if EM_AF_LINK_PTHREAD is
# defined.
ifeq ($(findstring -DEM_AF_LINK_PTHREAD,$(DEFINES)),-DEM_AF_LINK_PTHREAD)
  LINKER_FLAGS += \
    -lpthread
endif

ARCHIVE_FLAGS ?= rus

# Rules

.PHONY: all
all: $(TARGET_FILE)

ifneq ($(MAKECMDGOALS),clean)
-include $(APPLICATION_OBJECTS:.o=.d)
endif

ifdef GENERATE_LIBRARY
$(TARGET_FILE): $(APPLICATION_OBJECTS) $(LIBRARIES)
	$(ARCHIVE) $(ARCHIVE_FLAGS) $(TARGET_FILE) $^
	@echo -e '\n$@ build success'
else
$(TARGET_FILE): $(APPLICATION_OBJECTS) $(LIBRARIES)
	$(LD) $^ $(LINKER_FLAGS) -o $(TARGET_FILE)
	@echo -e '\n$@ build success'
endif

.PHONY: clean
clean:
	rm -rf $(OUTPUT_DIR)

$(OUTPUT_DIR_CREATED):
	mkdir -p $(OUTPUT_DIR)
	mkdir -p $(EXE_DIR)
	touch $(OUTPUT_DIR_CREATED)

# To facilitate generating all output files in a single output directory, we
# must create separate .o and .d rules for all the different sub-directories
# used by the source files.
# If additional directories are added that are not already in the
# $(APPLICATION_FILES) above, new rules will have to be created below.

# Object File rules

# NOTE:  We escape the commands in this rule because we don't want
# them to be interpreted when the function executes.  We don't escape
# the dependency rule itself (1st line) because we want this to be 
# explicit for each target.
define create-build-rules 
$(OUTPUT_DIR)/$(notdir $(1:%.c=%.o)): $1 | $(OUTPUT_DIR_CREATED) 
	$$(CC) $$(CPPFLAGS) -c $$< -o $$@
	$$(DEPENDENCY_POST_PROCESS)
endef 

$(foreach d, $(APPLICATION_FILES), $(eval $(call create-build-rules,$d))) 
 

# Dependency rules
# No explicit rules.  Dependencies are generated as part of the compile step.

编译生成静态库

进入esp32工程项目,先用make clean清除编译环境,然后用make命令编译生成静态库,如下图所示。

成功编译后,会在build/exe目录生成Z3GatewayHost_ESP32.a静态库文件

用readelf -h Z3GatewayHost_ESP32.a命令,可以看到静态库信息如下:

至此,为esp32调用的准备工作结束,接下来将转到esp32的开发环境进行后续的集成工作。


本来想一篇文章把整个esp32移植过程写完,但是写得太长了,看着也累。还是分开几篇吧,这里先写到这,怎么使用静态库,下一篇再写。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值