Skip to content

Commit af18ef1

Browse files
committed
Almost working on SAMD
1 parent 6b6ccec commit af18ef1

19 files changed

+222
-2799
lines changed

ArduinoCloudThing.cpp

Lines changed: 163 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,63 @@
11
#include <Arduino.h>
22
#include <ArduinoCloudThing.h>
33

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
512

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
649
}
750

851
/*
952
* begin() should prepare the environment
1053
* connect
1154
*/
1255

13-
static constexpr char* PLACEHOLDER = "placeholder";
14-
1556
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);
2061

2162
// using WiFi client and ECC508 connect to server
2263
while (!connect()) {
@@ -27,162 +68,203 @@ void ArduinoCloudThing::begin(Client &client) {
2768

2869
bool ArduinoCloudThing::connect() {
2970

30-
#ifdef TESTING
71+
#ifdef TESTING_PROTOCOL
3172
return true;
3273
#endif
3374

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) {
4876
// set status to ON
4977
status = ON;
50-
addProperty(status, WRITE);
51-
// execute first poll() to syncronize the "manifest"
52-
poll();
78+
addProperty(status, READ);
5379
// subscribe to "general" topic
54-
client->subscribe("placeholder", MQTT::QOS0, NULL);
80+
client->subscribe(GENERAL_TOPIC);
5581
return true;
5682
}
5783

5884
return false;
5985
}
6086

61-
void ArduinoCloudThing::publish() {
87+
void ArduinoCloudThing::publish(CborDynamicOutput& output) {
6288

6389
bool retained = false;
6490

65-
CborDynamicOutput output;
66-
CborWriter writer(output);
91+
unsigned char *buf = output.getData();
6792

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());
6998

7099
for (int i = 0; i < list.size(); i++) {
71100
ArduinoCloudPropertyGeneric *p = list.get(i);
72-
p->append(writer);
101+
p->updateShadow();
73102
}
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);
86103
}
87104

88105
// Reconnect to the mqtt broker
89106
int ArduinoCloudThing::poll() {
90107

91-
#ifndef TESTING
92-
if (!client->isConnected()){
108+
#ifndef TESTING_PROTOCOL
109+
if (!client->connected()){
93110
if (!connect()){
94111
return 0;
95112
}
96113
}
97-
if(!network.connected() && client->isConnected()) {
98-
client->disconnect();
99-
}
100114
#endif
101115

102116
// 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);
108123
}
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+
}
111143
}
112-
client->yield();
113-
return diff_in;
114144
}
115145

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+
}
117156

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;
118165
}
119166

120167
void ArduinoCloudThing::addPropertyReal(int& property, String name, permissionType permission) {
168+
if (exists(name)) {
169+
return;
170+
}
121171
ArduinoCloudProperty<int> *thing = new ArduinoCloudProperty<int>(property, name, permission);
122172
list.add(thing);
123173
}
124174

125175
void ArduinoCloudThing::addPropertyReal(bool& property, String name, permissionType permission) {
176+
if (exists(name)) {
177+
return;
178+
}
126179
ArduinoCloudProperty<bool> *thing = new ArduinoCloudProperty<bool>(property, name, permission);
127180
list.add(thing);
128181
}
129182

130183
void ArduinoCloudThing::addPropertyReal(float& property, String name, permissionType permission) {
184+
if (exists(name)) {
185+
return;
186+
}
131187
ArduinoCloudProperty<float> *thing = new ArduinoCloudProperty<float>(property, name, permission);
132188
list.add(thing);
133189
}
134190

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);
145193
}
146194

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) {
150196
CborInput input(payload, length);
151197

152198
CborReader reader(input);
153-
CborPropertyListener listener(list_shadow);
199+
CborPropertyListener listener(&list);
154200
reader.SetListener(listener);
155201
reader.Run();
156202
}
157203

158204
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);
160209
}
161210

162211
void CborPropertyListener::OnBytes(unsigned char *data, unsigned int size) {
163212
printf("bytes with size: %d", size);
164213
}
165214

166215
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+
}
168236
}
169237

170238
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+
}
172245
}
173246

174247
void CborPropertyListener::OnMap(unsigned int size) {
175-
printf("map: %d\n", size);
176248
}
177249

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+
}
180256
}
181257

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+
}
184267
}
185268

186269
void CborPropertyListener::OnError(const char *error) {
187-
printf("error: %s\n", error);
188270
}

0 commit comments

Comments
 (0)