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

原创 2017年04月27日 02:54:14

本文将在前面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上的是一样的,以后有时间再上图吧。

后面有时间把整个工程打包上传上来。


以下是上述介绍的源码:
一、MQTTClient-C部分:

1、MQTTRTThread.h


#include <rtthread.h>  

//----------------------------------------------------------
typedef struct Timer
{
    int left_ms;
    rt_timer_t timer_ptr;
} Timer;


void TimerInit(Timer*);
char TimerIsExpired(Timer*);
void TimerCountdownMS(Timer*, int);
void TimerCountdown(Timer*, 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

#ifdef __DEBUG
#include <stdarg.h>
#include <string.h>
static const char *getCurrentFileName()
{
    const char *p = strrchr(__FILE__,'\\');
    return ++p;
}
#define dprintf(fmt,...) rt_kprintf("%s,line:%d,"fmt,getCurrentFileName(),__LINE__,##__VA_ARGS__)
#else
#define dprintf(fmt,...)
#endif

//int RTThreadLwIP_read(Network* n, unsigned char* buffer, int len, int timeout_ms);
//int RTThreadLwIP_write(Network* n, unsigned char* buffer, int len, int timeout_ms);

//因为10ms才调用一次
void SetTimerTimeout(void* timer)
{
    Timer* tmr=(Timer*)timer;
    if(tmr->left_ms<0)
        return;
    tmr->left_ms -= 10;
    //dprintf("left_ms=%d\n",tmr->left_ms);
}

void TimerInit(Timer* timer)
{
    timer->left_ms = 0;
    timer->timer_ptr = 0;

}

char TimerIsExpired(Timer* timer)
{
    //dprintf("timer->left_ms=%d\n",timer->left_ms);
    return timer->left_ms<=0?1:0;
}


void TimerCountdownMS(Timer* timer, int timeout)
{
    static int i=0;
    if(timer->timer_ptr)
    {
        rt_timer_stop(timer->timer_ptr);
    }
    else
    {
        char str[16]={0};
        sprintf(str,"ms%d",i++);
        timer->timer_ptr = rt_timer_create(str,SetTimerTimeout, timer,1,/* 定时长度为1个OS Tick 。一个tick是1/RT_TICK_PER_SECOND秒,默认是10ms*/
            RT_TIMER_FLAG_PERIODIC);        
    }
    timer->left_ms = timeout;
    if (timer->timer_ptr != RT_NULL) 
        rt_timer_start(timer->timer_ptr);
    else
    {
        dprintf("err:timer->timer_ptr=NULL\n"); 
    }
}


void TimerCountdown(Timer* timer, int timeout)
{
    static int i=0;
    if(timer->timer_ptr)
    {
        rt_timer_stop(timer->timer_ptr);
    }
    else
    {
        char str[16]={0};
        sprintf(str,"s%d",i++);
        timer->timer_ptr = rt_timer_create(str,SetTimerTimeout, timer,1,/* 定时长度为1个OS Tick 。一个tick是1/RT_TICK_PER_SECOND秒,默认是10ms*/
            RT_TIMER_FLAG_PERIODIC);    
    }
    timer->left_ms = timeout*1000;
    rt_timer_start(timer->timer_ptr);
}


int TimerLeftMS(Timer* timer)
{
    return timer->left_ms;
}

void DeleteTimer(Timer* timer)
{
    if(timer->timer_ptr)
    {
        rt_timer_delete(timer->timer_ptr);
    }
}

void tcp_time_out(void * data)
{
    int * time = (int*)data;
    if(time && *time>0)
    {
        (*time) -= 10;          
    }
}

int RTThreadLwIP_read(Network* n, unsigned char* buffer, int len, int timeout_ms)
{
    int bytes = 0;
#if 0 /* Commented @ 2017-Apr-26 1:23:16 */
    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;
    }
#endif /* Commented */
    int time_out = timeout_ms;

    static int i=0;
    char str[16]={0};
    sprintf(str,"recv_timer_%d",i++);
    //dprintf("timeout_ms=%d\n",timeout_ms);

    //lwip_setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval, sizeof(struct timeval));
    lwip_setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&time_out, sizeof(int));
    rt_timer_t timer = rt_timer_create(str, tcp_time_out, &time_out, 1,RT_TIMER_FLAG_PERIODIC); 
    rt_timer_start(timer);
    while (bytes < len)
    {
        int rc = lwip_recv(n->my_socket, &buffer[bytes], (size_t)(len - bytes), 0);
        if (rc == -1)
        {
            if (errno != ENOTCONN && errno != ECONNRESET)
            {
                bytes = -1;
                break;
            }
        }
        else if(time_out>0)
        {
            bytes += rc;
        }
        else
        {
            bytes = -1;
            break;
        }
    }
    rt_timer_delete(timer);
    return bytes;
}


