1
1
#include < Arduino.h>
2
2
#include < ArduinoCloudThing.h>
3
3
4
- ArduinoCloudThing::ArduinoCloudThing () {
4
+ #ifdef DEBUG_MEMORY
5
+ extern " C" char *sbrk (int i);
6
+ void PrintFreeRam (void )
7
+ {
8
+ char stack_dummy = 0 ;
9
+ Serial.print (" Free RAM: " ); Serial.println (&stack_dummy - sbrk (0 ));
10
+ }
11
+ #endif
5
12
13
+ #ifdef ARDUINO_ARCH_SAMD
14
+ static void utox8 (uint32_t val, char * s) {
15
+ for (int i = 0 ; i < 8 ; i++) {
16
+ int d = val & 0XF ;
17
+ val = (val >> 4 );
18
+
19
+ s[7 - i] = d > 9 ? ' A' + d - 10 : ' 0' + d;
20
+ }
21
+ }
22
+ #endif
23
+
24
+ #ifdef USE_ARDUINO_CLOUD
25
+
26
+ char MQTT_SERVER[] = " 10.130.22.94" ;
27
+ int MQTT_PORT = 1883 ;
28
+ char GENERAL_TOPIC[] = " /main" ;
29
+ char MQTT_USER[] = " " ;
30
+ char MQTT_PASSWORD[] = " " ;
31
+ char LWT_TOPIC[] = " " ;
32
+ char LWT_MESSAGE[] = " " ;
33
+
34
+ #endif
35
+
36
+ ArduinoCloudThing::ArduinoCloudThing () {
37
+ #ifdef ARDUINO_ARCH_SAMD
38
+ #define SERIAL_NUMBER_WORD_0 *(volatile uint32_t *)(0x0080A00C )
39
+ #define SERIAL_NUMBER_WORD_1 *(volatile uint32_t *)(0x0080A040 )
40
+ #define SERIAL_NUMBER_WORD_2 *(volatile uint32_t *)(0x0080A044 )
41
+ #define SERIAL_NUMBER_WORD_3 *(volatile uint32_t *)(0x0080A048 )
42
+
43
+ utox8 (SERIAL_NUMBER_WORD_0, &uuid[0 ]);
44
+ utox8 (SERIAL_NUMBER_WORD_1, &uuid[8 ]);
45
+ utox8 (SERIAL_NUMBER_WORD_2, &uuid[16 ]);
46
+ utox8 (SERIAL_NUMBER_WORD_3, &uuid[24 ]);
47
+ uuid[32 ] = ' \0 ' ;
48
+ #endif
6
49
}
7
50
8
51
/*
9
52
* begin() should prepare the environment
10
53
* connect
11
54
*/
12
55
13
- static constexpr char * PLACEHOLDER = " placeholder" ;
14
-
15
56
void ArduinoCloudThing::begin (Client &client) {
16
- this ->client = new MQTT::Client<ArduinoCloudThing, Network, Timer, MQTT_BUFFER_SIZE, 0 >(network );
17
- this ->network . setClient (& client);
18
- this ->options = MQTTPacket_connectData_initializer ;
19
- this ->client ->defaultMessageHandler . attach <ArduinoCloudThing>( this , &ArduinoCloudThing::callback );
57
+ this ->client = new MQTTClient ( );
58
+ this ->client -> onMessageAdvanced (ArduinoCloudThing::callback );
59
+ this ->client -> begin (MQTT_SERVER, MQTT_PORT, client) ;
60
+ this ->client ->setParent (( void *) this );
20
61
21
62
// using WiFi client and ECC508 connect to server
22
63
while (!connect ()) {
@@ -27,162 +68,203 @@ void ArduinoCloudThing::begin(Client &client) {
27
68
28
69
bool ArduinoCloudThing::connect () {
29
70
30
- #ifdef TESTING
71
+ #ifdef TESTING_PROTOCOL
31
72
return true ;
32
73
#endif
33
74
34
- if (!network.connect (PLACEHOLDER, 0xDEADBEEF )) {
35
- return false ;
36
- }
37
-
38
- options.clientID .cstring = PLACEHOLDER;
39
- options.username .cstring = PLACEHOLDER;
40
- options.password .cstring = PLACEHOLDER;
41
- options.keepAliveInterval = 10 ;
42
- options.willFlag = 0x1 ;
43
- options.will .topicName .cstring = PLACEHOLDER;
44
- options.will .message .cstring = PLACEHOLDER;
45
- options.will .retained = 0x1 ;
46
-
47
- if (client->connect (options) != 0 ) {
75
+ if (client->connect (uuid, MQTT_USER, MQTT_PASSWORD) != 0 ) {
48
76
// set status to ON
49
77
status = ON;
50
- addProperty (status, WRITE);
51
- // execute first poll() to syncronize the "manifest"
52
- poll ();
78
+ addProperty (status, READ);
53
79
// subscribe to "general" topic
54
- client->subscribe (" placeholder " , MQTT::QOS0, NULL );
80
+ client->subscribe (GENERAL_TOPIC );
55
81
return true ;
56
82
}
57
83
58
84
return false ;
59
85
}
60
86
61
- void ArduinoCloudThing::publish () {
87
+ void ArduinoCloudThing::publish (CborDynamicOutput& output ) {
62
88
63
89
bool retained = false ;
64
90
65
- CborDynamicOutput output;
66
- CborWriter writer (output);
91
+ unsigned char *buf = output.getData ();
67
92
68
- writer.writeTag (1 );
93
+ #ifdef TESTING_PROTOCOL
94
+ decode (buf, output.getSize ());
95
+ #endif
96
+
97
+ client->publish (GENERAL_TOPIC, (const char *)buf, output.getSize ());
69
98
70
99
for (int i = 0 ; i < list.size (); i++) {
71
100
ArduinoCloudPropertyGeneric *p = list.get (i);
72
- p->append (writer );
101
+ p->updateShadow ( );
73
102
}
74
-
75
- unsigned char *buf = output.getData ();
76
-
77
- decodeCBORData (buf, output.getSize ());
78
-
79
- MQTT::Message message;
80
- message.qos = MQTT::QOS0;
81
- message.retained = retained;
82
- message.dup = false ;
83
- message.payload = (void *)buf;
84
- message.payloadlen = output.getSize ();
85
- client->publish (topic, message);
86
103
}
87
104
88
105
// Reconnect to the mqtt broker
89
106
int ArduinoCloudThing::poll () {
90
107
91
- #ifndef TESTING
92
- if (!client->isConnected ()){
108
+ #ifndef TESTING_PROTOCOL
109
+ if (!client->connected ()){
93
110
if (!connect ()){
94
111
return 0 ;
95
112
}
96
113
}
97
- if (!network.connected () && client->isConnected ()) {
98
- client->disconnect ();
99
- }
100
114
#endif
101
115
102
116
// check if backing storage and cloud has diverged
103
- int diff_in = 0 ;
104
- int diff_out = 1 ;
105
- checkNewData (&diff_in , &diff_out);
106
- if (diff_out > 0 ) {
107
- publish ();
117
+ int diff = 0 ;
118
+ CborDynamicOutput output;
119
+ diff = checkNewData (output);
120
+ if (diff > 0 ) {
121
+ compress (output, diff);
122
+ publish (output);
108
123
}
109
- if (diff_in > 0 ) {
110
- update ();
124
+
125
+ #ifdef DEBUG_MEMORY
126
+ PrintFreeRam ();
127
+ #endif
128
+
129
+ return diff;
130
+ }
131
+
132
+ void ArduinoCloudThing::compress (CborDynamicOutput& output, int howMany) {
133
+
134
+ CborWriter writer (output);
135
+
136
+ writer.writeArray (howMany);
137
+
138
+ for (int i = 0 ; i < list.size (); i++) {
139
+ ArduinoCloudPropertyGeneric *p = list.get (i);
140
+ if (p->newData ()) {
141
+ p->append (writer);
142
+ }
111
143
}
112
- client->yield ();
113
- return diff_in;
114
144
}
115
145
116
- void ArduinoCloudThing::checkNewData (int * new_data_in, int * new_data_out) {
146
+ int ArduinoCloudThing::checkNewData (CborDynamicOutput& output) {
147
+ int counter = 0 ;
148
+ for (int i = 0 ; i < list.size (); i++) {
149
+ ArduinoCloudPropertyGeneric *p = list.get (i);
150
+ if (p->newData ()) {
151
+ counter++;
152
+ }
153
+ }
154
+ return counter;
155
+ }
117
156
157
+ bool ArduinoCloudThing::exists (String &name) {
158
+ for (int i = 0 ; i < list.size (); i++) {
159
+ ArduinoCloudPropertyGeneric *p = list.get (i);
160
+ if (p->getName () == name) {
161
+ return true ;
162
+ }
163
+ }
164
+ return false ;
118
165
}
119
166
120
167
void ArduinoCloudThing::addPropertyReal (int & property, String name, permissionType permission) {
168
+ if (exists (name)) {
169
+ return ;
170
+ }
121
171
ArduinoCloudProperty<int > *thing = new ArduinoCloudProperty<int >(property, name, permission);
122
172
list.add (thing);
123
173
}
124
174
125
175
void ArduinoCloudThing::addPropertyReal (bool & property, String name, permissionType permission) {
176
+ if (exists (name)) {
177
+ return ;
178
+ }
126
179
ArduinoCloudProperty<bool > *thing = new ArduinoCloudProperty<bool >(property, name, permission);
127
180
list.add (thing);
128
181
}
129
182
130
183
void ArduinoCloudThing::addPropertyReal (float & property, String name, permissionType permission) {
184
+ if (exists (name)) {
185
+ return ;
186
+ }
131
187
ArduinoCloudProperty<float > *thing = new ArduinoCloudProperty<float >(property, name, permission);
132
188
list.add (thing);
133
189
}
134
190
135
-
136
- ArduinoCloudThing ArduinoCloudThing::callback (MQTT::MessageData& messageData) {
137
- MQTT::Message &message = messageData.message ;
138
- // null terminate topic to create String object
139
-
140
- // unwrap message into a structure
141
- uint8_t * payload = (uint8_t *)message.payload ;
142
- decodeCBORData (payload, message.payloadlen );
143
-
144
- return *this ;
191
+ void ArduinoCloudThing::callback (MQTTClient *client, char topic[], char bytes[], int length) {
192
+ reinterpret_cast <ArduinoCloudThing*>(client->getParent ())->decode ((uint8_t *)bytes, length);
145
193
}
146
194
147
- void ArduinoCloudThing::decodeCBORData (uint8_t * payload, size_t length) {
148
- list_shadow.clear ();
149
-
195
+ void ArduinoCloudThing::decode (uint8_t * payload, size_t length) {
150
196
CborInput input (payload, length);
151
197
152
198
CborReader reader (input);
153
- CborPropertyListener listener (list_shadow );
199
+ CborPropertyListener listener (&list );
154
200
reader.SetListener (listener);
155
201
reader.Run ();
156
202
}
157
203
158
204
void CborPropertyListener::OnInteger (int32_t value) {
159
- printf (" integer: %d\n " , value);
205
+ if (currentListIndex < 0 ) {
206
+ return ;
207
+ }
208
+ reinterpret_cast <ArduinoCloudProperty<int >*>(list->get (currentListIndex))->write (value);
160
209
}
161
210
162
211
void CborPropertyListener::OnBytes (unsigned char *data, unsigned int size) {
163
212
printf (" bytes with size: %d" , size);
164
213
}
165
214
166
215
void CborPropertyListener::OnString (String &str) {
167
- printf (" string: '%.*s'\n " , (int )str.length (), str.c_str ());
216
+ // if tag arrived, search a string with the same name in the list
217
+ if (newElement == true ) {
218
+ newElement = false ;
219
+ for (int i = 0 ; i < list->size (); i++) {
220
+ ArduinoCloudPropertyGeneric *p = list->get (i);
221
+ if (p->getName () == str) {
222
+ currentListIndex = i;
223
+ break ;
224
+ }
225
+ if (i == list->size ()) {
226
+ Serial.println (" Property not found, skipping" );
227
+ currentListIndex = -1 ;
228
+ }
229
+ }
230
+ } else {
231
+ if (currentListIndex < 0 ) {
232
+ return ;
233
+ }
234
+ reinterpret_cast <ArduinoCloudProperty<String>*>(list->get (currentListIndex))->write (str);
235
+ }
168
236
}
169
237
170
238
void CborPropertyListener::OnArray (unsigned int size) {
171
- printf (" array: %d\n " , size);
239
+
240
+ // prepare for new properties to arrive
241
+ if (justStarted == true ) {
242
+ list_size = size;
243
+ justStarted = false ;
244
+ }
172
245
}
173
246
174
247
void CborPropertyListener::OnMap (unsigned int size) {
175
- printf (" map: %d\n " , size);
176
248
}
177
249
178
- void CborPropertyListener::OnTag (unsigned int tag) {
179
- printf (" tag: %d\n " , tag);
250
+ void CborPropertyListener::OnTag (uint32_t tag) {
251
+ newElement = true ;
252
+ list_size--;
253
+ if (list_size < 0 ) {
254
+ Serial.println (" problem, we got more properties than advertised" );
255
+ }
180
256
}
181
257
182
- void CborPropertyListener::OnSpecial (unsigned int code) {
183
- printf (" special: %d\n " , code);
258
+ void CborPropertyListener::OnSpecial (uint32_t code) {
259
+
260
+ if (currentListIndex < 0 ) {
261
+ return ;
262
+ }
263
+ if (list->get (currentListIndex)->getPermission () != code) {
264
+ Serial.println (" permission changed, updating" );
265
+ list->get (currentListIndex)->setPermission ((permissionType)code);
266
+ }
184
267
}
185
268
186
269
void CborPropertyListener::OnError (const char *error) {
187
- printf (" error: %s\n " , error);
188
270
}
0 commit comments