Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ArduinoCloudTCP: Separate the logic of the device and the logic of the thing in two different state machines #425

Closed
51 changes: 51 additions & 0 deletions src/AIoTC_Types.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
This file is part of ArduinoIoTCloud.

Copyright 2020 ARDUINO SA (http://www.arduino.cc/)

This software is released under the GNU General Public License version 3,
which covers the main part of arduino-cli.
The terms of this license can be found at:
https://www.gnu.org/licenses/gpl-3.0.en.html

You can be released from the requirements of the above licenses by purchasing
a commercial license. Buying such a license is mandatory if you want to modify or
otherwise use the software for commercial activities involving the Arduino
software without disclosing the source code of your own applications. To purchase
a commercial license, send an email to [email protected].
*/

#ifndef ARDUINO_AIOTC_TYPES_H_
#define ARDUINO_AIOTC_TYPES_H_

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#include <stdint.h>

/******************************************************************************
TYPEDEF
******************************************************************************/

typedef enum
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
typedef enum
typedef enum: uint8_t

We don't need and entire int32 to represent the R/W modes

{
READ = 0x01,
WRITE = 0x02,
READWRITE = READ | WRITE
} permissionType;

enum class ArduinoIoTConnectionStatus
{
IDLE,
CONNECTING,
CONNECTED,
DISCONNECTED,
RECONNECTING,
ERROR,
};

enum class ArduinoIoTCloudEvent
{
SYNC = 0, CONNECT = 1, DISCONNECT = 2
};

typedef void (*OnCloudEventCallback)(void);

typedef void (*ExecCloudEventCallback)(ArduinoIoTCloudEvent);

#endif /* ARDUINO_AIOTC_TYPES_H_ */
74 changes: 17 additions & 57 deletions src/ArduinoIoTCloud.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,10 @@

ArduinoIoTCloudClass::ArduinoIoTCloudClass()
: _connection{nullptr}
, _last_checked_property_index{0}
, _time_service(TimeService)
, _tz_offset{0}
, _tz_dst_until{0}
, _thing_id{""}
, _lib_version{AIOT_CONFIG_LIB_VERSION}
, _device_id{""}
, _cloud_event_callback{nullptr}
, _thing_id_outdated{false}
{

}
Expand All @@ -44,23 +39,6 @@ ArduinoIoTCloudClass::ArduinoIoTCloudClass()
* PUBLIC MEMBER FUNCTIONS
******************************************************************************/

void ArduinoIoTCloudClass::push()
{
requestUpdateForAllProperties(_thing_property_container);
}

bool ArduinoIoTCloudClass::setTimestamp(String const & prop_name, unsigned long const timestamp)
{
Property * p = getProperty(_thing_property_container, prop_name);

if (p == nullptr)
return false;

p->setTimestamp(timestamp);

return true;
}

void ArduinoIoTCloudClass::addCallback(ArduinoIoTCloudEvent const event, OnCloudEventCallback callback)
{
_cloud_event_callback[static_cast<size_t>(event)] = callback;
Expand Down Expand Up @@ -120,93 +98,71 @@ Property& ArduinoIoTCloudClass::addPropertyReal(String& property, String name, i
}
Property& ArduinoIoTCloudClass::addPropertyReal(Property& property, String name, int tag, Permission const permission)
{
return addPropertyToContainer(_thing_property_container, property, name, permission, tag);
return addInternalPropertyReal(property, name, tag, permission);
}

/* The following methods are deprecated but still used for non-LoRa boards */
void ArduinoIoTCloudClass::addPropertyReal(bool& property, String name, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property))
{
Property* p = new CloudWrapperBool(property);
addPropertyRealInternal(*p, name, -1, permission_type, seconds, fn, minDelta, synFn);
addInternalPropertyReal(*p, name, -1, permission_type, seconds, fn, minDelta, synFn);
}
void ArduinoIoTCloudClass::addPropertyReal(float& property, String name, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property))
{
Property* p = new CloudWrapperFloat(property);
addPropertyRealInternal(*p, name, -1, permission_type, seconds, fn, minDelta, synFn);
addInternalPropertyReal(*p, name, -1, permission_type, seconds, fn, minDelta, synFn);
}
void ArduinoIoTCloudClass::addPropertyReal(int& property, String name, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property))
{
Property* p = new CloudWrapperInt(property);
addPropertyRealInternal(*p, name, -1, permission_type, seconds, fn, minDelta, synFn);
addInternalPropertyReal(*p, name, -1, permission_type, seconds, fn, minDelta, synFn);
}
void ArduinoIoTCloudClass::addPropertyReal(unsigned int& property, String name, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property))
{
Property* p = new CloudWrapperUnsignedInt(property);
addPropertyRealInternal(*p, name, -1, permission_type, seconds, fn, minDelta, synFn);
addInternalPropertyReal(*p, name, -1, permission_type, seconds, fn, minDelta, synFn);
}
void ArduinoIoTCloudClass::addPropertyReal(String& property, String name, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property))
{
Property* p = new CloudWrapperString(property);
addPropertyRealInternal(*p, name, -1, permission_type, seconds, fn, minDelta, synFn);
addInternalPropertyReal(*p, name, -1, permission_type, seconds, fn, minDelta, synFn);
}
void ArduinoIoTCloudClass::addPropertyReal(Property& property, String name, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property))
{
addPropertyRealInternal(property, name, -1, permission_type, seconds, fn, minDelta, synFn);
addInternalPropertyReal(property, name, -1, permission_type, seconds, fn, minDelta, synFn);
}

