mirror of
https://github.com/digistump/DigistumpArduino.git
synced 2025-09-17 17:32:25 -07:00
switch to setup for Arduino Boards Manager
This commit is contained in:
4
digistump-sam/libraries/RF24Network/examples/sensornet/.gitignore
vendored
Normal file
4
digistump-sam/libraries/RF24Network/examples/sensornet/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
version.h
|
||||
output/
|
||||
ojam/
|
||||
.*.swp
|
@@ -0,0 +1,30 @@
|
||||
#ifndef __DUINODE_V3_H__
|
||||
#define __DUINODE_V3_H__
|
||||
|
||||
/**
|
||||
* @file DuinodeV1.h
|
||||
*
|
||||
* Contains hardware definitions for RF Duinode V1 (3V3)
|
||||
*/
|
||||
|
||||
#define PINS_DEFINED 1
|
||||
#define __PLATFORM__ "RF Duinode V1 (3V3)"
|
||||
|
||||
const int rf_irq = 0;
|
||||
|
||||
const int led_red = 0;
|
||||
const int led_yellow = 0;
|
||||
const int led_green = 0;
|
||||
const int button_a = 0;
|
||||
|
||||
const int rf_ce = 8;
|
||||
const int rf_csn = 9;
|
||||
|
||||
const int temp_pin = 2; // analog
|
||||
const int voltage_pin = 3; // analog
|
||||
|
||||
// 1.1V internal reference after 1M/470k divider, in 8-bit fixed point
|
||||
const unsigned voltage_reference = 0x371;
|
||||
|
||||
#endif // __DUINODE_V3_H__
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
@@ -0,0 +1,30 @@
|
||||
#ifndef __DUINODE_V3_H__
|
||||
#define __DUINODE_V3_H__
|
||||
|
||||
/**
|
||||
* @file DuinodeV3.h
|
||||
*
|
||||
* Contains hardware definitions for RF Duinode V3 (2V4)
|
||||
*/
|
||||
|
||||
#define PINS_DEFINED 1
|
||||
#define __PLATFORM__ "RF Duinode V3/V4 (2V4)"
|
||||
|
||||
const int rf_irq = 0;
|
||||
|
||||
const int led_red = 3;
|
||||
const int led_yellow = 4;
|
||||
const int led_green = 5;
|
||||
const int button_a = 6;
|
||||
|
||||
const int rf_ce = 8;
|
||||
const int rf_csn = 7;
|
||||
|
||||
const int temp_pin = 2; // analog
|
||||
const int voltage_pin = 3; // analog
|
||||
|
||||
// 1.1V internal reference after 1M/470k divider, in 8-bit fixed point
|
||||
const unsigned voltage_reference = 0x371;
|
||||
|
||||
#endif // __DUINODE_V3_H__
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
@@ -0,0 +1,30 @@
|
||||
#ifndef __DUINODE_V5_H__
|
||||
#define __DUINODE_V5_H__
|
||||
|
||||
/**
|
||||
* @file DuinodeV3.h
|
||||
*
|
||||
* Contains hardware definitions for RF Duinode V5 (2V4)
|
||||
*/
|
||||
|
||||
#define PINS_DEFINED 1
|
||||
#define __PLATFORM__ "RF Duinode V5 (2V4)"
|
||||
|
||||
const int rf_irq = 0;
|
||||
|
||||
const int led_red = 3;
|
||||
const int led_yellow = 4;
|
||||
const int led_green = 5;
|
||||
const int button_a = 6;
|
||||
|
||||
const int rf_ce = 14;
|
||||
const int rf_csn = 15;
|
||||
|
||||
const int temp_pin = 2; // analog
|
||||
const int voltage_pin = 3; // analog
|
||||
|
||||
// 1.1V internal reference after 1M/470k divider, in 8-bit fixed point
|
||||
const unsigned voltage_reference = 0x371;
|
||||
|
||||
#endif // __DUINODE_V5_H__
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
@@ -0,0 +1,6 @@
|
||||
SubDir TOP libraries RF24Network examples sensornet ;
|
||||
|
||||
LOCATE_SOURCE = $(SUBDIR)/$(PINS) ;
|
||||
LOCATE_TARGET = $(SUBDIR)/$(PINS) ;
|
||||
|
||||
ArduinoWithLibs Main : RF24Network RF24 Tictocs SPI ;
|
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright (C) 2011 J. Coliz <maniacbug@ymail.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.
|
||||
*/
|
||||
|
||||
// STL headers
|
||||
// C headers
|
||||
// Framework headers
|
||||
// Library headers
|
||||
#include "RF24Network_config.h"
|
||||
// Project headers
|
||||
// This component's header
|
||||
#include "S_message.h"
|
||||
|
||||
char S_message::buffer[32];
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
char* S_message::toString(void)
|
||||
{
|
||||
snprintf(buffer,sizeof(buffer),"%2u.%02uC /%2u.%02uV",
|
||||
temp_reading >> 8,
|
||||
( temp_reading & 0xFF ) * 100 / 256,
|
||||
voltage_reading >> 8,
|
||||
( voltage_reading & 0xFF ) * 100 / 256
|
||||
);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Copyright (C) 2011 J. Coliz <maniacbug@ymail.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.
|
||||
*/
|
||||
|
||||
#ifndef __S_MESSAGE_H__
|
||||
#define __S_MESSAGE_H__
|
||||
|
||||
// STL headers
|
||||
// C headers
|
||||
// Framework headers
|
||||
// Library headers
|
||||
// Project headers
|
||||
|
||||
/**
|
||||
* Sensor message (type 'S')
|
||||
*/
|
||||
|
||||
struct S_message
|
||||
{
|
||||
uint16_t temp_reading;
|
||||
uint16_t voltage_reading;
|
||||
static char buffer[];
|
||||
S_message(void): temp_reading(0), voltage_reading(0) {}
|
||||
char* toString(void);
|
||||
};
|
||||
|
||||
#endif // __S_MESSAGE_H__
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
@@ -0,0 +1 @@
|
||||
jam F_CPU=16000000 "CCFLAGS=-include DuinodeV1.h" -dx UPLOAD_SPEED=115200 u1 && screen /dev/ttyUSB1 57600
|
@@ -0,0 +1,3 @@
|
||||
AVR_BIN=/usr/local/avr/bin AVR_ETC=/usr/local/avr/etc jam F_CPU=8000000 sensornet.elf
|
||||
touch sensornet.pde
|
||||
AVR_BIN=/usr/local/avr/bin AVR_ETC=/usr/local/avr/etc jam F_CPU=8000000 "CCFLAGS=-include DuinodeV3.h" -dx UPLOAD_SPEED=57600 u1 && screen /dev/ttyUSB1 57600
|
@@ -0,0 +1 @@
|
||||
jam F_CPU=8000000 "CCFLAGS=-include DuinodeV5.h" -dx UPLOAD_SPEED=57600 u0 && picocom -b 57600 /dev/ttyUSB0
|
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.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 "RF24Network_config.h"
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "nodeconfig.h"
|
||||
|
||||
// Where in EEPROM is the address stored?
|
||||
uint8_t* address_at_eeprom_location = (uint8_t*)10;
|
||||
|
||||
eeprom_info_t eeprom_info;
|
||||
|
||||
const eeprom_info_t& nodeconfig_read(void)
|
||||
{
|
||||
eeprom_read_block(&eeprom_info,address_at_eeprom_location,sizeof(eeprom_info));
|
||||
|
||||
// Look for the token in EEPROM to indicate the following value is
|
||||
// a validly set node address
|
||||
if ( eeprom_info.isValid() )
|
||||
{
|
||||
printf_P(PSTR("ADDRESS: %o\n\r"),eeprom_info.address);
|
||||
printf_P(PSTR("ROLE: %S\n\r"),eeprom_info.relay ? PSTR("Relay") : PSTR("Leaf") );
|
||||
printf_P(PSTR("TEMP: %04x\n\r"),eeprom_info.temp_calibration);
|
||||
}
|
||||
else
|
||||
{
|
||||
eeprom_info.clear();
|
||||
|
||||
printf_P(PSTR("*** No valid address found. Send node address via serial of the form 011<cr>\n\r"));
|
||||
while(1)
|
||||
{
|
||||
nodeconfig_listen();
|
||||
}
|
||||
}
|
||||
|
||||
return eeprom_info;
|
||||
}
|
||||
|
||||
char serialdata[10];
|
||||
char* nextserialat = serialdata;
|
||||
const char* maxserial = serialdata + sizeof(serialdata) - 1;
|
||||
|
||||
void nodeconfig_listen(void)
|
||||
{
|
||||
//
|
||||
// Listen for serial input, which is how we set the address
|
||||
//
|
||||
if (Serial.available())
|
||||
{
|
||||
// If the character on serial input is in a valid range...
|
||||
char c = tolower(Serial.read());
|
||||
if ( (c >= '0' && c <= '9' ) || (c >= 'a' && c <= 'f' ) )
|
||||
{
|
||||
*nextserialat++ = c;
|
||||
if ( nextserialat == maxserial )
|
||||
{
|
||||
*nextserialat = 0;
|
||||
printf_P(PSTR("\r\n*** Unknown serial command: %s\r\n"),serialdata);
|
||||
nextserialat = serialdata;
|
||||
}
|
||||
}
|
||||
else if ( tolower(c) == 'r' )
|
||||
{
|
||||
eeprom_info.relay = true;
|
||||
printf_P(PSTR("ROLE: %S\n\r"),eeprom_info.relay ? PSTR("Relay") : PSTR("Leaf") );
|
||||
eeprom_update_block(&eeprom_info,address_at_eeprom_location,sizeof(eeprom_info));
|
||||
printf_P(PSTR("RESET NODE before changes take effect\r\n"));
|
||||
if ( ! eeprom_info.isValid() )
|
||||
printf_P(PSTR("Please assign an address\r\n"));
|
||||
}
|
||||
else if ( tolower(c) == 'l' )
|
||||
{
|
||||
eeprom_info.relay = false;
|
||||
printf_P(PSTR("ROLE: %S\n\r"),eeprom_info.relay ? PSTR("Relay") : PSTR("Leaf") );
|
||||
eeprom_update_block(&eeprom_info,address_at_eeprom_location,sizeof(eeprom_info));
|
||||
printf_P(PSTR("RESET NODE before changes take effect\r\n"));
|
||||
if ( ! eeprom_info.isValid() )
|
||||
printf_P(PSTR("Please assign an address\r\n"));
|
||||
}
|
||||
else if ( tolower(c) == 't' )
|
||||
{
|
||||
// Send temperature calibration as 2-digit 4.4-fixed decimal signed degrees
|
||||
// celcius--followed by a 't'. So, for -1.5 degrees, send "e8t". Or for +2 degrees
|
||||
// send "20t"
|
||||
|
||||
*nextserialat = 0;
|
||||
int8_t val = strtol(serialdata,NULL,16);
|
||||
nextserialat = serialdata;
|
||||
|
||||
set_temp_calibration( val * 0x10 );
|
||||
|
||||
printf_P(PSTR("RESET NODE before changes take effect\r\n"));
|
||||
if ( ! eeprom_info.isValid() )
|
||||
printf_P(PSTR("Please assign an address\r\n"));
|
||||
}
|
||||
else if ( c == 13 )
|
||||
{
|
||||
// Convert to octal
|
||||
char *pc = serialdata;
|
||||
uint16_t address = 0;
|
||||
while ( pc < nextserialat )
|
||||
{
|
||||
address <<= 3;
|
||||
address |= (*pc++ - '0');
|
||||
}
|
||||
|
||||
// It is our address
|
||||
eeprom_info.address = address;
|
||||
eeprom_update_block(&eeprom_info,address_at_eeprom_location,sizeof(eeprom_info));
|
||||
|
||||
// And we are done right now (no easy way to soft reset)
|
||||
printf_P(PSTR("\n\rManually set to address 0%o\n\rPress RESET to continue!"),address);
|
||||
while(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_temp_calibration(int16_t val)
|
||||
{
|
||||
eeprom_info.temp_calibration = val;
|
||||
printf_P(PSTR("TEMP: %02x\n\r"),eeprom_info.temp_calibration);
|
||||
eeprom_update_block(&eeprom_info,address_at_eeprom_location,sizeof(eeprom_info));
|
||||
}
|
||||
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.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.
|
||||
*/
|
||||
|
||||
#ifndef __NODECONFIG_H__
|
||||
#define __NODECONFIG_H__
|
||||
|
||||
// Additional info
|
||||
struct eeprom_info_t
|
||||
{
|
||||
uint8_t flag;
|
||||
uint16_t address;
|
||||
int16_t temp_calibration; // sensor adjustment in signed fixed-8.8 degrees, e.g. 0xFE80 is -1.5
|
||||
bool relay:1;
|
||||
|
||||
static const uint8_t valid_flag = 0xdd;
|
||||
|
||||
eeprom_info_t()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return (flag == valid_flag) && (address != 0xffff);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
flag = valid_flag;
|
||||
address = 0xffff;
|
||||
relay = false;
|
||||
temp_calibration = 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const eeprom_info_t& nodeconfig_read(void);
|
||||
void nodeconfig_listen(void);
|
||||
void set_temp_calibration(int16_t val);
|
||||
|
||||
#endif // __NODECONFIG_H__
|
||||
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
|
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright (C) 2011 J. Coliz <maniacbug@ymail.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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file printf.h
|
||||
*
|
||||
* Setup necessary to direct stdout to the Arduino Serial library, which
|
||||
* enables 'printf'
|
||||
*/
|
||||
|
||||
#ifndef __PRINTF_H__
|
||||
#define __PRINTF_H__
|
||||
|
||||
#ifdef ARDUINO
|
||||
|
||||
int serial_putc( char c, FILE * )
|
||||
{
|
||||
Serial.write( c );
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void printf_begin(void)
|
||||
{
|
||||
fdevopen( &serial_putc, 0 );
|
||||
}
|
||||
|
||||
#else
|
||||
#error This example is only for use on Arduino.
|
||||
#endif // ARDUINO
|
||||
|
||||
#endif // __PRINTF_H__
|
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Example of a sensor network
|
||||
*
|
||||
* This sketch demonstrates how to use the RF24Network library to
|
||||
* manage a set of low-power sensor nodes which mostly sleep but
|
||||
* awake regularly to send readings to the base.
|
||||
*
|
||||
* The example uses TWO sensors, a 'temperature' sensor and a 'voltage'
|
||||
* sensor.
|
||||
*
|
||||
* To see the underlying frames being relayed, compile RF24Network with
|
||||
* #define SERIAL_DEBUG.
|
||||
*
|
||||
* The logical node address of each node is set in EEPROM. The nodeconfig
|
||||
* module handles this by listening for a digit (0-9) on the serial port,
|
||||
* and writing that number to EEPROM.
|
||||
*/
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include <RF24Network.h>
|
||||
#include <RF24.h>
|
||||
#include <SPI.h>
|
||||
#include <Tictocs.h>
|
||||
#include <Button.h>
|
||||
#include <TictocTimer.h>
|
||||
#include "nodeconfig.h"
|
||||
#include "sleep.h"
|
||||
#include "S_message.h"
|
||||
#include "printf.h"
|
||||
|
||||
// This is for git version tracking. Safe to ignore
|
||||
#ifdef VERSION_H
|
||||
#include "version.h"
|
||||
#else
|
||||
#define __TAG__ "Unknown"
|
||||
#endif
|
||||
|
||||
// Pin definitions
|
||||
#ifndef PINS_DEFINED
|
||||
#define __PLATFORM__ "Getting Started board"
|
||||
|
||||
// Pins for radio
|
||||
const int rf_ce = 9;
|
||||
const int rf_csn = 10;
|
||||
|
||||
// Pins for sensors
|
||||
const int temp_pin = A2;
|
||||
const int voltage_pin = A3;
|
||||
|
||||
// Pins for status LED, or '0' for no LED connected
|
||||
const int led_red = 0;
|
||||
const int led_yellow = 0;
|
||||
const int led_green = 0;
|
||||
|
||||
// Button to control modes
|
||||
const int button_a = 4;
|
||||
|
||||
// What voltage is a reading of 1023?
|
||||
const unsigned voltage_reference = 5 * 256; // 5.0V
|
||||
#endif
|
||||
|
||||
RF24 radio(rf_ce,rf_csn);
|
||||
RF24Network network(radio);
|
||||
|
||||
// Our node configuration
|
||||
eeprom_info_t this_node;
|
||||
|
||||
// Sleep constants. In this example, the watchdog timer wakes up
|
||||
// every 4s, and every single wakeup we power up the radio and send
|
||||
// a reading. In real use, these numbers which be much higher.
|
||||
// Try wdt_8s and 7 cycles for one reading per minute.> 1
|
||||
const wdt_prescalar_e wdt_prescalar = wdt_8s;
|
||||
const int sleep_cycles_per_transmission = 1;
|
||||
|
||||
// Non-sleeping nodes need a timer to regulate their sending interval
|
||||
Timer send_timer(8000);
|
||||
|
||||
// Button controls functionality of the unit
|
||||
Button ButtonA(button_a);
|
||||
|
||||
// Long-press button
|
||||
Button ButtonLong(button_a,1000);
|
||||
|
||||
/**
|
||||
* Convenience class for handling LEDs. Handles the case where the
|
||||
* LED may not be populated on the board, so always checks whether
|
||||
* the pin is valid before setting a value.
|
||||
*/
|
||||
|
||||
class LED
|
||||
{
|
||||
private:
|
||||
int pin;
|
||||
public:
|
||||
LED(int _pin): pin(_pin)
|
||||
{
|
||||
if (pin > 0)
|
||||
{
|
||||
pinMode(pin,OUTPUT);
|
||||
digitalWrite(pin,LOW);
|
||||
}
|
||||
}
|
||||
void write(bool state) const
|
||||
{
|
||||
if (pin > 0)
|
||||
digitalWrite(pin,state?HIGH:LOW);
|
||||
}
|
||||
void operator=(bool state)
|
||||
{
|
||||
write(state);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Startup LED sequence. Lights up the LEDs in sequence first, then dims
|
||||
* them in the same sequence.
|
||||
*/
|
||||
|
||||
class StartupLEDs: public Timer
|
||||
{
|
||||
private:
|
||||
const LED** leds;
|
||||
const LED** current;
|
||||
const LED** end;
|
||||
bool state;
|
||||
protected:
|
||||
virtual void onFired(void)
|
||||
{
|
||||
(*current)->write(state);
|
||||
++current;
|
||||
if ( current >= end )
|
||||
{
|
||||
if ( state )
|
||||
{
|
||||
state = false;
|
||||
current = leds;
|
||||
}
|
||||
else
|
||||
disable();
|
||||
}
|
||||
}
|
||||
public:
|
||||
StartupLEDs(const LED** _leds, int _num): Timer(250), leds(_leds), current(_leds), end(_leds+_num), state(true)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Calibration LED sequence. Flashes all 3 in unison
|
||||
*/
|
||||
class CalibrationLEDs: public Timer
|
||||
{
|
||||
const LED** leds;
|
||||
const LED** end;
|
||||
bool state;
|
||||
protected:
|
||||
void write()
|
||||
{
|
||||
const LED** current = end;
|
||||
while (current-- > leds)
|
||||
(*current)->write(state);
|
||||
}
|
||||
virtual void onFired()
|
||||
{
|
||||
state = ! state;
|
||||
write();
|
||||
}
|
||||
public:
|
||||
CalibrationLEDs(const LED** _leds, int _num, unsigned long duration = 500): Timer(duration), leds(_leds), end(_leds+_num), state(false)
|
||||
{
|
||||
Timer::disable();
|
||||
}
|
||||
void begin()
|
||||
{
|
||||
Updatable::begin();
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
state = true;
|
||||
write();
|
||||
Timer::reset();
|
||||
}
|
||||
void disable()
|
||||
{
|
||||
state = false;
|
||||
write();
|
||||
Timer::disable();
|
||||
}
|
||||
};
|
||||
|
||||
LED Red(led_red), Yellow(led_yellow), Green(led_green);
|
||||
|
||||
const LED* leds[] = { &Red, &Yellow, &Green };
|
||||
const int num_leds = sizeof(leds)/sizeof(leds[0]);
|
||||
StartupLEDs startup_leds(leds,num_leds);
|
||||
CalibrationLEDs calibration_leds(leds,num_leds);
|
||||
|
||||
// Nodes in test mode do not sleep, but instead constantly try to send
|
||||
bool test_mode = false;
|
||||
|
||||
// Nodes in calibration mode are looking for temperature calibration
|
||||
bool calibration_mode = false;
|
||||
|
||||
// Helper functions to take readings
|
||||
|
||||
// How many measurements to take. 64*1024 = 65536, so 64 is the max we can fit in a uint16_t.
|
||||
const int num_measurements = 64;
|
||||
|
||||
uint32_t measure_temp()
|
||||
{
|
||||
int i = num_measurements;
|
||||
uint32_t reading = 0;
|
||||
while(i--)
|
||||
reading += analogRead(temp_pin);
|
||||
|
||||
// Convert the reading to celcius*256
|
||||
// This is the formula for MCP9700.
|
||||
// C = reading * 1.1
|
||||
// C = ( V - 1/2 ) * 100
|
||||
//
|
||||
// Then adjust for the calibation value on this sensor
|
||||
return ( ( ( ( reading * 0x120 ) - 0x800000 ) * 0x64 ) >> 16 ) + this_node.temp_calibration;
|
||||
}
|
||||
|
||||
uint32_t measure_voltage()
|
||||
{
|
||||
// Take the voltage reading
|
||||
int i = num_measurements;
|
||||
uint32_t reading = 0;
|
||||
while(i--)
|
||||
reading += analogRead(voltage_pin);
|
||||
|
||||
// Convert the voltage reading to volts*256
|
||||
return ( reading * voltage_reference ) >> 16;
|
||||
}
|
||||
|
||||
struct CalibrationData
|
||||
{
|
||||
uint8_t measurements_remaining;
|
||||
static const uint8_t measurements_needed = 16;
|
||||
int16_t accumulator;
|
||||
|
||||
CalibrationData()
|
||||
{
|
||||
measurements_remaining = measurements_needed;
|
||||
accumulator = 0;
|
||||
}
|
||||
void add(int16_t reading)
|
||||
{
|
||||
accumulator += reading / measurements_needed;
|
||||
if ( measurements_remaining )
|
||||
--measurements_remaining;
|
||||
}
|
||||
bool done() const
|
||||
{
|
||||
return measurements_remaining == 0;
|
||||
}
|
||||
int16_t result() const
|
||||
{
|
||||
return accumulator;
|
||||
}
|
||||
};
|
||||
|
||||
CalibrationData calibration_data;
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
//
|
||||
// Print preamble
|
||||
//
|
||||
|
||||
Serial.begin(57600);
|
||||
printf_begin();
|
||||
printf_P(PSTR("\n\rRF24Network/examples/sensornet/\n\r"));
|
||||
printf_P(PSTR("PLATFORM: " __PLATFORM__ "\n\r"));
|
||||
printf_P(PSTR("VERSION: " __TAG__ "\n\r"));
|
||||
|
||||
//
|
||||
// Pull node address out of eeprom
|
||||
//
|
||||
|
||||
// Which node are we?
|
||||
this_node = nodeconfig_read();
|
||||
|
||||
//
|
||||
// Prepare sleep parameters
|
||||
//
|
||||
|
||||
// Only the leaves sleep. Nodes 01-05 are presumed to be relay nodes.
|
||||
if ( ! this_node.relay )
|
||||
Sleep.begin(wdt_prescalar,sleep_cycles_per_transmission);
|
||||
|
||||
//
|
||||
// Set up board hardware
|
||||
//
|
||||
ButtonA.begin();
|
||||
ButtonLong.begin();
|
||||
|
||||
// Sensors use the stable internal 1.1V voltage
|
||||
#ifdef INTERNAL1V1
|
||||
analogReference(INTERNAL1V1);
|
||||
#else
|
||||
analogReference(INTERNAL);
|
||||
#endif
|
||||
|
||||
// Prepare the startup sequence
|
||||
send_timer.begin();
|
||||
startup_leds.begin();
|
||||
calibration_leds.begin();
|
||||
|
||||
//
|
||||
// Bring up the RF network
|
||||
//
|
||||
|
||||
SPI.begin();
|
||||
radio.begin();
|
||||
network.begin(/*channel*/ 92, /*node address*/ this_node.address);
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
// Update objects
|
||||
theUpdater.update();
|
||||
|
||||
// Pump the network regularly
|
||||
network.update();
|
||||
|
||||
// Is there anything ready for us?
|
||||
while ( network.available() )
|
||||
{
|
||||
// If so, grab it and print it out
|
||||
RF24NetworkHeader header;
|
||||
S_message message;
|
||||
network.read(header,&message,sizeof(message));
|
||||
printf_P(PSTR("%lu: APP Received #%u type %c %s from 0%o\n\r"),millis(),header.id,header.type,message.toString(),header.from_node);
|
||||
|
||||
// If we get a message, that's a little odd, because this sketch doesn't run on the
|
||||
// base node. Possibly it's a test message from a child node. Possibly it's a sensor
|
||||
// calibration message from a parent node.
|
||||
//
|
||||
// Either way, it only matters if we're NOT sleeping, and also only useful it we have
|
||||
// a temp sensor
|
||||
|
||||
// If we have a temp sensor AND we are not sleeping
|
||||
if ( temp_pin > -1 && ( ! Sleep || test_mode ) )
|
||||
{
|
||||
// if the received message is a test message, we can respond with a 'C' message in return
|
||||
if ( header.type == 'c' )
|
||||
{
|
||||
// Take a reading
|
||||
S_message response;
|
||||
response.temp_reading = measure_temp();
|
||||
response.voltage_reading = measure_voltage();
|
||||
|
||||
// Send it back as a calibration message
|
||||
RF24NetworkHeader response_header(/*to node*/ header.from_node, /*type*/ 'C');
|
||||
network.write(response_header,&response,sizeof(response));
|
||||
}
|
||||
else if ( header.type == 'C' )
|
||||
{
|
||||
// This is a calibration message. Calculate the diff
|
||||
uint16_t diff = message.temp_reading - measure_temp();
|
||||
printf_P(PSTR("%lu: APP Calibration received %04x diff %04x\n\r"),millis(),message.temp_reading,diff);
|
||||
calibration_data.add(diff);
|
||||
|
||||
if ( calibration_data.done() )
|
||||
{
|
||||
calibration_mode = false;
|
||||
calibration_leds.disable();
|
||||
printf_P(PSTR("%lu: APP Stop calibration mode. Calibrate by %04x\n\r"),millis(),calibration_data.result());
|
||||
|
||||
// Now apply the calibration
|
||||
this_node.temp_calibration += calibration_data.result();
|
||||
// And save it to eeprom...
|
||||
set_temp_calibration( this_node.temp_calibration );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we are the kind of node that sends readings,
|
||||
// AND we have a temp sensor
|
||||
// AND it's time to send a reading
|
||||
// AND we're in the mode where we send readings...
|
||||
if ( this_node.address > 0 && temp_pin > -1 && ( ( Sleep && ! test_mode ) || send_timer.wasFired() ) && ! startup_leds )
|
||||
{
|
||||
// Transmission beginning, TX LED ON
|
||||
Yellow = true;
|
||||
if ( test_mode && ! calibration_mode )
|
||||
{
|
||||
Green = false;
|
||||
Red = false;
|
||||
}
|
||||
|
||||
S_message message;
|
||||
message.temp_reading = measure_temp();
|
||||
message.voltage_reading = measure_voltage();
|
||||
|
||||
char message_type = 'S';
|
||||
if ( calibration_mode )
|
||||
message_type = 'c';
|
||||
else if (test_mode )
|
||||
message_type = 't';
|
||||
|
||||
// By default send to the base
|
||||
uint16_t to_node = 0;
|
||||
if ( test_mode )
|
||||
// In test mode, sent to our parent.
|
||||
to_node = network.parent();
|
||||
|
||||
printf_P(PSTR("---------------------------------\n\r"));
|
||||
printf_P(PSTR("%lu: APP Sending type-%c %s to 0%o...\n\r"),millis(),message_type,message.toString(),to_node);
|
||||
|
||||
RF24NetworkHeader header(to_node,message_type);
|
||||
bool ok = network.write(header,&message,sizeof(message));
|
||||
if (ok)
|
||||
{
|
||||
if ( test_mode && ! calibration_mode )
|
||||
Green = true;
|
||||
printf_P(PSTR("%lu: APP Send ok\n\r"),millis());
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( test_mode && ! calibration_mode )
|
||||
Red = true;
|
||||
printf_P(PSTR("%lu: APP Send failed\n\r"),millis());
|
||||
}
|
||||
|
||||
// Transmission complete, TX LED OFF
|
||||
Yellow = false;
|
||||
|
||||
if ( Sleep && ! test_mode )
|
||||
{
|
||||
// Power down the radio. Note that the radio will get powered back up
|
||||
// on the next write() call.
|
||||
radio.powerDown();
|
||||
|
||||
// Be sure to flush the serial first before sleeping, so everything
|
||||
// gets printed properly
|
||||
Serial.flush();
|
||||
|
||||
// Sleep the MCU. The watchdog timer will awaken in a short while, and
|
||||
// continue execution here.
|
||||
Sleep.go();
|
||||
}
|
||||
}
|
||||
|
||||
// Button
|
||||
unsigned a = ButtonA.wasReleased();
|
||||
if ( a && a < 500 )
|
||||
{
|
||||
// Pressing the button during startup sequences engages test mode.
|
||||
// Pressing it after turns off test mode.
|
||||
if ( startup_leds )
|
||||
{
|
||||
test_mode = true;
|
||||
send_timer.setInterval(1000);
|
||||
printf_P(PSTR("%lu: APP Start test mode\n\r"),millis());
|
||||
}
|
||||
else if ( calibration_mode )
|
||||
{
|
||||
calibration_mode = false;
|
||||
calibration_leds.disable();
|
||||
printf_P(PSTR("%lu: APP Stop calibration mode\n\r"),millis());
|
||||
}
|
||||
else if ( test_mode )
|
||||
{
|
||||
test_mode = false;
|
||||
Green = false;
|
||||
Red = false;
|
||||
send_timer.setInterval(8000);
|
||||
printf_P(PSTR("%lu: APP Stop test mode\n\r"),millis());
|
||||
}
|
||||
}
|
||||
|
||||
// Long press
|
||||
if ( ButtonLong.wasPressed() && test_mode )
|
||||
{
|
||||
calibration_mode = true;
|
||||
calibration_leds.reset();
|
||||
calibration_data = CalibrationData();
|
||||
printf_P(PSTR("%lu: APP Start calibration mode\n\r"),millis());
|
||||
}
|
||||
|
||||
// Listen for a new node address
|
||||
nodeconfig_listen();
|
||||
}
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
@@ -0,0 +1,55 @@
|
||||
|
||||
/*
|
||||
Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sleep.cpp
|
||||
*
|
||||
* Sleep helpers, definitions
|
||||
*/
|
||||
|
||||
#include "RF24Network_config.h"
|
||||
#include <avr/sleep.h>
|
||||
#include "sleep.h"
|
||||
|
||||
sleep_c Sleep;
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void sleep_c::begin(wdt_prescalar_e prescalar_in,short cycles)
|
||||
{
|
||||
sleep_cycles_remaining = cycles;
|
||||
sleep_cycles_per_transmission = cycles;
|
||||
|
||||
uint8_t prescalar = min(9,(uint8_t)prescalar_in);
|
||||
uint8_t wdtcsr = prescalar & 7;
|
||||
if ( prescalar & 8 )
|
||||
wdtcsr |= _BV(WDP3);
|
||||
|
||||
MCUSR &= ~_BV(WDRF);
|
||||
WDTCSR = _BV(WDCE) | _BV(WDE);
|
||||
WDTCSR = _BV(WDCE) | wdtcsr | _BV(WDIE);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void sleep_c::go(void)
|
||||
{
|
||||
while( sleep_cycles_remaining-- )
|
||||
{
|
||||
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
|
||||
sleep_mode();
|
||||
}
|
||||
|
||||
sleep_cycles_remaining = sleep_cycles_per_transmission;
|
||||
}
|
||||
|
||||
ISR(WDT_vect) {
|
||||
}
|
||||
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
@@ -0,0 +1,84 @@
|
||||
|
||||
/*
|
||||
Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sleep.h
|
||||
*
|
||||
* Declaration of the sleep_c class.
|
||||
*/
|
||||
|
||||
#ifndef __SLEEP_H__
|
||||
#define __SLEEP_H__
|
||||
|
||||
/**
|
||||
* Enums for the duration of the watchdog timer
|
||||
*/
|
||||
|
||||
typedef enum { wdt_16ms = 0, wdt_32ms, wdt_64ms, wdt_128ms, wdt_250ms, wdt_500ms, wdt_1s, wdt_2s, wdt_4s, wdt_8s } wdt_prescalar_e;
|
||||
|
||||
/**
|
||||
* Simplified sleeping handler
|
||||
*/
|
||||
|
||||
class sleep_c
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Enable the system to be able to sleep
|
||||
*
|
||||
* Does not actually do any sleeping.
|
||||
*
|
||||
* For example, to do something roughly evert minute, configure
|
||||
* it like this:
|
||||
*
|
||||
* @code
|
||||
* Sleep.begin(wdt_8s,7);
|
||||
* @endcode
|
||||
*
|
||||
* @param prescalar Duration of the watchdog timer interrupt.
|
||||
* The system will actually sleep for this long.
|
||||
* @param cycles Number of times the system will wake up before
|
||||
* returning from @p go().
|
||||
*/
|
||||
void begin(wdt_prescalar_e prescalar,short cycles);
|
||||
|
||||
/**
|
||||
* Go to sleep
|
||||
*
|
||||
* This will return after the watchdog has awoken for the number
|
||||
* of times specified in begin().
|
||||
*/
|
||||
void go(void);
|
||||
|
||||
/**
|
||||
* Test whether the node sleeps
|
||||
*
|
||||
* @retval true if the node will sleep
|
||||
*/
|
||||
operator bool(void) const
|
||||
{
|
||||
return sleep_cycles_per_transmission;
|
||||
}
|
||||
|
||||
private:
|
||||
volatile short sleep_cycles_remaining;
|
||||
short sleep_cycles_per_transmission;
|
||||
};
|
||||
|
||||
/**
|
||||
* Singleton instance for general use
|
||||
*
|
||||
* @warning: This class is hard-coded to ONLY work with this singleton.
|
||||
* Any other instances will fail.
|
||||
*/
|
||||
|
||||
extern sleep_c Sleep;
|
||||
|
||||
#endif // __SLEEP_H__
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Copyright (C) 2011 J. Coliz <maniacbug@ymail.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.
|
||||
*/
|
||||
|
||||
#ifndef __TIMER_H__
|
||||
#define __TIMER_H__
|
||||
|
||||
// STL headers
|
||||
// C headers
|
||||
// Framework headers
|
||||
// Library headers
|
||||
// Project headers
|
||||
|
||||
/**
|
||||
* Simple timer
|
||||
*/
|
||||
|
||||
struct timer_t
|
||||
{
|
||||
unsigned long last;
|
||||
unsigned long interval;
|
||||
timer_t(unsigned long _interval): interval(_interval) {}
|
||||
operator bool(void)
|
||||
{
|
||||
unsigned long now = millis();
|
||||
bool result = now - last >= interval;
|
||||
if ( result )
|
||||
last = now;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __TEMPLATE_H__
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
Reference in New Issue
Block a user