-
Notifications
You must be signed in to change notification settings - Fork 511
/
system_cloud.cpp
348 lines (308 loc) · 11.8 KB
/
system_cloud.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
/**
******************************************************************************
* @file system_cloud.cpp
* @author Satish Nair, Zachary Crockett, Mohit Bhoite, Matthew McGowan
* @version V1.0.0
* @date 13-March-2013
*
* Updated: 14-Feb-2014 David Sidrane <david_s5@usa.net>
* @brief
******************************************************************************
Copyright (c) 2013-2015 Particle Industries, Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either
version 3 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
******************************************************************************
*/
#include <cstdarg>
#include "logging.h"
#include "protocol_defs.h"
#include "spark_wiring_string.h"
#include "spark_wiring_timer.h"
#include "spark_wiring_cloud.h"
#include "system_cloud.h"
#include "system_cloud_internal.h"
#include "system_cloud_connection.h"
#include "system_publish_vitals.h"
#include "system_task.h"
#include "system_threading.h"
#include "system_update.h"
#include "system_cloud_internal.h"
#include "system_connection_manager.h"
#include "string_convert.h"
#include "spark_protocol_functions.h"
#include "events.h"
#include "coap_defs.h"
#include "deviceid_hal.h"
#include "system_mode.h"
#if PLATFORM_THREADING
#include "spark_wiring_timer.h"
#endif // PLATFORM_THREADING
extern void (*random_seed_from_cloud_handler)(unsigned int);
namespace
{
using namespace particle;
using namespace particle::system;
#if PLATFORM_THREADING
VitalsPublisher<Timer> _vitals;
#else // not PLATFORM_THREADING
VitalsPublisher<NullTimer> _vitals;
#endif // PLATFORM_THREADING
// These properties are forwarded to the protocol instance as is
static_assert(SPARK_CLOUD_PING_INTERVAL == (int)protocol::Connection::PING,
"The value of SPARK_CLOUD_PING_INTERVAL has changed");
static_assert(SPARK_CLOUD_FAST_OTA_ENABLED == (int)protocol::Connection::FAST_OTA,
"The value of SPARK_CLOUD_FAST_OTA_ENABLED has changed");
int getConnectionProperty(protocol::Connection::Enum property, void* data, size_t* size) {
const int r = spark_protocol_get_connection_property(sp, property, data, size, nullptr /* reserved */);
if (r != 0) {
return SYSTEM_ERROR_PROTOCOL;
}
return 0;
}
} // namespace
int spark_publish_vitals(system_tick_t period_s_, void* reserved_)
{
SYSTEM_THREAD_CONTEXT_SYNC(spark_publish_vitals(period_s_, reserved_));
int result;
switch (period_s_)
{
case particle::NOW:
result = _vitals.publish();
break;
case 0:
_vitals.disablePeriodicPublish();
result = _vitals.publish();
break;
default:
_vitals.period(period_s_);
_vitals.enablePeriodicPublish();
result = _vitals.publish();
}
return result;
}
bool spark_subscribe(const char* event_name, EventHandler handler, void* handler_data,
Spark_Subscription_Scope_TypeDef scope_deprecated, const char* device_id_deprecated, spark_subscribe_param* param)
{
SYSTEM_THREAD_CONTEXT_SYNC(spark_subscribe(event_name, handler, handler_data, scope_deprecated, device_id_deprecated, param));
int flags = 0;
if (param) {
if (param->flags & SUBSCRIBE_FLAG_CBOR_DATA) {
flags |= SubscriptionFlag::CBOR_DATA;
}
if (param->flags & SUBSCRIBE_FLAG_BINARY_DATA) {
flags |= SubscriptionFlag::BINARY_DATA;
}
}
bool ok = spark_protocol_add_event_handler(sp, event_name, handler, flags, nullptr /* device_id_deprecated */, handler_data);
if (ok && spark_cloud_flag_connected() && (system_mode() != AUTOMATIC || APPLICATION_SETUP_DONE)) {
ok = spark_protocol_send_subscription(sp, event_name, flags, nullptr /* reserved */);
}
return ok;
}
void spark_unsubscribe(void *reserved)
{
SYSTEM_THREAD_CONTEXT_ASYNC(spark_unsubscribe(reserved));
spark_protocol_remove_event_handlers(sp, NULL); // Clear all subscriptions
registerSystemSubscriptions(); // Re-add system subscriptions
// TODO: Notify the cloud that subscriptions have been cleared
}
static void spark_sync_time_impl()
{
SYSTEM_THREAD_CONTEXT_ASYNC(spark_sync_time_impl());
spark_protocol_send_time_request(sp);
}
bool spark_sync_time(void *reserved)
{
spark_sync_time_impl();
return spark_cloud_flag_connected();
}
bool spark_sync_time_pending(void* reserved)
{
SYSTEM_THREAD_CONTEXT_SYNC(spark_sync_time_pending(reserved));
return spark_protocol_time_request_pending(system_cloud_protocol_instance(), nullptr);
}
system_tick_t spark_sync_time_last(time32_t* tm32, time_t* tm)
{
SYSTEM_THREAD_CONTEXT_SYNC(spark_sync_time_last(tm32, tm));
return spark_protocol_time_last_synced(system_cloud_protocol_instance(), tm32, tm);
}
bool spark_send_event(const char* name, const char* data, int ttl, uint32_t flags, void* reserved)
{
if (flags & PUBLISH_EVENT_FLAG_ASYNC) {
SYSTEM_THREAD_CONTEXT_ASYNC_RESULT(spark_send_event(name, data, ttl, flags, reserved), true);
} else {
SYSTEM_THREAD_CONTEXT_SYNC(spark_send_event(name, data, ttl, flags, reserved));
}
spark_protocol_send_event_data d = {};
d.size = sizeof(d);
d.content_type = (int)protocol::CoapContentFormat::TEXT_PLAIN;
bool hasDataSize = false;
if (reserved) {
// Forward completion callback to the protocol implementation
auto r = static_cast<const spark_send_event_data*>(reserved);
d.handler_callback = r->handler_callback;
d.handler_data = r->handler_data;
if (r->size >= offsetof(spark_send_event_data, data_size) + sizeof(spark_send_event_data::data_size) +
sizeof(spark_send_event_data::content_type)) {
d.data_size = r->data_size;
d.content_type = r->content_type;
hasDataSize = true;
}
}
if (!hasDataSize) {
d.data_size = data ? std::strlen(data) : 0;
}
// Visibility flags no longer have effect
flags &= ~PUBLISH_EVENT_FLAG_PRIVATE;
return spark_protocol_send_event(sp, name, data, ttl, flags, &d);
}
bool spark_variable(const char *varKey, const void *userVar, Spark_Data_TypeDef userVarType, spark_variable_t* extra)
{
SYSTEM_THREAD_CONTEXT_SYNC(spark_variable(varKey, userVar, userVarType, extra));
User_Var_Lookup_Table_t* item = NULL;
if (NULL != userVar && NULL != varKey && strlen(varKey)<=USER_VAR_KEY_LENGTH)
{
item=find_var_by_key_or_add(varKey, userVar, userVarType, extra);
}
return item!=NULL;
}
/**
* This is the original released signature for firmware version 0 and needs to remain like this.
* (The original returned void - we can safely change to bool.)
*/
bool spark_function(const char *funcKey, p_user_function_int_str_t pFunc, void* reserved)
{
SYSTEM_THREAD_CONTEXT_SYNC(spark_function(funcKey, pFunc, reserved));
bool result;
if (funcKey) { // old call, with funcKey != NULL
cloud_function_descriptor desc = {};
desc.size = sizeof(desc);
desc.funcKey = funcKey;
desc.fn = call_raw_user_function;
desc.data = (void*)pFunc;
result = spark_function_internal(&desc, NULL);
}
else { // new call - pFunc is actually a pointer to a descriptor
result = spark_function_internal((cloud_function_descriptor*)pFunc, reserved);
}
return result;
}
bool spark_cloud_flag_connected(void)
{
return (SPARK_CLOUD_SOCKETED && SPARK_CLOUD_CONNECTED);
}
int spark_cloud_disconnect(const spark_cloud_disconnect_options* options, void* reserved)
{
CloudDisconnectOptions opts;
if (options) {
opts = CloudDisconnectOptions::fromSystemOptions(options);
}
if (spark_cloud_flag_connected()) {
CloudConnectionSettings::instance()->setPendingDisconnectOptions(std::move(opts));
spark_cloud_flag_disconnect();
} else {
spark_cloud_flag_disconnect();
if (opts.isClearSessionSet() && opts.clearSession()) {
SYSTEM_THREAD_CONTEXT_SYNC_CALL([]() {
clearSessionData();
return 0;
}());
// Note: The above SYSTEM_THREAD_CONTEXT_SYNC_CALL() causes this function to return
}
}
return 0;
}
bool spark_process(void)
{
// application thread will pump application messages
#if PLATFORM_THREADING
if (APPLICATION_THREAD_CURRENT()) {
if (system_thread_get_state(NULL)) {
bool result = ApplicationThread.process();
g_lastAppLoopProcessTime = HAL_Timer_Get_Milli_Seconds();
return result;
} else {
Spark_Idle_Events(true);
}
}
#else
// run the background processing loop, and specifically also pump cloud events
Spark_Idle_Events(true);
#endif // PLATFORM_THREADING
return false;
}
String spark_deviceID(void)
{
unsigned len = hal_get_device_id(NULL, 0);
uint8_t id[len];
hal_get_device_id(id, len);
return bytes2hex(id, len);
}
int spark_set_connection_property(unsigned property, unsigned value, const void* data, void* reserved)
{
SYSTEM_THREAD_CONTEXT_SYNC(spark_set_connection_property(property, value, data, reserved));
switch (property) {
case SPARK_CLOUD_DISCONNECT_OPTIONS: {
const auto d = (const spark_cloud_disconnect_options*)data;
auto opts = CloudDisconnectOptions::fromSystemOptions(d);
CloudConnectionSettings::instance()->setDefaultDisconnectOptions(std::move(opts));
return 0;
}
// These properties are forwarded to the protocol instance as is
case SPARK_CLOUD_PING_INTERVAL:
case SPARK_CLOUD_FAST_OTA_ENABLED: {
const auto d = (const protocol::connection_properties_t*)data;
const auto r = spark_protocol_set_connection_property(sp, property, value, d, reserved);
return spark_protocol_to_system_error(r);
}
default:
return SYSTEM_ERROR_INVALID_ARGUMENT;
}
}
int spark_get_connection_property(unsigned property, void* data, size_t* size, void* reserved)
{
SYSTEM_THREAD_CONTEXT_SYNC(spark_get_connection_property(property, data, size, reserved));
switch (property) {
case SPARK_CLOUD_MAX_EVENT_DATA_SIZE:
if (!SPARK_CLOUD_CONNECTED) {
return SYSTEM_ERROR_INVALID_STATE;
}
return getConnectionProperty(protocol::Connection::MAX_EVENT_DATA_SIZE, data, size);
case SPARK_CLOUD_MAX_VARIABLE_VALUE_SIZE:
if (!SPARK_CLOUD_CONNECTED) {
return SYSTEM_ERROR_INVALID_STATE;
}
return getConnectionProperty(protocol::Connection::MAX_VARIABLE_VALUE_SIZE, data, size);
case SPARK_CLOUD_MAX_FUNCTION_ARGUMENT_SIZE:
if (!SPARK_CLOUD_CONNECTED) {
return SYSTEM_ERROR_INVALID_STATE;
}
return getConnectionProperty(protocol::Connection::MAX_FUNCTION_ARGUMENT_SIZE, data, size);
case SPARK_CLOUD_GET_NETWORK_INTERFACE: {
if (*size >= sizeof(network_interface_t)) {
#if HAL_PLATFORM_IFAPI
*((network_interface_t*)data) = ConnectionManager::instance()->getCloudConnectionNetwork();
#else
*((network_interface_t*)data) = NETWORK_INTERFACE_ALL;
#endif
return 0;
}
return SYSTEM_ERROR_INVALID_ARGUMENT;
}
default:
return SYSTEM_ERROR_INVALID_ARGUMENT;
}
}
int spark_set_random_seed_from_cloud_handler(void (*handler)(unsigned int), void* reserved)
{
random_seed_from_cloud_handler = handler;
return 0;
}