为了充分利用domoticz平台的对MQTT客户端的控制功能,现在,受控设备端代码的核心任务转移到了对domoticz/out主题的MQTT消息解析上。本文将设计一个简单框架来实现对其消息的解析和功能回调。
一、对消息参数名字稍作研究。
我们的开关设备也就在这里封装的。
从这段代码中可以看到:
有10个参数名字是固定的
["idx"]
["id"]
["unit"]
["name"]
["dtype"]
["stype"]
["switchType"]
["RSSI"]
["Battery"]
["nvalue"]
还有个参数名字不固定:
"svalue"
它可以是以后缀1为开头:"svalue1" 或者"svalue2"、……"svalue(n)"
这意味着参数数量总体是不固定的。
我们实际的开关量收到的消息如下:
{
"Battery" : 255,
"RSSI" : 12,
"dtype" : "Light/Switch",
"id" : "00014051",
"idx" : 1,
"name" : "LED鐏,
"nvalue" : 1,
"stype" : "Switch",
"svalue1" : "0",
"switchType" : "On/Off",
"unit" : 1
}
收到了"svalue1"。
要写出一个灵活的框架来适应svalue数量可变,还是有点难度的,先不做这么复杂的。
后文中将写一个能够接收名字固定的参数,再加上"svalue1" 、"svalue2" ,共处理12个参数类型。(或许有时间写个对"svalue"参数数量可变的处理函数?)
当然,domoticz源码是公开的,我们也可以在c++级别源代码上添加自己所需要的参数。
2、场景消息。
在
void MQTT::SendSceneInfo(const unsigned long long SceneIdx, const std::string &SceneName)
中进行封装的。
暂时没用到,暂不分析。
详情请参考相关资料和源代码。
二、编写一个简单的消息解析框架。
框架设计如下:图中红色箭头的过程就是我们主要要实现的过程。
右边两个虚边框就是我们设计的框架。
具体实现代码如下:
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 --*/
/******************************************************************************
*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;
};
}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 --*/
/******************************************************************************
* 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();
extern void initHardwareSettings();
extern void CloseHardwares();
extern int RegisterHaraware(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
#include
#include
#include
//------------------------------------------------------------------------------
//GetHardWare interface
Hardware* g_HardwareContainer[HARDWARE_MAX_NUM];
/******************************************************************************
* 函数名: RegisterHaraware
* 功能描述:向硬件容器注册一个索引号为idx的硬件
* 参数1 :Hardware *hardware [I]:该硬件的指针
* 参数2 :int idx [I]:要分配的索引号
* 返回值: int ,成功则返回1,失败则返回错误号
* 创建时间:2017-Apr-17 22:08:58
* 修改时间:2017-Apr-17 22:08:58
* 版本记录:
* 其他说明:为了使用方便应该做一个配置文件以适配硬件信息
******************************************************************************/
int RegisterHaraware(Hardware *hardware,int idx)
{
int i;
assert(hardware);
for(i=0;iRegisterIDX==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;iRegisterIDX==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;iRegisterIDX==idx)
g_HardwareContainer[i] = 0;
return i;
}
return -1;
}
//------------------------------------------------------------------------------
//initionalize
int OpenHardwares()
{
int i;
int count=0;
for(i=0;iOpen)
return -i;//如果该硬件接口没有实现Open,则返回它在容器中的位置的相反数(<=0)
else
{
g_HardwareContainer[i]->Open();
count++;
}
}
}
return count;//如果成功返回执行Open的设备数量
}
void initHardwareSettings()
{
int i;
for(i=0;iInit)
{
g_HardwareContainer[i]->Init();
}
}
}
void CloseHardwares()
{
int i;
for(i=0;iClose)
g_HardwareContainer[i]->Close();
}
}
/*-- File end --*/
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();
extern void SetEnableParseItem(int item);
extern void SetDisableParseItem(int item);
extern int ParseDomoticzMessage(char* str);
//------------------------------------------------------------------------------
//hardware settings
extern void initHardWareSettings();
#ifdef __cplusplus
}
#endif
#endif /* #ifndef DOMOTICZ_MESSAGE_PARSER_H */
/*-- File end --*/
/******************************************************************************
* filename: DomoticzMessageParser.c
******************************************************************************/
/*-- #include --*/
#include "DomoticzMessageParser.h"
#include
#include
#include
#include
#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;i0)
{
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.strArg)>0)
{
dprintf("name=%s\n",pParser->bindHardware->parseArg.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.strArg)>0)
{
dprintf("id=%s\n",pParser->bindHardware->parseArg.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.uiVar))>0)
{
dprintf("uint=%u\n",pParser->bindHardware->parseArg.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.strArg)>0)
{
dprintf("dtype=%s\n",pParser->bindHardware->parseArg.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.strArg)>0)
{
dprintf("name=%s\n",pParser->bindHardware->parseArg.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.iVar))>0)
{
dprintf("nvalue=%d\n",pParser->bindHardware->parseArg.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.strArg)>0)
{
dprintf("svalue1=%s\n",pParser->bindHardware->parseArg.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.strArg)>0)
{
dprintf("svalue2=%s\n",pParser->bindHardware->parseArg.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.uiVar))>0)
{
dprintf("battery=%u\n",pParser->bindHardware->parseArg.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.iVar))>0)
{
dprintf("RSSI=%d\n",pParser->bindHardware->parseArg.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.strArg)>0)
{
dprintf("switchType=%s\n",pParser->bindHardware->parseArg.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=0 && itemMsgBuf[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 --*/
上面是框架,下面来两个例子(LED0、LED1):
LED0.h:
/******************************************************************************
* filename: LED0.h
******************************************************************************/
#ifndef LED0_H
#define LED0_H
#include "HardwareInterface.h"
extern Hardware* Create_LED0();
#endif /* #ifndef LED0_H */
/*-- File end --*/
#include "LED0.h"
extern int led_fd;
static Hardware LED0;
static int on;
static int led_no = 0;
/*
因为LED0~LED3均使用的led_fd文件描述符,应该统一执行打开、关闭,所以下面实现为
空操作
*/
int LED0_Open()
{
}
void LED0_Init()
{
ioctl(led_fd, 0, led_no);
}
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)
{
on = arg->iVar;
ioctl(led_fd, on, 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)
{
printf("%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;
}
LED1.h:
/******************************************************************************
* filename: LED1.h
******************************************************************************/
#ifndef LED1_H
#define LED1_H
#include "HardwareInterface.h"
extern Hardware* Create_LED1();
#endif /* #ifndef LED0_H */
/*-- File end --*/
LED1.c:
#include "LED1.h"
extern int led_fd;
static Hardware LED1;
static int on;
static int led_no = 1;
int LED1_Open()
{
}
void LED1_Init()
{
ioctl(led_fd, 0, led_no);
}
void LED1_Close()
{
}
int LED1_NVALUE_ParserCallbackImpl(ParserArg* arg)
{
//printf("LED0_IDX_ParserCallbackImpl is called!\n");
if(arg && arg->type==INT)
{
on = arg->iVar;
ioctl(led_fd, on, 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;
}
/*******************************************************************************
* Copyright (c) 2012, 2013 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:
* Ian Craggs - initial contribution
* Ian Craggs - change delimiter option from char to string
* Al Stockdill-Mander - Version using the embedded C client
*******************************************************************************/
/*
stdout subscriber
compulsory parameters:
topic to subscribe to
defaulted parameters:
--host localhost
--port 1883
--qos 2
--delimiter \n
--clientid stdout_subscriber
--userid none
--password none
for example:
stdoutsub topic/of/interest --host iot.eclipse.org
*/
#include
#include "MQTTClient.h"
#include
#include
#include
#include
//================== Added 2017-Apr-16 16:57:21 start ==================
#include
#include "DomoticzMessageParser.h"
#include "LED0.h"
#include "LED1.h"
//================== Added 2017-Apr-16 16:57:21 end ===================
volatile int toStop = 0;
#include
#define dprintf(msg,args...) printf("%s,line:%d,"msg,__FILE__,__LINE__,##args)
void usage()
{
printf("MQTT stdout subscriber\n");
printf("Usage: stdoutsub topicname , where options are:\n");
printf(" --host (default is localhost)\n");
printf(" --port (default is 1883)\n");
printf(" --qos (default is 2)\n");
printf(" --delimiter (default is \\n)\n");
printf(" --clientid (default is hostname+timestamp)\n");
printf(" --username none\n");
printf(" --password none\n");
printf(" --showtopics (default is on if the topic has a wildcard, else off)\n");
exit(-1);
}
void cfinish(int sig)
{
signal(SIGINT, NULL);
toStop = 1;
}
struct opts_struct
{
char* clientid;
int nodelimiter;
char* delimiter;
enum QoS qos;
char* username;
char* password;
char* host;
int port;
int showtopics;
} opts =
{
(char*)"stdout-subscriber", 0, (char*)"\n", QOS2, NULL, NULL, (char*)"localhost", 1883, 0
};
void getopts(int argc, char** argv)
{
int count = 2;
while (count < argc)
{
if (strcmp(argv[count], "--qos") == 0)
{
if (++count < argc)
{
if (strcmp(argv[count], "0") == 0)
opts.qos = QOS0;
else if (strcmp(argv[count], "1") == 0)
opts.qos = QOS1;
else if (strcmp(argv[count], "2") == 0)
opts.qos = QOS2;
else
usage();
}
else
usage();
}
else if (strcmp(argv[count], "--host") == 0)
{
if (++count < argc)
opts.host = argv[count];
else
usage();
}
else if (strcmp(argv[count], "--port") == 0)
{
if (++count < argc)
opts.port = atoi(argv[count]);
else
usage();
}
else if (strcmp(argv[count], "--clientid") == 0)
{
if (++count < argc)
opts.clientid = argv[count];
else
usage();
}
else if (strcmp(argv[count], "--username") == 0)
{
if (++count < argc)
opts.username = argv[count];
else
usage();
}
else if (strcmp(argv[count], "--password") == 0)
{
if (++count < argc)
opts.password = argv[count];
else
usage();
}
else if (strcmp(argv[count], "--delimiter") == 0)
{
if (++count < argc)
opts.delimiter = argv[count];
else
opts.nodelimiter = 1;
}
else if (strcmp(argv[count], "--showtopics") == 0)
{
if (++count < argc)
{
if (strcmp(argv[count], "on") == 0)
opts.showtopics = 1;
else if (strcmp(argv[count], "off") == 0)
opts.showtopics = 0;
else
usage();
}
else
usage();
}
count++;
}
}
void messageArrived(MessageData* md)
{
MQTTMessage* message = md->message;
if (opts.showtopics)
printf("%.*s\t", md->topicName->lenstring.len, md->topicName->lenstring.data);
if (opts.nodelimiter)
printf("%.*s", (int)message->payloadlen, (char*)message->payload);
else
printf("%.*s%s", (int)message->payloadlen, (char*)message->payload, opts.delimiter);
//fflush(stdout);
//================== Added 2017-Apr-16 16:56:59 start ==================
ParseDomoticzMessage((char*)message->payload);
//================== Added 2017-Apr-16 16:56:59 end ===================
}
int led_fd;
int main(int argc, char** argv)
{
int rc = 0;
unsigned char buf[100];
unsigned char readbuf[100];
if (argc < 2)
usage();
char* topic = argv[1];
if (strchr(topic, '#') || strchr(topic, '+'))
opts.showtopics = 1;
if (opts.showtopics)
printf("topic is %s\n", topic);
getopts(argc, argv);
Network n;
//Client c;
MQTTClient c;
signal(SIGINT, cfinish);
signal(SIGTERM, cfinish);
//================== Added 2017-Apr-16 16:56:44 start ==================
led_fd = open("/dev/leds0", 0);
if (led_fd < 0) {
led_fd = open("/dev/leds", 0);
}
if (led_fd < 0) {
perror("open device leds");
exit(1);
}
RegisterHaraware(Create_LED0(),1);
RegisterHaraware(Create_LED1(),2);
OpenHardwares();
SetupDomoitczMessageParser();
SetEnableParseItem(KEY_IDX);
SetEnableParseItem(KEY_NVALUE);
SetEnableParseItem(KEY_SWITCH_TYPE);
initHardwareSettings();
//================== Added 2017-Apr-16 16:56:44 end ===================
NetworkInit(&n);
NetworkConnect(&n, opts.host, opts.port);
MQTTClientInit(&c, &n, 1000, buf, 100, readbuf, 100);
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
data.willFlag = 0;
data.MQTTVersion = 3;
data.clientID.cstring = opts.clientid;
data.username.cstring = opts.username;
data.password.cstring = opts.password;
data.keepAliveInterval = 10;
data.cleansession = 1;
printf("Connecting to %s %d\n", opts.host, opts.port);
rc = MQTTConnect(&c, &data);
printf("Connected %d\n", rc);
printf("Subscribing to %s\n", topic);
rc = MQTTSubscribe(&c, topic, opts.qos, messageArrived);
printf("Subscribed %d\n", rc);
while (!toStop)
{
MQTTYield(&c, 1000);
}
printf("Stopping\n");
MQTTDisconnect(&c);
NetworkDisconnect(&n);
//================== Added 2017-Apr-16 16:57:50 start ==================
CloseHardwares();
close(led_fd);
exit(0);
//================== Added 2017-Apr-16 16:57:50 end ===================
return 0;
}
Makefile:
TOPDIR = ../..
CC:=arm-linux-gcc
INCDIR :=-I/usr/local/arm/paho.mqtt.embedded-c/include
COMPILE.c = $(CC) $(CFLAGS) $(INCDIR) -MMD -c
LINK.c = $(CC) $(LDFLAGS) -lpthread -lrt
.PHONY: all
%.o:%.c
$(COMPILE.c) $< -o $@
SRC_FILE := \
MQTTClient.c \
MQTTLinux.c \
DomoticzMessageParser.c \
HardwareControl.c \
LED0.c \
LED1.c \
stdoutsub.c
OBJS := $(addsuffix .o, $(basename $(SRC_FILE)))
DEPS :=$(OBJS:.o=.d)
all:mqtt
mqtt:$(OBJS)
$(LINK.c) $(OBJS) -lpaho-embed-mqtt3c -L/usr/local/arm/paho.mqtt.embedded-c/lib -o $@
install:
cp mqtt /work/rootfs/usr/my/
clean:
rm -f $(OBJS) mqtt
distclean:clean
rm -f $(DEPS)
-include $(DEPS)
make
make install
可执行文件已经拷贝到NFS的目标板目录上去了。
这个框架的代码在GCC上编译是OK的,理论上支持C99的编译器都应该没问题,其他编译器没有试过。
框架本身理论上可以用在其他嵌入式操作系统上,不过没试过。
用它来做个探索,方便后续的STM32平台的开发。