Merge branch 'master' into development
Conflicts: libraries/MySensors/MySensor.cpp
This commit is contained in:
+112
-144
@@ -33,9 +33,9 @@ static inline bool isValidDistance( const uint8_t distance ) {
|
||||
return distance != DISTANCE_INVALID;
|
||||
}
|
||||
|
||||
MySensor::MySensor() {
|
||||
radio = (MyRFDriver*) new MyRFDriverClass();
|
||||
}
|
||||
MySensor::MySensor() {
|
||||
radio = (MyRFDriver*) new MyRFDriverClass();
|
||||
}
|
||||
|
||||
|
||||
void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId) {
|
||||
@@ -94,19 +94,12 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b
|
||||
debug(PSTR("%s started, id=%d, parent=%d, distance=%d\n"), repeaterMode?"repeater":"sensor", nc.nodeId, nc.parentNodeId, nc.distance);
|
||||
}
|
||||
|
||||
// Open reading pipe for messages directed to this node (set write pipe to same)
|
||||
radio->setAddress(nc.nodeId);
|
||||
|
||||
// Send presentation for this radio node (attach
|
||||
present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE);
|
||||
|
||||
// Send a configuration exchange request to controller
|
||||
// Node sends parent node. Controller answers with latest node configuration
|
||||
// which is picked up in process()
|
||||
sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(nc.parentNodeId));
|
||||
|
||||
// Wait configuration reply.
|
||||
waitForReply();
|
||||
// If we got an id, set this node to use it
|
||||
if (nc.nodeId != AUTO) {
|
||||
setupNode();
|
||||
// Wait configuration reply.
|
||||
wait(2000);
|
||||
}
|
||||
}
|
||||
|
||||
void MySensor::setupRadio() {
|
||||
@@ -119,7 +112,6 @@ void MySensor::setupRepeaterMode(){
|
||||
eeprom_read_block((void*)childNodeTable, (void*)EEPROM_ROUTES_ADDRESS, 256);
|
||||
}
|
||||
|
||||
|
||||
uint8_t MySensor::getNodeId() {
|
||||
return nc.nodeId;
|
||||
}
|
||||
@@ -132,28 +124,37 @@ void MySensor::requestNodeId() {
|
||||
debug(PSTR("req node id\n"));
|
||||
radio->setAddress(nc.nodeId);
|
||||
sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set(""));
|
||||
waitForReply();
|
||||
wait(2000);
|
||||
}
|
||||
|
||||
void MySensor::setupNode() {
|
||||
// Open reading pipe for messages directed to this node (set write pipe to same)
|
||||
radio->setAddress(nc.nodeId);
|
||||
|
||||
// Send presentation for this radio node (attach
|
||||
present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE);
|
||||
|
||||
// Send a configuration exchange request to controller
|
||||
// Node sends parent node. Controller answers with latest node configuration
|
||||
// which is picked up in process()
|
||||
sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(nc.parentNodeId));
|
||||
}
|
||||
|
||||
void MySensor::findParentNode() {
|
||||
failedTransmissions = 0;
|
||||
|
||||
// Set distance to max
|
||||
nc.distance = 255;
|
||||
|
||||
// Send ping message to BROADCAST_ADDRESS (to which all relaying nodes and gateway listens and should reply to)
|
||||
debug(PSTR("find parent\n"));
|
||||
|
||||
build(msg, nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false).set("");
|
||||
// Write msg, but suppress recursive parent search
|
||||
sendWrite(BROADCAST_ADDRESS, msg, false);
|
||||
sendWrite(BROADCAST_ADDRESS, msg);
|
||||
|
||||
// Wait for ping response.
|
||||
waitForReply();
|
||||
}
|
||||
|
||||
void MySensor::waitForReply() {
|
||||
unsigned long enter = millis();
|
||||
// Wait a couple of seconds for response
|
||||
while (millis() - enter < 2000) {
|
||||
process();
|
||||
}
|
||||
wait(2000);
|
||||
}
|
||||
|
||||
boolean MySensor::sendRoute(MyMessage &message) {
|
||||
@@ -184,56 +185,37 @@ boolean MySensor::sendRoute(MyMessage &message) {
|
||||
|
||||
if (!isGateway) {
|
||||
// Should be routed back to gateway.
|
||||
return sendWrite(nc.parentNodeId, message);
|
||||
bool ok = sendWrite(nc.parentNodeId, message);
|
||||
|
||||
if (!ok) {
|
||||
// Failure when sending to parent node. The parent node might be down and we
|
||||
// need to find another route to gateway.
|
||||
if (autoFindParent && failedTransmissions > SEARCH_FAILURES) {
|
||||
findParentNode();
|
||||
} else {
|
||||
failedTransmissions++;
|
||||
}
|
||||
} else {
|
||||
failedTransmissions = 0;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean MySensor::sendWrite(uint8_t next, MyMessage &message, const bool allowFindParent) {
|
||||
bool ok = true;
|
||||
const bool broadcast = next == BROADCAST_ADDRESS;
|
||||
const bool toParent = next == nc.parentNodeId;
|
||||
// With current implementation parent node Id can equal the broadcast address when
|
||||
// starting with empty eeprom and AUTO node Id is active.
|
||||
// This behavior is undesired, as possible parents will report back to broadcast address.
|
||||
// debug(PSTR("sendWrite next=%d, parent=%d, distance=%d\n"), next, nc.parentNodeId, nc.distance);
|
||||
// If sending directly to parent node and distance is not set, then try to find parent now.
|
||||
if ( allowFindParent && toParent && !isValidDistance(nc.distance) ) {
|
||||
findParentNode();
|
||||
// Known distance indicates parent has been found
|
||||
ok = isValidDistance(nc.distance);
|
||||
}
|
||||
boolean MySensor::sendWrite(uint8_t to, MyMessage &message) {
|
||||
uint8_t length = mGetLength(message);
|
||||
message.last = nc.nodeId;
|
||||
mSetVersion(message, PROTOCOL_VERSION);
|
||||
bool ok = radio->send(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length));
|
||||
|
||||
if (ok) {
|
||||
uint8_t length = mGetLength(message);
|
||||
message.last = nc.nodeId;
|
||||
mSetVersion(message, PROTOCOL_VERSION);
|
||||
bool ok = radio->send(next, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length));
|
||||
debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,st=%s:%s\n"),
|
||||
message.sender,message.last, to, message.destination, message.sensor, mGetCommand(message), message.type,
|
||||
mGetPayloadType(message), mGetLength(message), to==BROADCAST_ADDRESS ? "bc" : (ok ? "ok":"fail"), message.getString(convBuf));
|
||||
|
||||
debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,st=%s:%s\n"),
|
||||
message.sender,message.last, next, message.destination, message.sensor, mGetCommand(message), message.type,
|
||||
mGetPayloadType(message), mGetLength(message), broadcast ? "bc" : (ok ? "ok":"fail"), message.getString(convBuf));
|
||||
|
||||
// If many successive transmissions to parent failed, the parent node might be down and we
|
||||
// need to find another route to gateway.
|
||||
if (toParent) {
|
||||
if (ok) {
|
||||
failedTransmissions = 0;
|
||||
} else {
|
||||
failedTransmissions++;
|
||||
if ( autoFindParent && (failedTransmissions >= SEARCH_FAILURES)) {
|
||||
debug(PSTR("lost parent\n"));
|
||||
// Set distance invalid to trigger parent search on next write.
|
||||
nc.distance = DISTANCE_INVALID;
|
||||
failedTransmissions = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
bool MySensor::send(MyMessage &message, bool enableAck) {
|
||||
message.sender = nc.nodeId;
|
||||
mSetCommand(message,C_SET);
|
||||
@@ -267,7 +249,6 @@ void MySensor::requestTime(void (* _timeCallback)(unsigned long)) {
|
||||
sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, false).set(""));
|
||||
}
|
||||
|
||||
|
||||
boolean MySensor::process() {
|
||||
uint8_t to = 0;
|
||||
if (!radio->available(&to))
|
||||
@@ -292,23 +273,7 @@ boolean MySensor::process() {
|
||||
uint8_t last = msg.last;
|
||||
uint8_t destination = msg.destination;
|
||||
|
||||
if (repeaterMode && command == C_INTERNAL && type == I_FIND_PARENT) {
|
||||
if (nc.distance == 255) {
|
||||
findParentNode();
|
||||
} else if (sender != nc.parentNodeId) {
|
||||
// Relaying nodes should always answer ping messages
|
||||
// Wait a random delay of 0-2 seconds to minimize collision
|
||||
// between ping ack messages from other relaying nodes
|
||||
delay(millis() & 0x3ff);
|
||||
sendWrite(sender, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance), true);
|
||||
}
|
||||
return false;
|
||||
} else if (command == C_INTERNAL && type == I_TIME) {
|
||||
if (timeCallback != NULL) {
|
||||
// Deliver time to callback
|
||||
timeCallback(msg.getULong());
|
||||
}
|
||||
} else if (destination == nc.nodeId) {
|
||||
if (destination == nc.nodeId) {
|
||||
// Check if sender requests an ack back.
|
||||
if (mGetRequestAck(msg)) {
|
||||
// Copy message
|
||||
@@ -355,15 +320,14 @@ boolean MySensor::process() {
|
||||
} else if (type == I_ID_RESPONSE) {
|
||||
if (nc.nodeId == AUTO) {
|
||||
nc.nodeId = msg.getByte();
|
||||
// Write id to EEPROM
|
||||
if (nc.nodeId == AUTO) {
|
||||
// sensor net gateway will return max id if all sensor id are taken
|
||||
debug(PSTR("full\n"));
|
||||
while (1); // Wait here. Nothing else we can do...
|
||||
} else {
|
||||
radio->setAddress(nc.nodeId);
|
||||
eeprom_write_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, nc.nodeId);
|
||||
}
|
||||
setupNode();
|
||||
// Write id to EEPROM
|
||||
eeprom_write_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, nc.nodeId);
|
||||
debug(PSTR("id=%d\n"), nc.nodeId);
|
||||
}
|
||||
} else if (type == I_CONFIG) {
|
||||
@@ -378,9 +342,10 @@ boolean MySensor::process() {
|
||||
if (repeaterMode && msg.getString()[0] == 'C') {
|
||||
// Clears child relay data for this node
|
||||
debug(PSTR("rd=clear\n"));
|
||||
for (uint8_t i=0;i< sizeof(childNodeTable); i++) {
|
||||
uint8_t i = 255;
|
||||
do {
|
||||
removeChildRoute(i);
|
||||
}
|
||||
} while (i--);
|
||||
// Clear parent node id & distance to gw
|
||||
eeprom_write_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, 0xFF);
|
||||
eeprom_write_byte((uint8_t*)EEPROM_DISTANCE_ADDRESS, 0xFF);
|
||||
@@ -398,54 +363,66 @@ boolean MySensor::process() {
|
||||
}
|
||||
// Return true if message was addressed for this node...
|
||||
return true;
|
||||
} else if (repeaterMode && to == nc.nodeId) {
|
||||
// We should try to relay this message to another node
|
||||
} else if (repeaterMode && nc.nodeId != AUTO) {
|
||||
// Relaying nodes should answer only after set an id
|
||||
|
||||
uint8_t route = getChildRoute(msg.destination);
|
||||
if (route>0 && route<255) {
|
||||
// This message should be forwarded to a child node. If we send message
|
||||
// to this nodes pipe then all children will receive it because the are
|
||||
// all listening to this nodes pipe.
|
||||
//
|
||||
// +----B
|
||||
// -A
|
||||
// +----C------D
|
||||
//
|
||||
// We're node C, Message comes from A and has destination D
|
||||
//
|
||||
// lookup route in table and send message there
|
||||
sendWrite(route, msg);
|
||||
} else if (sender == GATEWAY_ADDRESS && destination == BROADCAST_ADDRESS) {
|
||||
// A net gateway reply to a message previously sent by us from a 255 node
|
||||
// We should broadcast this back to the node
|
||||
sendWrite(destination, msg, true);
|
||||
} else {
|
||||
// A message comes from a child node and we have no
|
||||
// route for it.
|
||||
//
|
||||
// +----B
|
||||
// -A
|
||||
// +----C------D <-- Message comes from D
|
||||
//
|
||||
// We're node C
|
||||
//
|
||||
// Message should be passed to node A (this nodes relay)
|
||||
if (command == C_INTERNAL && type == I_FIND_PARENT) {
|
||||
if (nc.distance == 255) {
|
||||
findParentNode();
|
||||
} else if (sender != nc.parentNodeId) {
|
||||
// Relaying nodes should always answer ping messages
|
||||
// Wait a random delay of 0-2 seconds to minimize collision
|
||||
// between ping ack messages from other relaying nodes
|
||||
delay(millis() & 0x3ff);
|
||||
sendWrite(BROADCAST_ADDRESS, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance));
|
||||
}
|
||||
} else if (to == nc.nodeId) {
|
||||
// We should try to relay this message to another node
|
||||
|
||||
// This message should be routed back towards sensor net gateway
|
||||
sendWrite(nc.parentNodeId, msg);
|
||||
// Add this child to our "routing table" if it not already exist
|
||||
addChildRoute(sender, last);
|
||||
uint8_t route = getChildRoute(msg.destination);
|
||||
if (route>0 && route<255) {
|
||||
// This message should be forwarded to a child node. If we send message
|
||||
// to this nodes pipe then all children will receive it because the are
|
||||
// all listening to this nodes pipe.
|
||||
//
|
||||
// +----B
|
||||
// -A
|
||||
// +----C------D
|
||||
//
|
||||
// We're node C, Message comes from A and has destination D
|
||||
//
|
||||
// lookup route in table and send message there
|
||||
sendWrite(route, msg);
|
||||
} else if (sender == GATEWAY_ADDRESS && destination == BROADCAST_ADDRESS) {
|
||||
// A net gateway reply to a message previously sent by us from a 255 node
|
||||
// We should broadcast this back to the node
|
||||
sendWrite(BROADCAST_ADDRESS, msg);
|
||||
} else {
|
||||
// A message comes from a child node and we have no
|
||||
// route for it.
|
||||
//
|
||||
// +----B
|
||||
// -A
|
||||
// +----C------D <-- Message comes from D
|
||||
//
|
||||
// We're node C
|
||||
//
|
||||
// Message should be passed to node A (this nodes relay)
|
||||
|
||||
// This message should be routed back towards sensor net gateway
|
||||
sendWrite(nc.parentNodeId, msg);
|
||||
// Add this child to our "routing table" if it not already exist
|
||||
addChildRoute(sender, last);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
MyMessage& MySensor::getLastMessage() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
void MySensor::saveState(uint8_t pos, uint8_t value) {
|
||||
if (loadState(pos) != value) {
|
||||
eeprom_write_byte((uint8_t*)(EEPROM_LOCAL_CONFIG_ADDRESS+pos), value);
|
||||
@@ -455,7 +432,6 @@ uint8_t MySensor::loadState(uint8_t pos) {
|
||||
return eeprom_read_byte((uint8_t*)(EEPROM_LOCAL_CONFIG_ADDRESS+pos));
|
||||
}
|
||||
|
||||
|
||||
void MySensor::addChildRoute(uint8_t childId, uint8_t route) {
|
||||
if (childNodeTable[childId] != route) {
|
||||
childNodeTable[childId] = route;
|
||||
@@ -474,7 +450,6 @@ uint8_t MySensor::getChildRoute(uint8_t childId) {
|
||||
return childNodeTable[childId];
|
||||
}
|
||||
|
||||
|
||||
int8_t pinIntTrigger = 0;
|
||||
void wakeUp() //place to send the interrupts
|
||||
{
|
||||
@@ -507,19 +482,13 @@ void MySensor::sleep(unsigned long ms) {
|
||||
}
|
||||
|
||||
void MySensor::wait(unsigned long ms) {
|
||||
bool slept_enough = false;
|
||||
unsigned long start = millis();
|
||||
unsigned long now;
|
||||
|
||||
// Let serial prints finish (debug, log etc)
|
||||
Serial.flush();
|
||||
|
||||
while (!slept_enough) {
|
||||
MySensor::process();
|
||||
now = millis();
|
||||
if (now - start > ms) {
|
||||
slept_enough = true;
|
||||
}
|
||||
unsigned long enter = millis();
|
||||
while (millis() - enter < ms) {
|
||||
// reset watchdog
|
||||
wdt_reset();
|
||||
process();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,7 +566,6 @@ void MySensor::debugPrint(const char *fmt, ... ) {
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
int MySensor::freeRam (void) {
|
||||
extern int __heap_start, *__brkval;
|
||||
|
||||
Reference in New Issue
Block a user