You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Update to rebuild timestamps for conditions where the imp boots offline and has no RTC.
This is accomplished by logging hardware.millis() to the spiflashlogger and then syncing hardware.millis() with time(), once our cloud connection is made and time() is restored
Copy file name to clipboardExpand all lines: ImpPager.class.nut
+93-31
Original file line number
Diff line number
Diff line change
@@ -1,14 +1,16 @@
1
1
#require "SPIFlashLogger.class.nut:2.1.0"
2
2
#require "ConnectionManager.class.nut:1.0.1"
3
3
#require "Serializer.class.nut:1.0.0"
4
-
#require "bullwinkle.class.nut:2.3.1"
4
+
#require "bullwinkle.class.nut:2.3.2"
5
5
6
6
const IMP_PAGER_MESSAGE_TIMEOUT =1;
7
7
const IMP_PAGER_RETRY_PERIOD_SEC =0.5;
8
8
9
9
const IMP_PAGER_CM_DEFAULT_SEND_TIMEOUT =1;
10
10
const IMP_PAGER_CM_DEFAULT_BUFFER_SIZE =8096;
11
11
12
+
const RTC_INVALID_TIME =946684800; //Saturday 1st January 2000 12:00:00 AM UTC - this is what time() returns if the RTC signal from the imp cloud has not been received this boot.
13
+
12
14
classImpPager {
13
15
14
16
// Bullwinkle instance
@@ -23,10 +25,16 @@ class ImpPager {
23
25
// Message retry timer
24
26
_retryTimer =null;
25
27
28
+
// The number of boots that this device has had - used to detect if multiple reboots without a RTC have occurred. If bootNumber is not set, we will not attempt to recover from a lack of RTC.
29
+
_bootNumber =null;
30
+
31
+
// array of [lastTSmillis, lastTStimeSec] used for rebuilding timestamps for if/when we didn't have a RTC.
// Set the bootNumber. If a BootNumber is provided, we will try to rebuild timestamps for conditions where we boot offline and without a RTC. Otherwise, we won't.
48
+
_bootNumber = bootNumber
49
+
39
50
// Schedule routine to retry sending messages
40
51
_scheduleRetryIfConnected();
41
52
42
53
_debug = debug;
43
54
}
44
55
45
-
functionsend(messageName, data =null) {
46
-
_send(messageName, data);
56
+
functionsend(messageName, data =null, ts =null) {
57
+
if(ts ==null) ts =time()
58
+
if(_bootNumber!=null&& ts == RTC_INVALID_TIME) ts = _bootNumber +"-"+ hardware.millis() //provides ms accurate delta times that can be up to 25 days (2^31ms) apart. We use typeof(ts) == "string" to detect that our RTC has not been set in the .onFail.
_log_debug("Failed to deliver message id "+ message.id+" with name: '"+ message.name+"' and data: "+ message.data+", err: "+ err);
77
+
62
78
// On fail write the message to the SPI Flash for further processing
63
79
// only if it's not already there.
64
80
if (!("metadata"in message) ||!("addr"in message.metadata) ||!(message.metadata.addr)) {
81
+
delete message.type//Not needed to write to SPIFlash, as the type will always be BULLWINKLE_MESSAGE_TYPE.SEND
82
+
83
+
if(typeof(message.ts) =="string") { // We have a _bootNumber and invalid RTC - add some metadata so that we can try to restore the timestamp once we have RTC.
84
+
message.metadata <- {
85
+
"boot": split(message.ts, "-")[0].tointeger()
86
+
"rtc": false
87
+
}
88
+
message.ts=split(message.ts, "-")[1].tointeger()
89
+
}
65
90
_spiFlashLogger.write(message);
91
+
message.type <- BULLWINKLE_MESSAGE_TYPE.TIMEOUT // We are mucking around with the internal logic of Bullwinkle so we need to repair the message object here
66
92
}
67
93
_scheduleRetryIfConnected();
68
94
}
69
95
70
-
function_send(messageName, data) {
71
-
return _bullwinkle.send(messageName, data)
72
-
.onSuccess(_onSuccess.bindenv(this))
73
-
.onFail(_onFail.bindenv(this));
74
-
}
75
-
76
96
// This is a hack to resend the message with metainformation
_lastTS = [hardware.millis(), time()] //With these two datapoints, we can now re-establish all of our timestamps
138
+
_log_debug("Discovered most recent datapoint saved to SPIFlash without RTC - "+ dataPoint.id+" attempting to rebuild timestamps with ms = "+ _lastTS[0] +" and time = "+ _lastTS[1])
139
+
}
140
+
141
+
_log_debug("Found log without RTC. ID="+ dataPoint.id+" and ts="+dataPoint.ts)
dataPoint.ts= _lastTS[1] - deltaTSeconds //All integer math, so no need to worry about decimal points
147
+
148
+
_log_debug("Calculated new ts as "+ dataPoint.ts+"(deltaT = "+ deltaTMillis +" ms)")
149
+
150
+
//update _lastTS so that we can have 25 days between datapoints instead of 25 days total of timestamps that we can rebuild
151
+
_lastTS[0] -= (deltaTSeconds*1000)
152
+
_lastTS[1] = dataPoint.ts
153
+
154
+
// Our RTC has been reset - delete the metadata
155
+
delete dataPoint.metadata.rtc
156
+
157
+
158
+
159
+
} else {
160
+
server.error("Warning - dataPoint bootNumber "+ dpBootNum +" != device bootNumber "+ _bootNumber +" for message ID "+ dataPoint.id+". Unable to rebuild ts...")
161
+
}
162
+
}
163
+
164
+
_resendLoggedData(dataPoint);
165
+
104
166
// Don't do any further scanning until we get an ACK for already sent message
105
167
next(false);
106
168
}.bindenv(this),
107
-
function() {
108
-
_log_debug("Finished processing all pending messages");
109
-
}.bindenv(this)
169
+
170
+
null,
171
+
172
+
-1// Read through the data from most recent (which is important for real-time apps) to oldest, 1 at a time. This also allows us to rebuild our timestamps from newest to oldest
110
173
);
111
174
}
112
175
@@ -156,15 +219,15 @@ class ImpPager.ConnectionManager extends ConnectionManager {
156
219
constructor(settings = {}) {
157
220
base.constructor(settings);
158
221
159
-
// Override the timeout to make it a nonzero, but still
160
-
// a small value. This is needed to avoid accedental
222
+
// Override the timeout to make it a nonzero, but still
223
+
// a small value. This is needed to avoid accedental
161
224
// imp disconnects when using ConnectionManager library
0 commit comments