完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本文将在前面mini2440建立的domoticz、mosquitto为服务器的基础上,以Android做远程客户端来实现对STM32芯片的开发板的LED进行灯控制,当然,这是一个基本功能的实现,如果长期使用的话,还需要做很多其他的工作(例如断网重连,重连多少次重启系统等等,还要有个可以在SD卡上读入的硬件配置信息等等)。
首先展示一下开发板这边情况,硬件方面是在2011年买的“金牛开发板”,主控芯片是STM32F107VC,PHY芯片是DP83848,烧固件的工具是随开发板带来的Jlink,从JTAG口烧录进去。 软件方面,使用RTThread-2.1.0作为操作系统,该系统自带移植的嵌入式TCP/IP协议栈LwIP。 本文中使用的LwIP协议栈版本是1.4.1,是rtthread默认bsp中默认的版本。 bsp工程文件位置:rt-threadbspstm32f107project.uvproj bsp已经实现了PHY芯片DP83848的驱动,所以就省了很多事。 使用的集成开发环境是:MDK 4.11 版本 本人在工程中是用了对c99的支持(主要是为了调试)。 本来看介绍,还以为RTThread-2.1.0已经移植好了MQTT客户端程序,但实际上,只是把代码放过来,还没有做什么移植。 所以,要实现本文的目标,就需要对MQTT客户端做个移植。 mqtt的客户端程序在rtthread软件包的位置是: rt-threadcomponentsexternalpaho-mqtt 不知道这个是什么版本的,总之,本人是用在mini2440上已经验证过的版本,就是官方在GitHub上的最新版本,封包解包的那部分用MQTTPacket,可以不用改动,直接就用。 MQTTClient-C这个模块部分,用自己的实现。 放到rt-threadcomponentsexternalpaho-mqttMQTTClient-Csamplesdomoticz目录下。 主要实现有三个部分: 1、对socket的读写的基本操作简单封装。相关内容放到MQTTRTThread.h和MQTTRTThread.c中。 2、对MQTT连接和消息的解析详细过程。相关内容放到MQTTClient.h和MQTTClient.c中。 3、对整个过程的控制,使用rtthread的一个线程实现。相关内容放到DomoticzThread.h和DomoticzThread.c中。 源码放在后面附上。 接下来要说的内容就是把曾在mini2440上用过的domoticz消息解析框架移植过来。 果然keil的arm编译器跟GCC是不同的,要做一些改动。改好的源码在后面附上。 这一部分放在rt-threadbspstm32f107applications目录下。 在STM32开发板上,也控制了两个LED作为例程。 效果跟mini2440上的是一样的,以后有时间再上图吧。 后面有时间把整个工程打包上传上来。 以下是上述介绍的源码: dprintf.h #ifndef __DPRINTF_H__ #define __DPRINTF_H__ #ifdef __cplusplus extern “C”{ #endif #ifdef __DEBUG #include 《stdarg.h》 #include 《string.h》 //just get file name without the path static const char *getCurrentFileName(const char * strFileName) { const char *p = strrchr(strFileName,‘\’); return p==NULL?strFileName:++p; } #define dprintf(fmt,。..) rt_kprintf(“%s,line:%d,”fmt,getCurrentFileName(__FILE__),__LINE__,##__VA_ARGS__) #else #define dprintf(fmt,。..) #endif #ifdef __cplusplus } #endif #endif 一、MQTTClient-C部分: 1、MQTTRTThread.h #include 《rtthread.h》 //---------------------------------------------------------- typedef struct Timer { rt_tick_t end_tick; } Timer; void TimerInit(Timer*); char TimerIsExpired(Timer*); void TimerCountdownMS(Timer*, unsigned int); void TimerCountdown(Timer*, unsigned int); int TimerLeftMS(Timer*); void DeleteTimer(Timer*); //------------------------------------------------------- typedef struct Network { int my_socket; int (*mqttread) (struct Network*, unsigned char*, int, int); int (*mqttwrite) (struct Network*, unsigned char*, int, int); } Network; void NetworkInit(Network*); int NetworkConnect(Network*, char*, int); void NetworkDisconnect(Network*); MQTTRTThread.c #include “MQTTRTThread.h” #include 《lwip/netdb.h》 #include 《lwip/sockets.h》 #include 《stdio.h》 //#define __DEBUG #include “dprintf.h” void TimerInit(Timer* timer) { timer-》end_tick = 0; } char TimerIsExpired(Timer* timer) { return timer-》end_tick 《= rt_tick_get(); } void TimerCountdownMS(Timer* timer, unsigned int timeout) { timer-》end_tick = rt_tick_get() + timeout*RT_TICK_PER_SECOND/1000; } void TimerCountdown(Timer* timer, unsigned int timeout) { timer-》end_tick = rt_tick_get() + timeout*RT_TICK_PER_SECOND; } int TimerLeftMS(Timer* timer) { return timer-》end_tick - rt_tick_get() ; } int RTThreadLwIP_read(Network* n, unsigned char* buffer, int len, int timeout_ms) { int bytes = 0; struct timeval interval ; interval.tv_sec = timeout_ms / 1000; interval.tv_usec = (timeout_ms % 1000) * 1000; if (interval.tv_sec 《 0 || (interval.tv_sec == 0 && interval.tv_usec 《= 0)) { interval.tv_sec = 0; interval.tv_usec = 100; } lwip_setsockopt(n-》my_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval, sizeof(struct timeval)); while (bytes 《 len) { int rc = recv(n-》my_socket, &buffer[bytes], (size_t)(len - bytes), MSG_DONTWAIT); if (rc == -1) {//dprintf(“errno=%dn”,errno); //if (errno != ENOTCONN && errno != ECONNRESET) if (errno != ETIMEDOUT && errno != ECONNRESET) { bytes = -1; } break; } else if (rc == 0) { bytes = 0; break; } else bytes += rc; } return bytes; } int RTThreadLwIP_write(Network* n, unsigned char* buffer, int len, int timeout_ms) { int rc; struct timeval tv; tv.tv_sec = timeout_ms / 1000; tv.tv_usec = (timeout_ms % 1000) * 1000; if (tv.tv_sec 《 0 || (tv.tv_sec == 0 && tv.tv_usec 《= 0)) { tv.tv_sec = 0; tv.tv_usec = 100; } lwip_setsockopt(n-》my_socket, SOL_SOCKET, SO_SNDTIMEO, (void *)&tv,sizeof(struct timeval)); rc = lwip_write(n-》my_socket, buffer, len); return rc; } void NetworkInit(Network* n) { n-》my_socket = 0; n-》mqttread = RTThreadLwIP_read; n-》mqttwrite = RTThreadLwIP_write; } int NetworkConnect(Network* n, char* addr, int port) { struct hostent *host; struct in_addr ip_addr; struct sockaddr_in sockaddr; int rc = -1; // 第一步 DNS地址解析 rt_kprintf(“calling gethostbyname with: %srn”, addr); host = gethostbyname(addr); ip_addr.s_addr = *(unsigned long *) host-》h_addr_list[0]; rt_kprintf(“MQTTThread IP Address:%srn” , inet_ntoa(ip_addr)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); sockaddr.sin_addr = ip_addr; rt_memset(&(sockaddr.sin_zero), 0, sizeof(sockaddr.sin_zero)); // 第二步 创建套接字 n-》my_socket = socket(AF_INET, SOCK_STREAM, 0); if (n-》my_socket != -1) { rt_kprintf(“n-》my_socket: %drn”, n-》my_socket); rc = lwip_connect(n-》my_socket, (struct sockaddr*)&sockaddr, sizeof(struct sockaddr)); if (rc == -1) { rt_kprintf(“Connect fail!n”); lwip_close(n-》my_socket); //rt_free(recv_data); } else { rt_kprintf(“Connect success!n”); } } return rc; } void NetworkDisconnect(Network* n) { lwip_close(n-》my_socket); } 2、MQTTClient.h /******************************************************************************* * 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: * Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation * Ian Craggs - documentation and platform specific header * Ian Craggs - add setMessageHandler function *******************************************************************************/ #if !defined(MQTT_CLIENT_H) #define MQTT_CLIENT_H #if defined(__cplusplus) 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 #include “MQTTPacket.h” #include “MQTTRTThread.h” #include “stdio.h” #if defined(MQTTCLIENT_PLATFORM_HEADER) /* The following sequence of macros converts the MQTTCLIENT_PLATFORM_HEADER value * into a string constant suitable for use with include. */ #define xstr(s) str(s) #define str(s) #s #include xstr(MQTTCLIENT_PLATFORM_HEADER) #endif #define MAX_PACKET_ID 65535 /* according to the MQTT specification - do not change! */ #if !defined(MAX_MESSAGE_HANDLERS) #define MAX_MESSAGE_HANDLERS 5 /* redefinable - how many subscriptions do you want? */ #endif enum QoS { QOS0, QOS1, QOS2, SUBFAIL=0x80 }; /* all failure return codes must be negative */ enum returnCode { BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 }; /* The Platform specific header must define the Network and Timer structures and functions * which operate on them. * typedef struct Network { int (*mqttread)(Network*, unsigned char* read_buffer, int, int); int (*mqttwrite)(Network*, unsigned char* send_buffer, int, int); } Network;*/ /* The Timer structure must be defined in the platform specific header, * and have the following functions to operate on it. */ extern void TimerInit(Timer*); extern char TimerIsExpired(Timer*); extern void TimerCountdownMS(Timer*, unsigned int); extern void TimerCountdown(Timer*, unsigned int); extern int TimerLeftMS(Timer*); typedef struct MQTTMessage { enum QoS qos; unsigned char retained; unsigned char dup; unsigned short id; void *payload; size_t payloadlen; } MQTTMessage; typedef struct MessageData { MQTTMessage* message; MQTTString* topicName; } MessageData; typedef struct MQTTConnackData { unsigned char rc; unsigned char sessionPresent; } MQTTConnackData; typedef struct MQTTSubackData { enum QoS grantedQoS; } MQTTSubackData; typedef void (*messageHandler)(MessageData*); typedef struct MQTTClient { unsigned int next_packetid, command_timeout_ms; size_t buf_size, readbuf_size; unsigned char *buf, *readbuf; unsigned int keepAliveInterval; char ping_outstanding; int ping_timeout_times; int isconnected; int cleansession; struct MessageHandlers { const char* topicFilter; void (*fp) (MessageData*); } messageHandlers[MAX_MESSAGE_HANDLERS]; /* Message handlers are indexed by subscription topic */ void (*defaultMessageHandler) (MessageData*); Network* ipstack; Timer last_sent, last_received; #if defined(MQTT_TASK) Mutex mutex; Thread thread; #endif } MQTTClient; #define DefaultClient {0, 0, 0, 0, NULL, NULL, 0, 0, 0} /** * Create an MQTT client object * @param client * @param network * @param command_timeout_ms * @param */ DLLExport void MQTTClientInit(MQTTClient* client, Network* network, unsigned int command_timeout_ms, unsigned char* sendbuf, size_t sendbuf_size, unsigned char* readbuf, size_t readbuf_size); /** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack * The nework object must be connected to the network endpoint before calling this * @param options - connect options * @return success code */ DLLExport int MQTTConnectWithResults(MQTTClient* client, MQTTPacket_connectData* options, MQTTConnackData* data); /** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack * The nework object must be connected to the network endpoint before calling this * @param options - connect options * @return success code */ DLLExport int MQTTConnect(MQTTClient* client, MQTTPacket_connectData* options); /** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs * @param client - the client object to use * @param topic - the topic to publish to * @param message - the message to send * @return success code */ DLLExport int MQTTPublish(MQTTClient* client, const char*, MQTTMessage*); /** MQTT SetMessageHandler - set or remove a per topic message handler * @param client - the client object to use * @param topicFilter - the topic filter set the message handler for * @param messageHandler - pointer to the message handler function or NULL to remove * @return success code */ DLLExport int MQTTSetMessageHandler(MQTTClient* c, const char* topicFilter, messageHandler messageHandler); /** MQTT Subscribe - send an MQTT subscribe packet and wait for suback before returning. * @param client - the client object to use * @param topicFilter - the topic filter to subscribe to * @param message - the message to send * @return success code */ DLLExport int MQTTSubscribe(MQTTClient* client, const char* topicFilter, enum QoS, messageHandler); /** MQTT Subscribe - send an MQTT subscribe packet and wait for suback before returning. * @param client - the client object to use * @param topicFilter - the topic filter to subscribe to * @param message - the message to send * @param data - suback granted QoS returned * @return success code */ DLLExport int MQTTSubscribeWithResults(MQTTClient* client, const char* topicFilter, enum QoS, messageHandler, MQTTSubackData* data); /** MQTT Subscribe - send an MQTT unsubscribe packet and wait for unsuback before returning. * @param client - the client object to use * @param topicFilter - the topic filter to unsubscribe from * @return success code */ DLLExport int MQTTUnsubscribe(MQTTClient* client, const char* topicFilter); /** MQTT Disconnect - send an MQTT disconnect packet and close the connection * @param client - the client object to use * @return success code */ DLLExport int MQTTDisconnect(MQTTClient* client); /** MQTT Yield - MQTT background * @param client - the client object to use * @param time - the time, in milliseconds, to yield for * @return success code */ DLLExport int MQTTYield(MQTTClient* client, int time); /** MQTT isConnected * @param client - the client object to use * @return truth value indicating whether the client is connected to the server */ DLLExport int MQTTIsConnected(MQTTClient* client); DLLExport int keepalive(MQTTClient* client); void MQTTCleanSession(MQTTClient* c); #if defined(MQTT_TASK) /** MQTT start background thread for a client. After this, MQTTYield should not be called. * @param client - the client object to use * @return success code */ DLLExport int MQTTStartTask(MQTTClient* client); #endif #if defined(__cplusplus) } #endif #endif |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1780 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1081 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1679 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
596浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
556浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 18:03 , Processed in 0.980529 second(s), Total 75, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号