forked from mysensors/Raspberry
-
Notifications
You must be signed in to change notification settings - Fork 1
/
MyGateway.cpp
320 lines (280 loc) · 7.87 KB
/
MyGateway.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
/*
The MySensors library adds a new layer on top of the RF24 library.
It handles radio network routing, relaying and ids.
Created by Henrik Ekblad <henrik.ekblad@gmail.com>
12/10/14 - Ported to Raspberry Pi by OUJABER Mohamed <m.oujaber@gmail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
#include "MyGateway.h"
using namespace std;
#ifndef __Raspberry_Pi
#include "utility/MsTimer2.h"
#include "utility/PinChangeInt.h"
uint8_t pinRx;
uint8_t pinTx;
uint8_t pinEr;
volatile uint8_t countRx;
volatile uint8_t countTx;
volatile uint8_t countErr;
#endif
boolean buttonTriggeredInclusion;
boolean inclusionMode; // Keeps track on inclusion mode
#ifdef __Raspberry_Pi
MyGateway::MyGateway(uint8_t _cepin, uint8_t _cspin, uint32_t spispeed, uint8_t _inclusion_time ) : MySensor(_cepin, _cspin, spispeed ) {
inclusionTime = _inclusion_time;
}
#else
MyGateway::MyGateway(uint8_t _cepin, uint8_t _cspin, uint8_t _inclusion_time, uint8_t _inclusion_pin, uint8_t _rx, uint8_t _tx, uint8_t _er) : MySensor(_cepin, _cspin) {
pinInclusion = _inclusion_pin;
inclusionTime = _inclusion_time;
pinRx = _rx;
pinTx = _tx;
pinEr = _er;
}
#endif
void MyGateway::begin(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate, void (*inDataCallback)(char *)) {
#ifndef __Raspberry_Pi
Serial.begin(BAUD_RATE);
#endif
repeaterMode = true;
isGateway = true;
setupRepeaterMode();
if (inDataCallback != NULL) {
useWriteCallback = true;
dataCallback = inDataCallback;
} else {
useWriteCallback = false;
}
nc.nodeId = 0;
nc.distance = 0;
inclusionMode = 0;
buttonTriggeredInclusion = false;
#ifndef __Raspberry_Pi
countRx = 0;
countTx = 0;
countErr = 0;
// Setup led pins
pinMode(pinRx, OUTPUT);
pinMode(pinTx, OUTPUT);
pinMode(pinEr, OUTPUT);
digitalWrite(pinRx, LOW);
digitalWrite(pinTx, LOW);
digitalWrite(pinEr, LOW);
// Setup digital in that triggers inclusion mode
pinMode(pinInclusion, INPUT);
digitalWrite(pinInclusion, HIGH);
// Set initial state of leds
digitalWrite(pinRx, HIGH);
digitalWrite(pinTx, HIGH);
digitalWrite(pinEr, HIGH);
#endif
// Start up the radio library
setupRadio(paLevel, channel, dataRate);
RF24::openReadingPipe(WRITE_PIPE, BASE_RADIO_ID);
RF24::openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID);
RF24::startListening();
#ifndef __Raspberry_Pi
// Add led timer interrupt
MsTimer2::set(300, ledTimersInterrupt);
MsTimer2::start();
// Add interrupt for inclusion button to pin
PCintPort::attachInterrupt(pinInclusion, startInclusionInterrupt, RISING);
#endif
// Send startup log message on serial
serial(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY);
}
void startInclusionInterrupt() {
buttonTriggeredInclusion = true;
}
void MyGateway::checkButtonTriggeredInclusion() {
if (buttonTriggeredInclusion) {
// Ok, someone pressed the inclusion button on the gateway
// start inclusion mode for 1 munute.
serial(PSTR("0;0;%d;0;%d;Inclusion started by button.\n"), C_INTERNAL, I_LOG_MESSAGE);
buttonTriggeredInclusion = false;
setInclusionMode(true);
}
}
void MyGateway::checkInclusionFinished() {
if (inclusionMode && millis()-inclusionStartTime>60000UL*inclusionTime) {
// inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode
setInclusionMode(false);
}
}
uint8_t MyGateway::h2i(char c) {
uint8_t i = 0;
if (c <= '9')
i += c - '0';
else if (c >= 'a')
i += c - 'a' + 10;
else
i += c - 'A' + 10;
return i;
}
void MyGateway::parseAndSend(char *commandBuffer) {
boolean ok = false;
char *str, *p, *value=NULL;
uint8_t bvalue[MAX_PAYLOAD];
uint8_t blen = 0;
int i = 0;
uint16_t destination = 0;
uint8_t sensor = 0;
uint8_t command = 0;
uint8_t type = 0;
uint8_t ack = 0;
// Extract command data coming on serial line
for (str = strtok_r(commandBuffer, ";", &p); // split using semicolon
str && i < 6; // loop while str is not null an max 5 times
str = strtok_r(NULL, ";", &p) // get subsequent tokens
) {
switch (i) {
case 0: // Radioid (destination)
destination = atoi(str);
break;
case 1: // Childid
sensor = atoi(str);
break;
case 2: // Message type
command = atoi(str);
break;
case 3: // Should we request ack from destination?
ack = atoi(str);
break;
case 4: // Data type
type = atoi(str);
break;
case 5: // Variable value
if (command == C_STREAM) {
blen = 0;
uint8_t val;
while (*str) {
val = h2i(*str++) << 4;
val += h2i(*str++);
bvalue[blen] = val;
blen++;
}
} else {
value = str;
// Remove ending carriage return character (if it exists)
uint8_t lastCharacter = strlen(value)-1;
if (value[lastCharacter] == '\r')
value[lastCharacter] = 0;
}
break;
}
i++;
}
if (destination==GATEWAY_ADDRESS && command==C_INTERNAL) {
// Handle messages directed to gateway
if (type == I_VERSION) {
// Request for version
serial(PSTR("0;0;%d;0;%d;%s\n"),C_INTERNAL, I_VERSION, LIBRARY_VERSION);
} else if (type == I_INCLUSION_MODE) {
// Request to change inclusion mode
setInclusionMode(atoi(value) == 1);
}
} else {
txBlink(1);
msg.sender = GATEWAY_ADDRESS;
msg.destination = destination;
msg.sensor = sensor;
msg.type = type;
mSetCommand(msg,command);
mSetRequestAck(msg,ack?1:0);
mSetAck(msg,false);
if (command == C_STREAM)
msg.set(bvalue, blen);
else
msg.set(value);
ok = sendRoute(msg);
if (!ok) {
errBlink(1);
}
}
}
void MyGateway::setInclusionMode(boolean newMode) {
if (newMode != inclusionMode)
inclusionMode = newMode;
// Send back mode change on serial line to ack command
serial(PSTR("0;0;%d;0;%d;%d\n"), C_INTERNAL, I_INCLUSION_MODE, inclusionMode?1:0);
if (inclusionMode) {
inclusionStartTime = millis();
}
}
void MyGateway::processRadioMessage() {
if (process()) {
// A new message was received from one of the sensors
MyMessage message = getLastMessage();
if (mGetCommand(message) == C_PRESENTATION && inclusionMode) {
rxBlink(3);
} else {
rxBlink(1);
}
// Pass along the message from sensors to serial line
serial(message);
}
checkButtonTriggeredInclusion();
checkInclusionFinished();
}
void MyGateway::serial(const char *fmt, ... ) {
va_list args;
va_start (args, fmt );
vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args);
va_end (args);
#ifndef __Raspberry_Pi
Serial.print(serialBuffer);
#endif
if (useWriteCallback) {
// We have a registered write callback (probably Ethernet)
dataCallback(serialBuffer);
}
}
void MyGateway::serial(MyMessage &msg) {
serial(PSTR("%d;%d;%d;%d;%d;%s\n"),msg.sender, msg.sensor, mGetCommand(msg), mGetAck(msg), msg.type, msg.getString(convBuf));
}
void ledTimersInterrupt() {
#ifndef __Raspberry_Pi
if(countRx && countRx != 255) {
// switch led on
digitalWrite(pinRx, LOW);
} else if(!countRx) {
// switching off
digitalWrite(pinRx, HIGH);
}
if(countRx != 255) { countRx--; }
if(countTx && countTx != 255) {
// switch led on
digitalWrite(pinTx, LOW);
} else if(!countTx) {
// switching off
digitalWrite(pinTx, HIGH);
}
if(countTx != 255) { countTx--; }
else if(inclusionMode) { countTx = 8; }
if(countErr && countErr != 255) {
// switch led on
digitalWrite(pinEr, LOW);
} else if(!countErr) {
// switching off
digitalWrite(pinEr, HIGH);
}
if(countErr != 255) { countErr--; }
#endif
}
void MyGateway::rxBlink(uint8_t cnt) {
#ifndef __Raspberry_Pi
if(countRx == 255) { countRx = cnt; }
#endif
}
void MyGateway::txBlink(uint8_t cnt) {
#ifndef __Raspberry_Pi
if(countTx == 255 && !inclusionMode) { countTx = cnt; }
#endif
}
void MyGateway::errBlink(uint8_t cnt) {
#ifndef __Raspberry_Pi
if(countErr == 255) { countErr = cnt; }
#endif
}