本文将在前面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;
}
/*@}*/