int RTThreadLwIP_write(Network* n, unsigned char* buffer, int len, int timeout_ms)
{
    int rc;
#if 0 /* Commented by sunq @ 2017-Apr-27 1:06:05 */
    struct timeval tv;

    tv.tv_sec = 0;  /* 30 Secs Timeout */
    tv.tv_usec = timeout_ms * 1000;  // Not init'ing this can cause strange errors

    lwip_setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
#endif /* Commented by sunq */
    int time_out = timeout_ms;

    static int i=0;
    char str[16]={0};
    sprintf(str,"write_timer_%d",i++);

    lwip_setsockopt(n->my_socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&time_out, sizeof(int));
    rt_timer_t timer = rt_timer_create(str, tcp_time_out, &time_out, 1,RT_TIMER_FLAG_PERIODIC); 
    rt_timer_start(timer);
    rc = lwip_write(n->my_socket, buffer, len);

    rt_timer_delete(timer);
    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, 2015 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
 *******************************************************************************/

#if !defined(__MQTT_CLIENT_C_)
#define __MQTT_CLIENT_C_

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

/* 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*, int);
extern void TimerCountdown(Timer*, 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 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 isconnected;

    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 ping_timer;
#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 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 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 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);

#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, 2015 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
 *******************************************************************************/
#include "MQTTClient.h"
#include <rtthread.h> 

//#define __DEBUG

#ifdef __DEBUG
#include <stdarg.h>
#include <string.h>
static const char *getCurrentFileName()
{
    const char *p = strrchr(__FILE__,'\\');
    return ++p;
}
#define dprintf(fmt,...) rt_kprintf("%s,line:%d,"fmt,getCurrentFileName(),__LINE__,##__VA_ARGS__)
#else
#define dprintf(fmt,...)
#endif

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->ping_timer, 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->ping_outstanding = 0;
    c->defaultMessageHandler = NULL;
    c->next_packetid = 1;
    TimerInit(&c->ping_timer);
    dprintf("\n");
}


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)
{
    int rc = FAILURE;
    MQTTHeader header = {0};
    int len = 0;
    int rem_len = 0;

    /* 1. read the header byte.  This has the packet type in it */
    if (c->ipstack->mqttread(c->ipstack, c->readbuf, 1, TimerLeftMS(timer)) != 1)
        goto exit;
    len = 1;
    /* 2. read the remaining length.  This is variable in itself */
    decodePacket(c, &rem_len, TimerLeftMS(timer));
    dprintf("data len ,,,, rem_len=%d\n",rem_len);
    len += MQTTPacket_encode(c->readbuf + 1, rem_len); /* put the original remaining length back into the buffer */

    int data_real_len=0;
    /* 3. read the rest of the buffer using a callback to supply the rest of the data */
    if (rem_len > 0 && ((data_real_len=c->ipstack->mqttread(c->ipstack, c->readbuf + len, rem_len, TimerLeftMS(timer))) != rem_len))
    {   
        goto exit;
    }
#if 0 /* Commented @ 2017-Apr-25 1:34:59 */
    else
    {
        dprintf("data len=%d ,,,, data_real_len=%d\n",rem_len,data_real_len);
        dprintf("c->readbuf=\n",c->readbuf);
        int i;
        for(i=0;i<data_real_len;i++)
        {
            rt_kprintf("%02X ,",c->readbuf[i]);
            if(i%10==9)
                rt_kprintf("\n");
        }
    }
#endif /* Commented */

    header.byte = c->readbuf[0];
    rc = header.bits.type;
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 = FAILURE;

    if (c->keepAliveInterval == 0)
    {
        rc = SUCCESS;
        goto exit;
    }

    if (TimerIsExpired(&c->ping_timer))
    {
        if (!c->ping_outstanding)
        {
            Timer timer;
            int len;
            TimerInit(&timer);
            TimerCountdownMS(&timer, 1000);
            len = MQTTSerialize_pingreq(c->buf, c->buf_size);
            rc = sendPacket(c, len, &timer);
            if (len > 0 && rc == SUCCESS) // send the ping packet
            {
                c->ping_outstanding = 1;
            }
            else if(rc== FAILURE)
            {
                c->ping_outstanding = 1;
            }
            DeleteTimer(&timer);

        }
    }

exit:
    return rc;
}


