Skip to content

Instantly share code, notes, and snippets.

@chris-pws
Last active July 28, 2018 03:23
Show Gist options
  • Save chris-pws/a249a2181dff57c1c4900667b47b093a to your computer and use it in GitHub Desktop.
Save chris-pws/a249a2181dff57c1c4900667b47b093a to your computer and use it in GitHub Desktop.
#include <SPI.h>
#include "RF24.h"
//#include <SoftwareSerial.h>
#include <avr/sleep.h>
// Set packet data structure
struct data_t {
byte stn_id;
byte msg_type;
unsigned short msg_value;
unsigned long ts;
};
data_t message;
void radioInit(uint8_t dir);
bool sendMsg(struct data_t msg, char retry = -1);
void setWdt();
void clearWdt();
uint16_t readVcc(uint8_t sample);
#define CHANNEL 68
#define MSG_RETRY 5
#define VCC_SAMPLE 60
const uint8_t doorPin = 8;
const uint16_t vccInterval = 1000;
volatile long counter = 0;
const bool dir = 0; // 0 - Write, 1 - Read
bool doorState = 0;
bool swState = 0;
byte addresses[][6] = {"1Node","2Node"}; // Radio pipe addresses for the 2 nodes to communicate.
RF24 radio(10,9);
void setup() {
if (!dir) {
OSCCAL = 0x7A; // Calibration offset for internal oscillator
clearWdt(); // Clear watchdog timer
ADCSRA &= ~(1<<ADEN); // Disable ADC
}
delay(250);
/*
Serial.begin(9600);
delay(4000);
Serial.println(F("nrf_node"));
radioInit(dir);
delay(5000);
*/
message.stn_id = 1;
if (!dir) {
setWdt(); // Set watchdog in preparation for sleepytime
radio.powerDown(); // Turn off the radio to save power
}
}
void loop() {
// transmitter code
if (!dir) {
radio.stopListening();
//sleep_bod_disable();
sleep_mode();
clearWdt();
/*
* Run readVcc every interval
*/
if (counter >= vccInterval) {
counter = 0;
message.msg_type = 2;
message.msg_value = readVcc(VCC_SAMPLE);
message.ts = millis();
radio.powerUp();
/*
Serial.print(message.msg_value);
Serial.println(F(" VCC "));
*/
sendMsg(message, MSG_RETRY);
radio.powerDown();
}
swState = digitalRead(doorPin); // read the state of the switch
if (doorState != swState) { // if switch differs with last state set
if (swState == 0) message.msg_value = 7; // closed
else message.msg_value = 15; // open
message.msg_type = 1;
message.ts = millis(); // set timestamp as unique packet identifier
/*
Serial.print(F("Xmit ")); // Use a simple byte counter as payload
Serial.print(message.msg_value);
Serial.print(F(" ts: "));
Serial.println(message.ts);
*/
radio.powerUp();
if (sendMsg(message, MSG_RETRY)) {
//Serial.println(F("OK"));
doorState = swState; // state has successfully been communicated
} else {
//Serial.println(F("FAIL"));
doorState = swState; // setting new state removes failed message from queue
}
radio.powerDown();
}
setWdt();
}
// receiver code
if (dir==1){
byte pipeNo; // Declare variables for the pipe
radio.powerUp();
while( radio.available(&pipeNo)){ // Read all available payloads
radio.read( &message, sizeof(data_t) );
Serial.print(F("Recv: "));
Serial.print(message.msg_value);
Serial.print(F(" ts: "));
Serial.print(message.ts);
unsigned long tsAck = message.ts; // directly with an ack payload.
// we'll send the ack back when we have recorded the message
radio.writeAckPayload(pipeNo, &tsAck, sizeof(tsAck) ); // This can be commented out to send empty payloads.
Serial.print(F(" Xmit: "));
Serial.println(tsAck);
//Serial.print(F(" "));
//Serial.print(radio.whatHappened());
}
}
}
void radioInit(uint8_t dir=0) {
radio.begin();
radio.setChannel(CHANNEL);
radio.enableAckPayload(); // Allow optional ack payloads
radio.enableDynamicPayloads(); // Ack payloads are dynamic payloads
radio.setDataRate(RF24_250KBPS);
radio.setPALevel(RF24_PA_MIN);
if (dir==0) {
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
} else {
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1,addresses[0]);
}
/*
Serial.print(F("Init "));
if (radio.isPVariant()) {
Serial.println(F("OK"));
} else {
Serial.println(F("Fail"));
}
*/
radio.startListening(); // Start listening
}
bool sendMsg(struct data_t msg, int retry) {
unsigned long tsAck; // Initialize a variable for the incoming response
if (retry <= 0) return false; // Baseline condition
if ( radio.write(&msg, sizeof(data_t)) ){ // Send the counter variable to the other radio
if(!radio.available()){ // If nothing in the buffer, we got an ack but it is blank
retry--; // Incorrect ts ack received, subtract a retry
} else {
while(radio.available() ){ // If an ack with payload was received
radio.read( &tsAck, sizeof(tsAck) );
if (tsAck != msg.ts) {
retry--; // Incorrect ts ack received, subtract a retry
break;
}
return true; // Return true on successful acknowledgement
}
}
} else {
retry--; // Couldn't send the packet, so subtract a retry
}
delay(50);
sendMsg(msg, retry); // Run recursive until baseline met
}
void setWdt() {
cli(); // disable global interrupts
// Clear WDRF in MCUSR
MCUSR &= ~(1<<WDRF);
// Prep the watchdog register
WDTCSR |= (1<<WDCE) | (1<<WDE);
// Set interrupt mode with a timeout of 1 sec
WDTCSR = (1<<WDIE) | (1<<WDP1) | (1<<WDP2);
//WDTCR = ((1<<WDIE));
SMCR = (1<<SM1); // Enable power down sleep mode
sei(); // Enable global interrupts
//pinMode(doorPin, OUTPUT);
//digitalWrite(doorPin, LOW);
return;
}
void clearWdt() {
cli();
// Clear WDRF in MCUSR
MCUSR &= ~(1<<WDRF);
// Write logical one to WDCE and WDE
// Keep old prescaler setting to prevent unintentional time-out
WDTCSR |= (1<<WDCE) | (1<<WDE);
// Turn off WDT
WDTCSR = 0x00;
sei();
return;
}
uint16_t readVcc(uint8_t sample) {
// Use ADC and 1.1V internal bandgap voltage reference to determine V_cc
ADMUX = 0b01001110; // Set to AV_cc, no ADLAR, MUX 1110 = single end V_bg
ADCSRA |= (1<<ADEN);
delay(250); // Wait for the dust to settle
uint16_t sum = 0;
for (uint8_t i=0;i<sample;i++) {
// Read ADC i times and avg the result
ADCSRA |= (1<<ADSC); // start ADC conversion
while( ADCSRA & (1<<ADSC) ) ; // Wait for 1st conversion to be ready...
uint8_t low = ADCL; // read low bit
uint8_t high = ADCH; // read high bit
uint16_t result = (high<<8) | low; // with our powers combined
sum += result;
}
ADCSRA &= ~(1<<ADEN); // disable ADC
return sum ? (1100L * 1023) / (sum/sample) : -1; // return the oversampled voltage
}
ISR(WDT_vect) {
// Keep track of sleep time
counter++;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment