xpl lib

Dependents:   XPL-App4_cleanup XPL-App5

xPL_Message.cpp

Committer:
richnash
Date:
2018-10-09
Revision:
0:23c0d0e1c31d

File content as of revision 0:23c0d0e1c31d:

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