基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(十)使用domoticz+mosquitto+Android客户端实现控制STM32板上的LED(一)

本文主要是介绍基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(十)使用domoticz+mosquitto+Android客户端实现控制STM32板上的LED(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文将在前面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-thread\bsp\stm32f107\project.uvproj
bsp已经实现了PHY芯片DP83848的驱动,所以就省了很多事。

使用的集成开发环境是:MDK 4.11 版本

本人在工程中是用了对c99的支持(主要是为了调试)。

本来看介绍,还以为RTThread-2.1.0已经移植好了MQTT客户端程序,但实际上,只是把代码放过来,还没有做什么移植。

所以,要实现本文的目标,就需要对MQTT客户端做个移植。

mqtt的客户端程序在rtthread软件包的位置是:
rt-thread\components\external\paho-mqtt

不知道这个是什么版本的,总之,本人是用在mini2440上已经验证过的版本,就是官方在GitHub上的最新版本,封包解包的那部分用MQTTPacket,可以不用改动,直接就用。

MQTTClient-C这个模块部分,用自己的实现。
放到rt-thread\components\external\paho-mqtt\MQTTClient-C\samples\domoticz目录下。

主要实现有三个部分:

1、对socket的读写的基本操作简单封装。相关内容放到MQTTRTThread.h和MQTTRTThread.c中。

2、对MQTT连接和消息的解析详细过程。相关内容放到MQTTClient.h和MQTTClient.c中。

3、对整个过程的控制,使用rtthread的一个线程实现。相关内容放到DomoticzThread.h和DomoticzThread.c中。

源码放在后面附上。

接下来要说的内容就是把曾在mini2440上用过的domoticz消息解析框架移植过来。
果然keil的arm编译器跟GCC是不同的,要做一些改动。改好的源码在后面附上。
这一部分放在rt-thread\bsp\stm32f107\applications目录下。

在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=%d\n",errno);//if (errno != ENOTCONN && errno != ECONNRESET)if (errno != ETIMEDOUT && errno != ECONNRESET){bytes = -1;				}break;}else if (rc == 0){bytes = 0;break;}elsebytes += 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: %s\r\n", addr);  host = gethostbyname(addr);  ip_addr.s_addr = *(unsigned long *) host->h_addr_list[0];  rt_kprintf("MQTTThread IP Address:%s\r\n" , 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: %d\r\n", 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? */
#endifenum 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

MQTTClient.c

/******************************************************************************** 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 - fix for #96 - check rem_len in readPacket*   Ian Craggs - add ability to set message handler separately #6*******************************************************************************/
#include "MQTTClient.h"
#include <rtthread.h> 
#include <lwip/sockets.h>  //#define __DEBUG
#include "dprintf.h"static void NewMessageData(MessageData* md, MQTTString* aTopicName, MQTTMessage* aMessage) {md->topicName = aTopicName;md->message = aMessage;
}static int getNextPacketId(MQTTClient *c) {return c->next_packetid = (c->next_packetid == MAX_PACKET_ID) ? 1 : c->next_packetid + 1;
}static int sendPacket(MQTTClient* c, int length, Timer* timer)
{int rc = FAILURE, sent = 0;while (sent < length && !TimerIsExpired(timer)){rc = c->ipstack->mqttwrite(c->ipstack, &c->buf[sent], length, TimerLeftMS(timer));if (rc < 0)  // there was an error writing the data{dprintf("error!!!!\n");break;}sent += rc;}if (sent == length){TimerCountdown(&c->last_sent, c->keepAliveInterval); // record the fact that we have successfully sent the packetrc = SUCCESS;}elserc = FAILURE;return rc;
}void MQTTClientInit(MQTTClient* c, Network* network, unsigned int command_timeout_ms,unsigned char* sendbuf, size_t sendbuf_size, unsigned char* readbuf, size_t readbuf_size)
{int i;c->ipstack = network;for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)c->messageHandlers[i].topicFilter = 0;c->command_timeout_ms = command_timeout_ms;c->buf = sendbuf;c->buf_size = sendbuf_size;c->readbuf = readbuf;c->readbuf_size = readbuf_size;c->isconnected = 0;c->cleansession = 0;c->ping_outstanding = 0;c->ping_timeout_times = 0;	c->defaultMessageHandler = NULL;c->next_packetid = 1;TimerInit(&c->last_sent);TimerInit(&c->last_received);
#if defined(MQTT_TASK)MutexInit(&c->mutex);
#endif
}static int decodePacket(MQTTClient* c, int* value, int timeout)
{unsigned char i;int multiplier = 1;int len = 0;const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4;*value = 0;do{int rc = MQTTPACKET_READ_ERROR;if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES){rc = MQTTPACKET_READ_ERROR; /* bad data */goto exit;}rc = c->ipstack->mqttread(c->ipstack, &i, 1, timeout);if (rc != 1)goto exit;*value += (i & 127) * multiplier;multiplier *= 128;} while ((i & 128) != 0);
exit:return len;
}static int readPacket(MQTTClient* c, Timer* timer)
{MQTTHeader header = {0};int len = 0;int rem_len = 0;/* 1. read the header byte.  This has the packet type in it */int rc = c->ipstack->mqttread(c->ipstack, c->readbuf, 1, TimerLeftMS(timer));if (rc != 1)goto exit;len = 1;/* 2. read the remaining length.  This is variable in itself */decodePacket(c, &rem_len, TimerLeftMS(timer));len += MQTTPacket_encode(c->readbuf + 1, rem_len); /* put the original remaining length back into the buffer */if (rem_len > (c->readbuf_size - len)){	rc = BUFFER_OVERFLOW;goto exit;}/* 3. read the rest of the buffer using a callback to supply the rest of the data */if (rem_len > 0 && (rc = c->ipstack->mqttread(c->ipstack, c->readbuf + len, rem_len, TimerLeftMS(timer)) != rem_len)) {rc = 0;goto exit;}header.byte = c->readbuf[0];rc = header.bits.type;if (c->keepAliveInterval > 0)TimerCountdown(&c->last_received, c->keepAliveInterval); // record the fact that we have successfully received a packet
exit:return rc;
}// assume topic filter and name is in correct format
// # can only be at end
// + and # can only be next to separator
static char isTopicMatched(char* topicFilter, MQTTString* topicName)
{char* curf = topicFilter;char* curn = topicName->lenstring.data;char* curn_end = curn + topicName->lenstring.len;while (*curf && curn < curn_end){if (*curn == '/' && *curf != '/')break;if (*curf != '+' && *curf != '#' && *curf != *curn)break;if (*curf == '+'){   // skip until we meet the next separator, or end of stringchar* nextpos = curn + 1;while (nextpos < curn_end && *nextpos != '/')nextpos = ++curn + 1;}else if (*curf == '#')curn = curn_end - 1;    // skip until end of stringcurf++;curn++;};return (curn == curn_end) && (*curf == '\0');
}int deliverMessage(MQTTClient* c, MQTTString* topicName, MQTTMessage* message)
{int i;int rc = FAILURE;// we have to find the right message handler - indexed by topicfor (i = 0; i < MAX_MESSAGE_HANDLERS; ++i){if (c->messageHandlers[i].topicFilter != 0 && (MQTTPacket_equals(topicName, (char*)c->messageHandlers[i].topicFilter) ||isTopicMatched((char*)c->messageHandlers[i].topicFilter, topicName))){if (c->messageHandlers[i].fp != NULL){MessageData md;NewMessageData(&md, topicName, message);c->messageHandlers[i].fp(&md);rc = SUCCESS;}}}if (rc == FAILURE && c->defaultMessageHandler != NULL) {MessageData md;NewMessageData(&md, topicName, message);c->defaultMessageHandler(&md);rc = SUCCESS;}   return rc;
}int keepalive(MQTTClient* c)
{ int rc = SUCCESS;if (c->keepAliveInterval == 0)goto exit;//dprintf("TimerLeftMS(&c->last_sent)=%d,TimerLeftMS(&c->last_received)=%d\n",TimerLeftMS(&c->last_sent),TimerLeftMS(&c->last_received));if (TimerIsExpired(&c->last_sent) || TimerIsExpired(&c->last_received)){TimerCountdown(&c->last_sent, c->keepAliveInterval);TimerCountdown(&c->last_received, c->keepAliveInterval);//if (c->ping_outstanding)//    rc = FAILURE; /* PINGRESP not received in keepalive interval *///else{dprintf("sent ping!!!!\n");Timer timer;TimerInit(&timer);TimerCountdownMS(&timer, 1000);int len = MQTTSerialize_pingreq(c->buf, c->buf_size);if (len > 0 && (rc = sendPacket(c, len, &timer)) == SUCCESS) // send the ping packet{  dprintf("sent ping OK!!\n");  c->ping_outstanding = 1;							}c->ping_timeout_times++;}}exit:return rc;
}void MQTTCleanSession(MQTTClient* c)
{int i = 0;for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)c->messageHandlers[i].topicFilter = NULL;}void MQTTCloseSession(MQTTClient* c)
{c->ping_outstanding = 0;c->isconnected = 0;if (c->cleansession)MQTTCleanSession(c);
}int cycle(MQTTClient* c, Timer* timer)
{int len = 0,rc = SUCCESS;int packet_type = readPacket(c, timer);     /* read the socket, see what work is due */switch (packet_type){default:/* no more data to read, unrecoverable. Or read packet fails due to unexpected network error */if(errno != 0 && errno!=EAGAIN){  rc = packet_type;dprintf("errno=%d\n",errno);					}goto exit;case 0: /* timed out reading packet */break;case CONNACK:case PUBACK:case SUBACK:case UNSUBACK:break;case PUBLISH:{MQTTString topicName;MQTTMessage msg;int intQoS;msg.payloadlen = 0; /* this is a size_t, but deserialize publish sets this as int */if (MQTTDeserialize_publish(&msg.dup, &intQoS, &msg.retained, &msg.id, &topicName,(unsigned char**)&msg.payload, (int*)&msg.payloadlen, c->readbuf, c->readbuf_size) != 1)goto exit;msg.qos = (enum QoS)intQoS;deliverMessage(c, &topicName, &msg);if (msg.qos != QOS0){  if (msg.qos == QOS1)len = MQTTSerialize_ack(c->buf, c->buf_size, PUBACK, 0, msg.id);else if (msg.qos == QOS2)len = MQTTSerialize_ack(c->buf, c->buf_size, PUBREC, 0, msg.id);if (len <= 0)rc = FAILURE;elserc = sendPacket(c, len, timer);if (rc == FAILURE){dprintf("\n");goto exit;} // there was a problem}break;}case PUBREC:case PUBREL:{unsigned short mypacketid;unsigned char dup, type;if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)rc = FAILURE;else if ((len = MQTTSerialize_ack(c->buf, c->buf_size,(packet_type == PUBREC) ? PUBREL : PUBCOMP, 0, mypacketid)) <= 0)rc = FAILURE;else if ((rc = sendPacket(c, len, timer)) != SUCCESS) // send the PUBREL packetrc = FAILURE; // there was a problemif (rc == FAILURE)goto exit; // there was a problembreak;}case PUBCOMP:break;case PINGRESP:c->ping_outstanding = 0;c->ping_timeout_times = 0;//接收到应答包清空计数器break;case BUFFER_OVERFLOW:rt_kprintf("readPacket() err: BUFFER_OVERFLOW!\n");break;}exit:if (keepalive(c) != SUCCESS) {dprintf("\n");//check only keepalive FAILURE status so that previous FAILURE status can be considered as FAULTrc = FAILURE;}if (rc == SUCCESS)rc = packet_type;else if (c->isconnected){dprintf("\n");MQTTCloseSession(c);}return rc;
}int MQTTYield(MQTTClient* c, int timeout_ms)
{  int rc = SUCCESS; 	Timer timer;TimerInit(&timer);TimerCountdownMS(&timer, timeout_ms);do{ //dprintf("TimerLeftMS(timer)=%d\n",TimerLeftMS(&timer));if (cycle(c, &timer) < 0){rc = FAILURE;break;}} while (!TimerIsExpired(&timer));return rc;
}int MQTTIsConnected(MQTTClient* client)
{return client->isconnected;
}void MQTTRun(void* parm)
{Timer timer;MQTTClient* c = (MQTTClient*)parm;TimerInit(&timer);while (1){
#if defined(MQTT_TASK)MutexLock(&c->mutex);
#endifTimerCountdownMS(&timer, 500); /* Don't wait too long if no traffic is incoming */cycle(c, &timer);
#if defined(MQTT_TASK)MutexUnlock(&c->mutex);
#endif} 
}#if defined(MQTT_TASK)
int MQTTStartTask(MQTTClient* client)
{return ThreadStart(&client->thread, &MQTTRun, client);
}
#endifint waitfor(MQTTClient* c, int packet_type, Timer* timer)
{int rc = FAILURE;do{rt_thread_delay(10);//不延时或延时太短会出错if (TimerIsExpired(timer))break; // we timed outrc = cycle(c, timer);}while (rc != packet_type && rc >= 0);return rc;
}int MQTTConnectWithResults(MQTTClient* c, MQTTPacket_connectData* options, MQTTConnackData* data)
{Timer connect_timer;int rc = FAILURE;MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer;int len = 0;#if defined(MQTT_TASK)MutexLock(&c->mutex);
#endifif (c->isconnected) /* don't send connect packet again if we are already connected */goto exit;TimerInit(&connect_timer);TimerCountdownMS(&connect_timer, c->command_timeout_ms);if (options == 0)options = &default_options; /* set default options if none were supplied */c->keepAliveInterval = options->keepAliveInterval;c->cleansession = options->cleansession;TimerCountdown(&c->last_received, c->keepAliveInterval);if ((len = MQTTSerialize_connect(c->buf, c->buf_size, options)) <= 0)goto exit;if ((rc = sendPacket(c, len, &connect_timer)) != SUCCESS)  // send the connect packetgoto exit; // there was a problem// this will be a blocking call, wait for the connackif (waitfor(c, CONNACK, &connect_timer) == CONNACK){data->rc = 0;data->sessionPresent = 0;if (MQTTDeserialize_connack(&data->sessionPresent, &data->rc, c->readbuf, c->readbuf_size) == 1)rc = data->rc;elserc = FAILURE;}elserc = FAILURE;exit:if (rc == SUCCESS){dprintf("rc == SUCCESS,c->isconnected=1\n");c->isconnected = 1;c->ping_outstanding = 0;}#if defined(MQTT_TASK)MutexUnlock(&c->mutex);
#endifreturn rc;
}int MQTTConnect(MQTTClient* c, MQTTPacket_connectData* options)
{MQTTConnackData data;return MQTTConnectWithResults(c, options, &data);
}int MQTTSetMessageHandler(MQTTClient* c, const char* topicFilter, messageHandler messageHandler)
{int rc = FAILURE;int i = -1;/* first check for an existing matching slot */for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i){if (c->messageHandlers[i].topicFilter != NULL && strcmp(c->messageHandlers[i].topicFilter, topicFilter) == 0){if (messageHandler == NULL) /* remove existing */{c->messageHandlers[i].topicFilter = NULL;c->messageHandlers[i].fp = NULL;}rc = SUCCESS; /* return i when adding new subscription */break;}}/* if no existing, look for empty slot (unless we are removing) */if (messageHandler != NULL) {if (rc == FAILURE){for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i){if (c->messageHandlers[i].topicFilter == NULL){rc = SUCCESS;break;}}}if (i < MAX_MESSAGE_HANDLERS){c->messageHandlers[i].topicFilter = topicFilter;c->messageHandlers[i].fp = messageHandler;}}return rc;
}int MQTTSubscribeWithResults(MQTTClient* c, const char* topicFilter, enum QoS qos,messageHandler messageHandler, MQTTSubackData* data)
{ int rc = FAILURE;  Timer timer;int len = 0;MQTTString topic = MQTTString_initializer;topic.cstring = (char *)topicFilter;#if defined(MQTT_TASK)MutexLock(&c->mutex);
#endifif (!c->isconnected){dprintf("\n");goto exit;}TimerInit(&timer);TimerCountdownMS(&timer, c->command_timeout_ms);dprintf("topic.cstring=%s\n",topic.cstring);len = MQTTSerialize_subscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic, (int*)&qos);if (len <= 0){dprintf("len=%d\n",len);goto exit;}if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet{dprintf("\n");;goto exit;}             // there was a problemif (waitfor(c, SUBACK, &timer) == SUBACK)      // wait for suback {int count = 0;unsigned short mypacketid;data->grantedQoS = QOS0;if (MQTTDeserialize_suback(&mypacketid, 1, &count, (int*)&data->grantedQoS, c->readbuf, c->readbuf_size) == 1){if (data->grantedQoS != 0x80)rc = MQTTSetMessageHandler(c, topicFilter, messageHandler);dprintf("rc=%d\n",rc);}}else{dprintf("\n");rc = FAILURE;}exit:if (rc == FAILURE){dprintf("\n");MQTTCloseSession(c);}
#if defined(MQTT_TASK)MutexUnlock(&c->mutex);
#endifreturn rc;
}int MQTTSubscribe(MQTTClient* c, const char* topicFilter, enum QoS qos,messageHandler messageHandler)
{MQTTSubackData data;return MQTTSubscribeWithResults(c, topicFilter, qos, messageHandler, &data);
}int MQTTUnsubscribe(MQTTClient* c, const char* topicFilter)
{   int rc = FAILURE;Timer timer; MQTTString topic = MQTTString_initializer;topic.cstring = (char *)topicFilter;int len = 0;#if defined(MQTT_TASK)MutexLock(&c->mutex);
#endifif (!c->isconnected)goto exit;TimerInit(&timer);TimerCountdownMS(&timer, c->command_timeout_ms);if ((len = MQTTSerialize_unsubscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic)) <= 0)goto exit;if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packetgoto exit; // there was a problemif (waitfor(c, UNSUBACK, &timer) == UNSUBACK){unsigned short mypacketid;  // should be the same as the packetid aboveif (MQTTDeserialize_unsuback(&mypacketid, c->readbuf, c->readbuf_size) == 1){/* remove the subscription message handler associated with this topic, if there is one */MQTTSetMessageHandler(c, topicFilter, NULL);}}elserc = FAILURE;exit:if (rc == FAILURE)MQTTCloseSession(c);
#if defined(MQTT_TASK)MutexUnlock(&c->mutex);
#endifreturn rc;
}int MQTTPublish(MQTTClient* c, const char* topicName, MQTTMessage* message)
{int rc = FAILURE;Timer timer;MQTTString topic = MQTTString_initializer;topic.cstring = (char *)topicName;int len = 0;#if defined(MQTT_TASK)MutexLock(&c->mutex);
#endifif (!c->isconnected)goto exit;TimerInit(&timer);TimerCountdownMS(&timer, c->command_timeout_ms);if (message->qos == QOS1 || message->qos == QOS2)message->id = getNextPacketId(c);len = MQTTSerialize_publish(c->buf, c->buf_size, 0, message->qos, message->retained, message->id, topic, (unsigned char*)message->payload, message->payloadlen);if (len <= 0)goto exit;if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packetgoto exit; // there was a problemif (message->qos == QOS1){if (waitfor(c, PUBACK, &timer) == PUBACK){unsigned short mypacketid;unsigned char dup, type;if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)rc = FAILURE;}elserc = FAILURE;}else if (message->qos == QOS2){if (waitfor(c, PUBCOMP, &timer) == PUBCOMP){unsigned short mypacketid;unsigned char dup, type;if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)rc = FAILURE;}elserc = FAILURE;}exit:if (rc == FAILURE){dprintf("\n");MQTTCloseSession(c);}
#if defined(MQTT_TASK)MutexUnlock(&c->mutex);
#endifreturn rc;
}int MQTTDisconnect(MQTTClient* c)
{  int rc = FAILURE;Timer timer;     // we might wait for incomplete incoming publishes to completeint len = 0;#if defined(MQTT_TASK)MutexLock(&c->mutex);
#endifTimerInit(&timer);TimerCountdownMS(&timer, c->command_timeout_ms);len = MQTTSerialize_disconnect(c->buf, c->buf_size);if (len > 0)rc = sendPacket(c, len, &timer);            // send the disconnect packetMQTTCloseSession(c);#if defined(MQTT_TASK)MutexUnlock(&c->mutex);
#endifreturn rc;
}

3、DomoticzThread.h:

#ifndef __DOMOTICZ_THREAD_H__
#define  __DOMOTICZ_THREAD_H__extern void domoticz_thread_init(void);#endif

DomoticzThread.c:

#include <rtthread.h>
#include "MQTTClient.h"
//#include "led.h"
#include "DomoticzMessageParser.h"
#include "LED0.h"
#include "LED1.h"
#include "HardwareControl.h"//#define __DEBUG
#include "dprintf.h"struct opts_struct
{char* clientid;int nodelimiter;char* delimiter;enum QoS qos;char* username;char* password;char* host;int port;int showtopics;
} opts =
{(char*)"subscriber on STM32", 0, (char*)"\n", QOS2, NULL, NULL, (char*)"192.168.1.230", 1883, 0
};int is_over;void quit_domoticz_thread(void)
{is_over = 1;
}//================== Added 2017-Apr-27 8:06:53 start ==================
//处理连接的状态机结构
typedef struct 
{enum{UNCONNECTED = 0,NETWORK_CONNECTED=1,MQTT_CONNECTED=2,SUBSCRIBING_SUCCESS=3,WAIT_TIME_OUT=4,//SUBSCRIBING_FAILURE = 4}state;int timeout_s;//超时时间,单位为秒int times_count;//累计连续尝试连接次数,在连接成功后清零
}Connection_t;void connect_time_out(void * data)
{Connection_t* con =(Connection_t*)data;if(con && con->timeout_s>0){con->timeout_s --;}
}#define NETWORK_CONNECT_TIMEOUT 5 //5s
#define MAX_NETWORK_CONNECT_TIMES 5
#define MQTT_CONNECT_TIMEOUT 1 //1s
#define MAX_MQTT_CONNECT_TIMES 5
#define SUBSCRIB_TIMEOUT 1 //1s
#define MAX_SUBSCRIB_TIMES 5
#define MAX_NO_PING_RESPONS_TIMES 10Connection_t connection={UNCONNECTED,NETWORK_CONNECT_TIMEOUT,0};//================== Added 2017-Apr-27 8:06:53  end ===================void messageArrived(MessageData* md)
{MQTTMessage* message = md->message;#if 0 /* Commented @ 2017-Apr-23 1:18:29 */if (opts.showtopics)rt_kprintf("%.*s\t", md->topicName->lenstring.len, md->topicName->lenstring.data);if (opts.nodelimiter)rt_kprintf("%.*s", (int)message->payloadlen, (char*)message->payload);elsert_kprintf("%.*s%s", (int)message->payloadlen, (char*)message->payload, opts.delimiter);
#endif /* Commented */dprintf("payloadlen=%d,%s\n",(int)message->payloadlen,(char*)message->payload);dprintf("strlen(payload)=%d\n",strlen((char*)message->payload));	//fflush(stdout);((char*)message->payload)[(int)message->payloadlen]=0;ParseDomoticzMessage((char*)message->payload);//dprintf("MSG: qos %d, retained %d, dup %d, packetid %d\n", message->qos, message->retained, message->dup, message->id);
}void set_host(char *host)
{opts.host = host;
}#define MAX_BUF_SIZE  512void domoticz_thread_entry(void* parameter)
{int rc = 0;unsigned char buf[MAX_BUF_SIZE]={0};//buf[100];unsigned char readbuf[MAX_BUF_SIZE]={0};//readbuf[100];char* topic = "domoticz/out";Network n;MQTTClient c;MQTTPacket_connectData data = MQTTPacket_connectData_initializer;  rt_timer_t timer = rt_timer_create("connect_timer", connect_time_out, &connection, RT_TICK_PER_SECOND, RT_TIMER_FLAG_PERIODIC);is_over = 0;rt_kprintf("domoticz_thread_entry\n");//================== Added 2017-Apr-26 2:36:53 start ==================RegisterHardware(Create_LED0(),1);RegisterHardware(Create_LED1(),6);OpenHardwares();SetupDomoitczMessageParser();	SetEnableParseItem(KEY_IDX);SetEnableParseItem(KEY_NVALUE);SetEnableParseItem(KEY_SWITCH_TYPE);initHardwareSettings();
//================== Added 2017-Apr-26 2:36:53  end ===================data.willFlag = 0;data.MQTTVersion = 3;data.clientID.cstring = opts.clientid;data.username.cstring = opts.username;data.password.cstring = opts.password;data.keepAliveInterval = 10;data.cleansession = 0;rt_timer_start(timer);while(!is_over){   switch(connection.state){case UNCONNECTED://dprintf("\n");if(connection.timeout_s>0)continue;dprintf("state = UNCONNECTED\n");rt_kprintf("Connecting to %s:%d\n", opts.host, opts.port);NetworkInit(&n);rc = NetworkConnect(&n, opts.host, opts.port);dprintf("rc=%d\n",rc);if(rc==SUCCESS){//socket ????connection.state = NETWORK_CONNECTED;connection.times_count = 0;rt_kprintf("NetworkConnect ok!\n");//MQTTClientInit(&c, &n, 1000, buf, sizeof(buf), readbuf, sizeof(readbuf));MQTTClientInit(&c, &n, 1000, buf,MAX_BUF_SIZE, readbuf, MAX_BUF_SIZE);}else if(connection.times_count <MAX_NETWORK_CONNECT_TIMES){dprintf("\n");connection.times_count++;connection.timeout_s = NETWORK_CONNECT_TIMEOUT;}else{//reboot system,restartdprintf("\n");connection.times_count=0;connection.timeout_s = NETWORK_CONNECT_TIMEOUT*6;rt_kprintf("we will reconnect after %d senconds\n",connection.timeout_s);//usleep(30*1000000);//30????//goto exit;}break;case NETWORK_CONNECTED: if(connection.timeout_s>0)continue;dprintf("\n");rt_kprintf("state = NETWORK_CONNECTED\n");rc = MQTTConnect(&c, &data);dprintf("rc=%d\n",rc);if(rc == SUCCESS){connection.state = MQTT_CONNECTED;connection.times_count = 0;connection.timeout_s = 0;//printf("MQTTConnected!\n");rt_kprintf("MQTTConnected! Subscribing to %s\n", topic); }else if(connection.times_count <MAX_MQTT_CONNECT_TIMES){//printf("MQTTConnect times=%d, err:%d! \n",connection.times_count,rc);rt_kprintf("MQTTConnect times=%d, err:%d!\n",connection.times_count,rc);connection.times_count++;connection.timeout_s = MQTT_CONNECT_TIMEOUT;}else{//????network??dprintf("\n");NetworkDisconnect(&n);connection.state = UNCONNECTED;connection.times_count=0;connection.timeout_s = NETWORK_CONNECT_TIMEOUT*6;rt_kprintf("we will reconnect after %d senconds\n",connection.timeout_s);}break;case MQTT_CONNECTED:		if(connection.timeout_s>0)continue;dprintf("state = MQTT_CONNECTED\n");rc = MQTTSubscribe(&c, topic, opts.qos, messageArrived);dprintf("rc=%d\n",rc);if(rc == SUCCESS){rt_kprintf("Subscribed %s\n", topic);connection.state = SUBSCRIBING_SUCCESS;connection.times_count = 0;}else if(connection.times_count <MAX_SUBSCRIB_TIMES && MQTTIsConnected(&c)==1){rt_kprintf("MQTTSubscribe times=%d, err:%d! \n",connection.times_count,rc);connection.times_count++;connection.timeout_s = MQTT_CONNECT_TIMEOUT;}else{if(MQTTIsConnected(&c)==1)MQTTDisconnect(&c);elseMQTTCleanSession(&c);NetworkDisconnect(&n);connection.state = UNCONNECTED;connection.times_count=0;connection.timeout_s = NETWORK_CONNECT_TIMEOUT*6;rt_kprintf("we will reconnect after %d senconds\n",connection.timeout_s);}break;case SUBSCRIBING_SUCCESS:MQTTYield(&c, 1000);if(c.ping_timeout_times>=MAX_NO_PING_RESPONS_TIMES+1 || MQTTIsConnected(&c)==0)			{              if(MQTTIsConnected(&c)==1)MQTTDisconnect(&c);elseMQTTCleanSession(&c);NetworkDisconnect(&n);connection.state = UNCONNECTED;connection.times_count = 0;connection.timeout_s = NETWORK_CONNECT_TIMEOUT*6;rt_kprintf("we will reconnect after %d senconds\n",connection.timeout_s);}else{connection.times_count = 0;}break;default:rt_kprintf("satte = default,err!\n");break;}}exit:rt_kprintf("Stopping\n");	MQTTDisconnect(&c);NetworkDisconnect(&n);	rt_timer_delete(timer);}void domoticz_thread_init(void)
{rt_thread_t domoticz_thread;domoticz_thread = rt_thread_create("DomoticzThread", domoticz_thread_entry, RT_NULL,0xf00, 28, 10);if (domoticz_thread != RT_NULL)rt_thread_startup(domoticz_thread);}#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(set_host, set domoticz host ip addr);
FINSH_FUNCTION_EXPORT(domoticz_thread_init,to run domoticz thread );
FINSH_FUNCTION_EXPORT(quit_domoticz_thread,quit domoticz thread );
#endif

二、domoticz消息解析和控制例程部分。
1、CommonTypes.h:

/******************************************************************************
*filename: CommonTypes.h
******************************************************************************/#ifndef COMMON_TYPES_H
#define COMMON_TYPES_H#ifdef __cplusplus
extern "C"
{
#endif//------------------------------------------------------------------------------
//common defines#define KEY_IDX		0
#define KEY_NAME	1
#define KEY_ID		2
#define KEY_UINT	3
#define KEY_DTYPE	4
#define KEY_STYPE	5
#define KEY_NVALUE	6
#define KEY_SVALUE1	7
#define KEY_SVALUE2	8
#define KEY_BATTERY	9
#define KEY_RSSI	10
#define KEY_SWITCH_TYPE	11#define MSG_MAX_LEN 128
#define KEY_WORDS_NUM 12//------------------------------------------------------------------------------
//common types
typedef enum 
{STRING=0,INT=1,UINT=2
}ARG_TYPE_t;#ifdef __cplusplus
}
#endif#endif /* #ifndef COMMON_TYPES_H */
/*-- File end --*/

HardwareInterface.h:

/******************************************************************************
*filename: HardwareInterface.h
******************************************************************************/
#ifndef HARDWARE_INTERFACE_H
#define HARDWARE_INTERFACE_H#ifdef __cplusplus
extern "C"
{
#endif#include "CommonTypes.h"//------------------------------------------------------------------------------
//common Hardware interface
typedef struct
{ //解析出来的消息参数类型(STRING、INT、UINT中的一种)ARG_TYPE_t type;//下面是解析出来的具体消息参数数据union {char strArg[MSG_MAX_LEN];int iVar;unsigned int uiVar;}param;
}ParserArg;typedef struct
{//----------------respons parser interface----------------------------------//int(*IDX_ParserCallback)(ParserArg* arg);//无需处理idxint(*NAME_ParserCallback)(ParserArg* arg);int(*ID_ParserCallback)(ParserArg* arg);int(*UINT_ParserCallback)(ParserArg* arg);int(*DTYPE_ParserCallback)(ParserArg* arg);int(*STYPE_ParserCallback)(ParserArg* arg);int(*NVALUE_ParserCallback)(ParserArg* arg);int(*SVALUE1_ParserCallback)(ParserArg* arg);int(*SVALUE2_ParserCallback)(ParserArg* arg);int(*BATTERY_ParserCallback)(ParserArg* arg);int(*RSSI_ParserCallback)(ParserArg* arg);int(*SWITCH_TYPE_ParserCallback)(ParserArg* arg);ParserArg parseArg;int RegisterIDX;//--------------device base operation---------------------------------------//must be implementint (*Open)();void (*Init)();void (*Close)();}Hardware;typedef int(*ParserCallback)(ParserArg* arg);#ifdef __cplusplus
}
#endif#endif /* #ifndef HARDWARE_INTERFACE_H */
/*-- File end --*/

2、HardwareControl.h:

/******************************************************************************
* filename: HardwareControl.h
******************************************************************************/#ifndef HARDWARE_CONTROL_H
#define HARDWARE_CONTROL_H
#ifdef __cplusplus
extern "C"
{
#endif#include "HardwareInterface.h"#define HARDWARE_MAX_NUM 32#define REGISTER_SUCCESED 1
#define REGISTER_ERR1 -1 //索引号已经被使用
#define REGISTER_ERR2 -2 //容器已满,不能注册extern int OpenHardwares(void);
extern void initHardwareSettings(void);
extern void CloseHardwares(void);extern int RegisterHardware(Hardware *hardware,int idx);
extern Hardware* GetHardware(int idx);
extern int UnregisterHaraware(int idx);#ifdef __cplusplus
}
#endif#endif /* #ifndef HARDWARE_CONTROL_H */
/*-- File end --*/

HardwareControl.c:

/******************************************************************************
* filename: HardwareControl.c
******************************************************************************/
#include "HardwareControl.h"
#include <stdio.h>
#include <assert.h>//------------------------------------------------------------------------------
//GetHardWare interface
Hardware* g_HardwareContainer[HARDWARE_MAX_NUM];/******************************************************************************
* 函数名: RegisterHardware
* 功能描述:向硬件容器注册一个索引号为idx的硬件
* 参数1 :Hardware *hardware [I]:该硬件的指针
* 参数2 :int idx [I]:要分配的索引号
* 返回值: int ,成功则返回1,失败则返回错误号
* 创建时间:2017-Apr-17 22:08:58
* 修改时间:2017-Apr-17 22:08:58
* 版本记录:
* 其他说明:为了使用方便应该做一个配置文件以适配硬件信息
******************************************************************************/int RegisterHardware(Hardware *hardware,int idx)
{int i;assert(hardware);for(i=0;i<HARDWARE_MAX_NUM;i++){if(g_HardwareContainer[i]){if(g_HardwareContainer[i]->RegisterIDX==idx)return REGISTER_ERR1;elsecontinue;}else{g_HardwareContainer[i] = hardware ;g_HardwareContainer[i]->RegisterIDX = idx;return 1;	}}return REGISTER_ERR2;	
}/******************************************************************************
* 函数名: GetHardWare
* 功能描述: 根据索引号获取相应的硬件设备指针
* 参数1 :int idx [I]:设备索引号
* 返回值: 成功则返回对应硬件指针,失败返回0(NULL)
* 创建时间:2017-Apr-16 18:52:10
* 修改时间:2017-Apr-16 18:52:10
* 版本记录:
******************************************************************************/
Hardware* GetHardware(int idx)
{int i;for(i=0;i<HARDWARE_MAX_NUM;i++){if(g_HardwareContainer[i] && g_HardwareContainer[i]->RegisterIDX==idx)return g_HardwareContainer[i];}return 0;
}/******************************************************************************
* 函数名: UnregisterHaraware
* 功能描述:取消索引号为idx的硬件注册
* 参数1 :int idx [I]:要取消注册的硬件的idx号
* 返回值: 成功则返回取消注册的位置,失败返回-1
* 创建时间:2017-Apr-17 22:06:25
* 修改时间:2017-Apr-17 22:06:25
* 版本记录:
******************************************************************************/
int UnregisterHaraware(int idx)
{int i;for(i=0;i<HARDWARE_MAX_NUM;i++){if(g_HardwareContainer[i] && g_HardwareContainer[i]->RegisterIDX==idx)g_HardwareContainer[i] = 0;return i;}return -1;
}//------------------------------------------------------------------------------
//initionalizeint OpenHardwares()
{int i;int count=0;for(i=0;i<HARDWARE_MAX_NUM;i++){if(g_HardwareContainer[i]){if(!g_HardwareContainer[i]->Open)return -i;//如果该硬件接口没有实现Open,则返回它在容器中的位置的相反数(<=0)else{g_HardwareContainer[i]->Open();count++;}}}return count;//如果成功返回执行Open的设备数量
}void initHardwareSettings()
{int i;for(i=0;i<HARDWARE_MAX_NUM;i++){if(g_HardwareContainer[i] && g_HardwareContainer[i]->Init){g_HardwareContainer[i]->Init();}}
}void CloseHardwares()
{int i;for(i=0;i<HARDWARE_MAX_NUM;i++){if(g_HardwareContainer[i] && g_HardwareContainer[i]->Close)g_HardwareContainer[i]->Close();}
}/*-- File end --*/

3、DomoticzMessageParser.h:

/******************************************************************************
* filename: DomoticzMessageParser.h
******************************************************************************/#ifndef DOMOTICZ_MESSAGE_PARSER_H
#define DOMOTICZ_MESSAGE_PARSER_H
#ifdef __cplusplus
extern "C"
{
#endif#include "HardwareInterface.h"typedef struct{char *str;//分割字符串后,消息存入buf中时所需对比的关键字char *parseStr;//解析消息时所使用的匹配字符串ARG_TYPE_t type;//该消息对应的类型(STRING、INT、UINT中的一种)
}KeyWord_t;extern int GetKeywordIndex(const char* str);//------------------------------------------------------------------------------
//common DomoitczMessageParser interfacetypedef struct DomoitczMessageParser DomoitczMessageParser;struct DomoitczMessageParser
{int(*IDX_Handler)(DomoitczMessageParser* pParser, const char* message);int(*NAME_Handler)(DomoitczMessageParser* pParser, const char* message);int(*ID_Handler)(DomoitczMessageParser* pParser, const char* message);int(*UINT_Handler)(DomoitczMessageParser* pParser, const char* message);int(*DTYPE_Handler)(DomoitczMessageParser* pParser, const char* message);int(*STYPE_Handler)(DomoitczMessageParser* pParser, const char* message);int(*NVALUE_Handler)(DomoitczMessageParser* pParser, const char* message);int(*SVALUE1_Handler)(DomoitczMessageParser* pParser, const char* message);int(*SVALUE2_Handler)(DomoitczMessageParser* pParser, const char* message);int(*BATTERY_Handler)(DomoitczMessageParser* pParser, const char* message);int(*RSSI_Handler)(DomoitczMessageParser* pParser, const char* message);int(*SWITCH_TYPE_Handler)(DomoitczMessageParser* pParser, const char* message);int (*FillArgStr)(DomoitczMessageParser* pParser,const char* value);char MsgBuf[KEY_WORDS_NUM][MSG_MAX_LEN];	Hardware* bindHardware;
};typedef	int(*DomoitczMessageParserHandler)(DomoitczMessageParser* pParser, const char* message);extern DomoitczMessageParser g_DMP;
extern DomoitczMessageParser* g_pParser;extern void SetupDomoitczMessageParser(void);extern void SetEnableParseItem(int item);
extern void SetDisableParseItem(int item);extern int ParseDomoticzMessage(char* str);
//------------------------------------------------------------------------------
//hardware settings
extern void initHardWareSettings(void);#ifdef __cplusplus
}
#endif#endif /* #ifndef DOMOTICZ_MESSAGE_PARSER_H */
/*-- File end --*/

DomoticzMessageParser.c:

/******************************************************************************
* filename: DomoticzMessageParser.c
******************************************************************************//*-- #include --*/
#include "DomoticzMessageParser.h"
#include "HardwareControl.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdarg.h>#ifdef _DEBUG
#define dprintf(msg,...)  printf("%s,line:%d,"msg,__FILE__,__LINE__,##__VA_ARGS__)
#else
#define dprintf(msg,...)
#endifKeyWord_t KeyWords[KEY_WORDS_NUM+1]=
{{"idx","   \"idx\" : %d,",INT},{"name","   \"name\" : \"%s\",",STRING},{"id","   \"id\" : \"%s\",",STRING},{"unit","   \"unit\" : %u",UINT},{"dtype","   \"dtype\" : \"%s\",",STRING},{"stype","   \"stype\" : \"%s\",",STRING},{"nvalue","   \"nvalue\" : %d,",INT},{"svalue1","   \"svalue1\" : \"%s\",",STRING},{"svalue2","   \"svalue2\" : \"%s\",",STRING},{"Battery","   \"Battery\" : %u,",UINT},{"RSSI","   \"RSSI\" : %d,",INT},{"switchType","   \"switchType\" : \"%s\",",STRING},{"unknown","unknown",STRING}//防止越界访问	
};/******************************************************************************
* 函数名: GetKeywordIndex
* 功能描述: 根据关键字获取含该关键字的消息在KeyWords的位置索引号
* 参数1 :const char* str [I]:要查询的具体关键字字符串
* 返回值: 消息在KeyWords的位置索引号
* 创建时间:2017-Apr-16 19:09:26
* 修改时间:2017-Apr-16 19:09:26
* 版本记录:
******************************************************************************/
int GetKeywordIndex(const char* str)
{int i;for(i=0;i<KEY_WORDS_NUM;i++){if(strstr(str,KeyWords[i].str)){return i;}}return KEY_WORDS_NUM;
}//------------------------------------------------------------------------------
//DomoitczMessageParser interface implemention
//#0
int IDX_HandlerImpl(DomoitczMessageParser* pParser, const char* message)
{int idx;if(!pParser)return 0;		if(sscanf(message,KeyWords[KEY_IDX].parseStr,&idx)>0){dprintf("idx=%d\n",idx);		pParser->bindHardware = GetHardware(idx);//根据设备索引号搜索硬件设备//pParser->bindHardware->IDX_ParserCallback(&(pParser->bindHardware->parseArg));return pParser->bindHardware?1:0;		}return 0;
}//#1
int NAME_HandlerImpl(DomoitczMessageParser* pParser,const char* message)
{ParserCallback funcParseCallback;if(!pParser ||!pParser->bindHardware ||!pParser->bindHardware->NAME_ParserCallback)return 0;	funcParseCallback = pParser->bindHardware->NAME_ParserCallback;if(sscanf(message,KeyWords[KEY_NAME].parseStr,pParser->bindHardware->parseArg.param.strArg)>0){dprintf("name=%s\n",pParser->bindHardware->parseArg.param.strArg);pParser->bindHardware->parseArg.type = KeyWords[KEY_NAME].type;funcParseCallback(&(pParser->bindHardware->parseArg));return 1;}return 0;
}//#2
int ID_HandlerImpl(DomoitczMessageParser* pParser,const char* message)
{ParserCallback funcParseCallback;if(!pParser ||!pParser->bindHardware ||!pParser->bindHardware->ID_ParserCallback)return 0;	funcParseCallback = pParser->bindHardware->ID_ParserCallback;	if(sscanf(message,KeyWords[KEY_ID].parseStr,pParser->bindHardware->parseArg.param.strArg)>0){dprintf("id=%s\n",pParser->bindHardware->parseArg.param.strArg);pParser->bindHardware->parseArg.type = KeyWords[KEY_ID].type;funcParseCallback(&(pParser->bindHardware->parseArg));return 1;}return 0;
}//#3
int UINT_HandlerImpl(DomoitczMessageParser* pParser,const char* message)
{ParserCallback funcParseCallback;if(!pParser ||!pParser->bindHardware ||!pParser->bindHardware->UINT_ParserCallback)return 0;	funcParseCallback = pParser->bindHardware->UINT_ParserCallback;	if(sscanf(message,KeyWords[KEY_UINT].parseStr,&(pParser->bindHardware->parseArg.param.uiVar))>0){dprintf("uint=%u\n",pParser->bindHardware->parseArg.param.uiVar);pParser->bindHardware->parseArg.type = KeyWords[KEY_UINT].type;funcParseCallback(&(pParser->bindHardware->parseArg));return 1;}return 0;
}//#4
int DTYPE_HandlerImpl(DomoitczMessageParser* pParser,const char* message)
{ParserCallback funcParseCallback;if(!pParser ||!pParser->bindHardware ||!pParser->bindHardware->DTYPE_ParserCallback)return 0;	funcParseCallback = pParser->bindHardware->DTYPE_ParserCallback;		if(sscanf(message,KeyWords[KEY_DTYPE].parseStr,pParser->bindHardware->parseArg.param.strArg)>0){dprintf("dtype=%s\n",pParser->bindHardware->parseArg.param.strArg);pParser->bindHardware->parseArg.type = KeyWords[KEY_DTYPE].type;funcParseCallback(&(pParser->bindHardware->parseArg));return 1;}return 0;
}//#5
int STYPE_HandlerImpl(DomoitczMessageParser* pParser,const char* message)
{ParserCallback funcParseCallback;if(!pParser ||!pParser->bindHardware ||!pParser->bindHardware->STYPE_ParserCallback)return 0;	funcParseCallback = pParser->bindHardware->STYPE_ParserCallback;	if(sscanf(message,KeyWords[KEY_STYPE].parseStr,pParser->bindHardware->parseArg.param.strArg)>0){dprintf("name=%s\n",pParser->bindHardware->parseArg.param.strArg);pParser->bindHardware->parseArg.type = KeyWords[KEY_STYPE].type;funcParseCallback(&(pParser->bindHardware->parseArg));return 1;}return 0;
}//#6
int NVALUE_HandlerImpl(DomoitczMessageParser* pParser,const char* message)
{ParserCallback funcParseCallback;if(!pParser || !pParser->bindHardware || !pParser->bindHardware->NVALUE_ParserCallback)return 0;funcParseCallback = pParser->bindHardware->NVALUE_ParserCallback;		if(sscanf(message,KeyWords[KEY_NVALUE].parseStr,&(pParser->bindHardware->parseArg.param.iVar))>0){dprintf("nvalue=%d\n",pParser->bindHardware->parseArg.param.iVar);pParser->bindHardware->parseArg.type = KeyWords[KEY_NVALUE].type;funcParseCallback(&(pParser->bindHardware->parseArg));return 1;}return 0;
}//#7
int SVALUE1_HandlerImpl(DomoitczMessageParser* pParser,const char* message)
{ParserCallback funcParseCallback;if(!pParser ||!pParser->bindHardware ||!pParser->bindHardware->SVALUE1_ParserCallback)return 0;	funcParseCallback = pParser->bindHardware->SVALUE1_ParserCallback;		if(sscanf(message,KeyWords[KEY_SVALUE1].parseStr,pParser->bindHardware->parseArg.param.strArg)>0){dprintf("svalue1=%s\n",pParser->bindHardware->parseArg.param.strArg);pParser->bindHardware->parseArg.type = KeyWords[KEY_SVALUE1].type;funcParseCallback(&(pParser->bindHardware->parseArg));return 1;}return 0;
}//#8
int SVALUE2_HandlerImpl(DomoitczMessageParser* pParser,const char* message)
{ParserCallback funcParseCallback;if(!pParser ||!pParser->bindHardware ||!pParser->bindHardware->SVALUE2_ParserCallback)return 0;	funcParseCallback = pParser->bindHardware->SVALUE2_ParserCallback;if(sscanf(message,KeyWords[KEY_SVALUE2].parseStr,pParser->bindHardware->parseArg.param.strArg)>0){dprintf("svalue2=%s\n",pParser->bindHardware->parseArg.param.strArg);pParser->bindHardware->parseArg.type = KeyWords[KEY_SVALUE2].type;funcParseCallback(&(pParser->bindHardware->parseArg));return 1;}return 0;
}//#9
int BATTERY_HandlerImpl(DomoitczMessageParser* pParser,const char* message)
{ParserCallback funcParseCallback;if(!pParser ||!pParser->bindHardware ||!pParser->bindHardware->BATTERY_ParserCallback)return 0;	funcParseCallback = pParser->bindHardware->BATTERY_ParserCallback;if(sscanf(message,KeyWords[KEY_BATTERY].parseStr,&(pParser->bindHardware->parseArg.param.uiVar))>0){dprintf("battery=%u\n",pParser->bindHardware->parseArg.param.uiVar);pParser->bindHardware->parseArg.type = KeyWords[KEY_BATTERY].type;funcParseCallback(&(pParser->bindHardware->parseArg));return 1;}return 0;
}//#10
int RSSI_HandlerImpl(DomoitczMessageParser* pParser,const char* message)
{ParserCallback funcParseCallback;if(!pParser ||!pParser->bindHardware ||!pParser->bindHardware->RSSI_ParserCallback)return 0;	funcParseCallback = pParser->bindHardware->RSSI_ParserCallback;if(sscanf(message,KeyWords[KEY_RSSI].parseStr,&(pParser->bindHardware->parseArg.param.iVar))>0){dprintf("RSSI=%d\n",pParser->bindHardware->parseArg.param.iVar);pParser->bindHardware->parseArg.type = KeyWords[KEY_RSSI].type;funcParseCallback(&(pParser->bindHardware->parseArg));return 1;		}return 0;
}//#11
int SWITCH_TYPE_HandlerImpl(DomoitczMessageParser* pParser,const char* message)
{ParserCallback funcParseCallback;if(!pParser ||!pParser->bindHardware ||!pParser->bindHardware->SWITCH_TYPE_ParserCallback)return 0;	funcParseCallback = pParser->bindHardware->SWITCH_TYPE_ParserCallback;if(sscanf(message,KeyWords[KEY_SWITCH_TYPE].parseStr,pParser->bindHardware->parseArg.param.strArg)>0){dprintf("switchType=%s\n",pParser->bindHardware->parseArg.param.strArg);pParser->bindHardware->parseArg.type = KeyWords[KEY_SWITCH_TYPE].type;funcParseCallback(&(pParser->bindHardware->parseArg));return 1;		}return 0;
}/******************************************************************************
* 函数名: FillArgStrImpl
* 功能描述: .
* 参数1 :DomoitczMessageParser* pParser [I]:param description.
* 参数2 :const char* value [I]:param description.
* 返回值: int return variable description.
* 创建时间:2017-Apr-16 19:16:58
* 修改时间:2017-Apr-16 19:16:58
* 版本记录:
******************************************************************************/
int FillArgStrImpl(DomoitczMessageParser* pParser,const char* value)
{int key;if(!pParser)return -1;key = GetKeywordIndex(value);if(key>=KEY_WORDS_NUM)return -1;strcpy(pParser->MsgBuf[key],value);return key;
}//------------------------------------------------------------------------------
//Setup DomoitczMessageParserstatic int CALL_PARSER_FUNC_FLAG = 0;DomoitczMessageParser g_DMP;
DomoitczMessageParser* g_pParser = &g_DMP;static DomoitczMessageParserHandler HandlerPool[KEY_WORDS_NUM];/******************************************************************************
* 函数名: SetupDomoitczMessageParser
* 功能描述: 构建消息解析器
* 参数1 :DomoitczMessageParser* pDMP [I]:要构建的domoticz消息解析器指针
* 参数2 :Hardware* bindHardware [I]:初始化消息解析器解析回调对象
* 返回值: 
* 创建时间:2017-Apr-16 19:13:29
* 修改时间:2017-Apr-16 19:13:29
* 版本记录:
******************************************************************************/
void SetupDomoitczMessageParser()
{g_pParser->IDX_Handler = IDX_HandlerImpl;g_pParser->NAME_Handler = NAME_HandlerImpl;g_pParser->ID_Handler = ID_HandlerImpl;g_pParser->UINT_Handler = UINT_HandlerImpl;g_pParser->DTYPE_Handler = DTYPE_HandlerImpl;g_pParser->STYPE_Handler = STYPE_HandlerImpl;g_pParser->NVALUE_Handler = NVALUE_HandlerImpl;g_pParser->SVALUE1_Handler = SVALUE1_HandlerImpl;g_pParser->SVALUE2_Handler = SVALUE2_HandlerImpl;g_pParser->BATTERY_Handler = BATTERY_HandlerImpl;g_pParser->RSSI_Handler = RSSI_HandlerImpl;g_pParser->SWITCH_TYPE_Handler = SWITCH_TYPE_HandlerImpl;g_pParser->bindHardware = 0;g_pParser->FillArgStr = FillArgStrImpl;HandlerPool[KEY_IDX] = IDX_HandlerImpl;HandlerPool[KEY_NAME] = NAME_HandlerImpl;	HandlerPool[KEY_ID] = 	ID_HandlerImpl;	HandlerPool[KEY_UINT] = UINT_HandlerImpl;	HandlerPool[KEY_DTYPE] = DTYPE_HandlerImpl;HandlerPool[KEY_STYPE] = STYPE_HandlerImpl;HandlerPool[KEY_NVALUE] = NVALUE_HandlerImpl;	HandlerPool[KEY_SVALUE1] = 	SVALUE1_HandlerImpl;HandlerPool[KEY_SVALUE2] = SVALUE2_HandlerImpl	;HandlerPool[KEY_BATTERY] = 	BATTERY_HandlerImpl;HandlerPool[KEY_RSSI] = RSSI_HandlerImpl;HandlerPool[KEY_SWITCH_TYPE] = SWITCH_TYPE_HandlerImpl;}// 将str字符以spl分割,存于g_pParser->MsgBuf中,并返回子字符串数量
int split(char* str, const char* delim)
{int n = 0;char *result = NULL;assert(g_pParser);result = strtok(str, delim);while( result != NULL ){		g_pParser->FillArgStr(g_pParser,result);dprintf("result=%s\n",result);result = strtok(NULL, delim);}return n;
}/******************************************************************************
* 函数名: SetEnableParseItem
* 功能描述: 设置CALLPARSER_FUNC_FLAG的item位置上的标志位为1
* 参数1 :int item [I]:要置1的位置,由右往左数0,1,2,3,...。
* 该参数不能超过KEY_WORDS_NUM,且不能超过31,否则视为无效。
*
* 返回值: 
* 创建时间:2017-Apr-16 20:15:51
* 修改时间:2017-Apr-16 20:15:51
* 版本记录:
******************************************************************************/
void SetEnableParseItem(int item)
{assert(item<32);if(item>=0 && item<KEY_WORDS_NUM){CALL_PARSER_FUNC_FLAG |= 1<<item;}
}/******************************************************************************
* 函数名: SetEnableParseItem
* 功能描述: 设置CALLPARSER_FUNC_FLAG的item位置上的标志位为0
* 参数1 :int item [I]:要清零的位置,由右往左数0,1,2,3,...。
* 该参数不能超过KEY_WORDS_NUM,且不能超过31,否则视为无效。
*
* 返回值: 
* 创建时间:2017-Apr-16 20:15:51
* 修改时间:2017-Apr-16 20:15:51
* 版本记录:
******************************************************************************/
void SetDisableParseItem(int item)
{assert(item<32);if(item>=0 && item<KEY_WORDS_NUM){CALL_PARSER_FUNC_FLAG &= ~(1<<item);}
}/******************************************************************************
* 函数名: ParseDomoticzMessage
* 功能描述: 解析消息,并回调与消息相应的硬件处理函数
* 参数1 :char* str [I]:要解析的目标消息字符串
* 返回值: int 
* 创建时间:2017-Apr-16 19:18:17
* 修改时间:2017-Apr-16 19:18:17
* 版本记录:
******************************************************************************/
int ParseDomoticzMessage(char* str)
{	int nCount ;//printf("---------------------------------------\n");int i;int CallFlag ;nCount = split(str,"\n");//SetDisableParseItem(KEY_SWITCH_TYPE);		CallFlag = CALL_PARSER_FUNC_FLAG;//dprintf("CALL_PARSER_FUNC_FLAG=0x%X\n",CALL_PARSER_FUNC_FLAG);for(i=0;i<KEY_WORDS_NUM && i<32;i++){if(CallFlag&0x1){HandlerPool[i](g_pParser,g_pParser->MsgBuf[i]);//dprintf("i=%d\n",i);}CallFlag>>=1;}//g_pParser->IDX_Handler(g_pParser,g_pParser->MsgBuf[KEY_IDX]);//g_pParser->NVALUE_Handler(g_pParser,g_pParser->MsgBuf[KEY_NVALUE]);return 1;
}/*-- File end --*/

4、例程部分。
1)led硬件驱动:
led.h

/** File      : led.h* This file is part of RT-Thread RTOS* COPYRIGHT (C) 2009, RT-Thread Development Team** The license and distribution terms for this file may be* found in the file LICENSE in this distribution or at* http://www.rt-thread.org/license/LICENSE** Change Logs:* Date           Author       Notes* 2009-01-05     Bernard      the first version*/#ifndef __LED_H__
#define __LED_H__#include <rtthread.h>void rt_hw_led_init(void);
void rt_hw_led_on(rt_uint32_t led);
void rt_hw_led_off(rt_uint32_t led);#endif

led.c:

/*
* File      : led.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2009, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date           Author       Notes
* 2009-01-05     Bernard      the first version
*/
#include <rtthread.h>
#include <stm32f10x.h>#define led1_rcc                    RCC_APB2Periph_GPIOD
#define led1_gpio                   GPIOD
#define led1_pin                    (GPIO_Pin_2)#define led2_rcc                    RCC_APB2Periph_GPIOD
#define led2_gpio                   GPIOD
#define led2_pin                    (GPIO_Pin_3)void rt_hw_led_init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(led1_rcc|led2_rcc,ENABLE);GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin   = led1_pin;GPIO_Init(led1_gpio, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin   = led2_pin;GPIO_Init(led2_gpio, &GPIO_InitStructure);
}void rt_hw_led_on(rt_uint32_t n)
{switch (n){case 0:GPIO_SetBits(led1_gpio, led1_pin);break;case 1:GPIO_SetBits(led2_gpio, led2_pin);break;default:break;}
}void rt_hw_led_off(rt_uint32_t n)
{switch (n){case 0:GPIO_ResetBits(led1_gpio, led1_pin);break;case 1:GPIO_ResetBits(led2_gpio, led2_pin);break;default:break;}
}void led_toggle(rt_uint32_t n)
{switch (n){case 0:GPIO_WriteBit(led1_gpio, led1_pin, (BitAction)((GPIO_ReadOutputDataBit(led1_gpio,led1_pin))^1) );break;case 1:GPIO_WriteBit(led2_gpio, led2_pin, (BitAction)((GPIO_ReadOutputDataBit(led2_gpio,led2_pin))^1) );break;default:break;}}
void rt_led_disp_thread_entry(void* parameter)
{rt_uint32_t i=0;while(1){i=0x50000;do{i--;}while(i>0);led_toggle(0);i=0x50000;do{i--;}while(i>0);led_toggle(1);}
}void rt_led_disp_init(void)
{rt_thread_t init_led_thread;init_led_thread = rt_thread_create("led_disp", rt_led_disp_thread_entry, RT_NULL,128, 28, 10);if (init_led_thread != RT_NULL)rt_thread_startup(init_led_thread);}static rt_uint8_t led_inited = 0;
void led(rt_uint32_t led, rt_uint32_t value)
{/* init led configuration if it's not inited. */if (!led_inited){rt_hw_led_init();led_inited = 1;}if ( led == 0 ){/* set led status */switch (value){case 0:rt_hw_led_off(0);break;case 1:rt_hw_led_on(0);break;default:break;}}if ( led == 1 ){/* set led status */switch (value){case 0:rt_hw_led_off(1);break;case 1:rt_hw_led_on(1);break;default:break;}}
}#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(led, set led[0 - 1] on[1] or off[0])
FINSH_FUNCTION_EXPORT(led_toggle, toggle the leds)#endif

2)例程:
LED0.h

/******************************************************************************
* filename: LED0.h
******************************************************************************/
#ifndef LED0_H
#define LED0_H#include "HardwareInterface.h"extern Hardware* Create_LED0(void);extern int getLED0Status(void);#endif /* #ifndef LED0_H */
/*-- File end --*/

LED0.c:

#include "led.h"
#include "LED0.h"static Hardware LED0;
static int led_no = 0;
static int status=0;int LED0_Open()
{return 0;
}void LED0_Init()
{rt_hw_led_off(led_no);status = 0;
}void LED0_Close()
{}/******************************************************************************
* 函数名: LED0_NVALUE_ParserCallbackImpl
* 功能描述: 在DomoiticzMessageParser进行解析"nvalue"消息参数后,
* 被回调以执行相应功能
*
* 参数1 :ParserArg* arg [I]:已经解析的消息参数
* 返回值: 成功返回1,失败返回0
* 创建时间:2017-Apr-16 18:50:27
* 修改时间:2017-Apr-16 18:50:27
* 版本记录:
******************************************************************************/
int LED0_NVALUE_ParserCallbackImpl(ParserArg* arg)
{//printf("LED0_IDX_ParserCallbackImpl is called!\n");if(arg && arg->type==INT){status = arg->param.iVar;if(status==1)rt_hw_led_on(led_no);else if(status ==0)rt_hw_led_off(led_no);		return 1;}return 0;
}int LED0_SWITCH_TYPE_ParserCallbackImpl(ParserArg* arg)
{//printf("LED0_SWITCH_TYPE_ParserCallbackImpl is called!\n");	if(arg && arg->type==STRING){//dprintf("%s\n",arg->strArg);	return 1;}return 0;
}Hardware* Create_LED0()
{LED0.Open = LED0_Open;LED0.Init= LED0_Init;LED0.Close= LED0_Close;LED0.NVALUE_ParserCallback = LED0_NVALUE_ParserCallbackImpl;LED0.SWITCH_TYPE_ParserCallback = LED0_SWITCH_TYPE_ParserCallbackImpl;return &LED0;
}int getLED0Status()
{return status;
}

LED1.h:

/******************************************************************************
* filename: LED1.h
******************************************************************************/
#ifndef LED1_H
#define LED1_H#include "HardwareInterface.h"extern Hardware* Create_LED1(void);#endif /* #ifndef LED0_H */
/*-- File end --*/

LED1.c

#include "led.h"
#include "LED1.h"static Hardware LED1;
static int led_no = 1;int LED1_Open()
{return 0;
}void LED1_Init()
{rt_hw_led_off(led_no);
}void LED1_Close()
{}int LED1_NVALUE_ParserCallbackImpl(ParserArg* arg)
{//dprintf("LED0_IDX_ParserCallbackImpl is called!\n");if(arg && arg->type==INT){if(arg->param.iVar==1)rt_hw_led_on(led_no);else if(arg->param.iVar ==0)rt_hw_led_off(led_no);		return 1;}return 0;
}Hardware* Create_LED1()
{LED1.Open = LED1_Open;LED1.Init= LED1_Init;LED1.Close= LED1_Close;LED1.NVALUE_ParserCallback = LED1_NVALUE_ParserCallbackImpl;return &LED1;
}

5、在应用启动上加入我们的启动调用,位置在rt-thread\bsp\stm32f107\applications\application.c中。
改后的代码如下:

application.c:

/** File      : application.c* This file is part of RT-Thread RTOS* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team** The license and distribution terms for this file may be* found in the file LICENSE in this distribution or at* http://www.rt-thread.org/license/LICENSE** Change Logs:* Date           Author       Notes* 2009-01-05     Bernard      the first version*//*** @addtogroup STM32*/
/*@{*/#include <board.h>
#include <rtthread.h>#ifdef RT_USING_DFS
#include <dfs_fs.h>
#include <dfs_init.h>
#include <dfs_elm.h>
#endif#ifdef RT_USING_LWIP
#include <stm32_eth.h>
#include <netif/ethernetif.h>
extern int lwip_system_init(void);
#endif#ifdef RT_USING_FINSH
#include <shell.h>
#include <finsh.h>
#endif//================== Added  2017-Apr-20 5:01:52 start ==================
#include "led.h"
#include "../../../components/external/paho-mqtt/MQTTClient-C/samples/domoticz/DomoticzThread.h" 
//================== Added  2017-Apr-20 5:01:52  end ===================void rt_init_thread_entry(void* parameter)
{{extern void rt_platform_init(void);rt_platform_init();}/* Filesystem Initialization */
#if defined(RT_USING_DFS) && defined(RT_USING_DFS_ELMFAT)/* initialize the device file system */dfs_init();/* initialize the elm chan FatFS file system*/elm_init();/* mount sd card fat partition 1 as root directory */if (dfs_mount("sd0", "/", "elm", 0, 0) == 0){rt_kprintf("File System initialized!\n");}else{rt_kprintf("File System initialzation failed!\n");}
#endif /* RT_USING_DFS && RT_USING_DFS_ELMFAT */#ifdef RT_USING_LWIP/* initialize lwip stack *//* register ethernetif device */eth_system_device_init();//================== Added  2017-Apr-20 5:49:03 start ==================rt_hw_led_init();rt_hw_led_off(0);rt_hw_led_off(1);
//================== Added  2017-Apr-20 5:49:03  end ===================/* initialize lwip system */lwip_system_init();rt_kprintf("TCP/IP initialized!\n");//================== Added  2017-Apr-20 5:49:03 start ==================domoticz_thread_init();
//================== Added  2017-Apr-20 5:49:03  end ===================
#endif#ifdef RT_USING_FINSH/* initialize finsh */finsh_system_init();finsh_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
}int rt_application_init(void)
{rt_thread_t tid;tid = rt_thread_create("init",rt_init_thread_entry, RT_NULL,2048, RT_THREAD_PRIORITY_MAX/3, 20);if (tid != RT_NULL) rt_thread_startup(tid);return 0;
}/*@}*/

这篇关于基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(十)使用domoticz+mosquitto+Android客户端实现控制STM32板上的LED(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/652516

相关文章

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip