
mbed xpl base example
Revision 0:0fc77069cf70, committed 2018-07-30
- Comitter:
- richnash
- Date:
- Mon Jul 30 14:10:27 2018 +0000
- Commit message:
- base xpl listener sender
Changed in this revision
diff -r 000000000000 -r 0fc77069cf70 Watchdog.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Watchdog.cpp Mon Jul 30 14:10:27 2018 +0000 @@ -0,0 +1,132 @@ +/// @file Watchdog.cpp provides the interface to the Watchdog module +/// +/// This provides basic Watchdog service for the mbed. You can configure +/// various timeout intervals that meet your system needs. Additionally, +/// it is possible to identify if the Watchdog was the cause of any +/// system restart. +/// +/// Adapted from Simon's Watchdog code from http://mbed.org/forum/mbed/topic/508/ +/// +/// @note Copyright © 2011 by Smartware Computing, all rights reserved. +/// This software may be used to derive new software, as long as +/// this copyright statement remains in the source file. +/// @author David Smart +/// +/// @note Copyright © 2015 by NBRemond, all rights reserved. +/// This software may be used to derive new software, as long as +/// this copyright statement remains in the source file. +/// +/// Added support for STM32 Nucleo platforms +/// +/// @author Bernaérd Remond +/// + +//#define LPC +#define ST_NUCLEO + + +#include "mbed.h" +#include "Watchdog.h" + + +/// Watchdog gets instantiated at the module level +Watchdog::Watchdog() { +#ifdef LPC + wdreset = (LPC_WDT->WDMOD >> 2) & 1; // capture the cause of the previous reset +#endif +#ifdef ST_NUCLEO + // capture the cause of the previous reset + /* Check if the system has resumed from IWDG reset */ + if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) { + //if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST)) { + wdreset = true; + } + else { + wdreset = false; + } + +// wdreset = false; +#endif + +} + +/// Load timeout value in watchdog timer and enable +void Watchdog::Configure(float timeout) { +#ifdef LPC + LPC_WDT->WDCLKSEL = 0x1; // Set CLK src to PCLK + uint32_t clk = SystemCoreClock / 16; // WD has a fixed /4 prescaler, PCLK default is /4 + LPC_WDT->WDTC = (uint32_t)(timeout * (float)clk); + LPC_WDT->WDMOD = 0x3; // Enabled and Reset +#endif +#ifdef ST_NUCLEO + // see http://embedded-lab.com/blog/?p=9662 + #define LsiFreq (45000) + + uint16_t PrescalerCode; + uint16_t Prescaler; + uint16_t ReloadValue; + float Calculated_timeout; + + if ((timeout * (LsiFreq/4)) < 0x7FF) { + PrescalerCode = IWDG_PRESCALER_4; + Prescaler = 4; + } + else if ((timeout * (LsiFreq/8)) < 0xFF0) { + PrescalerCode = IWDG_PRESCALER_8; + Prescaler = 8; + } + else if ((timeout * (LsiFreq/16)) < 0xFF0) { + PrescalerCode = IWDG_PRESCALER_16; + Prescaler = 16; + } + else if ((timeout * (LsiFreq/32)) < 0xFF0) { + PrescalerCode = IWDG_PRESCALER_32; + Prescaler = 32; + } + else if ((timeout * (LsiFreq/64)) < 0xFF0) { + PrescalerCode = IWDG_PRESCALER_64; + Prescaler = 64; + } + else if ((timeout * (LsiFreq/128)) < 0xFF0) { + PrescalerCode = IWDG_PRESCALER_128; + Prescaler = 128; + } + else { + PrescalerCode = IWDG_PRESCALER_256; + Prescaler = 256; + } + + // specifies the IWDG Reload value. This parameter must be a number between 0 and 0x0FFF. + ReloadValue = (uint32_t)(timeout * (LsiFreq/Prescaler)); + + Calculated_timeout = ((float)(Prescaler * ReloadValue)) / LsiFreq; + //printf("WATCHDOG set with prescaler:%d reload value: 0x%X - timeout:%f\r\n",Prescaler, ReloadValue, Calculated_timeout); + + IWDG->KR = 0x5555; //Disable write protection of IWDG registers + IWDG->PR = PrescalerCode; //Set PR value + IWDG->RLR = ReloadValue; //Set RLR value + IWDG->KR = 0xAAAA; //Reload IWDG + IWDG->KR = 0xCCCC; //Start IWDG - See more at: http://embedded-lab.com/blog/?p=9662#sthash.6VNxVSn0.dpuf +#endif + + Service(); +} + +/// "Service", "kick" or "feed" the dog - reset the watchdog timer +/// by writing this required bit pattern +void Watchdog::Service() { +#ifdef LPC + LPC_WDT->WDFEED = 0xAA; + LPC_WDT->WDFEED = 0x55; +#endif +#ifdef ST_NUCLEO + IWDG->KR = 0xAAAA; //Reload IWDG - See more at: http://embedded-lab.com/blog/?p=9662#sthash.6VNxVSn0.dpuf +#endif +} + +/// get the flag to indicate if the watchdog causes the reset +bool Watchdog::WatchdogCausedReset() { + return wdreset; +} + +
diff -r 000000000000 -r 0fc77069cf70 Watchdog.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Watchdog.h Mon Jul 30 14:10:27 2018 +0000 @@ -0,0 +1,101 @@ +/// @file Watchdog.h provides the interface to the Watchdog module +/// +/// This provides basic Watchdog service for the mbed. You can configure +/// various timeout intervals that meet your system needs. Additionally, +/// it is possible to identify if the Watchdog was the cause of any +/// system restart, permitting the application code to take appropriate +/// behavior. +/// +/// Adapted from Simon's Watchdog code from http://mbed.org/forum/mbed/topic/508/ +/// +/// @note Copyright © 2011 by Smartware Computing, all rights reserved. +/// This software may be used to derive new software, as long as +/// this copyright statement remains in the source file. +/// @author David Smart +/// +/// History +/// \li v1.00 - 20110616: initial release with some documentation improvements +/// +#ifndef WATCHDOG_H +#define WATCHDOG_H +#include "mbed.h" + +/// The Watchdog class provides the interface to the Watchdog feature +/// +/// Embedded programs, by their nature, are usually unattended. If things +/// go wrong, it is usually important that the system attempts to recover. +/// Aside from robust software, a hardware watchdog can monitor the +/// system and initiate a system reset when appropriate. +/// +/// This Watchdog is patterned after one found elsewhere on the mbed site, +/// however this one also provides a method for the application software +/// to determine the cause of the reset - watchdog or otherwise. +/// +/// example: +/// @code +/// Watchdog wd; +/// +/// ... +/// main() { +/// if (wd.WatchdogCausedReset()) +/// pc.printf("Watchdog caused reset.\r\n"); +/// +/// wd.Configure(3.0); // sets the timeout interval +/// for (;;) { +/// wd.Service(); // kick the dog before the timeout +/// // do other work +/// } +/// } +/// @endcode +/// +class Watchdog { +public: + /// Create a Watchdog object + /// + /// example: + /// @code + /// Watchdog wd; // placed before main + /// @endcode + Watchdog(); + + /// Configure the timeout for the Watchdog + /// + /// This configures the Watchdog service and starts it. It must + /// be serviced before the timeout, or the system will be restarted. + /// + /// example: + /// @code + /// ... + /// wd.Configure(1.4); // configure for a 1.4 second timeout + /// ... + /// @endcode + /// + /// @param[in] timeout in seconds, as a floating point number + /// @returns none + /// + void Configure(float timeout); + + /// Service the Watchdog so it does not cause a system reset + /// + /// example: + /// @code + /// wd.Service(); + /// @endcode + /// @returns none + void Service(); + + /// WatchdogCausedReset identifies if the cause of the system + /// reset was the Watchdog + /// + /// example: + /// @code + /// if (wd.WatchdogCausedReset())) { + /// @endcode + /// + /// @returns true if the Watchdog was the cause of the reset + bool WatchdogCausedReset(); +private: + bool wdreset; +}; + +#endif // WATCHDOG_H \ No newline at end of file
diff -r 000000000000 -r 0fc77069cf70 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Jul 30 14:10:27 2018 +0000 @@ -0,0 +1,435 @@ + +// ################################################################################## +// XPL Test Program +// ################################################################################## + +#if !FEATURE_LWIP + #error [NOT_SUPPORTED] LWIP not supported for this target +#endif + +// ----------------------------------------------------------- +// MBED Headers +#include "mbed.h" +#include "EthernetInterface.h" +#include "rtos.h" + +// ----------------------------------------------------------- +// My Headers +#include "Watchdog.h" +#include "xPL.h" + +// ----------------------------------------------------------- +// defines +#define UDP_PORT 3865 +#define UDP_BUFFER_SIZE 500 + +// ----------------------------------------------------------- +// global variables +Watchdog wd; +xPL xpl; + +DigitalOut led1(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); +DigitalOut led4(LED4); + +Serial logger(SERIAL_TX, SERIAL_RX); + +EthernetInterface gEth; +UDPSocket _socket; +UDPSocket _socketSender; +char in_buffer[UDP_BUFFER_SIZE]; + +// ----------------------------------------------------------- +// +// ----------------------------------------------------------- +void terminal_error_state( void ) +{ + led1=0; + led2=0; + led3=0; + logger.printf("\r\n\r\nJUST TO BE CLEAR - THIS IS BAD BAD NEWS !!! \r\n"); + logger.printf("\r\n\r\n---- WAITING FOR THE WATCHDOG TO RESET US ---- \r\n"); + while( 1 ) + { + led1 = !led1; + led2 = !led2; + led3 = !led3; + wait(0.3); + } +} + +// ----------------------------------------------------------- +// +// ----------------------------------------------------------- +static bool DeviceConnect() +{ + int retries = 10; + int rc = 0; + + while (retries--) + { + rc = gEth.connect(); + if (rc == 0) { + // done + return true; + } + else + { + logger.printf("Connecting... ERR %d\r\n", rc); + } + } + + logger.printf("Connecting... FAILED\r\n"); + return false; +} + +// ----------------------------------------------------------- +// +// ----------------------------------------------------------- +static bool DeviceEthStartup() +{ + int rc = 0; + + // get ethernet up ! + if( !DeviceConnect() ) terminal_error_state(); + + // Output the network address + const char *ip = gEth.get_ip_address(); + const char *netmask = gEth.get_netmask(); + const char *gateway = gEth.get_gateway(); + printf("IP address: %s\r\n", ip ? ip : "None"); + printf("Netmask: %s\r\n", netmask ? netmask : "None"); + printf("Gateway: %s\r\n", gateway ? gateway : "None"); + + // setup a UDP listener + _socket.set_blocking(true); + _socket.set_timeout(3000); + //_socket.set_broadcasting(true); + + // open the socket + rc = _socket.open((NetworkInterface*)&gEth); + if( rc != 0) + { + logger.printf("UDPSocket RECEIVER OPEN ERROR (rc=%d)\r\n", rc); + terminal_error_state(); + } + + // bind the XPL port + rc = _socket.bind(UDP_PORT); + logger.printf("Binding port %d\r\n", UDP_PORT); + if( rc != 0) + { + logger.printf("UDPSocket BIND ERROR (rc=%d)\r\n", rc); + terminal_error_state(); + } + + // open the sender socket + rc = _socketSender.open((NetworkInterface*)&gEth); + if( rc != 0) + { + logger.printf("UDPSocket SENDER OPEN ERROR (rc=%d)\r\n", rc); + terminal_error_state(); + } + //_socketSender.set_broadcasting(true); + + return true; +} + + +// ----------------------------------------------------------- +// +// ----------------------------------------------------------- +void SendUdPMessage(char *buffer) +{ + //const char * msg = "xpl-stat{\nhop=1\nsource=NIHH-NUCLEO1.100040\ntarget=*\n}\nsensor.basic\n{\ncurrent=133\ndevice=NUCLEO1\n}"; + + //SocketAddress *_sAddr = new SocketAddress("255.255.255.255",UDP_PORT); + //_socketSender.sendto( _sAddr, (const void *)buffer, strlen( buffer ) ); + + //int rc = _socketSender.sendto( "10.0.0.51", UDP_PORT, (const void *)buffer, strlen( buffer ) ); + //logger.printf("[SEND rc=%d] %s\r\n", rc, buffer); + + //int rc = _socketSender.sendto( "255.255.255.255", UDP_PORT, (const void *)msg, strlen( msg ) ); + //logger.printf("[SEND rc=%d] %s\r\n", rc, buffer); + + //int rc = _socketSender.sendto( "10.0.0.53", 3800, (const void *)buffer, strlen( buffer ) ); + //int rc = _socketSender.sendto( "10.0.0.53", UDP_PORT, (const void *)buffer, strlen( buffer ) ); + int rc = _socketSender.sendto( "255.255.255.255", UDP_PORT, (const void *)buffer, strlen( buffer ) ); + + //logger.printf("[SEND rc=%d] buffer[%d]\r\n", rc, strlen(buffer) ); + logger.printf("[SEND rc=%d] buffer[%d]\r\n%s\r\n", rc, strlen(buffer), buffer); + +/* + SocketAddress *_socketAddress; + _socketAddress = new SocketAddress((NetworkInterface*)&gEth, "10.0.0.255", UDP_PORT); + int rc = _socketSender.sendto( _socketAddress, (const void *)msg, strlen( msg ) ); + logger.printf("[SEND rc=%d] %s\r\n", rc, msg); +*/ +} + +/* ******************************************************* + +xpl-stat +{ +hop=1 +source=NIHH-NUCLEO1.100043 +target=* +} +clock.update +{ +time=20180730113315 +} + +xpl-stat +{ +hop=1 +source=NIHH-NUCLEO1.100043 +target=* +} +hbeat.app +{ +interval=300 +port=3865 +remote-ip=8.8.8.8 +version=1.0 +} + +******************************************************* */ + + + + +// ----------------------------------------------------------- +// +// ----------------------------------------------------------- +void SendXPLint(char *Device, int iCurrent ) +{ +// xPL_Message _message; +// _message.SetTarget( "*" ); +// _message.AddCommand("device", "xxxxx"); +// _message.AddCommand("current", "0"); +// xpl.SendMessage( &_message, true ); +} + + +// ----------------------------------------------------------- +// +// ----------------------------------------------------------- +void SendXPLString(char *Device, char *szCurrent ) +{ +// xPL_Message _message; +// _message.SetTarget( "*" ); +// _message.AddCommand("device", "xxxxx"); +// _message.AddCommand("current", "0"); +// xpl.SendMessage( &_message, true ); +} + + +// ----------------------------------------------------------- +// +// ----------------------------------------------------------- +void AfterParseAction(xPL_Message * message) +{ + /* + if (xpl.TargetIsMe(message)) + { + if (message->IsSchema("lighting", "basic")) + { + Serial.println("is lighting.basic"); + } + } + */ + + logger.printf("[%s]\r\n", message->source.device_id ); + + // do we have any data ??? maybe the parse failed.... + if( message->command_count == 0 ) + { + // + logger.printf("+++++++++++++\r\n%s\r\n", in_buffer ); + } + else + { + // output the message data + for (short i=0; i<message->command_count; i++) + { + //logger.printf("%s=%s\r\n", message->command[i].name, message->command[i].value); + } + } + + // output the full msg! + //logger.printf("%s\r\n", message->toString()); +} + + + +// ----------------------------------------------------------- +// +// ----------------------------------------------------------- +void Receiver_Thread(void const *argument) +{ + SocketAddress _sAddr; + int iNoDataCount = 0; + + // loop forever + while(1) + { + // receive from the udp socket + led2 = 0; + int n = _socket.recvfrom(&_sAddr, in_buffer, UDP_BUFFER_SIZE); + //led2 = 1; + + // see what weve got ! + if (n == NSAPI_ERROR_WOULD_BLOCK) + { + // timeout with no data... + ++iNoDataCount; + logger.printf("-- NoData (TIMEOUT)\r\n"); + led2 = 0; + } + else if (n < 0) + { + // some other error + ++iNoDataCount; + logger.printf("-- NoData (ERR) %i\r\n", n); + led2 = 0; + } + else if( n > 0) + { + // good data :) + iNoDataCount = 0; + in_buffer[n] = '\0'; + // logger.printf("[%d bytes] %s:%d\r\n", n, _sAddr.get_ip_address(), _sAddr.get_port()); + // logger.printf("%s\r\n", in_buffer); + led2 = 1; + + // try and parse the msg + xpl.ParseInputMessage(in_buffer); + } + + // have we stopped receiving data ?!?!? + if( iNoDataCount > 20 ) + { + logger.printf("-------- Arghhhh NO DATA !!! ---------\r\n"); + + // maybe - looks dodgy at least... try the reset + //gEth.disconnect(); + //wait(0.5); + //DeviceEthStartup(); + //Thread::wait(1000); + terminal_error_state(); + } + + // stroke the WD + wd.Service(); + } +} + + +// ----------------------------------------------------------- +// +// ----------------------------------------------------------- +int main() +{ + int iAppLoop=0; + int iXPLdata=0; + + // FIRST THINGS FIRST!!! set the WD timeout interval... + // enough to get up and running! + wd.Configure(1000.0); + + // setup the pc serial logger + logger.baud(115200); + logger.printf("\r\n\r\n<<<<<<<<< Basic UDP XPL Listener >>>>>>>>>>\r\n"); + + led1 = 0; + led2 = 0; + led3 = 0; + led4 = 0; + + // WatchDog Startup Information + logger.printf("\r\n------------------------------------------------------\r\n" ); + logger.printf("[SystemCoreClock] %d Hz\r\n", SystemCoreClock); + logger.printf("[Reset reason] "); + if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) logger.printf("Independant-Watchdog "); + if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST)) logger.printf("Window-Watchdog "); + if (__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST)) logger.printf("Low-Power-Reset "); + if (__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST)) logger.printf("Software-Reset "); + if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)) logger.printf("Power-On/Down-Reset "); + if (__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)) logger.printf("Reset-pin "); + if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) logger.printf("Brownout "); + if (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY)) logger.printf("Low-speed-internal-clock-ready "); + __HAL_RCC_CLEAR_RESET_FLAGS(); + logger.printf("\r\n------------------------------------------------------\r\n"); + + if (wd.WatchdogCausedReset()) + { + logger.printf("<<Watchdog caused reset>>\r\n"); + led3 = 1; + } + else + { + logger.printf("<<Normal Startup>>\r\n"); + led1 = 1; + led2 = 1; + led3 = 0; + } + logger.printf("------------------------------------------------------\r\n\r\n"); + + // Fireup the Ethernet + DeviceEthStartup(); + + // now set the WD to something to run with - between receving data + wd.Service(); + wd.Configure(300.0); + + // setup xpl + xpl.SendExternal = &SendUdPMessage; // pointer to the send callback + xpl.AfterParseAction = &AfterParseAction; // pointer to a post parsing action callback + xpl.SetSource( "NIHH", "NUCLEO1", "100043"); // parameters for hearbeat message + + // kick off the XPL receiver thread to run in the background + Thread thread1(Receiver_Thread, NULL, osPriorityHigh); //, DEFAULT_STACK_SIZE); + + // start running the main processing stuff here + while (true) + { + led1 = 0; + Thread::wait(2000); + led1 = 1; + logger.printf("*\r\n"); + Thread::wait(100); + + // allow xpl to do its thing... + xpl.Process(); + + // every 10 loops send an XPL msg + ++iAppLoop; + if( iAppLoop >= 5 ) + { + xPL_Message _message; + + /* + _message.SetSchema( "clock", "update" ); + _message.SetTarget( "*" ); + _message.type = XPL_STAT; + _message.hop = 1; + _message.AddCommand("time", "20180730113315"); + xpl.SendMessage( (xPL_Message *)&_message, true ); + */ + + _message.SetSchema( "sensor", "basic" ); + _message.SetTarget( "*" ); + _message.type = XPL_STAT; + _message.hop = 1; + _message.AddCommand("device", "test1"); + _message.AddCommand("type", "test"); + _message.AddCommand("current", "1"); + xpl.SendMessage( (xPL_Message *)&_message, true ); + + // reset + iAppLoop = 0; + } + } +}
diff -r 000000000000 -r 0fc77069cf70 mbed-os.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os.lib Mon Jul 30 14:10:27 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os/#50bd61a4a72332baa6b1bac6caccb44dc5423309
diff -r 000000000000 -r 0fc77069cf70 xPL.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xPL.cpp Mon Jul 30 14:10:27 2018 +0000 @@ -0,0 +1,399 @@ +/* + * 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); + + //(*SendExternal)(buffer); + SendMessage(buffer); +} + +/** + * \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
diff -r 000000000000 -r 0fc77069cf70 xPL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xPL.h Mon Jul 30 14:10:27 2018 +0000 @@ -0,0 +1,102 @@ +/* + * 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); + + 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
diff -r 000000000000 -r 0fc77069cf70 xPL_Message.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xPL_Message.cpp Mon Jul 30 14:10:27 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; +}
diff -r 000000000000 -r 0fc77069cf70 xPL_Message.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xPL_Message.h Mon Jul 30 14:10:27 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
diff -r 000000000000 -r 0fc77069cf70 xPL_utils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xPL_utils.cpp Mon Jul 30 14:10:27 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; + } +}
diff -r 000000000000 -r 0fc77069cf70 xPL_utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xPL_utils.h Mon Jul 30 14:10:27 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