/* The following methods are deprecated but still used for both LoRa and non-LoRa boards */
void ArduinoIoTCloudClass::addPropertyReal(bool& property, String name, int tag, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property))
{
Property* p = new CloudWrapperBool(property);
addPropertyRealInternal(*p, name, tag, permission_type, seconds, fn, minDelta, synFn);
addInternalPropertyReal(*p, name, tag, permission_type, seconds, fn, minDelta, synFn);
}
void ArduinoIoTCloudClass::addPropertyReal(float& property, String name, int tag, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property))
{
Property* p = new CloudWrapperFloat(property);
addPropertyRealInternal(*p, name, tag, permission_type, seconds, fn, minDelta, synFn);
addInternalPropertyReal(*p, name, tag, permission_type, seconds, fn, minDelta, synFn);
}
void ArduinoIoTCloudClass::addPropertyReal(int& property, String name, int tag, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property))
{
Property* p = new CloudWrapperInt(property);
addPropertyRealInternal(*p, name, tag, permission_type, seconds, fn, minDelta, synFn);
addInternalPropertyReal(*p, name, tag, permission_type, seconds, fn, minDelta, synFn);
}
void ArduinoIoTCloudClass::addPropertyReal(unsigned int& property, String name, int tag, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property))
{
Property* p = new CloudWrapperUnsignedInt(property);
addPropertyRealInternal(*p, name, tag, permission_type, seconds, fn, minDelta, synFn);
addInternalPropertyReal(*p, name, tag, permission_type, seconds, fn, minDelta, synFn);
}
void ArduinoIoTCloudClass::addPropertyReal(String& property, String name, int tag, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property))
{
Property* p = new CloudWrapperString(property);
addPropertyRealInternal(*p, name, tag, permission_type, seconds, fn, minDelta, synFn);
addInternalPropertyReal(*p, name, tag, permission_type, seconds, fn, minDelta, synFn);
}
void ArduinoIoTCloudClass::addPropertyReal(Property& property, String name, int tag, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property))
{
addPropertyRealInternal(property, name, tag, permission_type, seconds, fn, minDelta, synFn);
addInternalPropertyReal(property, name, tag, permission_type, seconds, fn, minDelta, synFn);
}

