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

本文介绍了如何在基于STM32F107的开发板上,利用RTThread操作系统和LwIP协议栈,结合MQTT客户端与Domoticz服务器,实现Android远程控制LED灯。文中详细阐述了硬件配置、软件环境、MQTT客户端移植及源码结构,并提及了STM32与Mini2440的差异处理。

本文将在前面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;
		}
		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: %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? */
#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


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 packet
        rc = SUCCESS;
    }
    else
        rc = 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 string
            char* nextpos = curn + 1;
            while (nextpos < curn_end && *nextpos != '/')
                nextpos = ++curn + 1;
        }
        else if (*curf == '#')
            curn = curn_end - 1;    // skip until end of string
        curf++;
        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 topic
    for (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;
                else
                    rc = 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 packet
                rc = FAILURE; // there was a problem
            if (rc == FAILURE)
                goto exit; // there was a problem
            break;
        }

        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 FAULT
        rc = 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);
#endif
		TimerCountdownMS(&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);
}
#endif


int waitfor(MQTTClient* c, int packet_type, Timer* timer)
{
    int rc = FAILURE;
    
    do
    {
			rt_thread_delay(10);//不延时或延时太短会出错
        if (TimerIsExpired(timer))
            break; // we timed out
        rc = 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);
#endif
	if (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 packet
        goto exit; // there was a problem

    // this will be a blocking call, wait for the connack
    if (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;
        else
            rc = FAILURE;
    }
    else
        rc = 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);
#endif

    return 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);
#endif
	  if (!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 problem
    
    if (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);
#endif
    return 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);
#endif
	if (!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 packet
        goto exit; // there was a problem
    
    if (waitfor(c, UNSUBACK, &timer) == UNSUBACK)
    {
        unsigned short mypacketid;  // should be the same as the packetid above
        if (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);
        }
    }
    else
        rc = FAILURE;
    
exit:
    if (rc == FAILURE)
        MQTTCloseSession(c);
#if defined(MQTT_TASK)
	MutexUnlock(&c->mutex);
#endif
    return 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);
#endif
	if (!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 packet
        goto exit; // there was a problem
    
    if (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;
        }
        else
            rc = 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;
        }
        else
            rc = FAILURE;
    }
    
exit:
    if (rc == FAILURE){dprintf("\n");
        MQTTCloseSession(c);}
#if defined(MQTT_TASK)
	MutexUnlock(&c->mutex);
#endif
				
    return rc;
}


int MQTTDisconnect(MQTTClient* c)
{  
    int rc = FAILURE;
    Timer timer;     // we might wait for incomplete incoming publishes to complete
    int len = 0;

#if defined(MQTT_TASK)
	MutexLock(&c->mutex);
#endif
    TimerInit(&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 packet
    MQTTCloseSession(c);

#if defined(MQTT_TASK)
	MutexUnlock(&c->mutex);
#endif
    return 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 10

Connection_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);
	else
		rt_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  512

void 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,restart
							dprintf("\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);
							else
								MQTTCleanSession(&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);
								else
									MQTTCleanSession(&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);//无需处理idx
	int(*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 implement
	int (*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;
			else
				continue;
		}
		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;
}

//------------------------------------------------------------------------------
//initionalize

int 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 interface

typedef 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,...)
#endif


KeyWord_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 DomoitczMessageParser

static 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;
}

/*@}*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值