From fb1c863ead95150d2baff4be155978751b94f11a Mon Sep 17 00:00:00 2001 From: Austin Eldridge Date: Tue, 27 Sep 2016 13:05:24 -0400 Subject: [PATCH 01/13] Bump Version --- Bullwinkle.class.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bullwinkle.class.nut b/Bullwinkle.class.nut index 83ead6f..3bac1d7 100644 --- a/Bullwinkle.class.nut +++ b/Bullwinkle.class.nut @@ -21,7 +21,7 @@ const BULLWINKLE_WATCHDOG_TIMER = 0.5; class Bullwinkle { - static version = [2,3,1]; + static version = [2,3,2]; // The bullwinkle message static BULLWINKLE = "bullwinkle"; From d07ea661a9d092320240af79627adb55333588f0 Mon Sep 17 00:00:00 2001 From: Austin Eldridge Date: Tue, 27 Sep 2016 13:10:23 -0400 Subject: [PATCH 02/13] Add prependID to settings This allows for creating globally Unique IDs (assuming the imp hits a reboot every 2,147,483,647 messages, which is over 68 years assuming 1 message/second). By setting prependID to the boot number of the device (which can be stored in a SPIFlashLogger), you can have this property. --- Bullwinkle.class.nut | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Bullwinkle.class.nut b/Bullwinkle.class.nut index 3bac1d7..e7074aa 100644 --- a/Bullwinkle.class.nut +++ b/Bullwinkle.class.nut @@ -50,6 +50,7 @@ class Bullwinkle { "retryTimeout": ("retryTimeout" in settings) ? settings["retryTimeout"].tostring().tointeger() : 60, "maxRetries": ("maxRetries" in settings) ? settings["maxRetries"].tostring().tointeger() : 0, "autoRetry" : ("autoRetry" in settings) ? settings["autoRetry"] : false, + "prependID" : ("prependID" in settings) ? settings["prependID"].tostring() + "|" : "" "onError" : ("onError" in settings) ? settings["onError"] : null }; @@ -122,7 +123,7 @@ class Bullwinkle { function _generateId() { // Get the next ID while (++_nextId in _packages) { - _nextId = (_nextId + 1) % RAND_MAX; + _nextId = _settings.prependID + ((_nextId + 1) % RAND_MAX); } // Return the generated ID From e58d8268b1c1c413e05b91f45f07d42ff37c470a Mon Sep 17 00:00:00 2001 From: Austin Eldridge Date: Tue, 27 Sep 2016 13:46:40 -0400 Subject: [PATCH 03/13] Allow custom timestamps to be used with .send(name, data, ts) --- Bullwinkle.class.nut | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Bullwinkle.class.nut b/Bullwinkle.class.nut index e7074aa..46f9ad0 100644 --- a/Bullwinkle.class.nut +++ b/Bullwinkle.class.nut @@ -96,10 +96,11 @@ class Bullwinkle { // Parameters: // name The message name // data Optional data + // ts Optional timestamp for the data // - // Returns: Rocky.Package object - function send(name, data = null) { - local message = _messageFactory(BULLWINKLE_MESSAGE_TYPE.SEND, name, data); + // Returns: Bullwinkle.Package object + function send(name, data = null, ts = null) { + local message = _messageFactory(BULLWINKLE_MESSAGE_TYPE.SEND, name, data, ts); local package = Bullwinkle.Package(message); _packages[message.id] <- package; _sendMessage(message); @@ -435,7 +436,7 @@ class Bullwinkle { } // if it's a message awaiting a reply - local ts = "retry" in message ? message.retry.ts : message.ts; + local ts = "retry" in message ? message.retry.ts : split(package._ts, "."); //Use either the retry ts or the package ts, but NOT the message ts so that it can be set for whenever the data was generated, instead of when Bullwinkle attempted to send it if (t >= (ts + _settings.messageTimeout)) { // Grab the onFail handler local handler = package.getHandler("onFail"); From 348fd2c7bb9578752f475e9f09088e2eeb3a4ca2 Mon Sep 17 00:00:00 2001 From: Austin Eldridge Date: Tue, 27 Sep 2016 13:48:10 -0400 Subject: [PATCH 04/13] Move message.tries into package._tries Eliminates the number of tries from being sent over the connection to reduce data consumption of the class. Also includes a bugfixes for storing the timestamp in the Bullwinkle.Package instead of the message object --- Bullwinkle.class.nut | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/Bullwinkle.class.nut b/Bullwinkle.class.nut index 46f9ad0..92f76a2 100644 --- a/Bullwinkle.class.nut +++ b/Bullwinkle.class.nut @@ -149,7 +149,6 @@ class Bullwinkle { "name": command, "data": data, "ts": ts, - "tries": 0, }; } @@ -164,9 +163,10 @@ class Bullwinkle { if (_watchdogTimer == null) _watchdog(); // Increment the tries - if (message.type == BULLWINKLE_MESSAGE_TYPE.SEND) { - message.tries++; + if (message.type == BULLWINKLE_MESSAGE_TYPE.SEND && message.id in _packages) { + _packages[message.id]._tries++; } + // Send the message _partner.send(BULLWINKLE, message); } @@ -367,17 +367,17 @@ class Bullwinkle { // Check the message is still valid if (!(message.id in _packages)) { // server.error(format("Bullwinkle message id=%d has expired", message.id)) - message.type = BULLWINKLE_MESSAGE_TYPE.DONE; - return false; - } - - // Check there are more retries available - if (_settings.maxRetries > 0 && message.tries >= _settings.maxRetries) { - // server.error(format("Bullwinkle message id=%d has no more retries", message.id)) - message.type = BULLWINKLE_MESSAGE_TYPE.DONE; - delete _packages[message.id]; - return false; - } + message.type = BULLWINKLE_MESSAGE_TYPE.DONE; + return false; + } + + // Check there are more retries available + if (_settings.maxRetries > 0 && _packages[message.id]._tries >= _settings.maxRetries) { + // server.error(format("Bullwinkle message id=%d has no more retries", message.id)) + message.type = BULLWINKLE_MESSAGE_TYPE.DONE; + delete _packages[message.id]; + return false; + } // Set timeout if required if (timeout == null) { timeout = _settings.retryTimeout; } @@ -416,7 +416,7 @@ class Bullwinkle { // message timeouts. function _watchdog() { // Get the current time - local t = time(); + local t = Bullwinkle._isAgent() ? time() : hardware.micros()/1000000 // Loop through all the cached packages foreach(idx, package in _packages) { @@ -436,7 +436,7 @@ class Bullwinkle { } // if it's a message awaiting a reply - local ts = "retry" in message ? message.retry.ts : split(package._ts, "."); //Use either the retry ts or the package ts, but NOT the message ts so that it can be set for whenever the data was generated, instead of when Bullwinkle attempted to send it + local ts = "retry" in message ? message.retry.ts : split(package._ts, ".")[0].tointeger(); //Use either the retry ts or the package ts, but NOT the message ts so that it can be set for whenever the data was generated, instead of when Bullwinkle attempted to send it if (t >= (ts + _settings.messageTimeout)) { // Grab the onFail handler local handler = package.getHandler("onFail"); @@ -485,6 +485,9 @@ class Bullwinkle.Package { // The timestamp of the original message _ts = null; + // the number of attempts we have made to send the message + _tries = null; + // Class constructor // // Parameters: @@ -493,6 +496,7 @@ class Bullwinkle.Package { _message = message; _handlers = {}; _ts = _timestamp(); + _tries = 0; } // Sets an onSuccess callback that will be invoked if the message is successfully @@ -567,5 +571,4 @@ class Bullwinkle.Package { return format("%d.%06d", d/1000000, d%1000000); } } - } From dabe7472ef3de370fcca7ff43d5e6deab12a2fa0 Mon Sep 17 00:00:00 2001 From: Austin Eldridge Date: Tue, 27 Sep 2016 14:57:37 -0400 Subject: [PATCH 05/13] Move _packageTimeout into its own workflow and call immediately if the server connection is unavailable --- Bullwinkle.class.nut | 62 ++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/Bullwinkle.class.nut b/Bullwinkle.class.nut index 92f76a2..78ac662 100644 --- a/Bullwinkle.class.nut +++ b/Bullwinkle.class.nut @@ -167,8 +167,11 @@ class Bullwinkle { _packages[message.id]._tries++; } - // Send the message - _partner.send(BULLWINKLE, message); + if(server.isconnected()) // Send the message + _partner.send(BULLWINKLE, message); + else if(message.id in _packages) //run the timeout flow (if the package exists) + _packageTimeout(_packages[message.id]) + } // Sends a response (ACK, NACK, REPLY) to a message @@ -399,6 +402,37 @@ class Bullwinkle { }.bindenv(this); }; + // Call the onFail handler when a timeout occurs + // + // Parameters: + // package The Bullwinkle.Package that has timed out + // + function _packageTimeout(package){ + // Grab the onFail handler + local handler = package.getHandler("onFail"); + + // If the handler doesn't exists + if (handler == null) { + // Delete the package, and move to next package + delete _packages[message.id]; + continue; + } + + // Grab a reference to this + local __bull = this; + + // Build the retry method for onFail + local retry = _retryFactory(message); + + // Invoke the handlers + message.type = BULLWINKLE_MESSAGE_TYPE.TIMEOUT + handler(BULLWINKLE_ERR_NO_RESPONSE, message, retry); + // Delete the message if there wasn't a retry attempt + if (message.type == BULLWINKLE_MESSAGE_TYPE.TIMEOUT) { + delete __bull._packages[message.id]; + } + } + // checks that TIMER was set, calles onError callback if needed // // Parameters: @@ -438,29 +472,7 @@ class Bullwinkle { // if it's a message awaiting a reply local ts = "retry" in message ? message.retry.ts : split(package._ts, ".")[0].tointeger(); //Use either the retry ts or the package ts, but NOT the message ts so that it can be set for whenever the data was generated, instead of when Bullwinkle attempted to send it if (t >= (ts + _settings.messageTimeout)) { - // Grab the onFail handler - local handler = package.getHandler("onFail"); - - // If the handler doesn't exists - if (handler == null) { - // Delete the package, and move to next package - delete _packages[message.id]; - continue; - } - - // Grab a reference to this - local __bull = this; - - // Build the retry method for onFail - local retry = _retryFactory(message); - - // Invoke the handlers - message.type = BULLWINKLE_MESSAGE_TYPE.TIMEOUT - handler(BULLWINKLE_ERR_NO_RESPONSE, message, retry); - // Delete the message if there wasn't a retry attempt - if (message.type == BULLWINKLE_MESSAGE_TYPE.TIMEOUT) { - delete __bull._packages[message.id]; - } + _packageTimeout(package) } } From 478450370c499022465d9b28713ec3b8a88a244a Mon Sep 17 00:00:00 2001 From: Austin Eldridge Date: Tue, 27 Sep 2016 15:19:37 -0400 Subject: [PATCH 06/13] Revert "Add prependID to settings" This reverts commit d07ea661a9d092320240af79627adb55333588f0. --- Bullwinkle.class.nut | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Bullwinkle.class.nut b/Bullwinkle.class.nut index 78ac662..0a39f7e 100644 --- a/Bullwinkle.class.nut +++ b/Bullwinkle.class.nut @@ -50,7 +50,6 @@ class Bullwinkle { "retryTimeout": ("retryTimeout" in settings) ? settings["retryTimeout"].tostring().tointeger() : 60, "maxRetries": ("maxRetries" in settings) ? settings["maxRetries"].tostring().tointeger() : 0, "autoRetry" : ("autoRetry" in settings) ? settings["autoRetry"] : false, - "prependID" : ("prependID" in settings) ? settings["prependID"].tostring() + "|" : "" "onError" : ("onError" in settings) ? settings["onError"] : null }; @@ -124,7 +123,7 @@ class Bullwinkle { function _generateId() { // Get the next ID while (++_nextId in _packages) { - _nextId = _settings.prependID + ((_nextId + 1) % RAND_MAX); + _nextId = (_nextId + 1) % RAND_MAX; } // Return the generated ID From e2149af0b3e32b7419a59c64a93f29cad95a35da Mon Sep 17 00:00:00 2001 From: Austin Eldridge Date: Mon, 3 Oct 2016 16:54:46 -0400 Subject: [PATCH 07/13] Bug fixes identified during testing --- Bullwinkle.class.nut | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Bullwinkle.class.nut b/Bullwinkle.class.nut index 0a39f7e..97780ea 100644 --- a/Bullwinkle.class.nut +++ b/Bullwinkle.class.nut @@ -169,7 +169,9 @@ class Bullwinkle { if(server.isconnected()) // Send the message _partner.send(BULLWINKLE, message); else if(message.id in _packages) //run the timeout flow (if the package exists) - _packageTimeout(_packages[message.id]) + imp.wakeup(0, function(){ // on the next tick so that the onFail handler can have a chance to register itself + _packageTimeout(_packages[message.id]) + }.bindenv(this)) } @@ -389,7 +391,7 @@ class Bullwinkle { // Add the retry information message.retry <- { - "ts": time() + timeout, + "ts": ( Bullwinkle._isAgent() ? time() : hardware.micros()/1000000 ) + timeout, "sent": false }; @@ -406,15 +408,15 @@ class Bullwinkle { // Parameters: // package The Bullwinkle.Package that has timed out // - function _packageTimeout(package){ + function _packageTimeout(package) { // Grab the onFail handler local handler = package.getHandler("onFail"); + local message = package._message // If the handler doesn't exists if (handler == null) { // Delete the package, and move to next package delete _packages[message.id]; - continue; } // Grab a reference to this From e5d00f7fcc12c5b6dbb9102e44c2af779080d49c Mon Sep 17 00:00:00 2001 From: Austin Eldridge Date: Tue, 4 Oct 2016 15:21:18 -0400 Subject: [PATCH 08/13] Bug fix for usage on Agent --- Bullwinkle.class.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bullwinkle.class.nut b/Bullwinkle.class.nut index 97780ea..623b48d 100644 --- a/Bullwinkle.class.nut +++ b/Bullwinkle.class.nut @@ -166,7 +166,7 @@ class Bullwinkle { _packages[message.id]._tries++; } - if(server.isconnected()) // Send the message + if(_isAgent() || server.isconnected()) // Send the message _partner.send(BULLWINKLE, message); else if(message.id in _packages) //run the timeout flow (if the package exists) imp.wakeup(0, function(){ // on the next tick so that the onFail handler can have a chance to register itself From adb215ac45d1b6c342d284ee60e04101be6d090a Mon Sep 17 00:00:00 2001 From: Austin Eldridge Date: Tue, 4 Oct 2016 15:50:34 -0400 Subject: [PATCH 09/13] Add lowMemoryThreshold setting to address #18. --- Bullwinkle.class.nut | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/Bullwinkle.class.nut b/Bullwinkle.class.nut index 623b48d..83147b8 100644 --- a/Bullwinkle.class.nut +++ b/Bullwinkle.class.nut @@ -9,13 +9,15 @@ enum BULLWINKLE_MESSAGE_TYPE { REPLY, ACK, NACK, - TIMEOUT, + FAILED, DONE } // Error messages const BULLWINKLE_ERR_NO_HANDLER = "No handler for Bullwinkle message"; const BULLWINKLE_ERR_NO_RESPONSE = "No Response from partner"; +const BULLWINKLE_ERR_LOW_MEMORY = "imp running below low memory threshold"; +const BULLWINKLE_ERR_NO_CONNECTION = "server.isconnected() == false" const BULLWINKLE_ERR_TOO_MANY_TIMERS = "Too many timers"; const BULLWINKLE_WATCHDOG_TIMER = 0.5; @@ -46,11 +48,12 @@ class Bullwinkle { constructor(settings = {}) { // Initialize settings _settings = { - "messageTimeout": ("messageTimeout" in settings) ? settings["messageTimeout"].tostring().tointeger() : 10, - "retryTimeout": ("retryTimeout" in settings) ? settings["retryTimeout"].tostring().tointeger() : 60, - "maxRetries": ("maxRetries" in settings) ? settings["maxRetries"].tostring().tointeger() : 0, - "autoRetry" : ("autoRetry" in settings) ? settings["autoRetry"] : false, - "onError" : ("onError" in settings) ? settings["onError"] : null + "messageTimeout": ("messageTimeout" in settings) ? settings["messageTimeout"].tostring().tointeger() : 10, + "retryTimeout": ("retryTimeout" in settings) ? settings["retryTimeout"].tostring().tointeger() : 60, + "maxRetries": ("maxRetries" in settings) ? settings["maxRetries"].tostring().tointeger() : 0, + "autoRetry" : ("autoRetry" in settings) ? settings["autoRetry"] : false, + "lowMemoryThreshold": ("lowMemoryThreshold" in settings) ? settings["lowMemoryThreshold"] : 15000, + "onError" : ("onError" in settings) ? settings["onError"] : null }; // Initialize out message handlers @@ -166,13 +169,14 @@ class Bullwinkle { _packages[message.id]._tries++; } - if(_isAgent() || server.isconnected()) // Send the message - _partner.send(BULLWINKLE, message); - else if(message.id in _packages) //run the timeout flow (if the package exists) - imp.wakeup(0, function(){ // on the next tick so that the onFail handler can have a chance to register itself - _packageTimeout(_packages[message.id]) + if(imp.getmemoryfree() > _settings.lowMemoryThreshold && (_isAgent() || server.isconnected())){ + _partner.send(BULLWINKLE, message); // Send the message + } else if(message.id in _packages){ //run the failure flow (if the package exists) + local reason = imp.getmemoryfree() <= _settings.lowMemoryThreshold ? BULLWINKLE_ERR_LOW_MEMORY : BULLWINKLE_ERR_NO_CONNECTION + imp.wakeup(0, function(){ // run on the "next tick" so that the onFail handler can have a chance to register itself + _packageFailed(_packages[message.id], reason) }.bindenv(this)) - + } } // Sends a response (ACK, NACK, REPLY) to a message @@ -408,7 +412,7 @@ class Bullwinkle { // Parameters: // package The Bullwinkle.Package that has timed out // - function _packageTimeout(package) { + function _packageFailed(package, reason) { // Grab the onFail handler local handler = package.getHandler("onFail"); local message = package._message @@ -426,10 +430,10 @@ class Bullwinkle { local retry = _retryFactory(message); // Invoke the handlers - message.type = BULLWINKLE_MESSAGE_TYPE.TIMEOUT - handler(BULLWINKLE_ERR_NO_RESPONSE, message, retry); + message.type = BULLWINKLE_MESSAGE_TYPE.FAILED + handler(reason, message, retry); // Delete the message if there wasn't a retry attempt - if (message.type == BULLWINKLE_MESSAGE_TYPE.TIMEOUT) { + if (message.type == BULLWINKLE_MESSAGE_TYPE.FAILED) { delete __bull._packages[message.id]; } } @@ -473,7 +477,7 @@ class Bullwinkle { // if it's a message awaiting a reply local ts = "retry" in message ? message.retry.ts : split(package._ts, ".")[0].tointeger(); //Use either the retry ts or the package ts, but NOT the message ts so that it can be set for whenever the data was generated, instead of when Bullwinkle attempted to send it if (t >= (ts + _settings.messageTimeout)) { - _packageTimeout(package) + _packageFailed(package, BULLWINKLE_ERR_NO_RESPONSE) } } From 82ce3b4db2e1d8a1406716fe0d74ead5e3074960 Mon Sep 17 00:00:00 2001 From: Austin Eldridge Date: Wed, 5 Oct 2016 11:45:22 -0400 Subject: [PATCH 10/13] Bug fix for messages not calling their onFail handlers after a timeout --- Bullwinkle.class.nut | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/Bullwinkle.class.nut b/Bullwinkle.class.nut index 83147b8..d6a03a7 100644 --- a/Bullwinkle.class.nut +++ b/Bullwinkle.class.nut @@ -455,7 +455,7 @@ class Bullwinkle { // message timeouts. function _watchdog() { // Get the current time - local t = Bullwinkle._isAgent() ? time() : hardware.micros()/1000000 + local t = time() // Loop through all the cached packages foreach(idx, package in _packages) { @@ -475,9 +475,12 @@ class Bullwinkle { } // if it's a message awaiting a reply - local ts = "retry" in message ? message.retry.ts : split(package._ts, ".")[0].tointeger(); //Use either the retry ts or the package ts, but NOT the message ts so that it can be set for whenever the data was generated, instead of when Bullwinkle attempted to send it - if (t >= (ts + _settings.messageTimeout)) { - _packageFailed(package, BULLWINKLE_ERR_NO_RESPONSE) + local ts = "retry" in message ? message.retry.ts : split(package._ts, ".")[0].tointeger(); //Use either the retry ts or the package ts time(), but NOT the message ts so that it can be set for whenever the data was generated, instead of when Bullwinkle attempted to send it + if (t >= (ts + _settings.messageTimeout) || t == 946684800) { //RTC is invalid, which implies we have no connection and should retry immediately. + local timer = imp.wakeup(0.0, function(){ + _packageFailed(package, BULLWINKLE_ERR_NO_RESPONSE) + }.bindenv(this)); + _checkTimer(timer) } } @@ -568,10 +571,15 @@ class Bullwinkle.Package { // // Returns: The time difference in seconds (float) between the packages timestamp and now() function getLatency() { - local t0 = split(_ts, "."); - local t1 = split(_timestamp(), "."); - local diff = (t1[0].tointeger() - t0[0].tointeger()) + (t1[1].tointeger() - t0[1].tointeger()) / 1000000.0; + local t0 = split(_ts, "."); + local t1 = split(_timestamp(), "."); + + if (Bullwinkle._isAgent()) { + local diff = (t1[0].tointeger() - t0[0].tointeger()) + ( (t1[1].tointeger() - t0[1].tointeger()) / 1000000.0); return math.fabs(diff); + } else { + return (t1[1].tointeger() - t0[1].tointeger()) / 1000000.0; + } } // Returns the time in a string format that can be used for calculating latency @@ -584,8 +592,7 @@ class Bullwinkle.Package { local d = date(); return format("%d.%06d", d.time, d.usec); } else { - local d = math.abs(hardware.micros()); - return format("%d.%06d", d/1000000, d%1000000); + return format("%d.%06d", time(), hardware.micros()); //this can be a bit of an ugly _ts but it allows us to calculate latencies up to 36 minutes long... } } } From b9b01553e3fe454a4f0ca9687944c79a1a1c147b Mon Sep 17 00:00:00 2001 From: Austin Eldridge Date: Wed, 5 Oct 2016 11:45:46 -0400 Subject: [PATCH 11/13] Add _checkTimer for all imp.wakeup's --- Bullwinkle.class.nut | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Bullwinkle.class.nut b/Bullwinkle.class.nut index d6a03a7..38b4a41 100644 --- a/Bullwinkle.class.nut +++ b/Bullwinkle.class.nut @@ -173,9 +173,11 @@ class Bullwinkle { _partner.send(BULLWINKLE, message); // Send the message } else if(message.id in _packages){ //run the failure flow (if the package exists) local reason = imp.getmemoryfree() <= _settings.lowMemoryThreshold ? BULLWINKLE_ERR_LOW_MEMORY : BULLWINKLE_ERR_NO_CONNECTION - imp.wakeup(0, function(){ // run on the "next tick" so that the onFail handler can have a chance to register itself - _packageFailed(_packages[message.id], reason) - }.bindenv(this)) + + local timer = imp.wakeup(0.0, function(){ // run on the "next tick" so that the onFail handler can have a chance to register itself + _packageFailed(_packages[message.id], reason) + }.bindenv(this)); + _checkTimer(timer) } } @@ -438,7 +440,7 @@ class Bullwinkle { } } - // checks that TIMER was set, calles onError callback if needed + // checks that TIMER was set, calls onError callback if needed // // Parameters: // timer The value returned by calling imp.wakeup From 5e91b880aecd99c88cd1e3fe4322a756b87b64b3 Mon Sep 17 00:00:00 2001 From: Austin Eldridge Date: Wed, 5 Oct 2016 11:56:12 -0400 Subject: [PATCH 12/13] Add firstMessageID setting to Bullwinkle. When used with some kind of nv storage, this allows for preventing ID collisions on the Agent or with something like impPager. --- Bullwinkle.class.nut | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Bullwinkle.class.nut b/Bullwinkle.class.nut index 38b4a41..3472bff 100644 --- a/Bullwinkle.class.nut +++ b/Bullwinkle.class.nut @@ -52,7 +52,8 @@ class Bullwinkle { "retryTimeout": ("retryTimeout" in settings) ? settings["retryTimeout"].tostring().tointeger() : 60, "maxRetries": ("maxRetries" in settings) ? settings["maxRetries"].tostring().tointeger() : 0, "autoRetry" : ("autoRetry" in settings) ? settings["autoRetry"] : false, - "lowMemoryThreshold": ("lowMemoryThreshold" in settings) ? settings["lowMemoryThreshold"] : 15000, + "lowMemoryThreshold": ("lowMemoryThreshold" in settings) ? settings["lowMemoryThreshold"].tointeger() : 15000, + "firstMessageID": ("firstMessageID" in settings) ? settings["firstMessageID"].tointeger() : 0 "onError" : ("onError" in settings) ? settings["onError"] : null }; @@ -62,8 +63,8 @@ class Bullwinkle { // Initialize list of packages _packages = {}; - // Initialize the ID counter - _nextId = 0; + // Initialize the ID counter (can be set to math.rand() or the last message ID you have in nv to prevent ID collisions with something like impPager) + _nextId = settings.firstMessageID; // Setup the agent/device.on handler _partner = _isAgent() ? device : agent; From b1514ce82fc5501a40a0a5150e53ee48cec54dc2 Mon Sep 17 00:00:00 2001 From: Austin Eldridge Date: Sat, 26 Nov 2016 10:02:30 -0500 Subject: [PATCH 13/13] bugfix for ts --- Bullwinkle.class.nut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Bullwinkle.class.nut b/Bullwinkle.class.nut index 3472bff..426f422 100644 --- a/Bullwinkle.class.nut +++ b/Bullwinkle.class.nut @@ -99,7 +99,7 @@ class Bullwinkle { // Parameters: // name The message name // data Optional data - // ts Optional timestamp for the data + // ts Optional timestamp for the data // // Returns: Bullwinkle.Package object function send(name, data = null, ts = null) { @@ -343,7 +343,7 @@ class Bullwinkle { handler(BULLWINKLE_ERR_NO_HANDLER, message, retry); // Delete the message if the dev didn't retry - if (message.type == BULLWINKLE_MESSAGE_TYPE.NACK) { + if (message.type == BULLWINKLE_MESSAGE_TYPE.NACK && message.id in __bull.packages) { delete __bull._packages[message.id]; } });