void ArduinoIoTCloudClass::addPropertyRealInternal(Property& property, String name, int tag, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property))
{
Permission permission = Permission::ReadWrite;
if (permission_type == READ) {
permission = Permission::Read;
} else if (permission_type == WRITE) {
permission = Permission::Write;
} else {
permission = Permission::ReadWrite;
}

if (seconds == ON_CHANGE) {
addPropertyToContainer(_thing_property_container, property, name, permission, tag).publishOnChange(minDelta, Property::DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(synFn);
} else {
addPropertyToContainer(_thing_property_container, property, name, permission, tag).publishEvery(seconds).onUpdate(fn).onSync(synFn);
}
}

/******************************************************************************
* PROTECTED MEMBER FUNCTIONS
******************************************************************************/

void ArduinoIoTCloudClass::execCloudEventCallback(ArduinoIoTCloudEvent const event)
{
OnCloudEventCallback callback = _cloud_event_callback[static_cast<size_t>(event)];
Expand All @@ -215,6 +171,10 @@ void ArduinoIoTCloudClass::execCloudEventCallback(ArduinoIoTCloudEvent const eve
}
}

/******************************************************************************
* PROTECTED MEMBER FUNCTIONS
******************************************************************************/

__attribute__((weak)) void setDebugMessageLevel(int const /* level */)
{
/* do nothing */
Expand Down
64 changes: 17 additions & 47 deletions src/ArduinoIoTCloud.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#endif

#include "AIoTC_Const.h"
#include "AIoTC_Types.h"

#include "cbor/CBORDecoder.h"

Expand All @@ -44,34 +45,6 @@

#include "utility/time/TimeService.h"

/******************************************************************************
TYPEDEF
******************************************************************************/

typedef enum
{
READ = 0x01,
WRITE = 0x02,
READWRITE = READ | WRITE
} permissionType;

enum class ArduinoIoTConnectionStatus
{
IDLE,
CONNECTING,
CONNECTED,
DISCONNECTED,
RECONNECTING,
ERROR,
};

enum class ArduinoIoTCloudEvent : size_t
{
SYNC = 0, CONNECT = 1, DISCONNECT = 2
};

typedef void (*OnCloudEventCallback)(void);

/******************************************************************************
* CLASS DECLARATION
******************************************************************************/
Expand All @@ -87,26 +60,26 @@ class ArduinoIoTCloudClass
virtual void update () = 0;
virtual int connected () = 0;
virtual void printDebugInfo() = 0;
virtual bool deviceNotAttached() = 0;
virtual void setThingId (String const thing_id) = 0;
virtual String & getThingId () = 0;
virtual void setThingIdOutdatedFlag() = 0;
virtual void clrThingIdOutdatedFlag() = 0;
virtual bool getThingIdOutdatedFlag() = 0;

void push();
bool setTimestamp(String const & prop_name, unsigned long const timestamp);
virtual void push() = 0;
virtual bool setTimestamp(String const & prop_name, unsigned long const timestamp) = 0;

inline void setThingId (String const thing_id) { _thing_id = thing_id; };
inline String & getThingId () { return _thing_id; };
inline void setDeviceId(String const device_id) { _device_id = device_id; };
inline String & getDeviceId() { return _device_id; };

inline void setThingIdOutdatedFlag() { _thing_id_outdated = true ; }
inline void clrThingIdOutdatedFlag() { _thing_id_outdated = false ; }
inline bool getThingIdOutdatedFlag() { return _thing_id_outdated; }

inline bool deviceNotAttached() { return _thing_id == ""; }

inline ConnectionHandler * getConnection() { return _connection; }

inline unsigned long getInternalTime() { return _time_service.getTime(); }
inline unsigned long getLocalTime() { return _time_service.getLocalTime(); }
inline void updateInternalTimezoneInfo() { _time_service.setTimeZoneData(_tz_offset, _tz_dst_until); }
inline int tzOffset() { return _tz_offset; }
inline unsigned int getTzDstUntil() { return _tz_dst_until; }

void addCallback(ArduinoIoTCloudEvent const event, OnCloudEventCallback callback);

Expand Down Expand Up @@ -135,7 +108,6 @@ class ArduinoIoTCloudClass
* This approach reduces the required amount of data which is of great
* important when using LoRa.
*/

void addPropertyReal(Property& property, String name, int tag, permissionType permission_type = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, float minDelta = 0.0f, void(*synFn)(Property & property) = CLOUD_WINS) __attribute__((deprecated("Use addProperty(property, Permission::ReadWrite) instead.")));
void addPropertyReal(bool& property, String name, int tag, permissionType permission_type = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, float minDelta = 0.0f, void(*synFn)(Property & property) = CLOUD_WINS) __attribute__((deprecated("Use addProperty(property, Permission::ReadWrite) instead.")));
void addPropertyReal(float& property, String name, int tag, permissionType permission_type = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, float minDelta = 0.0f, void(*synFn)(Property & property) = CLOUD_WINS) __attribute__((deprecated("Use addProperty(property, Permission::ReadWrite) instead.")));
Expand All @@ -150,27 +122,25 @@ class ArduinoIoTCloudClass
Property& addPropertyReal(unsigned int& property, String name, int tag, Permission const permission);
Property& addPropertyReal(String& property, String name, int tag, Permission const permission);

virtual void addInternalPropertyReal(Property& property, String name, int tag, permissionType permission_type = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, float minDelta = 0.0f, void(*synFn)(Property & property) = CLOUD_WINS) = 0;
virtual Property& addInternalPropertyReal(Property& property, String name, int tag, Permission const permission) = 0;

void execCloudEventCallback(ArduinoIoTCloudEvent const event);

protected:

ConnectionHandler * _connection;
PropertyContainer _device_property_container;
PropertyContainer _thing_property_container;
unsigned int _last_checked_property_index;
TimeServiceClass & _time_service;
int _tz_offset;
unsigned int _tz_dst_until;
String _thing_id;
String _lib_version;

void execCloudEventCallback(ArduinoIoTCloudEvent const event);

private:

void addPropertyRealInternal(Property& property, String name, int tag, permissionType permission_type = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, float minDelta = 0.0f, void(*synFn)(Property & property) = CLOUD_WINS);

String _device_id;
OnCloudEventCallback _cloud_event_callback[3];
bool _thing_id_outdated;

};

#ifdef HAS_TCP
Expand Down
41 changes: 41 additions & 0 deletions src/ArduinoIoTCloudLPWAN.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ ArduinoIoTCloudLPWAN::ArduinoIoTCloudLPWAN()
, _retryEnable{false}
, _maxNumRetry{5}
, _intervalRetry{1000}
, _last_checked_property_index{0}
{

}
Expand Down Expand Up @@ -91,6 +92,46 @@ void ArduinoIoTCloudLPWAN::printDebugInfo()
DEBUG_INFO("Thing ID: %s", getThingId().c_str());
}

