261 lines
6.4 KiB
C++
261 lines
6.4 KiB
C++
/*
|
|
The Sensor Net Arduino 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>
|
|
|
|
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 "Gateway.h"
|
|
|
|
Gateway::Gateway(uint8_t _cepin, uint8_t _cspin, uint8_t _inclusion_time) : Relay(_cepin, _cspin) {
|
|
ledMode = false;
|
|
isRelay = true;
|
|
inclusionTime = _inclusion_time;
|
|
}
|
|
|
|
Gateway::Gateway(uint8_t _cepin, uint8_t _cspin, uint8_t _inclusion_time, uint8_t _inclusion_pin, uint8_t _rx, uint8_t _tx, uint8_t _er) : Relay(_cepin, _cspin) {
|
|
ledMode = true;
|
|
isRelay = true;
|
|
pinInclusion = _inclusion_pin;
|
|
inclusionTime = _inclusion_time;
|
|
pinRx = _rx;
|
|
pinTx = _tx;
|
|
pinEr = _er;
|
|
}
|
|
|
|
void Gateway::begin(rf24_pa_dbm_e paLevel, uint8_t channel, void (*inDataCallback)(char *)) {
|
|
Serial.begin(BAUD_RATE);
|
|
|
|
if (inDataCallback != NULL) {
|
|
useWriteCallback = true;
|
|
dataCallback = inDataCallback;
|
|
} else {
|
|
useWriteCallback = false;
|
|
}
|
|
|
|
radioId = 0;
|
|
distance = 0;
|
|
inclusionMode = 0;
|
|
buttonTriggeredInclusion = false;
|
|
countRx = 0;
|
|
countTx = 0;
|
|
countErr = 0;
|
|
|
|
if (ledMode) {
|
|
// 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);
|
|
|
|
}
|
|
|
|
// Start up the radio library
|
|
setupRadio(paLevel, channel);
|
|
RF24::openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID);
|
|
RF24::startListening();
|
|
|
|
// Send startup log message on serial
|
|
serial(PSTR("0;0;%d;%d;Arduino startup complete.\n"), M_INTERNAL, I_LOG_MESSAGE);
|
|
|
|
}
|
|
|
|
|
|
boolean Gateway::isLedMode() {
|
|
return ledMode;
|
|
}
|
|
|
|
void Gateway::startInclusionInterrupt() {
|
|
buttonTriggeredInclusion = true;
|
|
}
|
|
|
|
|
|
void Gateway::checkButtonTriggeredInclusion() {
|
|
if (buttonTriggeredInclusion) {
|
|
// Ok, someone pressed the inclusion button on the gateway
|
|
// start inclusion mode for 1 munute.
|
|
serial(PSTR("0;0;%d;%d;Inclusion started by button.\n"), M_INTERNAL, I_LOG_MESSAGE);
|
|
buttonTriggeredInclusion = false;
|
|
setInclusionMode(true);
|
|
|
|
#ifdef DEBUG
|
|
sendChildren();
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
void Gateway::checkInclusionFinished() {
|
|
if (inclusionMode && millis()-inclusionStartTime>60000UL*inclusionTime) {
|
|
// inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode
|
|
setInclusionMode(false);
|
|
}
|
|
}
|
|
|
|
|
|
void Gateway::parseAndSend(char *commandBuffer) {
|
|
boolean ok = false;
|
|
char *str, *p, *value=NULL;
|
|
int i = 0;
|
|
uint16_t sensorRadioId = 0;
|
|
uint8_t childId = 0;
|
|
uint8_t messageType = 0;
|
|
uint8_t type = 0;
|
|
|
|
// Extract command data coming on serial line
|
|
for (str = strtok_r(commandBuffer, ";", &p); // split using semicolon
|
|
str && i < 5; // loop while str is not null an max 5 times
|
|
str = strtok_r(NULL, ";", &p) // get subsequent tokens
|
|
) {
|
|
switch (i) {
|
|
case 0: // Radioid (destination)
|
|
sensorRadioId = atoi(str);
|
|
break;
|
|
case 1: // Childid
|
|
childId = atoi(str);
|
|
break;
|
|
case 2: // Message type
|
|
messageType = atoi(str);
|
|
break;
|
|
case 3: // Data type
|
|
type = atoi(str);
|
|
break;
|
|
case 4: // Variable value
|
|
value = str;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (sensorRadioId==GATEWAY_ADDRESS && messageType==M_INTERNAL) {
|
|
// Handle messages directed to gateway
|
|
if (type == I_VERSION) {
|
|
// Request for version
|
|
serial(PSTR("0;0;%d;%d;%s\n"),M_INTERNAL, I_VERSION, LIBRARY_VERSION);
|
|
} else if (type == I_INCLUSION_MODE) {
|
|
// Request to change inclusion mode
|
|
setInclusionMode(atoi(value) == 1);
|
|
}
|
|
} else {
|
|
txBlink(1);
|
|
|
|
ok = sendData(GATEWAY_ADDRESS, sensorRadioId, childId, messageType, type, value, strlen(value), false);
|
|
if (!ok) {
|
|
errBlink(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Gateway::setInclusionMode(boolean newMode) {
|
|
if (newMode != inclusionMode)
|
|
inclusionMode = newMode;
|
|
// Send back mode change on serial line to ack command
|
|
serial(PSTR("0;0;%d;%d;%d\n"), M_INTERNAL, I_INCLUSION_MODE, inclusionMode?1:0);
|
|
|
|
if (inclusionMode) {
|
|
inclusionStartTime = millis();
|
|
}
|
|
}
|
|
|
|
|
|
// Override normal validate to add error blink if crc check fails
|
|
uint8_t Gateway::validate(uint8_t length) {
|
|
uint8_t res = Sensor::validate(length);
|
|
if (res == VALIDATE_BAD_CRC) {
|
|
errBlink(1);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
void Gateway::processRadioMessage() {
|
|
if (messageAvailable()) {
|
|
// A new message was received from one of the sensors
|
|
message_s msg = getMessage();
|
|
if (msg.header.messageType == M_PRESENTATION && inclusionMode) {
|
|
rxBlink(3);
|
|
} else {
|
|
rxBlink(1);
|
|
}
|
|
// Pass along the message from sensors to serial line
|
|
serial(msg);
|
|
}
|
|
|
|
checkButtonTriggeredInclusion();
|
|
checkInclusionFinished();
|
|
}
|
|
|
|
void Gateway::serial(const char *fmt, ... ) {
|
|
va_list args;
|
|
va_start (args, fmt );
|
|
vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args);
|
|
va_end (args);
|
|
Serial.print(serialBuffer);
|
|
if (useWriteCallback) {
|
|
// We have a registered write callback (probably Ethernet)
|
|
dataCallback(serialBuffer);
|
|
}
|
|
}
|
|
|
|
void Gateway::serial(message_s msg) {
|
|
serial(PSTR("%d;%d;%d;%d;%s\n"),msg.header.from, msg.header.childId, msg.header.messageType, msg.header.type, msg.data);
|
|
}
|
|
|
|
|
|
void Gateway::ledTimersInterrupt() {
|
|
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--; }
|
|
|
|
}
|
|
|
|
void Gateway::rxBlink(uint8_t cnt) {
|
|
if(countRx == 255) { countRx = cnt; }
|
|
}
|
|
void Gateway::txBlink(uint8_t cnt) {
|
|
if(countTx == 255 && !inclusionMode) { countTx = cnt; }
|
|
}
|
|
void Gateway::errBlink(uint8_t cnt) {
|
|
if(countErr == 255) { countErr = cnt; }
|
|
}
|
|
|