latest test sketches and working request for id

This commit is contained in:
Henrik Ekblad
2014-05-19 20:08:12 +02:00
parent 9e043f3379
commit 67f4ca1fb4
9 changed files with 129 additions and 112 deletions
-1
View File
@@ -54,7 +54,6 @@
#include <PinChangeInt.h>
#include <MyGateway.h>
#include <stdarg.h>
//#include <avr/progmem.h>
#include <UIPEthernet.h> // Use this if you have attached a Ethernet ENC28J60 shields
//#include <Ethernet.h> // Use this fo WizNET module and Arduino Ethernet Shield
+5
View File
@@ -7,6 +7,11 @@ MyMessage::MyMessage() {
destination = 0; // Gateway is default destination
}
MyMessage::MyMessage(uint8_t _sensor, uint8_t _type) {
destination = 0; // Gateway is default destination
sensor = _sensor;
type = _type;
}
/* Getters for payload converted to desired form */
+2 -1
View File
@@ -40,7 +40,7 @@ typedef enum {
// Type of internal messages (for internal messages)
typedef enum {
I_BATTERY_LEVEL, I_TIME, I_VERSION, I_REQUEST_ID,
I_BATTERY_LEVEL, I_TIME, I_VERSION, I_ID_REQUEST, I_ID_RESPONSE,
I_INCLUSION_MODE, I_CONFIG, I_PING, I_PING_ACK,
I_LOG_MESSAGE, I_CHILDREN, I_SKETCH_NAME, I_SKETCH_VERSION
} internal;
@@ -114,6 +114,7 @@ public:
// Constructors
MyMessage();
MyMessage(uint8_t sensor, uint8_t type);
char* getString();
/**
+85 -89
View File
@@ -25,37 +25,8 @@ inline MyMessage* build (MyMessage* msg, uint8_t sender, uint8_t destination, ui
MySensor::MySensor(uint8_t _cepin, uint8_t _cspin) : RF24(_cepin, _cspin) {
}
void MySensor::setupRadio(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate) {
failedTransmissions = 0;
// Start up the radio library
RF24::begin();
if (!RF24::isPVariant()) {
debug(PSTR("check wires\n"));
while(1);
}
RF24::setAutoAck(1);
RF24::enableAckPayload();
RF24::setChannel(channel);
RF24::setPALevel(paLevel);
RF24::setDataRate(dataRate);
RF24::setRetries(5,15);
RF24::setCRCLength(RF24_CRC_16);
RF24::enableDynamicPayloads();
// All repeater nodes and gateway listen to broadcast pipe (for PING messages)
if (relayMode) {
RF24::openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS));
}
}
void MySensor::setupRelayMode(){
childNodeTable = new uint8_t[256];
eeprom_read_block((void*)childNodeTable, (void*)EEPROM_ROUTES_ADDRESS, 256);
}
void MySensor::begin(void (*_msgCallback)(MyMessage), boolean _relayMode, uint8_t _nodeId, rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate) {
void MySensor::begin(void (*_msgCallback)(MyMessage), uint8_t _nodeId, boolean _relayMode, rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate) {
Serial.begin(BAUD_RATE);
relayMode = _relayMode;
msgCallback = _msgCallback;
@@ -86,7 +57,7 @@ void MySensor::begin(void (*_msgCallback)(MyMessage), boolean _relayMode, uint8_
requestNodeId();
}
debug(PSTR("%s started\n"), relayMode?"relay":"sensor");
debug(PSTR("%s started, id %d\n"), relayMode?"relay":"sensor", nc.nodeId);
// Open reading pipe for messages directed to this node (set write pipe to same)
RF24::openReadingPipe(WRITE_PIPE, TO_ADDR(nc.nodeId));
@@ -99,8 +70,38 @@ void MySensor::begin(void (*_msgCallback)(MyMessage), boolean _relayMode, uint8_
// 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)->set(nc.parentNodeId));
Serial.print("XX");
Serial.println(nc.parentNodeId);
// Wait configuration reply.
waitForReply();
}
void MySensor::setupRadio(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate) {
failedTransmissions = 0;
// Start up the radio library
RF24::begin();
if (!RF24::isPVariant()) {
debug(PSTR("check wires\n"));
while(1);
}
RF24::setAutoAck(1);
RF24::setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast
RF24::enableAckPayload();
RF24::setChannel(channel);
RF24::setPALevel(paLevel);
RF24::setDataRate(dataRate);
RF24::setRetries(5,15);
RF24::setCRCLength(RF24_CRC_16);
RF24::enableDynamicPayloads();
// All nodes listen to broadcast pipe (for PING-ACK messages)
RF24::openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS));
}
void MySensor::setupRelayMode(){
childNodeTable = new uint8_t[256];
eeprom_read_block((void*)childNodeTable, (void*)EEPROM_ROUTES_ADDRESS, 256);
}
@@ -115,7 +116,8 @@ ControllerConfig MySensor::getConfig() {
void MySensor::requestNodeId() {
debug(PSTR("req node id\n"));
RF24::openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(nc.nodeId));
sendRoute(build(&msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_ID));
sendRoute(build(&msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST)->set(""));
waitForReply();
}
@@ -125,31 +127,33 @@ void MySensor::findParentNode() {
failedTransmissions = 0;
// Open a reading pipe for current nodeId (if it differs from broadcast)
if (nc.nodeId != BROADCAST_PIPE) {
RF24::openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(nc.nodeId));
}
// 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)
build(&msg, nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_PING);
build(&msg, nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_PING)->set("");
sendWrite(BROADCAST_ADDRESS, &msg, true);
// Wait for ping response.
waitForReply();
}
void MySensor::waitForReply() {
unsigned long enter = millis();
// Wait for ack responses slightly more than 1 second
while (millis() - enter < 1200) {
// Wait a couple of seconds for response
while (millis() - enter < 2000) {
process();
}
}
boolean MySensor::sendRoute(MyMessage *message) {
// Make sure to process any incoming messages before sending (could this end up in recursive loop?)
// process();
bool requestId = (mGetCommandP(message) == C_INTERNAL && message->type == I_ID_REQUEST);
bool responseId = (mGetCommandP(message) == C_INTERNAL && message->type == I_ID_RESPONSE);
// If we still don't have any node id, re-request and skip this message.
if (nc.nodeId == AUTO && !(mGetCommandP(message) == C_INTERNAL && message->type == I_REQUEST_ID)) {
if (nc.nodeId == AUTO && !requestId) {
requestNodeId();
return false;
}
@@ -157,16 +161,20 @@ boolean MySensor::sendRoute(MyMessage *message) {
if (relayMode) {
uint8_t dest = message->destination;
uint8_t route = getChildRoute(dest);
if (route>0 && route<255 && dest != GATEWAY_ADDRESS) {
debug(PSTR("route %d.\n"), route);
if (route>GATEWAY_ADDRESS && route<BROADCAST_ADDRESS && dest != GATEWAY_ADDRESS) {
// --- debug(PSTR("route %d.\n"), route);
// Message destination is not gateway and is in routing table for this node.
// Send it downstream
return sendWrite(route, message);
} else if (responseId && dest==BROADCAST_ADDRESS) {
// Node has not yet received any id. We need to send it
// by doing a broadcast sending,
return sendWrite(BROADCAST_ADDRESS, message, true);
}
}
if (nc.nodeId != GATEWAY_ADDRESS) {
debug(PSTR("route parent\n"));
// --- debug(PSTR("route parent\n"));
// Should be routed back to gateway.
bool ok = sendWrite(nc.parentNodeId, message);
@@ -190,7 +198,6 @@ boolean MySensor::sendWrite(uint8_t next, MyMessage *message, bool broadcast) {
message->last = nc.nodeId;
mSetVersionP(message, PROTOCOL_VERSION);
message->crc = crc8Message(message);
// Make sure radio has powered up
RF24::powerUp();
RF24::stopListening();
@@ -199,8 +206,8 @@ boolean MySensor::sendWrite(uint8_t next, MyMessage *message, bool broadcast) {
RF24::startListening();
// Only debug print payload if it is of string type
debug(PSTR("tx: %d-%d-%d-%d s=%d,c=%d,t=%d, st=%s:%s\n"),
message->sender,message->last, next, message->destination, message->sensor, mGetCommandP(message), message->type, ok?"ok":"fail", message->getString());
debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d, st=%s:%s\n"),
message->sender,message->last, next, message->destination, message->sensor, mGetCommandP(message), message->type, ok?"ok":"fail", message->getString(convBuf));
return ok;
}
@@ -259,8 +266,8 @@ boolean MySensor::process() {
// Make sure string gets terminated ok for full string messages.
msg.data[len - HEADER_SIZE ] = '\0';
debug(PSTR("rx: %d-%d-%d s=%d,c=%d,t=%d,cr=%s: %s\n"),
msg.sender, msg.last, msg.destination, msg.sensor, mGetCommand(msg), msg.type, valid==0?"ok":valid==1?"ec":"ev", msg.getString());
debug(PSTR("read: %d-%d-%d s=%d,c=%d,t=%d,cr=%s: %s\n"),
msg.sender, msg.last, msg.destination, msg.sensor, mGetCommand(msg), msg.type, valid==0?"ok":valid==1?"ec":"ev", msg.getString(convBuf));
if (!ok)
return false;
@@ -276,7 +283,7 @@ boolean MySensor::process() {
// 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_PING_ACK)->set(nc.distance));
sendWrite(sender, build(&msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_PING_ACK)->set(nc.distance), true);
return false;
} else if (destination == nc.nodeId) {
// This message is addressed to this node
@@ -286,8 +293,9 @@ boolean MySensor::process() {
}
if (command == C_INTERNAL) {
if (type == I_PING_ACK) {
// We've received a reply to our PING message looking for parent.
if (type == I_PING_ACK && nc.nodeId != GATEWAY_ADDRESS) {
// We've received a reply to a PING message. Check if the distance is
// shorter than we already have.
uint8_t distance = msg.getByte();
if (distance<nc.distance-1) {
// Found a neighbor closer to GW than previously found
@@ -295,14 +303,14 @@ boolean MySensor::process() {
nc.parentNodeId = msg.sender;
eeprom_write_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId);
eeprom_write_byte((uint8_t*)EEPROM_DISTANCE_ADDRESS, nc.distance);
debug(PSTR("p=%d, d=%d\n"), nc.parentNodeId, nc.distance);
debug(PSTR("new parent=%d, d=%d\n"), nc.parentNodeId, nc.distance);
}
return false;
} else if (sender == GATEWAY_ADDRESS) {
bool isMetric;
switch (type) {
case I_REQUEST_ID:
case I_ID_RESPONSE:
if (nc.nodeId == AUTO) {
nc.nodeId = msg.getByte();
// Write id to EEPROM
@@ -363,7 +371,7 @@ boolean MySensor::process() {
}
// Return true if message was addressed for this node...
return true;
} else if (relayMode) {
} else if (relayMode && pipe == CURRENT_NODE_PIPE) {
// We should try to relay this message to another node
uint8_t route = getChildRoute(msg.destination);
@@ -380,7 +388,7 @@ boolean MySensor::process() {
//
// lookup route in table and send message there
sendWrite(route, &msg);
} else if (pipe == CURRENT_NODE_PIPE) {
} else {
// A message comes from a child node and we have no
// route for it.
//
@@ -396,33 +404,6 @@ boolean MySensor::process() {
sendWrite(nc.parentNodeId, &msg);
// Add this child to our "routing table" if it not already exist
addChildRoute(sender, last);
} else {
// We're snooped a message directed to gateway from another branch
// Make sure to remove the sender node from our routing table.
//
// +-----B <-- Message comes from here
// -A
// +-----C <-- We're here
//
// So the sender of message should never be in our
// routing table.
//
// We could also end up in this else-statement if message
// destination has no route.
// This can happen if a node never has sent any message to
// sensor net gateway (which will build up routing information in all nodes
// that gets passed).
// THIS SHOULD NOT HAPPEN ANY MORE
/*if (nc.nodeId == GATEWAY_ADDRESS) {
// We should perhaps inform gateway about the no-route situation?!
debug(PSTR("ro=?\n"));
} else {
//debug(PSTR("Remove child node from routing table.\n"));
removeChildRoute(sender);
}*/
}
}
@@ -495,11 +476,11 @@ uint8_t MySensor::validate(MyMessage *message) {
void MySensor::saveState(uint8_t pos, uint8_t value) {
if (loadState(pos) != value) {
eeprom_write_byte((uint8_t*)EEPROM_LOCAL_CONFIG_ADDRESS+pos, value);
eeprom_write_byte((uint8_t*)(EEPROM_LOCAL_CONFIG_ADDRESS+pos), value);
}
}
uint8_t MySensor::loadState(uint8_t pos) {
return eeprom_read_byte((uint8_t*)EEPROM_LOCAL_CONFIG_ADDRESS+pos);
return eeprom_read_byte((uint8_t*)(EEPROM_LOCAL_CONFIG_ADDRESS+pos));
}
@@ -522,12 +503,27 @@ uint8_t MySensor::getChildRoute(uint8_t childId) {
}
long MySensor::getInternalTemp(void)
{
long result;
// Read internal temp sensor against 1.1V reference
ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX3);
delay(2); // Wait until Vref has settled
ADCSRA |= _BV(ADSC);
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = (result - 125) * 1075;
return result;
}
#ifdef DEBUG
void MySensor::debugPrint(const char *fmt, ... ) {
char fmtBuffer[300];
if (nc.nodeId == GATEWAY_ADDRESS) {
// prepend debug message to be handled correctly by gw
Serial.write("0;0;4;11;");
// prepend debug message to be handled correctly by gw (C_INTERNAL, I_LOG_MESSAGE)
Serial.write("0;0;4;8;");
}
va_list args;
va_start (args, fmt );
+17 -3
View File
@@ -93,14 +93,14 @@ class MySensor : public RF24
*
* Call this in setup(), before calling any other sensor net library methods.
* @param incomingMessageCallback Callback function for incoming messages from other nodes or controller and request responses. Default is NULL.
* @param relayMode Activate relay mode. This node will forward messages to other nodes in the radio network. Make sure to call process() regularly. Default in false
* @param nodeId The unique id (1-254) for this sensor. Default is AUTO(255) which means sensor tries to fetch an id from controller.
* @param relayMode Activate relay mode. This node will forward messages to other nodes in the radio network. Make sure to call process() regularly. Default in false
* @param paLevel Radio PA Level for this sensor. Default RF24_PA_MAX
* @param channel Radio channel. Default is channel 76
* @param dataRate Radio transmission speed. Default RF24_1MBPS
*/
void begin(void (* msgCallback)(MyMessage)=NULL, boolean relayMode=false, uint8_t nodeId=AUTO, rf24_pa_dbm_e paLevel=RF24_PA_LEVEL, uint8_t channel=RF24_CHANNEL, rf24_datarate_e dataRate=RF24_DATARATE);
void begin(void (* msgCallback)(MyMessage)=NULL, uint8_t nodeId=AUTO, boolean relayMode=false, rf24_pa_dbm_e paLevel=RF24_PA_LEVEL, uint8_t channel=RF24_CHANNEL, rf24_datarate_e dataRate=RF24_DATARATE);
/**
* Return the nodes nodeId.
@@ -194,6 +194,16 @@ class MySensor : public RF24
MyMessage* getLastMessage(void);
/**
* getInternalTemp
*
* Read temp from internal (ATMEGA328 only) temperature sensor
*
* @return Temperature in milli-degrees Celsius
*/
long getInternalTemp(void);
#ifdef DEBUG
void debugPrint(const char *fmt, ... );
@@ -214,12 +224,16 @@ class MySensor : public RF24
uint8_t validate(MyMessage *message);
private:
#ifdef DEBUG
char convBuf[MAX_PAYLOAD];
#endif
uint8_t failedTransmissions;
uint8_t *childNodeTable; // In memory buffer for routing information to other nodes. also stored in EEPROM
void (*timeCallback)(unsigned long); // Callback for requested time messages
void (*msgCallback)(MyMessage); // Callback for incoming messages from other nodes and gateway.
void requestNodeId();
void waitForReply();
void requestNodeId();
void findParentNode();
uint8_t crc8Message(MyMessage *message);
uint8_t getChildRoute(uint8_t childId);
@@ -17,7 +17,8 @@ float lastTemperature[MAX_ATTACHED_DS18B20];
int numSensors=0;
boolean receivedConfig = false;
boolean metric = true;
MyMessage out;
// Initialize temperature message
MyMessage msg(0,V_TEMP);
void setup()
{
@@ -37,9 +38,6 @@ void setup()
for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {
gw.present(i, S_TEMP);
}
// Initialize outgoing message to always send temperature
out.type = V_TEMP;
}
@@ -61,7 +59,7 @@ void loop()
if (lastTemperature[i] != temperature && temperature != -127.00) {
// Send in the new temperature
gw.send(out.setSensor(i)->set(temperature,1));
gw.send(msg.setSensor(i)->set(temperature,1));
lastTemperature[i]=temperature;
}
}
@@ -1,20 +1,22 @@
#include <MySensor.h>
#include <Sleep_n0m1.h>
#include <SPI.h>
#include <EEPROM.h>
#include <RF24.h>
#include <Sensor.h>
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your motion sensor. (Only 2 and 3 generates interrupt!)
#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
#define CHILD_ID 0 // Id of the sensor child
#define CHILD_ID 1 // Id of the sensor child
Sensor gw;
MySensor gw;
Sleep sleep;
// Initialize motion message
MyMessage msg(CHILD_ID, V_TRIPPED);
void setup()
{
EEPROM.write(EEPROM_RELAY_ID_ADDRESS, 0);
//eeprom_write_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, 1);
//eeprom_write_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, 255);
//delay(2000);
gw.begin();
// Send the sketch version information to the gateway and Controller
@@ -22,7 +24,10 @@ void setup()
pinMode(DIGITAL_INPUT_SENSOR, INPUT); // sets the motion sensor digital pin as input
// Register all sensors to gw (they will be created as child devices)
gw.sendSensorPresentation(CHILD_ID, S_MOTION);
delay(500);
gw.present(CHILD_ID, S_MOTION);
delay(1000);
}
void loop()
@@ -31,7 +36,7 @@ void loop()
boolean tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH;
Serial.println(tripped);
gw.sendVariable(CHILD_ID, V_TRIPPED, tripped?"1":"0"); // Send tripped value to gw
gw.send(msg.set(tripped?"1":"0")); // Send tripped value to gw
// Power down the radio. Note that the radio will get powered back up
// on the next write() call.
@@ -16,7 +16,7 @@ MySensor gw;
void setup()
{
// Initialize library and add callback for incoming messages
gw.begin(incomingMessage, false);
gw.begin(incomingMessage, AUTO, true);
// Send the sketch version information to the gateway and Controller
gw.sendSketchInfo("Relay", "1.0");
@@ -42,10 +42,9 @@ void incomingMessage(MyMessage message) {
// We only expect one type of message from controller. But we better check anyway.
if (message.type==V_LIGHT) {
// Change relay state
digitalWrite(message.sensor, message.getBool()?RELAY_ON:RELAY_OFF);
digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF);
// Store state in eeprom
gw.saveState(message.sensor, message.getBool());
// Write some debug info
Serial.print("Incoming change for sensor:");
Serial.print(message.sensor);
+2 -2
View File
@@ -680,10 +680,10 @@ void RF24::startWrite( const void* buf, uint8_t len, const bool multicast ){
// Send the payload
//write_payload( buf, len );
write_payload( buf, len,multicast? W_TX_PAYLOAD_NO_ACK : W_TX_PAYLOAD ) ;
write_payload( buf, len, multicast?static_cast<uint8_t>(W_TX_PAYLOAD_NO_ACK):static_cast<uint8_t>(W_TX_PAYLOAD)) ;
ce(HIGH);
ce(LOW);
ce(LOW);
}