int cycle(MQTTClient* c, Timer* timer)
{
    // read the socket, see what work is due
    unsigned short packet_type = readPacket(c, timer);

    int len = 0,
        rc = SUCCESS;
    switch (packet_type)
    {
        case CONNACK:
        case PUBACK:
        case SUBACK:
            break;
        case PUBLISH:
        {
            MQTTString topicName;
            MQTTMessage msg;
            int intQoS;
            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)
                    goto exit; // there was a problem
            }
            break;
        }
        case PUBREC:
        {
            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, PUBREL, 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;
            break;
    }
    keepalive(c);
    dprintf("\n");  
exit:
    if (rc == SUCCESS)
        rc = packet_type;
    return rc;
}


int MQTTYield(MQTTClient* c, int timeout_ms)
{  
    int rc = SUCCESS;   
    Timer timer;
    TimerInit(&timer);
    TimerCountdownMS(&timer, timeout_ms);
    //dprintf("c->readbuf=%p,c->readbuf_size=%u\n",c->readbuf,c->readbuf_size); 
    do
    { 
        if (cycle(c, &timer) == FAILURE)
        {
            rc = FAILURE;
            break;
        }
    } while (!TimerIsExpired(&timer));
    DeleteTimer(&timer);
    return rc;
}


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
    {
        if (TimerIsExpired(timer))
            break; // we timed out
    }
    while ((rc = cycle(c, timer)) != packet_type);  

    return rc;
}


int MQTTConnect(MQTTClient* c, MQTTPacket_connectData* options)
{
    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;
    TimerCountdown(&c->ping_timer, 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)
    {
        unsigned char connack_rc = 255;
        unsigned char sessionPresent = 0;
        if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, c->readbuf, c->readbuf_size) == 1)
            rc = connack_rc;
        else
            rc = FAILURE;
    }
    else
        rc = FAILURE;

exit:
    if (rc == SUCCESS)
        c->isconnected = 1;

#if defined(MQTT_TASK)
    MutexUnlock(&c->mutex);
#endif
    DeleteTimer(&connect_timer);
    return rc;
}


int MQTTSubscribe(MQTTClient* c, const char* topicFilter, enum QoS qos, messageHandler messageHandler)
{ 
    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)
        goto exit;
    TimerInit(&timer);
    TimerCountdownMS(&timer, c->command_timeout_ms);

    len = MQTTSerialize_subscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic, (int*)&qos);
    if (len <= 0)
        goto exit;
    if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
        goto exit;             // there was a problem

    if (waitfor(c, SUBACK, &timer) == SUBACK)      // wait for suback 
    {
        int count = 0, grantedQoS = -1;
        unsigned short mypacketid;
        if (MQTTDeserialize_suback(&mypacketid, 1, &count, &grantedQoS, c->readbuf, c->readbuf_size) == 1)
            rc = grantedQoS; // 0, 1, 2 or 0x80 
        if (rc != 0x80)
        {
            int i;
            for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
            {
                if (c->messageHandlers[i].topicFilter == 0)
                {
                    c->messageHandlers[i].topicFilter = topicFilter;
                    c->messageHandlers[i].fp = messageHandler;
                    rc = 0;
                    break;
                }
            }
        }
    }
    else 
        rc = FAILURE;

exit:
#if defined(MQTT_TASK)
    MutexUnlock(&c->mutex);
#endif
    DeleteTimer(&timer);
    return rc;
}


int MQTTUnsubscribe(MQTTClient* c, const char* topicFilter)
{   
    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)
        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)
            rc = 0; 
    }
    else
        rc = FAILURE;

exit:
#if defined(MQTT_TASK)
    MutexUnlock(&c->mutex);
#endif
    DeleteTimer(&timer);
    return rc;
}


int MQTTPublish(MQTTClient* c, const char* topicName, MQTTMessage* message)
{
    int rc = FAILURE;
    Timer timer;
    int len = 0;       
    MQTTString topic = MQTTString_initializer;
    topic.cstring = (char *)topicName;


#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 defined(MQTT_TASK)
    MutexUnlock(&c->mutex);
#endif
    DeleteTimer(&timer);
    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

    c->isconnected = 0;

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


//#define __DEBUG

#ifdef __DEBUG
#include <stdarg.h>
#include <string.h>
static const char *getCurrentFileName()
{
    const char *p = strrchr(__FILE__,'\\');
    return ++p;
}
#define dprintf(fmt,...) rt_kprintf("%s,line:%d,"fmt,getCurrentFileName(),__LINE__,##__VA_ARGS__)
#else
#define dprintf(fmt,...)
#endif

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

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);
    ParseDomoticzMessage((char*)message->payload);
}

void set_host(char *host)
{
    opts.host = host;
}

