Skip to content

Add GSM and Ethernet conn_manager + add fallback UDP based getTime() #31

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

Merged
merged 23 commits into from
Feb 26, 2019

Conversation

facchinm
Copy link
Contributor

No description provided.

@facchinm facchinm changed the title Add proper state machine for GSM connections Add GSM and Ethernet conn_manager + add fallback UDP based getTime() Feb 13, 2019
@facchinm facchinm requested review from ubidefeo and cmaglie February 13, 2019 13:22
@ubidefeo ubidefeo requested a review from aentinger February 15, 2019 15:18
int connectionTickTimeInterval;
GSMUDP Udp;
void sendNTPpacket(const char * address, uint8_t* packetBuffer);
unsigned long getNTPTime();
};

static const unsigned long NETWORK_CONNECTION_INTERVAL = 30000;

GSMConnectionManager::GSMConnectionManager(const char *pin, const char *apn, const char *login, const char *pass) :
Copy link
Contributor

Choose a reason for hiding this comment

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

The member variables pin, apn, login and pass are only stored as const char pointers. This implies that those variables must be of global scope within the calling code, otherwise we might read invalid data if we read them at a later point in time. A alternative would be to copy the content of those variables into the class, e.g. via a String data type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree, the structure is the same as WiFi wrapper that "requires" variables with global scope. I'd be ok to switch to strings, but it should be something shared between all the wrappers.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@lxrobotics @facchinm
because we use them in the Web IDE to create fields in the Secret tab, they are indeed globally defined for our cases.
storing them as String might make sense. I also side with @facchinm with having this kind of structure shared amongst the wrappers

return;
}
break;
case CONNECTION_STATE_GETTIME:
Copy link
Contributor

Choose a reason for hiding this comment

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

Add an exit condition from the CONNECTION_STATE_GETTIME state in a similar way of the WiFiConnectionManager.

@ubidefeo
Copy link
Collaborator

ubidefeo commented Feb 20, 2019

Fellows, I've been going through the source and although it will work with just a couple rectifications (such as @ilcato 's note related to MAX_GETTIME_RETRY), I've noticed that it needs a few adjustments to align to the structure of WiFiConnectionManager especially in matter of logging output.
I have used a support method to change state in order to add extra code into its enclosed cases rather than polluting the check() method: changing time interval, logging one message, cleanup and so on.
I expect the same amount of work to be required for EthernetConnectionManager.
I'm working on it :)

- minor refactoring on WiFiConnectionManager
- changed library version to 0.5.1 (new feature: GSM)
- aligned INTERVAL definitions between WiFi and GSM
- fixed typo
@ubidefeo
Copy link
Collaborator

ok folks
I have done my work, there are some conflicts related to implementations I brought back from master to this branch and changes I made after.
I have also bumped up version in library.properties as this should be a tentative 0.5.1 version with a stable GSMConnectionManager and a refined WiFiConnectionManager.
This took a lot of work, and I have tested it as I went with no errors whatsoever.
I am confident it's flawless, but I'd really need some help reviewing it as I've been at it for over 7 hours today only.
Let me know and hopefully we can merge it tomorrow for Monday.
Goes without saying that I have to reserve the same lifting treatment to EthernetConnectionManager which I have not even looked at.
Thanks :)

- fixed typo in example
- cleanup GSMConnectionManager
- cleanup WiFiConnectionManager
- fixed missing WiFiUDP member which broke compilation
- removed unnecessary call to _mqttReconnect(...) in ArduinoIoTCloud
- removed unncessary begin() into case IOT_STATUS_IDLE in ArduinoIoTCloud
- removed unnecessary calls to update() in CloudSerial
- fixed if statement in ConnectionManager
@ubidefeo ubidefeo requested a review from aentinger February 25, 2019 14:48
Copy link
Contributor

@aentinger aentinger left a comment

Choose a reason for hiding this comment

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

Looks good to me 👍

The following include line is used for WiFi enabled boards (MKR1000, MKR WiFi 1010)
*/
ConnectionManager *ArduinoIoTPreferredConnection = new WiFiConnectionManager(SECRET_SSID, SECRET_PASS);
Copy link
Contributor