Property& ArduinoIoTCloudLPWAN::addInternalPropertyReal(Property& property, String name, int tag, Permission const permission)
{
return addPropertyToContainer(_thing_property_container, property, name, permission, tag);
}

void ArduinoIoTCloudLPWAN::addInternalPropertyReal(Property& property, String name, int tag, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property))
{
Permission permission = Permission::ReadWrite;
if (permission_type == READ) {
permission = Permission::Read;
} else if (permission_type == WRITE) {
permission = Permission::Write;
} else {
permission = Permission::ReadWrite;
}

if (seconds == ON_CHANGE) {
addPropertyToContainer(_thing_property_container, property, name, permission, tag).publishOnChange(minDelta, Property::DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(synFn);
} else {
addPropertyToContainer(_thing_property_container, property, name, permission, tag).publishEvery(seconds).onUpdate(fn).onSync(synFn);
}
}

void ArduinoIoTCloudLPWAN::push()
{
requestUpdateForAllProperties(_thing_property_container);
}

bool ArduinoIoTCloudLPWAN::setTimestamp(String const & prop_name, unsigned long const timestamp)
{
Property * p = getProperty(_thing_property_container, prop_name);

if (p == nullptr)
return false;

p->setTimestamp(timestamp);

return true;
}

/******************************************************************************
* PRIVATE MEMBER FUNCTIONS
******************************************************************************/
Expand Down
Loading
Loading