xpl lib
Dependents: XPL-App4_cleanup XPL-App5
Revision 0:23c0d0e1c31d, committed 2018-10-09
- Comitter:
- richnash
- Date:
- Tue Oct 09 17:37:05 2018 +0000
- Commit message:
- ready to move to cli to explore D11 pin fix
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xPL.cpp Tue Oct 09 17:37:05 2018 +0000 @@ -0,0 +1,402 @@ +/* + * xPL.Arduino v0.1, xPL Implementation for Arduino + * + * This code is parsing a xPL message stored in 'received' buffer + * - isolate and store in 'line' buffer each part of the message -> detection of EOL character (DEC 10) + * - analyse 'line', function of its number and store information in xpl_header memory + * - check for each step if the message respect xPL protocol + * - parse each command line + * + * Copyright (C) 2012 johan@pirlouit.ch, olivier.lebrun@gmail.com + * Original version by Gromain59@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "xPL.h" + +#define XPL_LINE_MESSAGE_BUFFER_MAX 128 // max length of a line // maximum command in a xpl message +#define XPL_END_OF_LINE 10 + +// define the line number identifier +#define XPL_MESSAGE_TYPE_IDENTIFIER 1 +#define XPL_OPEN_HEADER 2 +#define XPL_HOP_COUNT 3 +#define XPL_SOURCE 4 +#define XPL_TARGET 5 +#define XPL_CLOSE_HEADER 6 +#define XPL_SCHEMA_IDENTIFIER 7 +#define XPL_OPEN_SCHEMA 8 + +// Heartbeat request class definition +//prog_char XPL_HBEAT_REQUEST_CLASS_ID[] PROGMEM = "hbeat"; +//prog_char XPL_HBEAT_REQUEST_TYPE_ID[] PROGMEM = "request"; +//prog_char XPL_HBEAT_ANSWER_CLASS_ID[] PROGMEM = "hbeat"; +//prog_char XPL_HBEAT_ANSWER_TYPE_ID[] PROGMEM = "basic"; //app, basic +#define XPL_HBEAT_REQUEST_CLASS_ID "hbeat" +#define XPL_HBEAT_REQUEST_TYPE_ID "request" +#define XPL_HBEAT_ANSWER_CLASS_ID "hbeat" +#define XPL_HBEAT_ANSWER_TYPE_ID "app" + +/* xPL Class */ +xPL::xPL() +{ + udp_port = XPL_UDP_PORT; + + SendExternal = NULL; + +#ifdef ENABLE_PARSING + AfterParseAction = NULL; + + last_heartbeat = 0; + hbeat_interval = XPL_DEFAULT_HEARTBEAT_INTERVAL; + xpl_accepted = XPL_ACCEPT_ALL; +#endif +} + +xPL::~xPL() +{ +} + +/// Set the source of outgoing xPL messages +void xPL::SetSource(const char * _vendorId, const char * _deviceId, const char * _instanceId) +{ + memcpy(source.vendor_id, _vendorId, XPL_VENDOR_ID_MAX); + memcpy(source.device_id, _deviceId, XPL_DEVICE_ID_MAX); + memcpy(source.instance_id, _instanceId, XPL_INSTANCE_ID_MAX); +} + +/** + * \brief Send an xPL message + * \details There is no validation of the message, it is sent as is. + * \param buffer buffer containing the xPL message. + */ +void xPL::SendMessage(char *_buffer) +{ + (*SendExternal)(_buffer); +} + +/** + * \brief Send an xPL message + * \details There is no validation of the message, it is sent as is. + * \param message An xPL message. + * \param _useDefaultSource if true, insert the default source (defined in SetSource) on the message. + */ +void xPL::SendMessage(xPL_Message *_message, bool _useDefaultSource) +{ + if(_useDefaultSource) + { + _message->SetSource(source.vendor_id, source.device_id, source.instance_id); + } + + SendMessage(_message->toString()); +} + +#ifdef ENABLE_PARSING + +/** + * \brief xPL Stuff + * \details Send heartbeat messages at "hbeat_interval" interval + */ +void xPL::Process() +{ + static bool bFirstRun = true; + + // Check heartbeat + send + //if ((millis()-last_heartbeat >= (unsigned long)hbeat_interval * 1000) + // || (bFirstRun && millis() > 3000)) + if ((clock()-last_heartbeat >= (unsigned long)hbeat_interval * 1000) + || (bFirstRun && clock() > 3000)) + { + SendHBeat(); + bFirstRun = false; + } +} + +/** + * \brief Parse an ingoing xPL message + * \details Parse a message, check for hearbeat request and call user defined callback for post processing. + * \param buffer buffer of the ingoing UDP Packet + */ +void xPL::ParseInputMessage(char* _buffer) +{ + xPL_Message* xPLMessage = new xPL_Message(); + Parse(xPLMessage, _buffer); + + // check if the message is an hbeat.request to send a heartbeat + if (CheckHBeatRequest(xPLMessage)) + { + SendHBeat(); + } + + // call the user defined callback to execute an action + if(AfterParseAction != NULL) + { + (*AfterParseAction)(xPLMessage); + } + + delete xPLMessage; +} + +/** + * \brief Check the xPL message target + * \details Check if the xPL message is for us + * \param _message an xPL message + */ +bool xPL::TargetIsMe(xPL_Message * _message) +{ + if (memcmp(_message->target.vendor_id, source.vendor_id, strlen(source.vendor_id)) != 0) + return false; + + if (memcmp(_message->target.device_id, source.device_id, strlen(source.device_id)) != 0) + return false; + + if (memcmp(_message->target.instance_id, source.instance_id, strlen(source.instance_id)) != 0) + return false; + + return true; +} + +/** + * \brief Send a heartbeat message + */ +void xPL::SendHBeat() +{ + last_heartbeat = clock(); //millis(); + char buffer[XPL_MESSAGE_BUFFER_MAX]; + +// sprintf_P(buffer, PSTR("xpl-stat\n{\nhop=1\nsource=%s-%s.%s\ntarget=*\n}\n%s.%s\n{\ninterval=%d\n}\n"), source.vendor_id, source.device_id, source.instance_id, XPL_HBEAT_ANSWER_CLASS_ID, XPL_HBEAT_ANSWER_TYPE_ID, hbeat_interval); + //sprintf(buffer, "xpl-stat\r\n{\r\nhop=1\r\nsource=%s-%s.%s\r\ntarget=*\r\n}\r\n%s.%s\r\n{\r\ninterval=%d\r\nport=3865\r\nremote-ip=8.8.8.8\r\nversion=1.0\r\n}\r\n", source.vendor_id, source.device_id, source.instance_id, XPL_HBEAT_ANSWER_CLASS_ID, XPL_HBEAT_ANSWER_TYPE_ID, hbeat_interval); + sprintf(buffer, "xpl-stat\n{\nhop=1\nsource=%s-%s.%s\ntarget=*\n}\n%s.%s\n{\ninterval=%d\nport=3865\nremote-ip=8.8.8.8\nversion=1.0\n}\n", source.vendor_id, source.device_id, source.instance_id, XPL_HBEAT_ANSWER_CLASS_ID, XPL_HBEAT_ANSWER_TYPE_ID, hbeat_interval); + + //(*SendExternal)(buffer); + SendMessage(buffer); + + printf("XPL: HB Sent\r\n"); +} + +/** + * \brief Check if the message is a heartbeat request + * \param _message an xPL message + */ +inline bool xPL::CheckHBeatRequest(xPL_Message* _message) +{ + if (!TargetIsMe(_message)) + return false; + + return _message->IsSchema(XPL_HBEAT_REQUEST_CLASS_ID, XPL_HBEAT_REQUEST_TYPE_ID); +} + +/** + * \brief Parse a buffer and generate a xPL_Message + * \details Line based xPL parser + * \param _xPLMessage the result xPL message + * \param _message the buffer + */ +void xPL::Parse(xPL_Message* _xPLMessage, char* _buffer) +{ + int len = strlen(_buffer); + + short j=0; + short line=0; + int result=0; + char lineBuffer[XPL_LINE_MESSAGE_BUFFER_MAX+1]; + + // read each character of the message + for(short i = 0; i < len; i++) + { + // load byte by byte in 'line' buffer, until '\n' is detected + if(_buffer[i] == XPL_END_OF_LINE) // is it a linefeed (ASCII: 10 decimal) + { + ++line; + lineBuffer[j]='\0'; // add the end of string id + + if(line <= XPL_OPEN_SCHEMA) + { + // first part: header and schema determination + // we analyse the line, function of the line number in the xpl message + result = AnalyseHeaderLine(_xPLMessage, lineBuffer ,line); + } + + if(line > XPL_OPEN_SCHEMA) + { + // second part: command line + // we analyse the specific command line, function of the line number in the xpl message + result = AnalyseCommandLine(_xPLMessage, lineBuffer, line-9, j); + + if(result == _xPLMessage->command_count+1) + break; + } + + if (result < 0) break; + + j = 0; // reset the buffer pointer + clearStr(lineBuffer); // clear the buffer + } + else + { + // next character + lineBuffer[j++] = _buffer[i]; + } + } +} + +/** + * \brief Parse the header part of the xPL message line by line + * \param _xPLMessage the result xPL message + * \param _buffer the line to parse + * \param _line the line number + */ +short xPL::AnalyseHeaderLine(xPL_Message* _xPLMessage, char* _buffer, short _line) +{ + switch (_line) + { + case XPL_MESSAGE_TYPE_IDENTIFIER: //message type identifier + + if (memcmp(_buffer,"xpl-",4)==0) //xpl + { + if (memcmp(_buffer+4,"cmnd",4)==0) //command type + { + _xPLMessage->type=XPL_CMND; //xpl-cmnd + } + else if (memcmp(_buffer+4,"stat",4)==0) //statut type + { + _xPLMessage->type=XPL_STAT; //xpl-stat + } + else if (memcmp(_buffer+4,"trig",4)==0) // trigger type + { + _xPLMessage->type=XPL_TRIG; //xpl-trig + } + } + else + { + return 0; //unknown message + } + + return 1; + + //break; + + case XPL_OPEN_HEADER: //header begin + + if (memcmp(_buffer,"{",1)==0) + { + return 2; + } + //else + //{ + return -2; + //} + + //break; + + case XPL_HOP_COUNT: //hop + if (sscanf(_buffer, XPL_HOP_COUNT_PARSER, &_xPLMessage->hop)) + { + return 3; + } + //else + //{ + return -3; + //} + + //break; + + case XPL_SOURCE: //source + if (sscanf(_buffer, XPL_SOURCE_PARSER, &_xPLMessage->source.vendor_id, &_xPLMessage->source.device_id, &_xPLMessage->source.instance_id) == 3) + { + return 4; + } + //else + //{ + return -4; + //} + + //break; + + case XPL_TARGET: //target + + if (sscanf(_buffer, XPL_TARGET_PARSER, &_xPLMessage->target.vendor_id, &_xPLMessage->target.device_id, &_xPLMessage->target.instance_id) == 3) + { + return 5; + } + //else + //{ + if(memcmp(_xPLMessage->target.vendor_id,"*", 1) == 0) // check if broadcast message + { + return 5; + } + //else + //{ + return -5; + //} + //} + //break; + + case XPL_CLOSE_HEADER: //header end + if (memcmp(_buffer,"}",1)==0) + { + return 6; + } + //else + //{ + return -6; + //} + + //break; + + case XPL_SCHEMA_IDENTIFIER: //schema + sscanf(_buffer, XPL_SCHEMA_PARSER, &_xPLMessage->schema.class_id, &_xPLMessage->schema.type_id); + return 7; + + case XPL_OPEN_SCHEMA: //header begin + if (memcmp(_buffer,"{",1)==0) + { + return 8; + } + //else + //{ + return -8; + //} + //break; + } + + return -100; +} + +/** + * \brief Parse the body part of the xPL message line by line + * \param _xPLMessage the result xPL message + * \param _buffer the line to parse + * \param _command_line the line number + */ +short xPL::AnalyseCommandLine(xPL_Message * _xPLMessage, char *_buffer, short _command_line, short line_length) +{ + if (memcmp(_buffer,"}",1) == 0) // End of schema + { + return _xPLMessage->command_count+1; + } + else // parse the next command + { + struct_command newcmd; + + sscanf(_buffer, XPL_COMMAND_PARSER, &newcmd.name, &newcmd.value); + + _xPLMessage->AddCommand(newcmd.name, newcmd.value); + + return _command_line; + } +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xPL.h Tue Oct 09 17:37:05 2018 +0000 @@ -0,0 +1,104 @@ +/* + * xPL.Arduino v0.1, xPL Implementation for Arduino + * + * This code is parsing a xPL message stored in 'received' buffer + * - isolate and store in 'line' buffer each part of the message -> detection of EOL character (DEC 10) + * - analyse 'line', function of its number and store information in xpl_header memory + * - check for each step if the message respect xPL protocol + * - parse each command line + * + * Copyright (C) 2012 johan@pirlouit.ch, olivier.lebrun@gmail.com + * Original version by Gromain59@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef xPL_h +#define xPL_h + +#define ENABLE_PARSING 1 + +//#include "Arduino.h" +#include "mbed.h" + +#include "xPL_utils.h" +#include "xPL_Message.h" + +#define XPL_CMND 1 +#define XPL_STAT 2 +#define XPL_TRIG 3 + +#define XPL_DEFAULT_HEARTBEAT_INTERVAL 300 + +#define XPL_UDP_PORT 3865 + +#define XPL_PORT_L 0x19 +#define XPL_PORT_H 0xF + +typedef enum {XPL_ACCEPT_ALL, XPL_ACCEPT_SELF, XPL_ACCEPT_SELF_ANY} xpl_accepted_type; +// XPL_ACCEPT_ALL = all xpl messages +// XPL_ACCEPT_SELF = only for me +// XPL_ACCEPT_SELF_ANY = only for me and any (*) + +typedef void (*xPLSendExternal)(char*); +typedef void (*xPLAfterParseAction)(xPL_Message * message); + +class xPL +{ + public: + xPL(); + ~xPL(); + + struct_id source; // my source + unsigned short udp_port; // default 3865 + + xPLSendExternal SendExternal; + + void SendMessage(char *); + void SendMessage(xPL_Message *, bool = true); + + void SetSource(const char *,const char *,const char *); // define my source + +#ifdef ENABLE_PARSING + xPLAfterParseAction AfterParseAction; + + + //byte hbeat_interval; // default 5 + short hbeat_interval; // default 5 + xpl_accepted_type xpl_accepted; + + + void Process(); + void ParseInputMessage(char *buffer); + + bool TargetIsMe(xPL_Message * message); + + void SendHBeat(); + + private: + //void ClearData(); + unsigned long last_heartbeat; +// void SendHBeat(); + bool CheckHBeatRequest(xPL_Message * message); + + void Parse(xPL_Message *, char *); + //byte AnalyseHeaderLine(xPL_Message *, char *, byte ); + //byte AnalyseCommandLine(xPL_Message *, char *, byte, byte ); + short AnalyseHeaderLine(xPL_Message *, char *, short ); + short AnalyseCommandLine(xPL_Message *, char *, short, short ); +#endif +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xPL_Message.cpp Tue Oct 09 17:37:05 2018 +0000 @@ -0,0 +1,215 @@ +/* + * xPL.Arduino v0.1, xPL Implementation for Arduino + * + * This code is parsing a xPL message stored in 'received' buffer + * - isolate and store in 'line' buffer each part of the message -> detection of EOL character (DEC 10) + * - analyse 'line', function of its number and store information in xpl_header memory + * - check for each step if the message respect xPL protocol + * - parse each command line + * + * Copyright (C) 2012 johan@pirlouit.ch, olivier.lebrun@gmail.com + * Original version by Gromain59@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "xPL_Message.h" + +xPL_Message::xPL_Message() +{ + command = NULL; + command_count = 0; +} + +xPL_Message::~xPL_Message() +{ + if(command != NULL) + { + free(command); + } +} + +/** + * \brief Set source of the message (optional) + * \param _vendorId vendor id. + * \param _deviceId device id. + * \param _instanceId instance id. + */ +void xPL_Message::SetSource(char * _vendorId, char * _deviceId, char * _instanceId) +{ + memcpy(source.vendor_id, _vendorId, XPL_VENDOR_ID_MAX + 1); + memcpy(source.device_id, _deviceId, XPL_DEVICE_ID_MAX + 1); + memcpy(source.instance_id, _instanceId, XPL_INSTANCE_ID_MAX + 1); +} + +/** + * \brief Set Target of the message + * \details insert "*" into _vendorId to broadcast the message + * \param _vendorId vendor id. + * \param _deviceId device id. (optional) + * \param _instanceId instance id. (optional) + */ +void xPL_Message::SetTarget(const char * _vendorId, const char * _deviceId, const char * _instanceId) +{ + memcpy(target.vendor_id, _vendorId, XPL_VENDOR_ID_MAX + 1); + if(_deviceId != NULL) memcpy(target.device_id, _deviceId, XPL_DEVICE_ID_MAX + 1); + if(_instanceId != NULL) memcpy(target.instance_id, _instanceId, XPL_INSTANCE_ID_MAX + 1); +} + +/** + * \brief Set Schema of the message + * \param _classId Class + * \param _typeId Type + */ +void xPL_Message::SetSchema(const char * _classId, const char * _typeId) +{ + memcpy(schema.class_id, _classId, XPL_CLASS_ID_MAX + 1); + memcpy(schema.type_id, _typeId, XPL_TYPE_ID_MAX + 1); +} + +/** + * \brief Create a new command/value pair + * \details Check if maximun command is reach and add memory to command array + */ +bool xPL_Message::CreateCommand() +{ + struct_command *ncommand; + + // Maximun command reach + // To avoid oom, we arbitrary accept only XPL_MESSAGE_COMMAND_MAX command + if(command_count > XPL_MESSAGE_COMMAND_MAX) + return false; + + ncommand = (struct_command*)realloc ( command, (command_count + 1) * sizeof(struct_command) ); + + if (ncommand != NULL) { + command = ncommand; + command_count++; + return true; + } + else + return false; +} + +/** + * \brief Add a command to the message's body + * \details PROGMEM Version + * \param _name name of the command + * \param _value value of the command + */ +bool xPL_Message::AddCommand(const char* _name, const char* _value) +{ + if(!CreateCommand()) return false; + + struct_command newcmd; + memcpy(newcmd.name, _name, XPL_NAME_LENGTH_MAX + 1); + memcpy(newcmd.value, _value, XPL_VALUE_LENGTH_MAX + 1); + command[command_count-1] = newcmd; + return true; +} + +/** + * \brief Add a command to the message's body + * \details char* Version + * \param _name name of the command + * \param _value value of the command + */ +bool xPL_Message::AddCommand(char* _name, char* _value) +{ + if(!CreateCommand()) return false; + + struct_command newcmd; + memcpy(newcmd.name, _name, XPL_NAME_LENGTH_MAX + 1); + memcpy(newcmd.value, _value, XPL_VALUE_LENGTH_MAX + 1); + command[command_count-1] = newcmd; + return true; +} + +/** + * \brief Convert xPL_Message to char* buffer + */ +char message_buffer[XPL_MESSAGE_BUFFER_MAX]; +char* xPL_Message::toString() +{ + int pos; + + clearStr(message_buffer); + + switch(type) + { + case (XPL_CMND): + pos = sprintf(message_buffer, "xpl-cmnd"); + break; + case (XPL_STAT): + pos = sprintf(message_buffer, "xpl-stat"); + break; + case (XPL_TRIG): + pos = sprintf(message_buffer, "xpl-trig"); + break; + } + + pos += sprintf(message_buffer + pos, "\n{\nhop=1\nsource=%s-%s.%s\ntarget=", source.vendor_id, source.device_id, source.instance_id); + + if(memcmp(target.vendor_id,"*", 1) == 0) // check if broadcast message + { + pos += sprintf(message_buffer + pos, "*\n}\n"); + } + else + { + pos += sprintf(message_buffer + pos, "%s-%s.%s\n}\n",target.vendor_id, target.device_id, target.instance_id); + } + + pos += sprintf(message_buffer + pos, "%s.%s\n{\n",schema.class_id, schema.type_id); + + for (short i=0; i<command_count; i++) + { + pos += sprintf(message_buffer + pos, "%s=%s\n", command[i].name, command[i].value); + } + + sprintf(message_buffer + pos, "}\n"); + + return message_buffer; +} + +bool xPL_Message::IsSchema(char* _classId, char* _typeId) +{ + if (strcmp(schema.class_id, _classId) == 0) + { + if (strcmp(schema.type_id, _typeId) == 0) + { + return true; + } + } + + return false; +} + +/** + * \brief Check the message's schema + * \param _classId class + * \param _typeId type + */ +bool xPL_Message::IsSchema(const char* _classId, const char* _typeId) +{ + if (strncmp(schema.class_id, _classId, XPL_CLASS_ID_MAX) == 0) + { + if (strncmp(schema.type_id, _typeId, XPL_TYPE_ID_MAX) == 0) + { + return true; + } + } + + return false; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xPL_Message.h Tue Oct 09 17:37:05 2018 +0000 @@ -0,0 +1,76 @@ +/* + * xPL.Arduino v0.1, xPL Implementation for Arduino + * + * This code is parsing a xPL message stored in 'received' buffer + * - isolate and store in 'line' buffer each part of the message -> detection of EOL character (DEC 10) + * - analyse 'line', function of its number and store information in xpl_header memory + * - check for each step if the message respect xPL protocol + * - parse each command line + * + * Copyright (C) 2012 johan@pirlouit.ch, olivier.lebrun@gmail.com + * Original version by Gromain59@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef xPLMessage_h +#define xPLMessage_h + +//#include "Arduino.h" +#include "mbed.h" +#include "xPL_utils.h" + +#define XPL_CMND 1 +#define XPL_STAT 2 +#define XPL_TRIG 3 + +#define XPL_MESSAGE_BUFFER_MAX 256 // going over 256 would mean changing index from byte to int +#define XPL_MESSAGE_COMMAND_MAX 10 + +class xPL_Message +{ + public: + short type; // 1=cmnd, 2=stat, 3=trig + short hop; // Hop count + + struct_id source; // source identification + struct_id target; // target identification + + struct_xpl_schema schema; + struct_command *command; + //byte command_count; + short command_count; + + bool AddCommand(const char *,const char *); + bool AddCommand(char*, char*); + + xPL_Message(); + ~xPL_Message(); + + char *toString(); + + bool IsSchema(char*, char*); + bool IsSchema(const char*, const char*); + + void SetSource(char *, char *, char *); // define my source + void SetTarget(const char *, const char * = NULL, const char * = NULL); + void SetSchema(const char *, const char *); + + + private: + bool CreateCommand(); +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xPL_utils.cpp Tue Oct 09 17:37:05 2018 +0000 @@ -0,0 +1,38 @@ +/* + * xPL.Arduino v0.1, xPL Implementation for Arduino + * + * This code is parsing a xPL message stored in 'received' buffer + * - isolate and store in 'line' buffer each part of the message -> detection of EOL character (DEC 10) + * - analyse 'line', function of its number and store information in xpl_header memory + * - check for each step if the message respect xPL protocol + * - parse each command line + * + * Copyright (C) 2012 johan@pirlouit.ch, olivier.lebrun@gmail.com + * Original version by Gromain59@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "xPL_utils.h" + +// Function to clear a string +void clearStr (char* str) +{ + int len = strlen(str); + for (short c = 0; c < len; c++) + { + str[c] = 0; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xPL_utils.h Tue Oct 09 17:37:05 2018 +0000 @@ -0,0 +1,74 @@ +/* + * xPL.Arduino v0.1, xPL Implementation for Arduino + * + * This code is parsing a xPL message stored in 'received' buffer + * - isolate and store in 'line' buffer each part of the message -> detection of EOL character (DEC 10) + * - analyse 'line', function of its number and store information in xpl_header memory + * - check for each step if the message respect xPL protocol + * - parse each command line + * + * Copyright (C) 2012 johan@pirlouit.ch, olivier.lebrun@gmail.com + * Original version by Gromain59@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef xPLutil_h +#define xPLutil_h + +//#include "Arduino.h" +#include "mbed.h" +#include <string.h> + +#define XPL_VENDOR_ID_MAX 8 +#define XPL_DEVICE_ID_MAX 20 +#define XPL_INSTANCE_ID_MAX 16 +#define XPL_CLASS_ID_MAX 8 +#define XPL_TYPE_ID_MAX 8 +#define XPL_NAME_LENGTH_MAX 20 +#define XPL_VALUE_LENGTH_MAX 128 // should be 128 but need to spare RAM + +#define XPL_HOP_COUNT_PARSER "hop=%d" +#define XPL_SOURCE_PARSER "source=%20[^-]-%20[^'.'].%16s" +#define XPL_TARGET_PARSER "target=%20[^-]-%20[^'.'].%16s" +#define XPL_SCHEMA_PARSER "%8[^'.'].%8s" +// 32 shall match XPL_VALUE_LENGTH_MAX +#define XPL_COMMAND_PARSER "%20[^'=']=%32s" + +typedef struct struct_id struct_id; +struct struct_id // source or target +{ + char vendor_id[XPL_VENDOR_ID_MAX+1]; // vendor id + char device_id[XPL_DEVICE_ID_MAX+1]; // device id + char instance_id[XPL_INSTANCE_ID_MAX+1]; // instance id +}; + +typedef struct struct_xpl_schema struct_xpl_schema; +struct struct_xpl_schema +{ + char class_id[XPL_CLASS_ID_MAX+1]; // class of schema (x10, alarm...) + char type_id[XPL_TYPE_ID_MAX+1]; // type of schema (basic...) +}; + +typedef struct struct_command struct_command; +struct struct_command // source or target +{ + char name[XPL_NAME_LENGTH_MAX+1]; // vendor id + char value[XPL_VALUE_LENGTH_MAX+1]; // device id +}; + +void clearStr (char* str); + +#endif