void domoticz_thread_entry(void* parameter)
{
    int rc = 0;
    unsigned char buf[512]={0};//buf[100];
    unsigned char readbuf[512]={0};//readbuf[100];

    char* topic = "domoticz/out";

    Network n;
    MQTTClient c;

    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;  

    is_over = 0;
    rt_kprintf("domoticz_thread_entry\n");

//================== Added 2017-Apr-26 2:36:53 start ==================
    RegisterHardware(Create_LED0(),2);
    RegisterHardware(Create_LED1(),3);
    OpenHardwares();
    SetupDomoitczMessageParser();   
    SetEnableParseItem(KEY_IDX);
    SetEnableParseItem(KEY_NVALUE);
    SetEnableParseItem(KEY_SWITCH_TYPE);
    initHardwareSettings();
//================== Added 2017-Apr-26 2:36:53  end ===================

    NetworkInit(&n);
    NetworkConnect(&n, opts.host, opts.port);
    rt_kprintf("NetworkConnect ok!\n");
    //MQTTClientInit(&c, &n, 1000, buf, 512, readbuf, 512);
    dprintf("readbuf=%p,readbuf size=%u\n",readbuf,sizeof(readbuf));
    MQTTClientInit(&c, &n, 1000, buf, sizeof(buf), readbuf, sizeof(readbuf));

    data.willFlag = 0;
    data.MQTTVersion = 3;
    data.clientID.cstring = opts.clientid;
    data.username.cstring = opts.username;
    data.password.cstring = opts.password;

    data.keepAliveInterval = 60;
    data.cleansession = 1;
    rt_kprintf("Connecting to %s %d\n", opts.host, opts.port);

    rc = MQTTConnect(&c, &data);
    dprintf("Connected %d\n", rc);
    if(rc==-1)
    {
        rt_kprintf("MQTTConnect err!\n");
        return;
    }
    rt_kprintf("Subscribing to %s\n", topic);
    rc = MQTTSubscribe(&c, topic, opts.qos, messageArrived);
    dprintf("Subscribed %d\n", rc);

    while (!is_over)
    {
        //dprintf("\n");
        MQTTYield(&c, 1000);
    }

    rt_kprintf("Stopping\n");

    MQTTDisconnect(&c);
    NetworkDisconnect(&n);

}

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

/*@}*/

相关文章推荐

基于ZigBee和STM32的智能家居控制系统的设计与实现(二)

基于ZigBee和STM32的智能家居控制系统的设计与实现(二)  上一篇博客中总体介绍智能家居系统的基本实现原理,这篇博客和以后的几篇博客会详细进行相应的介绍。这里首先进行硬件电路的设计。硬件电路的...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(六)使用domoticz联合arm上的mosquitto实现Android客户端远程控制

本篇将使用mini2440上的domoticz服务平台和mosquitto,以domoticz上的虚拟设备为例,实现对设备的控制,以及使用Android的客户端APP实现远程控制。...

rt-thread通过TCP连接(网络+shell)方式调用list_if()导致网络断开的问题分析

1.平常我们都是用串口的方式通过rt-thread的finish来调试,但是在遇到串口不够用或者板子没有焊串口。我们就需要通过网络+finish的方式来调试板子。但是在调试板子的时候发现通过通过TCP...
  • bobbat
  • bobbat
  • 2015年01月31日 23:03
  • 1139

QT程序到arm板(s5pv210)的移植之旅

前记:         由于毕设的原因,将来需要移植QT程序到arm板子运行,故有此文。         看博客寻资料,看到一位作者写道:知识来源于互联网,必将回报互联网。赞。         ...
  • marc07
  • marc07
  • 2017年03月20日 11:19
  • 373

【STM8L】STM8L之内部16M晶振

本文介绍STM8L系列如何分别实现内部的16M晶振的使用

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

本文在前一篇实现了STM32平台利用MQTT协议对接domoticz平台控制LED灯的基础上,完善了网络连接和MQTT的broker连接过程,实现了断网重连功能。...

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

为了充分利用domoticz平台的对MQTT客户端的控制功能,现在,受控设备端代码的核心任务转移到了对domoticz/out主题的MQTT消息解析上。本文将设计一个简单框架来实现对其消息的解析和功能...

基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(四)交叉编译OpenSSL、c-ares、e2fsprogs和mosquitto

本篇主旨是编译安装mosquitto,其他的库是它的依赖库。后面我们交叉编译的程序都将放置在主机的”/usr/local/arm/”目录中,以区别主机本地的应用程序。 我的mimi2440的根文件系...

基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(七)交叉编译paho.mqtt.embedded-c库和嵌入式linux样例程序

本篇将把paho.mqtt.embedded-c官方的源代码交叉编译成数据包封装库和应用程序两部分,并把样例应用程序在mini2440上运行。...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(十)使用domoticz+mosquitto+Android客户端实现控制STM32板上的LED(一)
举报原因:
原因补充:

(最多只允许输入30个字)