Choose a reason for hiding this comment

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

A quick side note: Everything that follows is a suggestion for improvement and must not necessarily implemented within this PR. We can (and probably should) do cleanups in further PRs after this is merged.

A misconception, for which I've fallen myself until quite recently, is that if you instantiate derived classes with virtual functions in it (C++ runtime polymorphism) you always need to use the keyword new, effectively allocating the memory on the heap at runtime. Interestingly enough, the following statement also works:

Suggested change
ConnectionManager *ArduinoIoTPreferredConnection = new WiFiConnectionManager(SECRET_SSID, SECRET_PASS);
WiFiConnectionManager connection_mgr(SECRET_SSID, SECRET_PASS);

Doing it this way the memory for the object is allocated on the stack and not on the heap (static memory allocation vs dynamic memory allocation - prefer the former whenever possible/feasible). The reason above statement works is because of a C++ "feature" called object slicing.

Now object slicing has some pitfalls to it but it can be used effectively in this scenario where we have an abstract base class (= one or more pure virtual functions in it) ConnectionManager from which WiFiConnectionManager and GSMConnectionManager are derived. ConnectionManager serves to define the interface for the derived classes and only those functions defined within ConnectionManager are called by users of the derived classes.

When passing the connection around to various classes you then have to use pass-by-reference.

void myFunc(ConnectionManager & connection_mgr) { ...

It´s also possible to store a reference of it as a class member variable.

class MyClass {
public:
  void MyClass(ConnectionManager & connection_mgr) : _connection_mgr(connection_mgr) { ... }
  void myMemberFunc();
private:
  ConnectionManager & _connection_mgr;
};

The ConnectionManager can than be accessed within member functions via the . operator instead of -> as would be the case if the ConnectionManager would be stored as a pointer (ConnectionManager * _connection_mgr;)

void MyClass:myMemberFunc() {
  _connection_mgr.check();
}

Furthermore I'd also suggest to keep variable names in lowercase so to not confuse them with class/type names.

Copy link
Collaborator

Choose a reason for hiding this comment

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

interesting...
I'm gonna level up on this stuff for the next version.
Thanks, @lxrobotics

I'll proceed to merge this PR in :)



char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
// Your THING_ID
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
// Your THING_ID
// Enter your THING_ID here

@@ -43,14 +43,12 @@ typedef struct {
extern ConnectionManager *ArduinoIoTPreferredConnection;

enum ArduinoIoTConnectionStatus {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it would be an idea to convert the enum into a enum class?

Suggested change
enum ArduinoIoTConnectionStatus {
enum class CloudConnectionState {
Idle,
Connecting,
Connected,
...

Copy link
Collaborator

Choose a reason for hiding this comment

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

@lxrobotics
I've been looking up enum class and I think it's a great way to go, but not for this PR.
We're awaiting on this merge to move forward and release MKR GSM support which after this is merged in will be ready.
this will definitely end up in the next update :)

@@ -130,7 +128,7 @@ class ArduinoIoTCloudClass {
ArduinoIoTConnectionStatus getIoTStatus() { return iotStatus; }
void setIoTConnectionState(ArduinoIoTConnectionStatus _newState);
private:
ArduinoIoTConnectionStatus iotStatus = IOT_STATUS_IDLE;
ArduinoIoTConnectionStatus iotStatus = IOT_STATUS_CLOUD_IDLE;
Copy link
Contributor

Choose a reason for hiding this comment

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

In case you want to go ahead with an enum class:

Suggested change
ArduinoIoTConnectionStatus iotStatus = IOT_STATUS_CLOUD_IDLE;
CloudConnectionState _iot_cloud_state = CloudConnectionState::Idle;

Copy link
Collaborator

Choose a reason for hiding this comment

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

same as above

@ubidefeo ubidefeo merged commit 25c5b71 into master Feb 26, 2019
@aentinger aentinger deleted the gsm_proper_connmanager branch February 27, 2019 06:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants