Added project
This commit is contained in:
parent
fe9aa14dfd
commit
2d73cc8845
186 changed files with 21174 additions and 0 deletions
179
lib-ext/dht.git/DHT.cpp
Normal file
179
lib-ext/dht.git/DHT.cpp
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
/* DHT library
|
||||
|
||||
MIT license
|
||||
written by Adafruit Industries
|
||||
*/
|
||||
|
||||
#include "DHT.h"
|
||||
|
||||
DHT::DHT(uint8_t pin, uint8_t type, uint8_t count) {
|
||||
_pin = pin;
|
||||
_type = type;
|
||||
_count = count;
|
||||
firstreading = true;
|
||||
}
|
||||
|
||||
void DHT::begin(void) {
|
||||
// set up the pins!
|
||||
pinMode(_pin, INPUT);
|
||||
digitalWrite(_pin, HIGH);
|
||||
_lastreadtime = 0;
|
||||
}
|
||||
|
||||
//boolean S == Scale. True == Farenheit; False == Celcius
|
||||
float DHT::readTemperature(bool S) {
|
||||
float f;
|
||||
|
||||
if (read()) {
|
||||
switch (_type) {
|
||||
case DHT11:
|
||||
f = data[2];
|
||||
if(S)
|
||||
f = convertCtoF(f);
|
||||
|
||||
return f;
|
||||
case DHT22:
|
||||
case DHT21:
|
||||
f = data[2] & 0x7F;
|
||||
f *= 256;
|
||||
f += data[3];
|
||||
f /= 10;
|
||||
if (data[2] & 0x80)
|
||||
f *= -1;
|
||||
if(S)
|
||||
f = convertCtoF(f);
|
||||
|
||||
return f;
|
||||
}
|
||||
}
|
||||
return NAN;
|
||||
}
|
||||
|
||||
float DHT::convertCtoF(float c) {
|
||||
return c * 9 / 5 + 32;
|
||||
}
|
||||
|
||||
float DHT::convertFtoC(float f) {
|
||||
return (f - 32) * 5 / 9;
|
||||
}
|
||||
|
||||
float DHT::readHumidity(void) {
|
||||
float f;
|
||||
if (read()) {
|
||||
switch (_type) {
|
||||
case DHT11:
|
||||
f = data[0];
|
||||
return f;
|
||||
case DHT22:
|
||||
case DHT21:
|
||||
f = data[0];
|
||||
f *= 256;
|
||||
f += data[1];
|
||||
f /= 10;
|
||||
return f;
|
||||
}
|
||||
}
|
||||
return NAN;
|
||||
}
|
||||
|
||||
float DHT::computeHeatIndex(float tempFahrenheit, float percentHumidity) {
|
||||
// Adapted from equation at: https://github.com/adafruit/DHT-sensor-library/issues/9 and
|
||||
// Wikipedia: http://en.wikipedia.org/wiki/Heat_index
|
||||
return -42.379 +
|
||||
2.04901523 * tempFahrenheit +
|
||||
10.14333127 * percentHumidity +
|
||||
-0.22475541 * tempFahrenheit*percentHumidity +
|
||||
-0.00683783 * pow(tempFahrenheit, 2) +
|
||||
-0.05481717 * pow(percentHumidity, 2) +
|
||||
0.00122874 * pow(tempFahrenheit, 2) * percentHumidity +
|
||||
0.00085282 * tempFahrenheit*pow(percentHumidity, 2) +
|
||||
-0.00000199 * pow(tempFahrenheit, 2) * pow(percentHumidity, 2);
|
||||
}
|
||||
|
||||
|
||||
boolean DHT::read(void) {
|
||||
uint8_t laststate = HIGH;
|
||||
uint8_t counter = 0;
|
||||
uint8_t j = 0, i;
|
||||
unsigned long currenttime;
|
||||
|
||||
// Check if sensor was read less than two seconds ago and return early
|
||||
// to use last reading.
|
||||
currenttime = millis();
|
||||
if (currenttime < _lastreadtime) {
|
||||
// ie there was a rollover
|
||||
_lastreadtime = 0;
|
||||
}
|
||||
if (!firstreading && ((currenttime - _lastreadtime) < 2000)) {
|
||||
return true; // return last correct measurement
|
||||
//delay(2000 - (currenttime - _lastreadtime));
|
||||
}
|
||||
firstreading = false;
|
||||
/*
|
||||
Serial.print("Currtime: "); Serial.print(currenttime);
|
||||
Serial.print(" Lasttime: "); Serial.print(_lastreadtime);
|
||||
*/
|
||||
_lastreadtime = millis();
|
||||
|
||||
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
|
||||
|
||||
// pull the pin high and wait 250 milliseconds
|
||||
digitalWrite(_pin, HIGH);
|
||||
delay(250);
|
||||
|
||||
// now pull it low for ~20 milliseconds
|
||||
pinMode(_pin, OUTPUT);
|
||||
digitalWrite(_pin, LOW);
|
||||
delay(20);
|
||||
noInterrupts();
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(40);
|
||||
pinMode(_pin, INPUT);
|
||||
|
||||
// read in timings
|
||||
for ( i=0; i< MAXTIMINGS; i++) {
|
||||
counter = 0;
|
||||
while (digitalRead(_pin) == laststate) {
|
||||
counter++;
|
||||
delayMicroseconds(1);
|
||||
if (counter == 255) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
laststate = digitalRead(_pin);
|
||||
|
||||
if (counter == 255) break;
|
||||
|
||||
// ignore first 3 transitions
|
||||
if ((i >= 4) && (i%2 == 0)) {
|
||||
// shove each bit into the storage bytes
|
||||
data[j/8] <<= 1;
|
||||
if (counter > _count)
|
||||
data[j/8] |= 1;
|
||||
j++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interrupts();
|
||||
|
||||
/*
|
||||
Serial.println(j, DEC);
|
||||
Serial.print(data[0], HEX); Serial.print(", ");
|
||||
Serial.print(data[1], HEX); Serial.print(", ");
|
||||
Serial.print(data[2], HEX); Serial.print(", ");
|
||||
Serial.print(data[3], HEX); Serial.print(", ");
|
||||
Serial.print(data[4], HEX); Serial.print(" =? ");
|
||||
Serial.println(data[0] + data[1] + data[2] + data[3], HEX);
|
||||
*/
|
||||
|
||||
// check we read 40 bits and that the checksum matches
|
||||
if ((j >= 40) &&
|
||||
(data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
41
lib-ext/dht.git/DHT.h
Normal file
41
lib-ext/dht.git/DHT.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef DHT_H
|
||||
#define DHT_H
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
/* DHT library
|
||||
|
||||
MIT license
|
||||
written by Adafruit Industries
|
||||
*/
|
||||
|
||||
// how many timing transitions we need to keep track of. 2 * number bits + extra
|
||||
#define MAXTIMINGS 85
|
||||
|
||||
#define DHT11 11
|
||||
#define DHT22 22
|
||||
#define DHT21 21
|
||||
#define AM2301 21
|
||||
|
||||
class DHT {
|
||||
private:
|
||||
uint8_t data[6];
|
||||
uint8_t _pin, _type, _count;
|
||||
unsigned long _lastreadtime;
|
||||
boolean firstreading;
|
||||
|
||||
public:
|
||||
DHT(uint8_t pin, uint8_t type, uint8_t count=6);
|
||||
void begin(void);
|
||||
float readTemperature(bool S=false);
|
||||
float convertCtoF(float);
|
||||
float convertFtoC(float);
|
||||
float computeHeatIndex(float tempFahrenheit, float percentHumidity);
|
||||
float readHumidity(void);
|
||||
boolean read(void);
|
||||
|
||||
};
|
||||
#endif
|
||||
3
lib-ext/dht.git/README.txt
Normal file
3
lib-ext/dht.git/README.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
This is an Arduino library for the DHT series of low cost temperature/humidity sensors.
|
||||
|
||||
To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder DHT. Check that the DHT folder contains DHT.cpp and DHT.h. Place the DHT library folder your <arduinosketchfolder>/libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE.
|
||||
71
lib-ext/dht.git/examples/DHTtester/DHTtester.ino
Normal file
71
lib-ext/dht.git/examples/DHTtester/DHTtester.ino
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// Example testing sketch for various DHT humidity/temperature sensors
|
||||
// Written by ladyada, public domain
|
||||
|
||||
#include "DHT.h"
|
||||
|
||||
#define DHTPIN 2 // what pin we're connected to
|
||||
|
||||
// Uncomment whatever type you're using!
|
||||
//#define DHTTYPE DHT11 // DHT 11
|
||||
#define DHTTYPE DHT22 // DHT 22 (AM2302)
|
||||
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
|
||||
|
||||
// Connect pin 1 (on the left) of the sensor to +5V
|
||||
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
|
||||
// to 3.3V instead of 5V!
|
||||
// Connect pin 2 of the sensor to whatever your DHTPIN is
|
||||
// Connect pin 4 (on the right) of the sensor to GROUND
|
||||
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor
|
||||
|
||||
// Initialize DHT sensor for normal 16mhz Arduino
|
||||
DHT dht(DHTPIN, DHTTYPE);
|
||||
// NOTE: For working with a faster chip, like an Arduino Due or Teensy, you
|
||||
// might need to increase the threshold for cycle counts considered a 1 or 0.
|
||||
// You can do this by passing a 3rd parameter for this threshold. It's a bit
|
||||
// of fiddling to find the right value, but in general the faster the CPU the
|
||||
// higher the value. The default for a 16mhz AVR is a value of 6. For an
|
||||
// Arduino Due that runs at 84mhz a value of 30 works.
|
||||
// Example to initialize DHT sensor for Arduino Due:
|
||||
//DHT dht(DHTPIN, DHTTYPE, 30);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
Serial.println("DHTxx test!");
|
||||
|
||||
dht.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Wait a few seconds between measurements.
|
||||
delay(2000);
|
||||
|
||||
// Reading temperature or humidity takes about 250 milliseconds!
|
||||
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
|
||||
float h = dht.readHumidity();
|
||||
// Read temperature as Celsius
|
||||
float t = dht.readTemperature();
|
||||
// Read temperature as Fahrenheit
|
||||
float f = dht.readTemperature(true);
|
||||
|
||||
// Check if any reads failed and exit early (to try again).
|
||||
if (isnan(h) || isnan(t) || isnan(f)) {
|
||||
Serial.println("Failed to read from DHT sensor!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute heat index
|
||||
// Must send in temp in Fahrenheit!
|
||||
float hi = dht.computeHeatIndex(f, h);
|
||||
|
||||
Serial.print("Humidity: ");
|
||||
Serial.print(h);
|
||||
Serial.print(" %\t");
|
||||
Serial.print("Temperature: ");
|
||||
Serial.print(t);
|
||||
Serial.print(" *C ");
|
||||
Serial.print(f);
|
||||
Serial.print(" *F\t");
|
||||
Serial.print("Heat index: ");
|
||||
Serial.print(hi);
|
||||
Serial.println(" *F");
|
||||
}
|
||||
3
lib-ext/ethercard.git/.gitignore
vendored
Normal file
3
lib-ext/ethercard.git/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
.DS_Store
|
||||
*.esproj
|
||||
/html
|
||||
22
lib-ext/ethercard.git/CONTRIBUTING.md
Normal file
22
lib-ext/ethercard.git/CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
Contributing to EtherCard
|
||||
=========================
|
||||
|
||||
Contributions to the EtherCard codebase are welcome using the usual Github pull request workflow.
|
||||
|
||||
Please remember that memory, particularly RAM, is often limited on Arduino, so try and be efficient when adding new features.
|
||||
|
||||
|
||||
Code Style
|
||||
----------
|
||||
|
||||
When making contributions, please use the following code style to keep the codebase consistent:
|
||||
|
||||
* Indent using *4 spaces* not tabs
|
||||
* When placing an opening brace on the same line, there should be one space before it
|
||||
* Closing braces should be broken from the preceding line
|
||||
|
||||
If in doubt, this is the same as the default [astyle] settings, so use the astyle tool to check your code.
|
||||
|
||||
|
||||
|
||||
[astyle]: http://astyle.sourceforge.net/
|
||||
1923
lib-ext/ethercard.git/Doxyfile
Normal file
1923
lib-ext/ethercard.git/Doxyfile
Normal file
File diff suppressed because it is too large
Load diff
BIN
lib-ext/ethercard.git/Doxylogo.png
Normal file
BIN
lib-ext/ethercard.git/Doxylogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
73
lib-ext/ethercard.git/Doxymods.css
Normal file
73
lib-ext/ethercard.git/Doxymods.css
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/* Get rid of all those overriden font families */
|
||||
body, table, div, p, dl,
|
||||
#projectname,
|
||||
#projectbrief,
|
||||
#nav-tree .label {
|
||||
font: 15px/21px Georgia,serif
|
||||
}
|
||||
|
||||
#projectname {
|
||||
color: #990000;
|
||||
font-weight: bold;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
#titlearea table {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
dl.reflist dt, div.memproto {
|
||||
border: 1px solid #A8B8D9;
|
||||
}
|
||||
|
||||
dl.reflist dd, div.memdoc {
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
div.contents {
|
||||
margin-left: 20px; margin-right: 16px;
|
||||
width: 700 px;
|
||||
}
|
||||
|
||||
/* Get rid of the gradient backgrounds and background colors */
|
||||
div.header,
|
||||
#nav-tree,
|
||||
.navpath ul,
|
||||
.memproto, dl.reflist dt {
|
||||
background: none;
|
||||
}
|
||||
#nav-tree .selected {
|
||||
background: none;
|
||||
background-color: #990000;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
a, a:link, a:visited {
|
||||
color: #2A5685;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:active, a:hover {
|
||||
color: #CC0000;
|
||||
}
|
||||
|
||||
.directory tr.even,
|
||||
pre.fragment,
|
||||
.mdescLeft, .mdescRight, .memItemLeft, .memItemRight, .memTemplItemLeft, .memTemplItemRight, .memTemplParams,
|
||||
.memproto, dl.reflist dt {
|
||||
background-color: #EEE;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
.memdoc, dl.reflist dd {
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
pre.fragment {
|
||||
background-color: #FAFAFA;
|
||||
border: 1px solid #DADADA;
|
||||
margin: 1em 1em 1em 1.6em;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
width: auto;
|
||||
}
|
||||
416
lib-ext/ethercard.git/EtherCard.cpp
Normal file
416
lib-ext/ethercard.git/EtherCard.cpp
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
// This code slightly follows the conventions of, but is not derived from:
|
||||
// EHTERSHIELD_H library for Arduino etherShield
|
||||
// Copyright (c) 2008 Xing Yu. All right reserved. (this is LGPL v2.1)
|
||||
// It is however derived from the enc28j60 and ip code (which is GPL v2)
|
||||
// Author: Pascal Stang
|
||||
// Modified by: Guido Socher
|
||||
// DHCP code: Andrew Lindsay
|
||||
// Hence: GPL V2
|
||||
//
|
||||
// 2010-05-19 <jc@wippler.nl>
|
||||
|
||||
#include <EtherCard.h>
|
||||
#include <stdarg.h>
|
||||
#include <avr/eeprom.h>
|
||||
|
||||
//#define FLOATEMIT // uncomment line to enable $T in emit_P for float emitting
|
||||
|
||||
byte Stash::map[256/8];
|
||||
Stash::Block Stash::bufs[2];
|
||||
|
||||
uint8_t Stash::allocBlock () {
|
||||
for (uint8_t i = 0; i < sizeof map; ++i)
|
||||
if (map[i] != 0)
|
||||
for (uint8_t j = 0; j < 8; ++j)
|
||||
if (bitRead(map[i], j)) {
|
||||
bitClear(map[i], j);
|
||||
return (i << 3) + j;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Stash::freeBlock (uint8_t block) {
|
||||
bitSet(map[block>>3], block & 7);
|
||||
}
|
||||
|
||||
uint8_t Stash::fetchByte (uint8_t blk, uint8_t off) {
|
||||
return blk == bufs[0].bnum ? bufs[0].bytes[off] :
|
||||
blk == bufs[1].bnum ? bufs[1].bytes[off] :
|
||||
ether.peekin(blk, off);
|
||||
}
|
||||
|
||||
void Stash::initMap (uint8_t last) {
|
||||
while (--last > 0)
|
||||
freeBlock(last);
|
||||
}
|
||||
|
||||
void Stash::load (uint8_t idx, uint8_t blk) {
|
||||
if (blk != bufs[idx].bnum) {
|
||||
if (idx == 0) {
|
||||
ether.copyout(bufs[idx].bnum, bufs[idx].bytes);
|
||||
if (blk == bufs[1].bnum)
|
||||
bufs[1].bnum = 255; // forget read page if same
|
||||
} else if (blk == bufs[0].bnum) {
|
||||
// special case: read page is same as write buffer
|
||||
memcpy(&bufs[1], &bufs[0], sizeof bufs[0]);
|
||||
return;
|
||||
}
|
||||
bufs[idx].bnum = blk;
|
||||
ether.copyin(bufs[idx].bnum, bufs[idx].bytes);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Stash::freeCount () {
|
||||
uint8_t count = 0;
|
||||
for (uint8_t i = 0; i < 256/8; ++i)
|
||||
for (uint8_t m = 0x80; m != 0; m >>= 1)
|
||||
if (map[i] & m)
|
||||
++count;
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t Stash::create () {
|
||||
uint8_t blk = allocBlock();
|
||||
load(0, blk);
|
||||
bufs[0].head.count = 0;
|
||||
bufs[0].head.first = bufs[0].head.last = blk;
|
||||
bufs[0].tail = sizeof (StashHeader);
|
||||
bufs[0].next = 0;
|
||||
return open(blk);
|
||||
}
|
||||
|
||||
uint8_t Stash::open (uint8_t blk) {
|
||||
curr = blk;
|
||||
offs = sizeof (StashHeader);
|
||||
load(1, curr);
|
||||
memcpy((StashHeader*) this, bufs[1].bytes, sizeof (StashHeader));
|
||||
return curr;
|
||||
}
|
||||
|
||||
void Stash::save () {
|
||||
load(0, first);
|
||||
memcpy(bufs[0].bytes, (StashHeader*) this, sizeof (StashHeader));
|
||||
if (bufs[1].bnum == first)
|
||||
load(1, 0); // invalidates original in case it was the same block
|
||||
}
|
||||
|
||||
void Stash::release () {
|
||||
while (first > 0) {
|
||||
freeBlock(first);
|
||||
first = ether.peekin(first, 63);
|
||||
}
|
||||
}
|
||||
|
||||
void Stash::put (char c) {
|
||||
load(0, last);
|
||||
uint8_t t = bufs[0].tail;
|
||||
bufs[0].bytes[t++] = c;
|
||||
if (t <= 62)
|
||||
bufs[0].tail = t;
|
||||
else {
|
||||
bufs[0].next = allocBlock();
|
||||
last = bufs[0].next;
|
||||
load(0, last);
|
||||
bufs[0].tail = bufs[0].next = 0;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
char Stash::get () {
|
||||
load(1, curr);
|
||||
if (curr == last && offs >= bufs[1].tail)
|
||||
return 0;
|
||||
uint8_t b = bufs[1].bytes[offs];
|
||||
if (++offs >= 63 && curr != last) {
|
||||
curr = bufs[1].next;
|
||||
offs = 0;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
uint16_t Stash::size () {
|
||||
return 63 * count + fetchByte(last, 62) - sizeof (StashHeader);
|
||||
}
|
||||
|
||||
static char* wtoa (uint16_t value, char* ptr) {
|
||||
if (value > 9)
|
||||
ptr = wtoa(value / 10, ptr);
|
||||
*ptr = '0' + value % 10;
|
||||
*++ptr = 0;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void Stash::prepare (PGM_P fmt, ...) {
|
||||
Stash::load(0, 0);
|
||||
uint16_t* segs = Stash::bufs[0].words;
|
||||
*segs++ = strlen_P(fmt);
|
||||
#ifdef __AVR__
|
||||
*segs++ = (uint16_t) fmt;
|
||||
#else
|
||||
*segs++ = (uint32_t) fmt;
|
||||
*segs++ = (uint32_t) fmt >> 16;
|
||||
#endif
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
for (;;) {
|
||||
char c = pgm_read_byte(fmt++);
|
||||
if (c == 0)
|
||||
break;
|
||||
if (c == '$') {
|
||||
#ifdef __AVR__
|
||||
uint16_t argval = va_arg(ap, uint16_t), arglen = 0;
|
||||
#else
|
||||
uint32_t argval = va_arg(ap, int), arglen = 0;
|
||||
#endif
|
||||
switch (pgm_read_byte(fmt++)) {
|
||||
case 'D': {
|
||||
char buf[7];
|
||||
wtoa(argval, buf);
|
||||
arglen = strlen(buf);
|
||||
break;
|
||||
}
|
||||
case 'S':
|
||||
arglen = strlen((const char*) argval);
|
||||
break;
|
||||
case 'F':
|
||||
arglen = strlen_P((PGM_P) argval);
|
||||
break;
|
||||
case 'E': {
|
||||
byte* s = (byte*) argval;
|
||||
char d;
|
||||
while ((d = eeprom_read_byte(s++)) != 0)
|
||||
++arglen;
|
||||
break;
|
||||
}
|
||||
case 'H': {
|
||||
Stash stash (argval);
|
||||
arglen = stash.size();
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef __AVR__
|
||||
*segs++ = argval;
|
||||
#else
|
||||
*segs++ = argval;
|
||||
*segs++ = argval >> 16;
|
||||
#endif
|
||||
Stash::bufs[0].words[0] += arglen - 2;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
uint16_t Stash::length () {
|
||||
Stash::load(0, 0);
|
||||
return Stash::bufs[0].words[0];
|
||||
}
|
||||
|
||||
void Stash::extract (uint16_t offset, uint16_t count, void* buf) {
|
||||
Stash::load(0, 0);
|
||||
uint16_t* segs = Stash::bufs[0].words;
|
||||
#ifdef __AVR__
|
||||
PGM_P fmt = (PGM_P) *++segs;
|
||||
#else
|
||||
PGM_P fmt = (PGM_P)((segs[2] << 16) | segs[1]);
|
||||
segs += 2;
|
||||
#endif
|
||||
Stash stash;
|
||||
char mode = '@', tmp[7], *ptr = NULL, *out = (char*) buf;
|
||||
for (uint16_t i = 0; i < offset + count; ) {
|
||||
char c = 0;
|
||||
switch (mode) {
|
||||
case '@': {
|
||||
c = pgm_read_byte(fmt++);
|
||||
if (c == 0)
|
||||
return;
|
||||
if (c != '$')
|
||||
break;
|
||||
#ifdef __AVR__
|
||||
uint16_t arg = *++segs;
|
||||
#else
|
||||
uint32_t arg = *++segs;
|
||||
arg |= *++segs << 16;
|
||||
#endif
|
||||
mode = pgm_read_byte(fmt++);
|
||||
switch (mode) {
|
||||
case 'D':
|
||||
wtoa(arg, tmp);
|
||||
ptr = tmp;
|
||||
break;
|
||||
case 'S':
|
||||
case 'F':
|
||||
case 'E':
|
||||
ptr = (char*) arg;
|
||||
break;
|
||||
case 'H':
|
||||
stash.open(arg);
|
||||
ptr = (char*) &stash;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case 'D':
|
||||
case 'S':
|
||||
c = *ptr++;
|
||||
break;
|
||||
case 'F':
|
||||
c = pgm_read_byte(ptr++);
|
||||
break;
|
||||
case 'E':
|
||||
c = eeprom_read_byte((byte*) ptr++);
|
||||
break;
|
||||
case 'H':
|
||||
c = ((Stash*) ptr)->get();
|
||||
break;
|
||||
}
|
||||
if (c == 0) {
|
||||
mode = '@';
|
||||
continue;
|
||||
}
|
||||
if (i >= offset)
|
||||
*out++ = c;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void Stash::cleanup () {
|
||||
Stash::load(0, 0);
|
||||
uint16_t* segs = Stash::bufs[0].words;
|
||||
#ifdef __AVR__
|
||||
PGM_P fmt = (PGM_P) *++segs;
|
||||
#else
|
||||
PGM_P fmt = (PGM_P)((segs[2] << 16) | segs[1]);
|
||||
segs += 2;
|
||||
#endif
|
||||
for (;;) {
|
||||
char c = pgm_read_byte(fmt++);
|
||||
if (c == 0)
|
||||
break;
|
||||
if (c == '$') {
|
||||
#ifdef __AVR__
|
||||
uint16_t arg = *++segs;
|
||||
#else
|
||||
uint32_t arg = *++segs;
|
||||
arg |= *++segs << 16;
|
||||
#endif
|
||||
if (pgm_read_byte(fmt++) == 'H') {
|
||||
Stash stash (arg);
|
||||
stash.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BufferFiller::emit_p(PGM_P fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
for (;;) {
|
||||
char c = pgm_read_byte(fmt++);
|
||||
if (c == 0)
|
||||
break;
|
||||
if (c != '$') {
|
||||
*ptr++ = c;
|
||||
continue;
|
||||
}
|
||||
c = pgm_read_byte(fmt++);
|
||||
switch (c) {
|
||||
case 'D':
|
||||
#ifdef __AVR__
|
||||
wtoa(va_arg(ap, uint16_t), (char*) ptr);
|
||||
#else
|
||||
wtoa(va_arg(ap, int), (char*) ptr);
|
||||
#endif
|
||||
break;
|
||||
#ifdef FLOATEMIT
|
||||
case 'T':
|
||||
dtostrf ( va_arg(ap, double), 10, 3, (char*)ptr );
|
||||
break;
|
||||
#endif
|
||||
case 'H': {
|
||||
#ifdef __AVR__
|
||||
char p1 = va_arg(ap, uint16_t);
|
||||
#else
|
||||
char p1 = va_arg(ap, int);
|
||||
#endif
|
||||
char p2;
|
||||
p2 = (p1 >> 4) & 0x0F;
|
||||
p1 = p1 & 0x0F;
|
||||
if (p1 > 9) p1 += 0x07; // adjust 0x0a-0x0f to come out 'a'-'f'
|
||||
p1 += 0x30; // and complete
|
||||
if (p2 > 9) p2 += 0x07; // adjust 0x0a-0x0f to come out 'a'-'f'
|
||||
p2 += 0x30; // and complete
|
||||
*ptr++ = p2;
|
||||
*ptr++ = p1;
|
||||
continue;
|
||||
}
|
||||
case 'L':
|
||||
ltoa(va_arg(ap, long), (char*) ptr, 10);
|
||||
break;
|
||||
case 'S':
|
||||
strcpy((char*) ptr, va_arg(ap, const char*));
|
||||
break;
|
||||
case 'F': {
|
||||
PGM_P s = va_arg(ap, PGM_P);
|
||||
char d;
|
||||
while ((d = pgm_read_byte(s++)) != 0)
|
||||
*ptr++ = d;
|
||||
continue;
|
||||
}
|
||||
case 'E': {
|
||||
byte* s = va_arg(ap, byte*);
|
||||
char d;
|
||||
while ((d = eeprom_read_byte(s++)) != 0)
|
||||
*ptr++ = d;
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
*ptr++ = c;
|
||||
continue;
|
||||
}
|
||||
ptr += strlen((char*) ptr);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
EtherCard ether;
|
||||
|
||||
uint8_t EtherCard::mymac[6]; // my MAC address
|
||||
uint8_t EtherCard::myip[4]; // my ip address
|
||||
uint8_t EtherCard::netmask[4]; // subnet mask
|
||||
uint8_t EtherCard::broadcastip[4]; // broadcast address
|
||||
uint8_t EtherCard::gwip[4]; // gateway
|
||||
uint8_t EtherCard::dhcpip[4]; // dhcp server
|
||||
uint8_t EtherCard::dnsip[4]; // dns server
|
||||
uint8_t EtherCard::hisip[4]; // ip address of remote host
|
||||
uint16_t EtherCard::hisport = 80; // tcp port to browse to
|
||||
bool EtherCard::using_dhcp = false;
|
||||
bool EtherCard::persist_tcp_connection = false;
|
||||
int16_t EtherCard::delaycnt = 0; //request gateway ARP lookup
|
||||
|
||||
uint8_t EtherCard::begin (const uint16_t size,
|
||||
const uint8_t* macaddr,
|
||||
uint8_t csPin) {
|
||||
using_dhcp = false;
|
||||
Stash::initMap(56);
|
||||
copyMac(mymac, macaddr);
|
||||
return initialize(size, mymac, csPin);
|
||||
}
|
||||
|
||||
bool EtherCard::staticSetup (const uint8_t* my_ip,
|
||||
const uint8_t* gw_ip,
|
||||
const uint8_t* dns_ip,
|
||||
const uint8_t* mask) {
|
||||
using_dhcp = false;
|
||||
|
||||
if (my_ip != 0)
|
||||
copyIp(myip, my_ip);
|
||||
if (gw_ip != 0)
|
||||
setGwIp(gw_ip);
|
||||
if (dns_ip != 0)
|
||||
copyIp(dnsip, dns_ip);
|
||||
if(mask != 0)
|
||||
copyIp(netmask, mask);
|
||||
updateBroadcastAddress();
|
||||
delaycnt = 0; //request gateway ARP lookup
|
||||
return true;
|
||||
}
|
||||
587
lib-ext/ethercard.git/EtherCard.h
Normal file
587
lib-ext/ethercard.git/EtherCard.h
Normal file
|
|
@ -0,0 +1,587 @@
|
|||
// This code slightly follows the conventions of, but is not derived from:
|
||||
// EHTERSHIELD_H library for Arduino etherShield
|
||||
// Copyright (c) 2008 Xing Yu. All right reserved. (this is LGPL v2.1)
|
||||
// It is however derived from the enc28j60 and ip code (which is GPL v2)
|
||||
// Author: Pascal Stang
|
||||
// Modified by: Guido Socher
|
||||
// DHCP code: Andrew Lindsay
|
||||
// Hence: GPL V2
|
||||
//
|
||||
// 2010-05-19 <jc@wippler.nl>
|
||||
//
|
||||
//
|
||||
// PIN Connections (Using Arduino UNO):
|
||||
// VCC - 3.3V
|
||||
// GND - GND
|
||||
// SCK - Pin 13
|
||||
// SO - Pin 12
|
||||
// SI - Pin 11
|
||||
// CS - Pin 8
|
||||
//
|
||||
#define __PROG_TYPES_COMPAT__
|
||||
|
||||
#ifndef EtherCard_h
|
||||
#define EtherCard_h
|
||||
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include <Arduino.h> // Arduino 1.0
|
||||
#define WRITE_RESULT size_t
|
||||
#define WRITE_RETURN return 1;
|
||||
#else
|
||||
#include <WProgram.h> // Arduino 0022
|
||||
#define WRITE_RESULT void
|
||||
#define WRITE_RETURN
|
||||
#endif
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include "enc28j60.h"
|
||||
#include "net.h"
|
||||
|
||||
/** This type definition defines the structure of a UDP server event handler callback funtion */
|
||||
typedef void (*UdpServerCallback)(
|
||||
uint16_t dest_port, ///< Port the packet was sent to
|
||||
uint8_t src_ip[4], ///< IP address of the sender
|
||||
const char *data, ///< UDP payload data
|
||||
uint16_t len); ///< Length of the payload data
|
||||
|
||||
/** This type definition defines the structure of a DHCP Option callback funtion */
|
||||
typedef void (*DhcpOptionCallback)(
|
||||
uint8_t option, ///< The option number
|
||||
const byte* data, ///< DHCP option data
|
||||
uint8_t len); ///< Length of the DHCP option data
|
||||
|
||||
|
||||
/** This structure describes the structure of memory used within the ENC28J60 network interface. */
|
||||
typedef struct {
|
||||
uint8_t count; ///< Number of allocated pages
|
||||
uint8_t first; ///< First allocated page
|
||||
uint8_t last; ///< Last allocated page
|
||||
} StashHeader;
|
||||
|
||||
/** This class provides access to the memory within the ENC28J60 network interface. */
|
||||
class Stash : public /*Stream*/ Print, private StashHeader {
|
||||
uint8_t curr; //!< Current page
|
||||
uint8_t offs; //!< Current offset in page
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint8_t bytes[64];
|
||||
uint16_t words[32];
|
||||
struct {
|
||||
StashHeader head;
|
||||
uint8_t filler[59];
|
||||
uint8_t tail;
|
||||
uint8_t next;
|
||||
};
|
||||
};
|
||||
uint8_t bnum;
|
||||
} Block;
|
||||
|
||||
static uint8_t allocBlock ();
|
||||
static void freeBlock (uint8_t block);
|
||||
static uint8_t fetchByte (uint8_t blk, uint8_t off);
|
||||
|
||||
static Block bufs[2];
|
||||
static uint8_t map[256/8];
|
||||
|
||||
public:
|
||||
static void initMap (uint8_t last);
|
||||
static void load (uint8_t idx, uint8_t blk);
|
||||
static uint8_t freeCount ();
|
||||
|
||||
Stash () : curr (0) { first = 0; }
|
||||
Stash (uint8_t fd) { open(fd); }
|
||||
|
||||
uint8_t create ();
|
||||
uint8_t open (uint8_t blk);
|
||||
void save ();
|
||||
void release ();
|
||||
|
||||
void put (char c);
|
||||
char get ();
|
||||
uint16_t size ();
|
||||
|
||||
virtual WRITE_RESULT write(uint8_t b) { put(b); WRITE_RETURN }
|
||||
|
||||
// virtual int available() {
|
||||
// if (curr != last)
|
||||
// return 1;
|
||||
// load(1, last);
|
||||
// return offs < bufs[1].tail;
|
||||
// }
|
||||
// virtual int read() {
|
||||
// return available() ? get() : -1;
|
||||
// }
|
||||
// virtual int peek() {
|
||||
// return available() ? bufs[1].bytes[offs] : -1;
|
||||
// }
|
||||
// virtual void flush() {
|
||||
// curr = last;
|
||||
// offs = 63;
|
||||
// }
|
||||
|
||||
static void prepare (PGM_P fmt, ...);
|
||||
static uint16_t length ();
|
||||
static void extract (uint16_t offset, uint16_t count, void* buf);
|
||||
static void cleanup ();
|
||||
|
||||
friend void dumpBlock (const char* msg, uint8_t idx); // optional
|
||||
friend void dumpStash (const char* msg, void* ptr); // optional
|
||||
};
|
||||
|
||||
/** This class populates network send and receive buffers.
|
||||
*
|
||||
* This class provides formatted printing into memory. Users can use it to write into send buffers.
|
||||
*
|
||||
* Nota: PGM_P: is a pointer to a string in program space (defined in the source code)
|
||||
*
|
||||
* # Format string
|
||||
*
|
||||
* | Format | Parameter | Output
|
||||
* |--------|-------------|----------
|
||||
* | $D | uint16_t | Decimal representation
|
||||
* | $T ¤ | double | Decimal representation with 3 digits after decimal sign ([-]d.ddd)
|
||||
* | $H | uint16_t | Hexadecimal value of lsb (from 00 to ff)
|
||||
* | $L | long | Decimal representation
|
||||
* | $S | const char* | Copy null terminated string from main memory
|
||||
* | $F | PGM_P | Copy null terminated string from program space
|
||||
* | $E | byte* | Copy null terminated string from EEPROM space
|
||||
* | $$ | _none_ | '$'
|
||||
*
|
||||
* ¤ _Available only if FLOATEMIT is defined_
|
||||
*
|
||||
* # Examples
|
||||
* ~~~~~~~~~~~~~{.c}
|
||||
* uint16_t ddd = 123;
|
||||
* double ttt = 1.23;
|
||||
* uint16_t hhh = 0xa4;
|
||||
* long lll = 123456789;
|
||||
* char * sss;
|
||||
* char fff[] PROGMEM = "MyMemory";
|
||||
*
|
||||
* sss[0] = 'G';
|
||||
* sss[1] = 'P';
|
||||
* sss[2] = 'L';
|
||||
* sss[3] = 0;
|
||||
* buf.emit_p( PSTR("ddd=$D\n"), ddd ); // "ddd=123\n"
|
||||
* buf.emit_p( PSTR("ttt=$T\n"), ttt ); // "ttt=1.23\n" **TO CHECK**
|
||||
* buf.emit_p( PSTR("hhh=$H\n"), hhh ); // "hhh=a4\n"
|
||||
* buf.emit_p( PSTR("lll=$L\n"), lll ); // "lll=123456789\n"
|
||||
* buf.emit_p( PSTR("sss=$S\n"), sss ); // "sss=GPL\n"
|
||||
* buf.emit_p( PSTR("fff=$F\n"), fff ); // "fff=MyMemory\n"
|
||||
* ~~~~~~~~~~~~~
|
||||
*
|
||||
*/
|
||||
class BufferFiller : public Print {
|
||||
uint8_t *start; //!< Pointer to start of buffer
|
||||
uint8_t *ptr; //!< Pointer to cursor position
|
||||
public:
|
||||
/** @brief Empty constructor
|
||||
*/
|
||||
BufferFiller () {}
|
||||
|
||||
/** @brief Constructor
|
||||
* @param buf Pointer to the ethernet data buffer
|
||||
*/
|
||||
BufferFiller (uint8_t* buf) : start (buf), ptr (buf) {}
|
||||
|
||||
/** @brief Add formatted text to buffer
|
||||
* @param fmt Format string (see Class description)
|
||||
* @param ... parameters for format string
|
||||
*/
|
||||
void emit_p (PGM_P fmt, ...);
|
||||
|
||||
/** @brief Add data to buffer from main memory
|
||||
* @param s Pointer to data
|
||||
* @param n Number of characters to copy
|
||||
*/
|
||||
void emit_raw (const char* s, uint16_t n) { memcpy(ptr, s, n); ptr += n; }
|
||||
|
||||
/** @brief Add data to buffer from program space string
|
||||
* @param p Program space string pointer
|
||||
* @param n Number of characters to copy
|
||||
*/
|
||||
void emit_raw_p (PGM_P p, uint16_t n) { memcpy_P(ptr, p, n); ptr += n; }
|
||||
|
||||
/** @brief Get pointer to start of buffer
|
||||
* @return <i>uint8_t*</i> Pointer to start of buffer
|
||||
*/
|
||||
uint8_t* buffer () const { return start; }
|
||||
|
||||
/** @brief Get cursor position
|
||||
* @return <i>uint16_t</i> Cursor postion
|
||||
*/
|
||||
uint16_t position () const { return ptr - start; }
|
||||
|
||||
/** @brief Write one byte to buffer
|
||||
* @param v Byte to add to buffer
|
||||
*/
|
||||
virtual WRITE_RESULT write (uint8_t v) { *ptr++ = v; WRITE_RETURN }
|
||||
};
|
||||
|
||||
/** This class provides the main interface to a ENC28J60 based network interface card and is the class most users will use.
|
||||
* @note All TCP/IP client (outgoing) connections are made from source port in range 2816-3071. Do not use these source ports for other purposes.
|
||||
*/
|
||||
class EtherCard : public Ethernet {
|
||||
public:
|
||||
static uint8_t mymac[6]; ///< MAC address
|
||||
static uint8_t myip[4]; ///< IP address
|
||||
static uint8_t netmask[4]; ///< Netmask
|
||||
static uint8_t broadcastip[4]; ///< Subnet broadcast address
|
||||
static uint8_t gwip[4]; ///< Gateway
|
||||
static uint8_t dhcpip[4]; ///< DHCP server IP address
|
||||
static uint8_t dnsip[4]; ///< DNS server IP address
|
||||
static uint8_t hisip[4]; ///< DNS lookup result
|
||||
static uint16_t hisport; ///< TCP port to connect to (default 80)
|
||||
static bool using_dhcp; ///< True if using DHCP
|
||||
static bool persist_tcp_connection; ///< False to break connections on first packet received
|
||||
static int16_t delaycnt; ///< Counts number of cycles of packetLoop when no packet received - used to trigger periodic gateway ARP request
|
||||
|
||||
// EtherCard.cpp
|
||||
/** @brief Initialise the network interface
|
||||
* @param size Size of data buffer
|
||||
* @param macaddr Hardware address to assign to the network interface (6 bytes)
|
||||
* @param csPin Arduino pin number connected to chip select. Default = 8
|
||||
* @return <i>uint8_t</i> Firmware version or zero on failure.
|
||||
*/
|
||||
static uint8_t begin (const uint16_t size, const uint8_t* macaddr,
|
||||
uint8_t csPin =8);
|
||||
|
||||
/** @brief Configure network interface with static IP
|
||||
* @param my_ip IP address (4 bytes). 0 for no change.
|
||||
* @param gw_ip Gateway address (4 bytes). 0 for no change. Default = 0
|
||||
* @param dns_ip DNS address (4 bytes). 0 for no change. Default = 0
|
||||
* @param mask Subnet mask (4 bytes). 0 for no change. Default = 0
|
||||
* @return <i>bool</i> Returns true on success - actually always true
|
||||
*/
|
||||
static bool staticSetup (const uint8_t* my_ip,
|
||||
const uint8_t* gw_ip = 0,
|
||||
const uint8_t* dns_ip = 0,
|
||||
const uint8_t* mask = 0);
|
||||
|
||||
// tcpip.cpp
|
||||
/** @brief Sends a UDP packet to the IP address of last processed received packet
|
||||
* @param data Pointer to data payload
|
||||
* @param len Size of data payload (max 220)
|
||||
* @param port Source IP port
|
||||
*/
|
||||
static void makeUdpReply (const char *data, uint8_t len, uint16_t port);
|
||||
|
||||
/** @brief Parse received data
|
||||
* @param plen Size of data to parse (e.g. return value of packetReceive()).
|
||||
* @return <i>uint16_t</i> Offset of TCP payload data in data buffer or zero if packet processed
|
||||
* @note Data buffer is shared by receive and transmit functions
|
||||
* @note Only handles ARP and IP
|
||||
*/
|
||||
static uint16_t packetLoop (uint16_t plen);
|
||||
|
||||
/** @brief Accept a TCP/IP connection
|
||||
* @param port IP port to accept on - do nothing if wrong port
|
||||
* @param plen Number of bytes in packet
|
||||
* @return <i>uint16_t</i> Offset within packet of TCP payload. Zero for no data.
|
||||
*/
|
||||
static uint16_t accept (uint16_t port, uint16_t plen);
|
||||
|
||||
/** @brief Send a response to a HTTP request
|
||||
* @param dlen Size of the HTTP (TCP) payload
|
||||
*/
|
||||
static void httpServerReply (uint16_t dlen);
|
||||
|
||||
/** @brief Send a response to a HTTP request
|
||||
* @param dlen Size of the HTTP (TCP) payload
|
||||
* @param flags TCP flags
|
||||
*/
|
||||
static void httpServerReply_with_flags (uint16_t dlen , uint8_t flags);
|
||||
|
||||
/** @brief Acknowledge TCP message
|
||||
* @todo Is this / should this be private?
|
||||
*/
|
||||
static void httpServerReplyAck ();
|
||||
|
||||
/** @brief Set the gateway address
|
||||
* @param gwipaddr Gateway address (4 bytes)
|
||||
*/
|
||||
static void setGwIp (const uint8_t *gwipaddr);
|
||||
|
||||
/** @brief Updates the broadcast address based on current IP address and subnet mask
|
||||
*/
|
||||
static void updateBroadcastAddress();
|
||||
|
||||
/** @brief Check if got gateway hardware address (ARP lookup)
|
||||
* @return <i>unit8_t</i> True if gateway found
|
||||
*/
|
||||
static uint8_t clientWaitingGw ();
|
||||
|
||||
/** @brief Check if got gateway DNS address (ARP lookup)
|
||||
* @return <i>unit8_t</i> True if DNS found
|
||||
*/
|
||||
static uint8_t clientWaitingDns ();
|
||||
|
||||
/** @brief Prepare a TCP request
|
||||
* @param result_cb Pointer to callback function that handles TCP result
|
||||
* @param datafill_cb Pointer to callback function that handles TCP data payload
|
||||
* @param port Remote TCP/IP port to connect to
|
||||
* @return <i>unit8_t</i> ID of TCP/IP session (0-7)
|
||||
* @note Return value provides id of the request to allow up to 7 concurrent requests
|
||||
*/
|
||||
static uint8_t clientTcpReq (uint8_t (*result_cb)(uint8_t,uint8_t,uint16_t,uint16_t),
|
||||
uint16_t (*datafill_cb)(uint8_t),uint16_t port);
|
||||
|
||||
/** @brief Prepare HTTP request
|
||||
* @param urlbuf Pointer to c-string URL folder
|
||||
* @param urlbuf_varpart Pointer to c-string URL file
|
||||
* @param hoststr Pointer to c-string hostname
|
||||
* @param additionalheaderline Pointer to c-string with additional HTTP header info
|
||||
* @param callback Pointer to callback function to handle response
|
||||
* @note Request sent in main packetloop
|
||||
*/
|
||||
static void browseUrl (const char *urlbuf, const char *urlbuf_varpart,
|
||||
const char *hoststr, const char *additionalheaderline,
|
||||
void (*callback)(uint8_t,uint16_t,uint16_t));
|
||||
|
||||
/** @brief Prepare HTTP request
|
||||
* @param urlbuf Pointer to c-string URL folder
|
||||
* @param urlbuf_varpart Pointer to c-string URL file
|
||||
* @param hoststr Pointer to c-string hostname
|
||||
* @param callback Pointer to callback function to handle response
|
||||
* @note Request sent in main packetloop
|
||||
*/
|
||||
static void browseUrl (const char *urlbuf, const char *urlbuf_varpart,
|
||||
const char *hoststr,
|
||||
void (*callback)(uint8_t,uint16_t,uint16_t));
|
||||
|
||||
/** @brief Prepare HTTP post message
|
||||
* @param urlbuf Pointer to c-string URL folder
|
||||
* @param hoststr Pointer to c-string hostname
|
||||
* @param additionalheaderline Pointer to c-string with additional HTTP header info
|
||||
* @param postval Pointer to c-string HTML Post value
|
||||
* @param callback Pointer to callback function to handle response
|
||||
* @note Request sent in main packetloop
|
||||
*/
|
||||
static void httpPost (const char *urlbuf, const char *hoststr,
|
||||
const char *additionalheaderline, const char *postval,
|
||||
void (*callback)(uint8_t,uint16_t,uint16_t));
|
||||
|
||||
/** @brief Send NTP request
|
||||
* @param ntpip IP address of NTP server
|
||||
* @param srcport IP port to send from
|
||||
*/
|
||||
static void ntpRequest (uint8_t *ntpip,uint8_t srcport);
|
||||
|
||||
/** @brief Process network time protocol response
|
||||
* @param time Pointer to integer to hold result
|
||||
* @param dstport_l Destination port to expect response. Set to zero to accept on any port
|
||||
* @return <i>uint8_t</i> True (1) on success
|
||||
*/
|
||||
static uint8_t ntpProcessAnswer (uint32_t *time, uint8_t dstport_l);
|
||||
|
||||
/** @brief Prepare a UDP message for transmission
|
||||
* @param sport Source port
|
||||
* @param dip Pointer to 4 byte destination IP address
|
||||
* @param dport Destination port
|
||||
*/
|
||||
static void udpPrepare (uint16_t sport, const uint8_t *dip, uint16_t dport);
|
||||
|
||||
/** @brief Transmit UDP packet
|
||||
* @param len Size of payload
|
||||
*/
|
||||
static void udpTransmit (uint16_t len);
|
||||
|
||||
/** @brief Sends a UDP packet
|
||||
* @param data Pointer to data
|
||||
* @param len Size of payload (maximum 220 octets / bytes)
|
||||
* @param sport Source port
|
||||
* @param dip Pointer to 4 byte destination IP address
|
||||
* @param dport Destination port
|
||||
*/
|
||||
static void sendUdp (const char *data, uint8_t len, uint16_t sport,
|
||||
const uint8_t *dip, uint16_t dport);
|
||||
|
||||
/** @brief Resister the function to handle ping events
|
||||
* @param cb Pointer to function
|
||||
*/
|
||||
static void registerPingCallback (void (*cb)(uint8_t*));
|
||||
|
||||
/** @brief Send ping
|
||||
* @param destip Ponter to 4 byte destination IP address
|
||||
*/
|
||||
static void clientIcmpRequest (const uint8_t *destip);
|
||||
|
||||
/** @brief Check for ping response
|
||||
* @param ip_monitoredhost Pointer to 4 byte IP address of host to check
|
||||
* @return <i>uint8_t</i> True (1) if ping response from specified host
|
||||
*/
|
||||
static uint8_t packetLoopIcmpCheckReply (const uint8_t *ip_monitoredhost);
|
||||
|
||||
/** @brief Send a wake on lan message
|
||||
* @param wolmac Pointer to 6 byte hardware (MAC) address of host to send message to
|
||||
*/
|
||||
static void sendWol (uint8_t *wolmac);
|
||||
|
||||
// new stash-based API
|
||||
/** @brief Send TCP request
|
||||
*/
|
||||
static uint8_t tcpSend ();
|
||||
|
||||
/** @brief Get TCP reply
|
||||
* @return <i>char*</i> Pointer to TCP reply payload. NULL if no data.
|
||||
*/
|
||||
static const char* tcpReply (uint8_t fd);
|
||||
|
||||
/** @brief Configure TCP connections to be persistent or not
|
||||
* @param persist True to maintain TCP connection. False to finish TCP connection after first packet.
|
||||
*/
|
||||
static void persistTcpConnection(bool persist);
|
||||
|
||||
//udpserver.cpp
|
||||
/** @brief Register function to handle incomint UDP events
|
||||
* @param callback Function to handle event
|
||||
* @param port Port to listen on
|
||||
*/
|
||||
static void udpServerListenOnPort(UdpServerCallback callback, uint16_t port);
|
||||
|
||||
/** @brief Pause listing on UDP port
|
||||
* @brief port Port to pause
|
||||
*/
|
||||
static void udpServerPauseListenOnPort(uint16_t port);
|
||||
|
||||
/** @brief Resume listing on UDP port
|
||||
* @brief port Port to pause
|
||||
*/
|
||||
static void udpServerResumeListenOnPort(uint16_t port);
|
||||
|
||||
/** @brief Check if UDP server is listening on any ports
|
||||
* @return <i>bool</i> True if listening on any ports
|
||||
*/
|
||||
static bool udpServerListening(); //called by tcpip, in packetLoop
|
||||
|
||||
/** @brief Passes packet to UDP Server
|
||||
* @param len Not used
|
||||
* @return <i>bool</i> True if packet processed
|
||||
*/
|
||||
static bool udpServerHasProcessedPacket(uint16_t len); //called by tcpip, in packetLoop
|
||||
|
||||
// dhcp.cpp
|
||||
/** @brief Update DHCP state
|
||||
* @param len Length of received data packet
|
||||
*/
|
||||
static void DhcpStateMachine(uint16_t len);
|
||||
|
||||
/** @brief Not implemented
|
||||
* @todo Implement dhcpStartTime or remove declaration
|
||||
*/
|
||||
static uint32_t dhcpStartTime ();
|
||||
|
||||
/** @brief Not implemented
|
||||
* @todo Implement dhcpLeaseTime or remove declaration
|
||||
*/
|
||||
static uint32_t dhcpLeaseTime ();
|
||||
|
||||
/** @brief Not implemented
|
||||
* @todo Implement dhcpLease or remove declaration
|
||||
*/
|
||||
static bool dhcpLease ();
|
||||
|
||||
/** @brief Configure network interface with DHCP
|
||||
* @return <i>bool</i> True if DHCP successful
|
||||
* @note Blocks until DHCP complete or timeout after 60 seconds
|
||||
*/
|
||||
static bool dhcpSetup (const char *hname = NULL, bool fromRam =false);
|
||||
|
||||
/** @brief Register a callback for a specific DHCP option number
|
||||
* @param option The option number to request from the DHCP server
|
||||
* @param callback The function to be call when the option is received
|
||||
*/
|
||||
static void dhcpAddOptionCallback(uint8_t option, DhcpOptionCallback callback);
|
||||
|
||||
// dns.cpp
|
||||
/** @brief Perform DNS lookup
|
||||
* @param name Host name to lookup
|
||||
* @param fromRam Set true to look up cached name. Default = false
|
||||
* @return <i>bool</i> True on success.
|
||||
* @note Result is stored in <i>hisip</i> member
|
||||
*/
|
||||
static bool dnsLookup (const char* name, bool fromRam =false);
|
||||
|
||||
// webutil.cpp
|
||||
/** @brief Copies an IP address
|
||||
* @param dst Pointer to the 4 byte destination
|
||||
* @param src Pointer to the 4 byte source
|
||||
* @note There is no check of source or destination size. Ensure both are 4 bytes
|
||||
*/
|
||||
static void copyIp (uint8_t *dst, const uint8_t *src);
|
||||
|
||||
/** @brief Copies a hardware address
|
||||
* @param dst Pointer to the 6 byte destination
|
||||
* @param src Pointer to the 6 byte destination
|
||||
* @note There is no check of source or destination size. Ensure both are 6 bytes
|
||||
*/
|
||||
static void copyMac (uint8_t *dst, const uint8_t *src);
|
||||
|
||||
/** @brief Output to serial port in dotted decimal IP format
|
||||
* @param buf Pointer to 4 byte IP address
|
||||
* @note There is no check of source or destination size. Ensure both are 4 bytes
|
||||
*/
|
||||
static void printIp (const uint8_t *buf);
|
||||
|
||||
/** @brief Output message and IP address to serial port in dotted decimal IP format
|
||||
* @param msg Pointer to null terminated string
|
||||
* @param buf Pointer to 4 byte IP address
|
||||
* @note There is no check of source or destination size. Ensure both are 4 bytes
|
||||
*/
|
||||
static void printIp (const char* msg, const uint8_t *buf);
|
||||
|
||||
/** @brief Output Flash String Helper and IP address to serial port in dotted decimal IP format
|
||||
* @param ifsh Pointer to Flash String Helper
|
||||
* @param buf Pointer to 4 byte IP address
|
||||
* @note There is no check of source or destination size. Ensure both are 4 bytes
|
||||
* @todo What is a FlashStringHelper?
|
||||
*/
|
||||
static void printIp (const __FlashStringHelper *ifsh, const uint8_t *buf);
|
||||
|
||||
/** @brief Search for a string of the form key=value in a string that looks like q?xyz=abc&uvw=defgh HTTP/1.1\\r\\n
|
||||
* @param str Pointer to the null terminated string to search
|
||||
* @param strbuf Pointer to buffer to hold null terminated result string
|
||||
* @param maxlen Maximum length of result
|
||||
* @param key Pointer to null terminated string holding the key to search for
|
||||
* @return <i>unit_t</i> Length of the value. 0 if not found
|
||||
* @note Ensure strbuf has memory allocated of at least maxlen + 1 (to accomodate result plus terminating null)
|
||||
*/
|
||||
static uint8_t findKeyVal(const char *str,char *strbuf,
|
||||
uint8_t maxlen, const char *key);
|
||||
|
||||
/** @brief Decode a URL string e.g "hello%20joe" or "hello+joe" becomes "hello joe"
|
||||
* @param urlbuf Pointer to the null terminated URL
|
||||
* @note urlbuf is modified
|
||||
*/
|
||||
static void urlDecode(char *urlbuf);
|
||||
|
||||
/** @brief Encode a URL, replacing illegal charaters like ' '
|
||||
* @param str Pointer to the null terminated string to encode
|
||||
* @param urlbuf Pointer to a buffer to contain the null terminated encoded URL
|
||||
* @note There must be enough space in urlbuf. In the worst case that is 3 times the length of str
|
||||
*/
|
||||
static void urlEncode(char *str,char *urlbuf);
|
||||
|
||||
/** @brief Convert an IP address from dotted decimal formated string to 4 bytes
|
||||
* @param bytestr Pointer to the 4 byte array to store IP address
|
||||
* @param str Pointer to string to parse
|
||||
* @return <i>uint8_t</i> 0 on success
|
||||
*/
|
||||
static uint8_t parseIp(uint8_t *bytestr,char *str);
|
||||
|
||||
/** @brief Convert a byte array to a human readable display string
|
||||
* @param resultstr Pointer to a buffer to hold the resulting null terminated string
|
||||
* @param bytestr Pointer to the byte array containing the address to convert
|
||||
* @param len Length of the array (4 for IP address, 6 for hardware (MAC) address)
|
||||
* @param separator Delimiter character (typically '.' for IP address and ':' for hardware (MAC) address)
|
||||
* @param base Base for numerical representation (typically 10 for IP address and 16 for hardware (MAC) address
|
||||
*/
|
||||
static void makeNetStr(char *resultstr,uint8_t *bytestr,uint8_t len,
|
||||
char separator,uint8_t base);
|
||||
};
|
||||
|
||||
extern EtherCard ether; //!< Global presentation of EtherCard class
|
||||
|
||||
#endif
|
||||
46
lib-ext/ethercard.git/README.md
Normal file
46
lib-ext/ethercard.git/README.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# EtherCard
|
||||
|
||||
**EtherCard** is a driver for the ENC28J60 chip, compatible with Arduino IDE.
|
||||
Adapted and extended from code written by Guido Socher and Pascal Stang.
|
||||
|
||||
License: GPL2
|
||||
|
||||
The documentation for this library is at http://jeelabs.net/pub/docs/ethercard/.
|
||||
|
||||
## Library Installation
|
||||
|
||||
1. Download the ZIP file from https://github.com/jcw/ethercard/archive/master.zip
|
||||
2. From the Arduino IDE: Sketch -> Import Library... -> Add Library...
|
||||
3. Restart the Arduino IDE to see the new "EtherCard" library with examples
|
||||
|
||||
See the comments in the example sketches for details about how to try them out.
|
||||
|
||||
## Physical Installation
|
||||
|
||||
### PIN Connections (Using Arduino UNO):
|
||||
|
||||
VCC - 3.3V
|
||||
GND - GND
|
||||
SCK - Pin 13
|
||||
SO - Pin 12
|
||||
SI - Pin 11
|
||||
CS - Pin 8 # Selectable with the ether.begin() function
|
||||
|
||||
### PIN Connections using an Arduino Mega
|
||||
|
||||
VCC - 3.3V
|
||||
GND - GND
|
||||
SCK - Pin 52
|
||||
SO - Pin 50
|
||||
SI - Pin 51
|
||||
CS - Pin 53 # Selectable with the ether.begin() function
|
||||
# The default CS pin defaults to 8, so you have to set it on a mega:
|
||||
ether.begin(sizeof Ethernet::buffer, mymac, 53)
|
||||
|
||||
## Support
|
||||
|
||||
For questions and help, see the [forums][F] (at JeeLabs.net).
|
||||
The issue tracker has been moved back to [Github][I] again.
|
||||
|
||||
[F]: http://jeenet.net/projects/cafe/boards
|
||||
[I]: https://github.com/jcw/ethercard/issues
|
||||
432
lib-ext/ethercard.git/dhcp.cpp
Normal file
432
lib-ext/ethercard.git/dhcp.cpp
Normal file
|
|
@ -0,0 +1,432 @@
|
|||
// DHCP look-up functions based on the udp client
|
||||
// http://www.ietf.org/rfc/rfc2131.txt
|
||||
//
|
||||
// Author: Andrew Lindsay
|
||||
// Rewritten and optimized by Jean-Claude Wippler, http://jeelabs.org/
|
||||
//
|
||||
// Rewritten dhcpStateMachine by Chris van den Hooven
|
||||
// as to implement dhcp-renew when lease expires (jun 2012)
|
||||
//
|
||||
// Various modifications and bug fixes contributed by Victor Aprea (oct 2012)
|
||||
//
|
||||
// Copyright: GPL V2
|
||||
// See http://www.gnu.org/licenses/gpl.html
|
||||
|
||||
//#define DHCPDEBUG
|
||||
|
||||
#include "EtherCard.h"
|
||||
#include "net.h"
|
||||
|
||||
#define gPB ether.buffer
|
||||
|
||||
#define DHCP_BOOTREQUEST 1
|
||||
#define DHCP_BOOTRESPONSE 2
|
||||
|
||||
// DHCP Message Type (option 53) (ref RFC 2132)
|
||||
#define DHCP_DISCOVER 1
|
||||
#define DHCP_OFFER 2
|
||||
#define DHCP_REQUEST 3
|
||||
#define DHCP_DECLINE 4
|
||||
#define DHCP_ACK 5
|
||||
#define DHCP_NAK 6
|
||||
#define DHCP_RELEASE 7
|
||||
|
||||
// DHCP States for access in applications (ref RFC 2131)
|
||||
enum {
|
||||
DHCP_STATE_INIT,
|
||||
DHCP_STATE_SELECTING,
|
||||
DHCP_STATE_REQUESTING,
|
||||
DHCP_STATE_BOUND,
|
||||
DHCP_STATE_RENEWING,
|
||||
};
|
||||
|
||||
/*
|
||||
op 1 Message op code / message type.
|
||||
1 = BOOTREQUEST, 2 = BOOTREPLY
|
||||
htype 1 Hardware address type, see ARP section in "Assigned
|
||||
Numbers" RFC; e.g., '1' = 10mb ethernet.
|
||||
hlen 1 Hardware address length (e.g. '6' for 10mb
|
||||
ethernet).
|
||||
hops 1 Client sets to zero, optionally used by relay agents
|
||||
when booting via a relay agent.
|
||||
xid 4 Transaction ID, a random number chosen by the
|
||||
client, used by the client and server to associate
|
||||
messages and responses between a client and a
|
||||
server.
|
||||
secs 2 Filled in by client, seconds elapsed since client
|
||||
began address acquisition or renewal process.
|
||||
flags 2 Flags (see figure 2).
|
||||
ciaddr 4 Client IP address; only filled in if client is in
|
||||
BOUND, RENEW or REBINDING state and can respond
|
||||
to ARP requests.
|
||||
yiaddr 4 'your' (client) IP address.
|
||||
siaddr 4 IP address of next server to use in bootstrap;
|
||||
returned in DHCPOFFER, DHCPACK by server.
|
||||
giaddr 4 Relay agent IP address, used in booting via a
|
||||
relay agent.
|
||||
chaddr 16 Client hardware address.
|
||||
sname 64 Optional server host name, null terminated string.
|
||||
file 128 Boot file name, null terminated string; "generic"
|
||||
name or null in DHCPDISCOVER, fully qualified
|
||||
directory-path name in DHCPOFFER.
|
||||
options var Optional parameters field. See the options
|
||||
documents for a list of defined options.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
// size 236
|
||||
typedef struct {
|
||||
byte op, htype, hlen, hops;
|
||||
uint32_t xid;
|
||||
uint16_t secs, flags;
|
||||
byte ciaddr[4], yiaddr[4], siaddr[4], giaddr[4];
|
||||
byte chaddr[16], sname[64], file[128];
|
||||
// options
|
||||
} DHCPdata;
|
||||
|
||||
#define DHCP_SERVER_PORT 67
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
|
||||
// timeouts im ms
|
||||
#define DHCP_REQUEST_TIMEOUT 10000
|
||||
|
||||
#define DHCP_HOSTNAME_MAX_LEN 32
|
||||
|
||||
// RFC 2132 Section 3.3:
|
||||
// The time value of 0xffffffff is reserved to represent "infinity".
|
||||
#define DHCP_INFINITE_LEASE 0xffffffff
|
||||
|
||||
static byte dhcpState = DHCP_STATE_INIT;
|
||||
static char hostname[DHCP_HOSTNAME_MAX_LEN] = "Arduino-00";
|
||||
static uint32_t currentXid;
|
||||
static uint32_t stateTimer;
|
||||
static uint32_t leaseStart;
|
||||
static uint32_t leaseTime;
|
||||
static byte* bufPtr;
|
||||
|
||||
static uint8_t dhcpCustomOptionNum = 0;
|
||||
static DhcpOptionCallback dhcpCustomOptionCallback = NULL;
|
||||
|
||||
// static uint8_t allOnes[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
static void addToBuf (byte b) {
|
||||
*bufPtr++ = b;
|
||||
}
|
||||
|
||||
static void addBytes (byte len, const byte* data) {
|
||||
while (len-- > 0)
|
||||
addToBuf(*data++);
|
||||
}
|
||||
|
||||
|
||||
// Main DHCP sending function
|
||||
|
||||
// implemented
|
||||
// state / msgtype
|
||||
// INIT / DHCPDISCOVER
|
||||
// SELECTING / DHCPREQUEST
|
||||
// BOUND (RENEWING) / DHCPREQUEST
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// | |SELECTING |RENEWING |INIT |
|
||||
// ----------------------------------------------------------
|
||||
// |broad/unicast |broadcast |unicast |broadcast |
|
||||
// |server-ip |MUST |MUST NOT |MUST NOT | option 54
|
||||
// |requested-ip |MUST |MUST NOT |MUST NOT | option 50
|
||||
// |ciaddr |zero |IP address |zero |
|
||||
// ----------------------------------------------------------
|
||||
|
||||
// options used (both send/receive)
|
||||
// 12 Host Name Option
|
||||
// 50 Requested IP Address
|
||||
// 51 IP Address Lease Time
|
||||
// 53 DHCP message type
|
||||
// 54 Server-identifier
|
||||
// 55 Parameter request list
|
||||
// 58 Renewal (T1) Time Value
|
||||
// 61 Client-identifier
|
||||
// 255 End
|
||||
|
||||
static void send_dhcp_message(uint8_t *requestip) {
|
||||
|
||||
uint8_t allOnes[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
memset(gPB, 0, UDP_DATA_P + sizeof( DHCPdata ));
|
||||
|
||||
EtherCard::udpPrepare(DHCP_CLIENT_PORT,
|
||||
(dhcpState == DHCP_STATE_BOUND ? EtherCard::dhcpip : allOnes),
|
||||
DHCP_SERVER_PORT);
|
||||
|
||||
// If we ever don't do this, the DHCP renewal gets sent to whatever random
|
||||
// destmacaddr was used by other code. Rather than cache the MAC address of
|
||||
// the DHCP server, just force a broadcast here in all cases.
|
||||
EtherCard::copyMac(gPB + ETH_DST_MAC, allOnes); //force broadcast mac
|
||||
|
||||
// Build DHCP Packet from buf[UDP_DATA_P]
|
||||
DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P);
|
||||
dhcpPtr->op = DHCP_BOOTREQUEST;
|
||||
dhcpPtr->htype = 1;
|
||||
dhcpPtr->hlen = 6;
|
||||
dhcpPtr->xid = currentXid;
|
||||
if (dhcpState == DHCP_STATE_BOUND) {
|
||||
EtherCard::copyIp(dhcpPtr->ciaddr, EtherCard::myip);
|
||||
}
|
||||
EtherCard::copyMac(dhcpPtr->chaddr, EtherCard::mymac);
|
||||
|
||||
// options defined as option, length, value
|
||||
bufPtr = gPB + UDP_DATA_P + sizeof( DHCPdata );
|
||||
// DHCP magic cookie, followed by message type
|
||||
static byte cookie[] = { 99, 130, 83, 99, 53, 1 };
|
||||
addBytes(sizeof cookie, cookie);
|
||||
// addToBuf(53); // DHCP_STATE_SELECTING, DHCP_STATE_REQUESTING
|
||||
// addToBuf(1); // Length
|
||||
addToBuf(dhcpState == DHCP_STATE_INIT ? DHCP_DISCOVER : DHCP_REQUEST);
|
||||
|
||||
// Client Identifier Option, this is the client mac address
|
||||
addToBuf(61); // Client identifier
|
||||
addToBuf(7); // Length
|
||||
addToBuf(0x01); // Ethernet
|
||||
addBytes(6, EtherCard::mymac);
|
||||
|
||||
addToBuf(12); // Host name Option
|
||||
addToBuf(10);
|
||||
addBytes(10, (byte*) hostname);
|
||||
|
||||
if (requestip != NULL) {
|
||||
addToBuf(50); // Request IP address
|
||||
addToBuf(4);
|
||||
addBytes(4, requestip);
|
||||
|
||||
addToBuf(54); // DHCP Server IP address
|
||||
addToBuf(4);
|
||||
addBytes(4, EtherCard::dhcpip);
|
||||
}
|
||||
|
||||
// Additional info in parameter list - minimal list for what we need
|
||||
byte len = 3;
|
||||
if (dhcpCustomOptionNum)
|
||||
len++;
|
||||
addToBuf(55); // Parameter request list
|
||||
addToBuf(len); // Length
|
||||
addToBuf(1); // Subnet mask
|
||||
addToBuf(3); // Route/Gateway
|
||||
addToBuf(6); // DNS Server
|
||||
if (dhcpCustomOptionNum)
|
||||
addToBuf(dhcpCustomOptionNum); // Custom option
|
||||
addToBuf(255); // end option
|
||||
|
||||
// packet size will be under 300 bytes
|
||||
EtherCard::udpTransmit((bufPtr - gPB) - UDP_DATA_P);
|
||||
}
|
||||
|
||||
static void process_dhcp_offer(uint16_t len, uint8_t *offeredip) {
|
||||
// Map struct onto payload
|
||||
DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P);
|
||||
|
||||
// Offered IP address is in yiaddr
|
||||
EtherCard::copyIp(offeredip, dhcpPtr->yiaddr);
|
||||
|
||||
// Search for the
|
||||
byte *ptr = (byte*) (dhcpPtr + 1) + 4;
|
||||
do {
|
||||
byte option = *ptr++;
|
||||
byte optionLen = *ptr++;
|
||||
if (option == 54) {
|
||||
EtherCard::copyIp(EtherCard::dhcpip, ptr);
|
||||
break;
|
||||
}
|
||||
ptr += optionLen;
|
||||
} while (ptr < gPB + len);
|
||||
}
|
||||
|
||||
static void process_dhcp_ack(uint16_t len) {
|
||||
// Map struct onto payload
|
||||
DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P);
|
||||
|
||||
// Allocated IP address is in yiaddr
|
||||
EtherCard::copyIp(EtherCard::myip, dhcpPtr->yiaddr);
|
||||
|
||||
// Scan through variable length option list identifying options we want
|
||||
byte *ptr = (byte*) (dhcpPtr + 1) + 4;
|
||||
bool done = false;
|
||||
do {
|
||||
byte option = *ptr++;
|
||||
byte optionLen = *ptr++;
|
||||
switch (option) {
|
||||
case 1:
|
||||
EtherCard::copyIp(EtherCard::netmask, ptr);
|
||||
break;
|
||||
case 3:
|
||||
EtherCard::copyIp(EtherCard::gwip, ptr);
|
||||
break;
|
||||
case 6:
|
||||
EtherCard::copyIp(EtherCard::dnsip, ptr);
|
||||
break;
|
||||
case 51:
|
||||
case 58:
|
||||
leaseTime = 0; // option 58 = Renewal Time, 51 = Lease Time
|
||||
for (byte i = 0; i<4; i++)
|
||||
leaseTime = (leaseTime << 8) + ptr[i];
|
||||
if (leaseTime != DHCP_INFINITE_LEASE) {
|
||||
leaseTime *= 1000; // milliseconds
|
||||
}
|
||||
break;
|
||||
case 255:
|
||||
done = true;
|
||||
break;
|
||||
default: {
|
||||
// Is is a custom configured option?
|
||||
if (dhcpCustomOptionCallback && option == dhcpCustomOptionNum) {
|
||||
dhcpCustomOptionCallback(option, ptr, optionLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
ptr += optionLen;
|
||||
} while (!done && ptr < gPB + len);
|
||||
}
|
||||
|
||||
static bool dhcp_received_message_type (uint16_t len, byte msgType) {
|
||||
// Map struct onto payload
|
||||
DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P);
|
||||
|
||||
if (len >= 70 && gPB[UDP_SRC_PORT_L_P] == DHCP_SERVER_PORT &&
|
||||
dhcpPtr->xid == currentXid ) {
|
||||
|
||||
byte *ptr = (byte*) (dhcpPtr + 1) + 4;
|
||||
do {
|
||||
byte option = *ptr++;
|
||||
byte optionLen = *ptr++;
|
||||
if(option == 53 && *ptr == msgType ) {
|
||||
// DHCP Message type match found
|
||||
return true;
|
||||
}
|
||||
ptr += optionLen;
|
||||
} while (ptr < gPB + len);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static char toAsciiHex(byte b) {
|
||||
char c = b & 0x0f;
|
||||
c += (c <= 9) ? '0' : 'A'-10;
|
||||
return c;
|
||||
}
|
||||
|
||||
bool EtherCard::dhcpSetup (const char *hname, bool fromRam) {
|
||||
// Use during setup, as this discards all incoming requests until it returns.
|
||||
// That shouldn't be a problem, because we don't have an IP-address yet.
|
||||
// Will try 60 secs to obtain DHCP-lease.
|
||||
|
||||
using_dhcp = true;
|
||||
|
||||
if(hname != NULL) {
|
||||
if(fromRam) {
|
||||
strncpy(hostname, hname, DHCP_HOSTNAME_MAX_LEN);
|
||||
}
|
||||
else {
|
||||
strncpy_P(hostname, hname, DHCP_HOSTNAME_MAX_LEN);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Set a unique hostname, use Arduino-?? with last octet of mac address
|
||||
hostname[8] = toAsciiHex(mymac[5] >> 4);
|
||||
hostname[9] = toAsciiHex(mymac[5]);
|
||||
}
|
||||
|
||||
dhcpState = DHCP_STATE_INIT;
|
||||
uint16_t start = millis();
|
||||
|
||||
while (dhcpState != DHCP_STATE_BOUND && (uint16_t) (millis() - start) < 60000) {
|
||||
if (isLinkUp()) DhcpStateMachine(packetReceive());
|
||||
}
|
||||
updateBroadcastAddress();
|
||||
delaycnt = 0;
|
||||
return dhcpState == DHCP_STATE_BOUND ;
|
||||
}
|
||||
|
||||
void EtherCard::dhcpAddOptionCallback(uint8_t option, DhcpOptionCallback callback)
|
||||
{
|
||||
dhcpCustomOptionNum = option;
|
||||
dhcpCustomOptionCallback = callback;
|
||||
}
|
||||
|
||||
void EtherCard::DhcpStateMachine (uint16_t len)
|
||||
{
|
||||
|
||||
#ifdef DHCPDEBUG
|
||||
if (dhcpState != DHCP_STATE_BOUND) {
|
||||
Serial.print(millis());
|
||||
Serial.print(" State: ");
|
||||
}
|
||||
switch (dhcpState) {
|
||||
case DHCP_STATE_INIT:
|
||||
Serial.println("Init");
|
||||
break;
|
||||
case DHCP_STATE_SELECTING:
|
||||
Serial.println("Selecting");
|
||||
break;
|
||||
case DHCP_STATE_REQUESTING:
|
||||
Serial.println("Requesting");
|
||||
break;
|
||||
case DHCP_STATE_RENEWING:
|
||||
Serial.println("Renew");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (dhcpState) {
|
||||
|
||||
case DHCP_STATE_BOUND:
|
||||
//!@todo Due to millis() 49 day wrap-around, DHCP renewal may not work as expected
|
||||
if (leaseTime != DHCP_INFINITE_LEASE && millis() >= leaseStart + leaseTime) {
|
||||
send_dhcp_message(myip);
|
||||
dhcpState = DHCP_STATE_RENEWING;
|
||||
stateTimer = millis();
|
||||
}
|
||||
break;
|
||||
|
||||
case DHCP_STATE_INIT:
|
||||
currentXid = millis();
|
||||
memset(myip,0,4); // force ip 0.0.0.0
|
||||
send_dhcp_message(NULL);
|
||||
enableBroadcast(true); //Temporarily enable broadcasts
|
||||
dhcpState = DHCP_STATE_SELECTING;
|
||||
stateTimer = millis();
|
||||
break;
|
||||
|
||||
case DHCP_STATE_SELECTING:
|
||||
if (dhcp_received_message_type(len, DHCP_OFFER)) {
|
||||
uint8_t offeredip[4];
|
||||
process_dhcp_offer(len, offeredip);
|
||||
send_dhcp_message(offeredip);
|
||||
dhcpState = DHCP_STATE_REQUESTING;
|
||||
stateTimer = millis();
|
||||
} else {
|
||||
if (millis() > stateTimer + DHCP_REQUEST_TIMEOUT) {
|
||||
dhcpState = DHCP_STATE_INIT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DHCP_STATE_REQUESTING:
|
||||
case DHCP_STATE_RENEWING:
|
||||
if (dhcp_received_message_type(len, DHCP_ACK)) {
|
||||
disableBroadcast(true); //Disable broadcast after temporary enable
|
||||
process_dhcp_ack(len);
|
||||
leaseStart = millis();
|
||||
if (gwip[0] != 0) setGwIp(gwip); // why is this? because it initiates an arp request
|
||||
dhcpState = DHCP_STATE_BOUND;
|
||||
} else {
|
||||
if (millis() > stateTimer + DHCP_REQUEST_TIMEOUT) {
|
||||
dhcpState = DHCP_STATE_INIT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
117
lib-ext/ethercard.git/dns.cpp
Normal file
117
lib-ext/ethercard.git/dns.cpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// DNS look-up functions based on the udp client
|
||||
// Author: Guido Socher
|
||||
// Copyright: GPL V2
|
||||
//
|
||||
// 2010-05-20 <jc@wippler.nl>
|
||||
|
||||
#include "EtherCard.h"
|
||||
#include "net.h"
|
||||
|
||||
#define gPB ether.buffer
|
||||
|
||||
static byte dnstid_l; // a counter for transaction ID
|
||||
#define DNSCLIENT_SRC_PORT_H 0xE0
|
||||
|
||||
static void dnsRequest (const char *hostname, bool fromRam) {
|
||||
++dnstid_l; // increment for next request, finally wrap
|
||||
if (ether.dnsip[0] == 0)
|
||||
memset(ether.dnsip, 8, 4); // use 8.8.8.8 Google DNS as default
|
||||
ether.udpPrepare((DNSCLIENT_SRC_PORT_H << 8) | dnstid_l, ether.dnsip, 53);
|
||||
memset(gPB + UDP_DATA_P, 0, 12);
|
||||
|
||||
byte *p = gPB + UDP_DATA_P + 12;
|
||||
char c;
|
||||
do {
|
||||
byte n = 0;
|
||||
for(;;) {
|
||||
c = fromRam ? *hostname : pgm_read_byte(hostname);
|
||||
++hostname;
|
||||
if (c == '.' || c == 0)
|
||||
break;
|
||||
p[++n] = c;
|
||||
}
|
||||
*p++ = n;
|
||||
p += n;
|
||||
} while (c != 0);
|
||||
|
||||
*p++ = 0; // terminate with zero, means root domain.
|
||||
*p++ = 0;
|
||||
*p++ = 1; // type A
|
||||
*p++ = 0;
|
||||
*p++ = 1; // class IN
|
||||
byte i = p - gPB - UDP_DATA_P;
|
||||
gPB[UDP_DATA_P] = i;
|
||||
gPB[UDP_DATA_P+1] = dnstid_l;
|
||||
gPB[UDP_DATA_P+2] = 1; // flags, standard recursive query
|
||||
gPB[UDP_DATA_P+5] = 1; // 1 question
|
||||
ether.udpTransmit(i);
|
||||
}
|
||||
|
||||
/** @brief Check if packet is DNS response.
|
||||
@param plen Size of packet
|
||||
@return <i>bool</i> True if DNS response has error. False if not DNS response or DNS response OK.
|
||||
@note hisip contains IP address of requested host or 0.0.0.0 on failure
|
||||
*/
|
||||
static bool checkForDnsAnswer (uint16_t plen) {
|
||||
byte *p = gPB + UDP_DATA_P; //start of UDP payload
|
||||
if (plen < 70 || gPB[UDP_SRC_PORT_L_P] != 53 || //from DNS source port
|
||||
gPB[UDP_DST_PORT_H_P] != DNSCLIENT_SRC_PORT_H || //response to same port as we sent from (MSB)
|
||||
gPB[UDP_DST_PORT_L_P] != dnstid_l || //response to same port as we sent from (LSB)
|
||||
p[1] != dnstid_l) //message id same as we sent
|
||||
return false; //not our DNS response
|
||||
if((p[3] & 0x0F) != 0)
|
||||
return true; //DNS response recieved with error
|
||||
|
||||
p += *p; // we encoded the query len into tid
|
||||
for (;;) {
|
||||
if (*p & 0xC0)
|
||||
p += 2;
|
||||
else
|
||||
while (++p < gPB + plen) {
|
||||
if (*p == 0) {
|
||||
++p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (p + 14 > gPB + plen)
|
||||
break;
|
||||
if (p[1] == 1 && p[9] == 4) { // type "A" and IPv4
|
||||
ether.copyIp(ether.hisip, p + 10);
|
||||
break;
|
||||
}
|
||||
p += p[9] + 10;
|
||||
}
|
||||
return false; //No error
|
||||
}
|
||||
|
||||
// use during setup, as this discards all incoming requests until it returns
|
||||
bool EtherCard::dnsLookup (const char* name, bool fromRam) {
|
||||
word start = millis();
|
||||
|
||||
while(!isLinkUp())
|
||||
{
|
||||
if ((word) (millis() - start) >= 30000)
|
||||
return false; //timeout waiting for link
|
||||
}
|
||||
while(clientWaitingDns())
|
||||
{
|
||||
packetLoop(packetReceive());
|
||||
if ((word) (millis() - start) >= 30000)
|
||||
return false; //timeout waiting for gateway ARP
|
||||
}
|
||||
|
||||
memset(hisip, 0, 4);
|
||||
dnsRequest(name, fromRam);
|
||||
|
||||
start = millis();
|
||||
while (hisip[0] == 0) {
|
||||
if ((word) (millis() - start) >= 30000)
|
||||
return false; //timout waiting for dns response
|
||||
word len = packetReceive();
|
||||
if (len > 0 && packetLoop(len) == 0) //packet not handled by tcp/ip packet loop
|
||||
if(checkForDnsAnswer(len))
|
||||
return false; //DNS response recieved with error
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
96
lib-ext/ethercard.git/docu.dox
Normal file
96
lib-ext/ethercard.git/docu.dox
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
@mainpage EtherCard is a driver for the ENC28J60 chip, compatible with Arduino IDE.<br/>
|
||||
Adapted and extended from code written by Guido Socher and Pascal Stang.<br/>
|
||||
The home page for this library is at http://jeelabs.net/projects/ethercard/wiki.<br/>
|
||||
License: <a href="http://www.gnu.org/licenses/gpl-2.0.html">GPL2</a><br/><br/>
|
||||
<b>PIN Connections (Using Arduino UNO):</b>
|
||||
<table border="1">
|
||||
<tr><th>EtherCard</th><th>Arduino UNO</th></tr>
|
||||
<tr><td>VCC</td><td>3.3V</td></tr>
|
||||
<tr><td>GND</td><td>GND</td></tr>
|
||||
<tr><td>SCK</td><td>Pin 13</td></tr>
|
||||
<tr><td>SO</td><td>Pin 12</td></tr>
|
||||
<tr><td>SI</td><td>Pin 11</td></tr>
|
||||
<tr><td>CS</td><td>Pin 8</td></tr>
|
||||
</table>
|
||||
|
||||
@section intro_sec Introduction
|
||||
EtherCard is a library that performs low-level interfacing with network interfaces based on the MicroChip (C) ENC28J60.
|
||||
High-level routines are provided to allow a variety of purposes including simple data transfer through to HTTP handling.
|
||||
EtherCard is a driver for the ENC28J60 chip, compatible with Arduino IDE.
|
||||
|
||||
Adapted and extended from code written by Guido Socher and Pascal Stang.
|
||||
|
||||
The documentation for this library is at http://jeelabs.net/pub/docs/ethercard/
|
||||
|
||||
The code is available on GitHub, at https://github.com/jcw/ethercard - to install:
|
||||
|
||||
Download the ZIP file from https://github.com/jcw/ethercard/archive/master.zip
|
||||
From the Arduino IDE: Sketch -> Import Library... -> Add Library...
|
||||
Restart the Arduino IDE to see the new "EtherCard" library with examples
|
||||
See the comments in the example sketches for details about how to try them out.
|
||||
|
||||
For questions and help, see the forums. For bugs and feature requests, see the issue tracker.
|
||||
@section eg_sec Examples
|
||||
Several @link examples example scripts @endlink are provided with the library which demonstrate various features. Below are descriptions on how to use the library.
|
||||
|
||||
<p>Note: <b>ether</b> is defined globally and may be used to access the library thus: ether.<i>member</i>.
|
||||
|
||||
@subsection Initiate To initiate the library call EtherCard::begin
|
||||
<pre>
|
||||
uint8_t Ethernet::buffer[700]; // configure buffer size to 700 octets
|
||||
static uint8_t mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; // define (unique on LAN) hardware (MAC) address
|
||||
|
||||
uint8_type nFirmwareVersion ether.begin(sizeof Ethernet::buffer, mymac);
|
||||
if(0 == nFirmwareVersion)
|
||||
{
|
||||
// handle failure to initiate network interface
|
||||
}
|
||||
</pre>
|
||||
|
||||
@subsection DHCP To configure IP address via DHCP use EtherCard::dhcpSetup
|
||||
<pre>
|
||||
if(!ether.dhcpSetup())
|
||||
{
|
||||
// handle failure to obtain IP address via DHCP
|
||||
}
|
||||
ether.printIp("IP: ", ether.myip); // output IP address to Serial
|
||||
ether.printIp("GW: ", ether.gwip); // output gateway address to Serial
|
||||
ether.printIp("Mask: ", ether.mymask); // output netmask to Serial
|
||||
ether.printIp("DHCP server: ", ether.dhcpip); // output IP address of the DHCP server
|
||||
</pre>
|
||||
|
||||
@subsection StaticIP To configure a static IP address use EtherCard::staticSetup
|
||||
<pre>
|
||||
const static uint8_t ip[] = {192,168,0,100};
|
||||
const static uint8_t gw[] = {192,168,0,254};
|
||||
const static uint8_t dns[] = {192,168,0,1};
|
||||
|
||||
if(!ether.staticSetup(ip, gw, dns);
|
||||
{
|
||||
// handle failure to configure static IP address (current implementation always returns true!)
|
||||
}
|
||||
</pre>
|
||||
|
||||
@subsection SendUDP Send UDP packet
|
||||
To send a UDP packet use EtherCard::sendUdp
|
||||
<pre>
|
||||
char payload[] = "My UDP message";
|
||||
uint8_t nSourcePort = 1234;
|
||||
uint8_t nDestinationPort = 5678;
|
||||
uint8_t ipDestinationAddress[4];
|
||||
ether.parseIp(ipDestinationAddress, "192.168.0.200");
|
||||
|
||||
ether.sendUdp(payload, sizeof(payload), nSourcePort, ipDestinationAddress, nDestinationPort);
|
||||
</pre>
|
||||
|
||||
@subsection DNSLookup DNS Lookup
|
||||
To perform a DNS lookup use EtherCard::dnsLookup
|
||||
<pre>
|
||||
if(!ether.dnsLookup("google.com"))
|
||||
{
|
||||
// handle failure of DNS lookup
|
||||
}
|
||||
ether.printIp("Server: ", ether.hispip); // Result of DNS lookup is placed in the hisip member of EtherCard.
|
||||
</pre>
|
||||
*/
|
||||
611
lib-ext/ethercard.git/enc28j60.cpp
Normal file
611
lib-ext/ethercard.git/enc28j60.cpp
Normal file
|
|
@ -0,0 +1,611 @@
|
|||
// Microchip ENC28J60 Ethernet Interface Driver
|
||||
// Author: Guido Socher
|
||||
// Copyright: GPL V2
|
||||
//
|
||||
// Based on the enc28j60.c file from the AVRlib library by Pascal Stang.
|
||||
// For AVRlib See http://www.procyonengineering.com/
|
||||
// Used with explicit permission of Pascal Stang.
|
||||
//
|
||||
// 2010-05-20 <jc@wippler.nl>
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include <Arduino.h> // Arduino 1.0
|
||||
#else
|
||||
#include <Wprogram.h> // Arduino 0022
|
||||
#endif
|
||||
#include "enc28j60.h"
|
||||
|
||||
uint16_t ENC28J60::bufferSize;
|
||||
bool ENC28J60::broadcast_enabled = false;
|
||||
|
||||
// ENC28J60 Control Registers
|
||||
// Control register definitions are a combination of address,
|
||||
// bank number, and Ethernet/MAC/PHY indicator bits.
|
||||
// - Register address (bits 0-4)
|
||||
// - Bank number (bits 5-6)
|
||||
// - MAC/PHY indicator (bit 7)
|
||||
#define ADDR_MASK 0x1F
|
||||
#define BANK_MASK 0x60
|
||||
#define SPRD_MASK 0x80
|
||||
// All-bank registers
|
||||
#define EIE 0x1B
|
||||
#define EIR 0x1C
|
||||
#define ESTAT 0x1D
|
||||
#define ECON2 0x1E
|
||||
#define ECON1 0x1F
|
||||
// Bank 0 registers
|
||||
#define ERDPT (0x00|0x00)
|
||||
#define EWRPT (0x02|0x00)
|
||||
#define ETXST (0x04|0x00)
|
||||
#define ETXND (0x06|0x00)
|
||||
#define ERXST (0x08|0x00)
|
||||
#define ERXND (0x0A|0x00)
|
||||
#define ERXRDPT (0x0C|0x00)
|
||||
// #define ERXWRPT (0x0E|0x00)
|
||||
#define EDMAST (0x10|0x00)
|
||||
#define EDMAND (0x12|0x00)
|
||||
// #define EDMADST (0x14|0x00)
|
||||
#define EDMACS (0x16|0x00)
|
||||
// Bank 1 registers
|
||||
#define EHT0 (0x00|0x20)
|
||||
#define EHT1 (0x01|0x20)
|
||||
#define EHT2 (0x02|0x20)
|
||||
#define EHT3 (0x03|0x20)
|
||||
#define EHT4 (0x04|0x20)
|
||||
#define EHT5 (0x05|0x20)
|
||||
#define EHT6 (0x06|0x20)
|
||||
#define EHT7 (0x07|0x20)
|
||||
#define EPMM0 (0x08|0x20)
|
||||
#define EPMM1 (0x09|0x20)
|
||||
#define EPMM2 (0x0A|0x20)
|
||||
#define EPMM3 (0x0B|0x20)
|
||||
#define EPMM4 (0x0C|0x20)
|
||||
#define EPMM5 (0x0D|0x20)
|
||||
#define EPMM6 (0x0E|0x20)
|
||||
#define EPMM7 (0x0F|0x20)
|
||||
#define EPMCS (0x10|0x20)
|
||||
// #define EPMO (0x14|0x20)
|
||||
#define EWOLIE (0x16|0x20)
|
||||
#define EWOLIR (0x17|0x20)
|
||||
#define ERXFCON (0x18|0x20)
|
||||
#define EPKTCNT (0x19|0x20)
|
||||
// Bank 2 registers
|
||||
#define MACON1 (0x00|0x40|0x80)
|
||||
#define MACON2 (0x01|0x40|0x80)
|
||||
#define MACON3 (0x02|0x40|0x80)
|
||||
#define MACON4 (0x03|0x40|0x80)
|
||||
#define MABBIPG (0x04|0x40|0x80)
|
||||
#define MAIPG (0x06|0x40|0x80)
|
||||
#define MACLCON1 (0x08|0x40|0x80)
|
||||
#define MACLCON2 (0x09|0x40|0x80)
|
||||
#define MAMXFL (0x0A|0x40|0x80)
|
||||
#define MAPHSUP (0x0D|0x40|0x80)
|
||||
#define MICON (0x11|0x40|0x80)
|
||||
#define MICMD (0x12|0x40|0x80)
|
||||
#define MIREGADR (0x14|0x40|0x80)
|
||||
#define MIWR (0x16|0x40|0x80)
|
||||
#define MIRD (0x18|0x40|0x80)
|
||||
// Bank 3 registers
|
||||
#define MAADR1 (0x00|0x60|0x80)
|
||||
#define MAADR0 (0x01|0x60|0x80)
|
||||
#define MAADR3 (0x02|0x60|0x80)
|
||||
#define MAADR2 (0x03|0x60|0x80)
|
||||
#define MAADR5 (0x04|0x60|0x80)
|
||||
#define MAADR4 (0x05|0x60|0x80)
|
||||
#define EBSTSD (0x06|0x60)
|
||||
#define EBSTCON (0x07|0x60)
|
||||
#define EBSTCS (0x08|0x60)
|
||||
#define MISTAT (0x0A|0x60|0x80)
|
||||
#define EREVID (0x12|0x60)
|
||||
#define ECOCON (0x15|0x60)
|
||||
#define EFLOCON (0x17|0x60)
|
||||
#define EPAUS (0x18|0x60)
|
||||
|
||||
// ENC28J60 ERXFCON Register Bit Definitions
|
||||
#define ERXFCON_UCEN 0x80
|
||||
#define ERXFCON_ANDOR 0x40
|
||||
#define ERXFCON_CRCEN 0x20
|
||||
#define ERXFCON_PMEN 0x10
|
||||
#define ERXFCON_MPEN 0x08
|
||||
#define ERXFCON_HTEN 0x04
|
||||
#define ERXFCON_MCEN 0x02
|
||||
#define ERXFCON_BCEN 0x01
|
||||
// ENC28J60 EIE Register Bit Definitions
|
||||
#define EIE_INTIE 0x80
|
||||
#define EIE_PKTIE 0x40
|
||||
#define EIE_DMAIE 0x20
|
||||
#define EIE_LINKIE 0x10
|
||||
#define EIE_TXIE 0x08
|
||||
#define EIE_WOLIE 0x04
|
||||
#define EIE_TXERIE 0x02
|
||||
#define EIE_RXERIE 0x01
|
||||
// ENC28J60 EIR Register Bit Definitions
|
||||
#define EIR_PKTIF 0x40
|
||||
#define EIR_DMAIF 0x20
|
||||
#define EIR_LINKIF 0x10
|
||||
#define EIR_TXIF 0x08
|
||||
#define EIR_WOLIF 0x04
|
||||
#define EIR_TXERIF 0x02
|
||||
#define EIR_RXERIF 0x01
|
||||
// ENC28J60 ESTAT Register Bit Definitions
|
||||
#define ESTAT_INT 0x80
|
||||
#define ESTAT_LATECOL 0x10
|
||||
#define ESTAT_RXBUSY 0x04
|
||||
#define ESTAT_TXABRT 0x02
|
||||
#define ESTAT_CLKRDY 0x01
|
||||
// ENC28J60 ECON2 Register Bit Definitions
|
||||
#define ECON2_AUTOINC 0x80
|
||||
#define ECON2_PKTDEC 0x40
|
||||
#define ECON2_PWRSV 0x20
|
||||
#define ECON2_VRPS 0x08
|
||||
// ENC28J60 ECON1 Register Bit Definitions
|
||||
#define ECON1_TXRST 0x80
|
||||
#define ECON1_RXRST 0x40
|
||||
#define ECON1_DMAST 0x20
|
||||
#define ECON1_CSUMEN 0x10
|
||||
#define ECON1_TXRTS 0x08
|
||||
#define ECON1_RXEN 0x04
|
||||
#define ECON1_BSEL1 0x02
|
||||
#define ECON1_BSEL0 0x01
|
||||
// ENC28J60 MACON1 Register Bit Definitions
|
||||
#define MACON1_LOOPBK 0x10
|
||||
#define MACON1_TXPAUS 0x08
|
||||
#define MACON1_RXPAUS 0x04
|
||||
#define MACON1_PASSALL 0x02
|
||||
#define MACON1_MARXEN 0x01
|
||||
// ENC28J60 MACON2 Register Bit Definitions
|
||||
#define MACON2_MARST 0x80
|
||||
#define MACON2_RNDRST 0x40
|
||||
#define MACON2_MARXRST 0x08
|
||||
#define MACON2_RFUNRST 0x04
|
||||
#define MACON2_MATXRST 0x02
|
||||
#define MACON2_TFUNRST 0x01
|
||||
// ENC28J60 MACON3 Register Bit Definitions
|
||||
#define MACON3_PADCFG2 0x80
|
||||
#define MACON3_PADCFG1 0x40
|
||||
#define MACON3_PADCFG0 0x20
|
||||
#define MACON3_TXCRCEN 0x10
|
||||
#define MACON3_PHDRLEN 0x08
|
||||
#define MACON3_HFRMLEN 0x04
|
||||
#define MACON3_FRMLNEN 0x02
|
||||
#define MACON3_FULDPX 0x01
|
||||
// ENC28J60 MICMD Register Bit Definitions
|
||||
#define MICMD_MIISCAN 0x02
|
||||
#define MICMD_MIIRD 0x01
|
||||
// ENC28J60 MISTAT Register Bit Definitions
|
||||
#define MISTAT_NVALID 0x04
|
||||
#define MISTAT_SCAN 0x02
|
||||
#define MISTAT_BUSY 0x01
|
||||
|
||||
// ENC28J60 EBSTCON Register Bit Definitions
|
||||
#define EBSTCON_PSV2 0x80
|
||||
#define EBSTCON_PSV1 0x40
|
||||
#define EBSTCON_PSV0 0x20
|
||||
#define EBSTCON_PSEL 0x10
|
||||
#define EBSTCON_TMSEL1 0x08
|
||||
#define EBSTCON_TMSEL0 0x04
|
||||
#define EBSTCON_TME 0x02
|
||||
#define EBSTCON_BISTST 0x01
|
||||
|
||||
// PHY registers
|
||||
#define PHCON1 0x00
|
||||
#define PHSTAT1 0x01
|
||||
#define PHHID1 0x02
|
||||
#define PHHID2 0x03
|
||||
#define PHCON2 0x10
|
||||
#define PHSTAT2 0x11
|
||||
#define PHIE 0x12
|
||||
#define PHIR 0x13
|
||||
#define PHLCON 0x14
|
||||
|
||||
// ENC28J60 PHY PHCON1 Register Bit Definitions
|
||||
#define PHCON1_PRST 0x8000
|
||||
#define PHCON1_PLOOPBK 0x4000
|
||||
#define PHCON1_PPWRSV 0x0800
|
||||
#define PHCON1_PDPXMD 0x0100
|
||||
// ENC28J60 PHY PHSTAT1 Register Bit Definitions
|
||||
#define PHSTAT1_PFDPX 0x1000
|
||||
#define PHSTAT1_PHDPX 0x0800
|
||||
#define PHSTAT1_LLSTAT 0x0004
|
||||
#define PHSTAT1_JBSTAT 0x0002
|
||||
// ENC28J60 PHY PHCON2 Register Bit Definitions
|
||||
#define PHCON2_FRCLINK 0x4000
|
||||
#define PHCON2_TXDIS 0x2000
|
||||
#define PHCON2_JABBER 0x0400
|
||||
#define PHCON2_HDLDIS 0x0100
|
||||
|
||||
// ENC28J60 Packet Control Byte Bit Definitions
|
||||
#define PKTCTRL_PHUGEEN 0x08
|
||||
#define PKTCTRL_PPADEN 0x04
|
||||
#define PKTCTRL_PCRCEN 0x02
|
||||
#define PKTCTRL_POVERRIDE 0x01
|
||||
|
||||
// SPI operation codes
|
||||
#define ENC28J60_READ_CTRL_REG 0x00
|
||||
#define ENC28J60_READ_BUF_MEM 0x3A
|
||||
#define ENC28J60_WRITE_CTRL_REG 0x40
|
||||
#define ENC28J60_WRITE_BUF_MEM 0x7A
|
||||
#define ENC28J60_BIT_FIELD_SET 0x80
|
||||
#define ENC28J60_BIT_FIELD_CLR 0xA0
|
||||
#define ENC28J60_SOFT_RESET 0xFF
|
||||
|
||||
// The RXSTART_INIT must be zero. See Rev. B4 Silicon Errata point 5.
|
||||
// Buffer boundaries applied to internal 8K ram
|
||||
// the entire available packet buffer space is allocated
|
||||
|
||||
#define RXSTART_INIT 0x0000 // start of RX buffer, room for 2 packets
|
||||
#define RXSTOP_INIT 0x0BFF // end of RX buffer
|
||||
|
||||
#define TXSTART_INIT 0x0C00 // start of TX buffer, room for 1 packet
|
||||
#define TXSTOP_INIT 0x11FF // end of TX buffer
|
||||
|
||||
#define SCRATCH_START 0x1200 // start of scratch area
|
||||
#define SCRATCH_LIMIT 0x2000 // past end of area, i.e. 3.5 Kb
|
||||
#define SCRATCH_PAGE_SHIFT 6 // addressing is in pages of 64 bytes
|
||||
#define SCRATCH_PAGE_SIZE (1 << SCRATCH_PAGE_SHIFT)
|
||||
|
||||
// max frame length which the conroller will accept:
|
||||
// (note: maximum ethernet frame length would be 1518)
|
||||
#define MAX_FRAMELEN 1500
|
||||
|
||||
#define FULL_SPEED 1 // switch to full-speed SPI for bulk transfers
|
||||
|
||||
static byte Enc28j60Bank;
|
||||
static int gNextPacketPtr;
|
||||
static byte selectPin;
|
||||
|
||||
void ENC28J60::initSPI () {
|
||||
pinMode(SS, OUTPUT);
|
||||
digitalWrite(SS, HIGH);
|
||||
pinMode(MOSI, OUTPUT);
|
||||
pinMode(SCK, OUTPUT);
|
||||
pinMode(MISO, INPUT);
|
||||
|
||||
digitalWrite(MOSI, HIGH);
|
||||
digitalWrite(MOSI, LOW);
|
||||
digitalWrite(SCK, LOW);
|
||||
|
||||
SPCR = bit(SPE) | bit(MSTR); // 8 MHz @ 16
|
||||
bitSet(SPSR, SPI2X);
|
||||
}
|
||||
|
||||
static void enableChip () {
|
||||
cli();
|
||||
digitalWrite(selectPin, LOW);
|
||||
}
|
||||
|
||||
static void disableChip () {
|
||||
digitalWrite(selectPin, HIGH);
|
||||
sei();
|
||||
}
|
||||
|
||||
static void xferSPI (byte data) {
|
||||
SPDR = data;
|
||||
while (!(SPSR&(1<<SPIF)))
|
||||
;
|
||||
}
|
||||
|
||||
static byte readOp (byte op, byte address) {
|
||||
enableChip();
|
||||
xferSPI(op | (address & ADDR_MASK));
|
||||
xferSPI(0x00);
|
||||
if (address & 0x80)
|
||||
xferSPI(0x00);
|
||||
byte result = SPDR;
|
||||
disableChip();
|
||||
return result;
|
||||
}
|
||||
|
||||
static void writeOp (byte op, byte address, byte data) {
|
||||
enableChip();
|
||||
xferSPI(op | (address & ADDR_MASK));
|
||||
xferSPI(data);
|
||||
disableChip();
|
||||
}
|
||||
|
||||
static void readBuf(uint16_t len, byte* data) {
|
||||
enableChip();
|
||||
xferSPI(ENC28J60_READ_BUF_MEM);
|
||||
while (len--) {
|
||||
xferSPI(0x00);
|
||||
*data++ = SPDR;
|
||||
}
|
||||
disableChip();
|
||||
}
|
||||
|
||||
static void writeBuf(uint16_t len, const byte* data) {
|
||||
enableChip();
|
||||
xferSPI(ENC28J60_WRITE_BUF_MEM);
|
||||
while (len--)
|
||||
xferSPI(*data++);
|
||||
disableChip();
|
||||
}
|
||||
|
||||
static void SetBank (byte address) {
|
||||
if ((address & BANK_MASK) != Enc28j60Bank) {
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_BSEL1|ECON1_BSEL0);
|
||||
Enc28j60Bank = address & BANK_MASK;
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, Enc28j60Bank>>5);
|
||||
}
|
||||
}
|
||||
|
||||
static byte readRegByte (byte address) {
|
||||
SetBank(address);
|
||||
return readOp(ENC28J60_READ_CTRL_REG, address);
|
||||
}
|
||||
|
||||
static uint16_t readReg(byte address) {
|
||||
return readRegByte(address) + (readRegByte(address+1) << 8);
|
||||
}
|
||||
|
||||
static void writeRegByte (byte address, byte data) {
|
||||
SetBank(address);
|
||||
writeOp(ENC28J60_WRITE_CTRL_REG, address, data);
|
||||
}
|
||||
|
||||
static void writeReg(byte address, uint16_t data) {
|
||||
writeRegByte(address, data);
|
||||
writeRegByte(address + 1, data >> 8);
|
||||
}
|
||||
|
||||
static uint16_t readPhyByte (byte address) {
|
||||
writeRegByte(MIREGADR, address);
|
||||
writeRegByte(MICMD, MICMD_MIIRD);
|
||||
while (readRegByte(MISTAT) & MISTAT_BUSY)
|
||||
;
|
||||
writeRegByte(MICMD, 0x00);
|
||||
return readRegByte(MIRD+1);
|
||||
}
|
||||
|
||||
static void writePhy (byte address, uint16_t data) {
|
||||
writeRegByte(MIREGADR, address);
|
||||
writeReg(MIWR, data);
|
||||
while (readRegByte(MISTAT) & MISTAT_BUSY)
|
||||
;
|
||||
}
|
||||
|
||||
byte ENC28J60::initialize (uint16_t size, const byte* macaddr, byte csPin) {
|
||||
bufferSize = size;
|
||||
if (bitRead(SPCR, SPE) == 0)
|
||||
initSPI();
|
||||
selectPin = csPin;
|
||||
pinMode(selectPin, OUTPUT);
|
||||
disableChip();
|
||||
|
||||
writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
|
||||
delay(2); // errata B7/2
|
||||
while (!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY)
|
||||
;
|
||||
|
||||
gNextPacketPtr = RXSTART_INIT;
|
||||
writeReg(ERXST, RXSTART_INIT);
|
||||
writeReg(ERXRDPT, RXSTART_INIT);
|
||||
writeReg(ERXND, RXSTOP_INIT);
|
||||
writeReg(ETXST, TXSTART_INIT);
|
||||
writeReg(ETXND, TXSTOP_INIT);
|
||||
enableBroadcast(); // change to add ERXFCON_BCEN recommended by epam
|
||||
writeReg(EPMM0, 0x303f);
|
||||
writeReg(EPMCS, 0xf7f9);
|
||||
writeRegByte(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
|
||||
writeRegByte(MACON2, 0x00);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, MACON3,
|
||||
MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
|
||||
writeReg(MAIPG, 0x0C12);
|
||||
writeRegByte(MABBIPG, 0x12);
|
||||
writeReg(MAMXFL, MAX_FRAMELEN);
|
||||
writeRegByte(MAADR5, macaddr[0]);
|
||||
writeRegByte(MAADR4, macaddr[1]);
|
||||
writeRegByte(MAADR3, macaddr[2]);
|
||||
writeRegByte(MAADR2, macaddr[3]);
|
||||
writeRegByte(MAADR1, macaddr[4]);
|
||||
writeRegByte(MAADR0, macaddr[5]);
|
||||
writePhy(PHCON2, PHCON2_HDLDIS);
|
||||
SetBank(ECON1);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
|
||||
|
||||
byte rev = readRegByte(EREVID);
|
||||
// microchip forgot to step the number on the silcon when they
|
||||
// released the revision B7. 6 is now rev B7. We still have
|
||||
// to see what they do when they release B8. At the moment
|
||||
// there is no B8 out yet
|
||||
if (rev > 5) ++rev;
|
||||
return rev;
|
||||
}
|
||||
|
||||
bool ENC28J60::isLinkUp() {
|
||||
return (readPhyByte(PHSTAT2) >> 2) & 1;
|
||||
}
|
||||
|
||||
void ENC28J60::packetSend(uint16_t len) {
|
||||
// see http://forum.mysensors.org/topic/536/
|
||||
// while (readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_TXRTS)
|
||||
if (readRegByte(EIR) & EIR_TXERIF) {
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF);
|
||||
}
|
||||
writeReg(EWRPT, TXSTART_INIT);
|
||||
writeReg(ETXND, TXSTART_INIT+len);
|
||||
writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
|
||||
writeBuf(len, buffer);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
|
||||
}
|
||||
|
||||
uint16_t ENC28J60::packetReceive() {
|
||||
uint16_t len = 0;
|
||||
if (readRegByte(EPKTCNT) > 0) {
|
||||
writeReg(ERDPT, gNextPacketPtr);
|
||||
|
||||
struct {
|
||||
uint16_t nextPacket;
|
||||
uint16_t byteCount;
|
||||
uint16_t status;
|
||||
} header;
|
||||
|
||||
readBuf(sizeof header, (byte*) &header);
|
||||
|
||||
gNextPacketPtr = header.nextPacket;
|
||||
len = header.byteCount - 4; //remove the CRC count
|
||||
if (len>bufferSize-1)
|
||||
len=bufferSize-1;
|
||||
if ((header.status & 0x80)==0)
|
||||
len = 0;
|
||||
else
|
||||
readBuf(len, buffer);
|
||||
buffer[len] = 0;
|
||||
if (gNextPacketPtr - 1 > RXSTOP_INIT)
|
||||
writeReg(ERXRDPT, RXSTOP_INIT);
|
||||
else
|
||||
writeReg(ERXRDPT, gNextPacketPtr - 1);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void ENC28J60::copyout (byte page, const byte* data) {
|
||||
uint16_t destPos = SCRATCH_START + (page << SCRATCH_PAGE_SHIFT);
|
||||
if (destPos < SCRATCH_START || destPos > SCRATCH_LIMIT - SCRATCH_PAGE_SIZE)
|
||||
return;
|
||||
writeReg(EWRPT, destPos);
|
||||
writeBuf(SCRATCH_PAGE_SIZE, data);
|
||||
}
|
||||
|
||||
void ENC28J60::copyin (byte page, byte* data) {
|
||||
uint16_t destPos = SCRATCH_START + (page << SCRATCH_PAGE_SHIFT);
|
||||
if (destPos < SCRATCH_START || destPos > SCRATCH_LIMIT - SCRATCH_PAGE_SIZE)
|
||||
return;
|
||||
writeReg(ERDPT, destPos);
|
||||
readBuf(SCRATCH_PAGE_SIZE, data);
|
||||
}
|
||||
|
||||
byte ENC28J60::peekin (byte page, byte off) {
|
||||
byte result = 0;
|
||||
uint16_t destPos = SCRATCH_START + (page << SCRATCH_PAGE_SHIFT) + off;
|
||||
if (SCRATCH_START <= destPos && destPos < SCRATCH_LIMIT) {
|
||||
writeReg(ERDPT, destPos);
|
||||
readBuf(1, &result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Contributed by Alex M. Based on code from: http://blog.derouineau.fr
|
||||
// /2011/07/putting-enc28j60-ethernet-controler-in-sleep-mode/
|
||||
void ENC28J60::powerDown() {
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
|
||||
while(readRegByte(ESTAT) & ESTAT_RXBUSY);
|
||||
while(readRegByte(ECON1) & ECON1_TXRTS);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV);
|
||||
}
|
||||
|
||||
void ENC28J60::powerUp() {
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV);
|
||||
while(!readRegByte(ESTAT) & ESTAT_CLKRDY);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
|
||||
}
|
||||
|
||||
void ENC28J60::enableBroadcast (bool temporary) {
|
||||
writeRegByte(ERXFCON, readRegByte(ERXFCON) | ERXFCON_BCEN);
|
||||
if(!temporary)
|
||||
broadcast_enabled = true;
|
||||
}
|
||||
|
||||
void ENC28J60::disableBroadcast (bool temporary) {
|
||||
if(!temporary)
|
||||
broadcast_enabled = false;
|
||||
if(!broadcast_enabled)
|
||||
writeRegByte(ERXFCON, readRegByte(ERXFCON) & ~ERXFCON_BCEN);
|
||||
}
|
||||
|
||||
void ENC28J60::enableMulticast () {
|
||||
writeRegByte(ERXFCON, readRegByte(ERXFCON) | ERXFCON_MCEN);
|
||||
}
|
||||
|
||||
void ENC28J60::disableMulticast () {
|
||||
writeRegByte(ERXFCON, readRegByte(ERXFCON) & ~ERXFCON_MCEN);
|
||||
}
|
||||
|
||||
uint8_t ENC28J60::doBIST ( byte csPin) {
|
||||
#define RANDOM_FILL 0b0000
|
||||
#define ADDRESS_FILL 0b0100
|
||||
#define PATTERN_SHIFT 0b1000
|
||||
#define RANDOM_RACE 0b1100
|
||||
|
||||
// init
|
||||
if (bitRead(SPCR, SPE) == 0)
|
||||
initSPI();
|
||||
selectPin = csPin;
|
||||
pinMode(selectPin, OUTPUT);
|
||||
disableChip();
|
||||
|
||||
writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
|
||||
delay(2); // errata B7/2
|
||||
while (!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY) ;
|
||||
|
||||
|
||||
// now we can start the memory test
|
||||
|
||||
uint16_t macResult;
|
||||
uint16_t bitsResult;
|
||||
|
||||
// clear some of the registers registers
|
||||
writeRegByte(ECON1, 0);
|
||||
writeReg(EDMAST, 0);
|
||||
|
||||
// Set up necessary pointers for the DMA to calculate over the entire memory
|
||||
writeReg(EDMAND, 0x1FFFu);
|
||||
writeReg(ERXND, 0x1FFFu);
|
||||
|
||||
// Enable Test Mode and do an Address Fill
|
||||
SetBank(EBSTCON);
|
||||
writeRegByte(EBSTCON, EBSTCON_TME | EBSTCON_BISTST | ADDRESS_FILL);
|
||||
|
||||
// wait for BISTST to be reset, only after that are we actually ready to
|
||||
// start the test
|
||||
// this was undocumented :(
|
||||
while (readOp(ENC28J60_READ_CTRL_REG, EBSTCON) & EBSTCON_BISTST);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME);
|
||||
|
||||
|
||||
// now start the actual reading an calculating the checksum until the end is
|
||||
// reached
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST | ECON1_CSUMEN);
|
||||
SetBank(EDMACS);
|
||||
while(readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
|
||||
macResult = readReg(EDMACS);
|
||||
bitsResult = readReg(EBSTCS);
|
||||
// Compare the results
|
||||
// 0xF807 should always be generated in Address fill mode
|
||||
if ((macResult != bitsResult) || (bitsResult != 0xF807)) {
|
||||
return 0;
|
||||
}
|
||||
// reset test flag
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME);
|
||||
|
||||
|
||||
// Now start the BIST with random data test, and also keep on swapping the
|
||||
// DMA/BIST memory ports.
|
||||
writeRegByte(EBSTSD, 0b10101010 | millis());
|
||||
writeRegByte(EBSTCON, EBSTCON_TME | EBSTCON_PSEL | EBSTCON_BISTST | RANDOM_FILL);
|
||||
|
||||
|
||||
// wait for BISTST to be reset, only after that are we actually ready to
|
||||
// start the test
|
||||
// this was undocumented :(
|
||||
while (readOp(ENC28J60_READ_CTRL_REG, EBSTCON) & EBSTCON_BISTST);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME);
|
||||
|
||||
|
||||
// now start the actual reading an calculating the checksum until the end is
|
||||
// reached
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST | ECON1_CSUMEN);
|
||||
SetBank(EDMACS);
|
||||
while(readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
|
||||
|
||||
macResult = readReg(EDMACS);
|
||||
bitsResult = readReg(EBSTCS);
|
||||
// The checksum should be equal
|
||||
return macResult == bitsResult;
|
||||
}
|
||||
|
||||
114
lib-ext/ethercard.git/enc28j60.h
Normal file
114
lib-ext/ethercard.git/enc28j60.h
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
// Microchip ENC28J60 Ethernet Interface Driver
|
||||
// Author: Pascal Stang
|
||||
// Modified by: Guido Socher
|
||||
// Copyright: GPL V2
|
||||
//
|
||||
// This driver provides initialization and transmit/receive
|
||||
// functions for the Microchip ENC28J60 10Mb Ethernet Controller and PHY.
|
||||
// This chip is novel in that it is a full MAC+PHY interface all in a 28-pin
|
||||
// chip, using an SPI interface to the host processor.
|
||||
//
|
||||
// 2010-05-20 <jc@wippler.nl>
|
||||
|
||||
#ifndef ENC28J60_H
|
||||
#define ENC28J60_H
|
||||
|
||||
/** This class provide low-level interfacing with the ENC28J60 network interface. This is used by the EtherCard class and not intended for use by (normal) end users. */
|
||||
class ENC28J60 {
|
||||
public:
|
||||
static uint8_t buffer[]; //!< Data buffer (shared by recieve and transmit)
|
||||
static uint16_t bufferSize; //!< Size of data buffer
|
||||
static bool broadcast_enabled; //!< True if broadcasts enabled (used to allow temporary disable of broadcast for DHCP or other internal functions)
|
||||
|
||||
static uint8_t* tcpOffset () { return buffer + 0x36; } //!< Pointer to the start of TCP payload
|
||||
|
||||
/** @brief Initialise SPI interface
|
||||
* @note Configures Arduino pins as input / output, etc.
|
||||
*/
|
||||
static void initSPI ();
|
||||
|
||||
/** @brief Initialise network interface
|
||||
* @param size Size of data buffer
|
||||
* @param macaddr Pointer to 6 byte hardware (MAC) address
|
||||
* @param csPin Arduino pin used for chip select (enable network interface SPI bus). Default = 8
|
||||
* @return <i>uint8_t</i> ENC28J60 firmware version or zero on failure.
|
||||
*/
|
||||
static uint8_t initialize (const uint16_t size, const uint8_t* macaddr,
|
||||
uint8_t csPin = 8);
|
||||
|
||||
/** @brief Check if network link is connected
|
||||
* @return <i>bool</i> True if link is up
|
||||
*/
|
||||
static bool isLinkUp ();
|
||||
|
||||
/** @brief Sends data to network interface
|
||||
* @param len Size of data to send
|
||||
* @note Data buffer is shared by recieve and transmit functions
|
||||
*/
|
||||
static void packetSend (uint16_t len);
|
||||
|
||||
/** @brief Copy recieved packets to data buffer
|
||||
* @return <i>uint16_t</i> Size of recieved data
|
||||
* @note Data buffer is shared by recieve and transmit functions
|
||||
*/
|
||||
static uint16_t packetReceive ();
|
||||
|
||||
/** @brief Copy data from ENC28J60 memory
|
||||
* @param page Data page of memory
|
||||
* @param data Pointer to buffer to copy data to
|
||||
*/
|
||||
static void copyout (uint8_t page, const uint8_t* data);
|
||||
|
||||
/** @brief Copy data to ENC28J60 memory
|
||||
* @param page Data page of memory
|
||||
* @param data Pointer to buffer to copy data from
|
||||
*/
|
||||
static void copyin (uint8_t page, uint8_t* data);
|
||||
|
||||
/** @brief Get single byte of data from ENC28J60 memory
|
||||
* @param page Data page of memory
|
||||
* @param off Offset of data within page
|
||||
* @return Data value
|
||||
*/
|
||||
static uint8_t peekin (uint8_t page, uint8_t off);
|
||||
|
||||
/** @brief Put ENC28J60 in sleep mode
|
||||
*/
|
||||
static void powerDown(); // contrib by Alex M.
|
||||
|
||||
/** @brief Wake ENC28J60 from sleep mode
|
||||
*/
|
||||
static void powerUp(); // contrib by Alex M.
|
||||
|
||||
/** @brief Enable reception of broadcast messages
|
||||
* @param temporary Set true to temporarily enable broadcast
|
||||
* @note This will increase load on recieved data handling
|
||||
*/
|
||||
static void enableBroadcast(bool temporary = false);
|
||||
|
||||
/** @brief Disable reception of broadcast messages
|
||||
* @param temporary Set true to only disable if temporarily enabled
|
||||
* @note This will reduce load on recieved data handling
|
||||
*/
|
||||
static void disableBroadcast(bool temporary = false);
|
||||
|
||||
/** @brief Enables reception of mulitcast messages
|
||||
* @note This will increase load on recieved data handling
|
||||
*/
|
||||
static void enableMulticast ();
|
||||
|
||||
/** @brief Disable reception of mulitcast messages
|
||||
* @note This will reduce load on recieved data handling
|
||||
*/
|
||||
static void disableMulticast();
|
||||
|
||||
/** @brief Reset and fully initialise ENC28J60
|
||||
* @param csPin Arduino pin used for chip select (enable SPI bus)
|
||||
* @return <i>uint8_t</i> 0 on failure
|
||||
*/
|
||||
static uint8_t doBIST(uint8_t csPin = 8);
|
||||
};
|
||||
|
||||
typedef ENC28J60 Ethernet; //!< Define alias Ethernet for ENC28J60
|
||||
|
||||
#endif
|
||||
320
lib-ext/ethercard.git/examples/JeeUdp/JeeUdp.ino
Normal file
320
lib-ext/ethercard.git/examples/JeeUdp/JeeUdp.ino
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
// Collect RF12 packets and send them on as UDP collectd packets on Ethernet.
|
||||
// 2010-05-20 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
|
||||
|
||||
// This sketch is derived from RF12eth.pde (and etherNode.ino):
|
||||
// May 2010, Andras Tucsni, http://opensource.org/licenses/mit-license.php
|
||||
|
||||
#include <EtherCard.h>
|
||||
#include <JeeLib.h>
|
||||
#include <avr/eeprom.h>
|
||||
|
||||
#define DEBUG 1 // set to 1 to display free RAM on web page
|
||||
#define SERIAL 1 // set to 1 to show incoming requests on serial port
|
||||
|
||||
#define CONFIG_EEPROM_ADDR ((byte*) 0x10)
|
||||
|
||||
// configuration, as stored in EEPROM
|
||||
struct Config {
|
||||
byte band;
|
||||
byte group;
|
||||
byte collect;
|
||||
word port;
|
||||
byte valid; // keep this as last byte
|
||||
} config;
|
||||
|
||||
// ethernet interface mac address - must be unique on your network
|
||||
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||
|
||||
// buffer for an outgoing data packet
|
||||
static byte outBuf[RF12_MAXDATA], outDest;
|
||||
static char outCount = -1;
|
||||
|
||||
// this buffer will be used to construct a collectd UDP packet
|
||||
static byte collBuf [200], collPos;
|
||||
|
||||
#define NUM_MESSAGES 3 // Number of messages saved in history
|
||||
#define MESSAGE_TRUNC 15 // Truncate message payload to reduce memory use
|
||||
|
||||
static BufferFiller bfill; // used as cursor while filling the buffer
|
||||
|
||||
static byte history_rcvd[NUM_MESSAGES][MESSAGE_TRUNC+1]; //history record
|
||||
static byte history_len[NUM_MESSAGES]; // # of RF12 messages+header in history
|
||||
static byte next_msg; // pointer to next rf12rcvd line
|
||||
static word msgs_rcvd; // total number of lines received modulo 10,000
|
||||
|
||||
byte Ethernet::buffer[700]; // tcp/ip send and receive buffer
|
||||
|
||||
static void loadConfig () {
|
||||
for (byte i = 0; i < sizeof config; ++i)
|
||||
((byte*) &config)[i] = eeprom_read_byte(CONFIG_EEPROM_ADDR + i);
|
||||
if (config.valid != 253) {
|
||||
config.valid = 253;
|
||||
config.band = 8;
|
||||
config.group = 1;
|
||||
config.collect = 1;
|
||||
config.port = 25827;
|
||||
}
|
||||
byte freq = config.band == 4 ? RF12_433MHZ :
|
||||
config.band == 8 ? RF12_868MHZ :
|
||||
RF12_915MHZ;
|
||||
rf12_initialize(31, freq, config.group);
|
||||
}
|
||||
|
||||
static void saveConfig () {
|
||||
for (byte i = 0; i < sizeof config; ++i)
|
||||
eeprom_write_byte(CONFIG_EEPROM_ADDR + i, ((byte*) &config)[i]);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
static int freeRam () {
|
||||
extern int __heap_start, *__brkval;
|
||||
int v;
|
||||
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
|
||||
}
|
||||
#endif
|
||||
|
||||
void setup (){
|
||||
Serial.begin(57600);
|
||||
Serial.println("\n[JeeUdp]");
|
||||
loadConfig();
|
||||
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||
Serial.println( "Failed to access Ethernet controller");
|
||||
if (!ether.dhcpSetup())
|
||||
Serial.println("DHCP failed");
|
||||
ether.printIp("IP: ", ether.myip);
|
||||
}
|
||||
|
||||
const char okHeader[] PROGMEM =
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Pragma: no-cache\r\n"
|
||||
;
|
||||
|
||||
static void homePage (BufferFiller& buf) {
|
||||
word mhz = config.band == 4 ? 433 : config.band == 8 ? 868 : 915;
|
||||
buf.emit_p(PSTR("$F\r\n"
|
||||
"<title>RF12 JeeUdp</title>"
|
||||
"<h2>RF12 JeeUdp @ $D - RF12 @ $D.$D</h2>"
|
||||
"<a href='c'>Configure</a> - <a href='s'>Send Packet</a>"
|
||||
"<h3>Last $D messages:</h3>"
|
||||
"<pre>"), okHeader, config.port, mhz, config.group, NUM_MESSAGES);
|
||||
for (byte i = 0; i < NUM_MESSAGES; ++i) {
|
||||
byte j = (next_msg + i) % NUM_MESSAGES;
|
||||
if (history_len[j] > 0) {
|
||||
word n = msgs_rcvd - NUM_MESSAGES + i;
|
||||
buf.emit_p(PSTR("\n$D$D$D$D: OK"), // hack, to show leading zero's
|
||||
n/1000, (n/100) % 10, (n/10) % 10, n % 10);
|
||||
for (byte k = 0; k < history_len[j]; ++k)
|
||||
buf.emit_p(PSTR(" $D"), history_rcvd[j][k]);
|
||||
}
|
||||
}
|
||||
long t = millis() / 1000;
|
||||
word h = t / 3600;
|
||||
byte m = (t / 60) % 60;
|
||||
byte s = t % 60;
|
||||
buf.emit_p(PSTR(
|
||||
"</pre>"
|
||||
"Uptime is $D$D:$D$D:$D$D"), h/10, h%10, m/10, m%10, s/10, s%10);
|
||||
#if DEBUG
|
||||
buf.emit_p(PSTR(" ($D bytes free)"), freeRam());
|
||||
#endif
|
||||
}
|
||||
|
||||
static int getIntArg(const char* data, const char* key, int value =-1) {
|
||||
char temp[10];
|
||||
if (ether.findKeyVal(data + 7, temp, sizeof temp, key) > 0)
|
||||
value = atoi(temp);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void configPage (const char* data, BufferFiller& buf) {
|
||||
// pick up submitted data, if present
|
||||
if (data[6] == '?') {
|
||||
byte b = getIntArg(data, "b", 8);
|
||||
byte g = getIntArg(data, "g", 1);
|
||||
byte c = getIntArg(data, "c", 0);
|
||||
word p = getIntArg(data, "p", 25827);
|
||||
if (1 <= g && g <= 250 && 1024 <= p && p <= 30000) {
|
||||
// store values as new settings
|
||||
config.band = b;
|
||||
config.group = g;
|
||||
config.collect = c;
|
||||
config.port = p;
|
||||
saveConfig();
|
||||
// re-init RF12 driver
|
||||
loadConfig();
|
||||
// clear history
|
||||
memset(history_len, 0, sizeof history_len);
|
||||
// redirect to the home page
|
||||
buf.emit_p(PSTR(
|
||||
"HTTP/1.0 302 found\r\n"
|
||||
"Location: /\r\n"
|
||||
"\r\n"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// else show a configuration form
|
||||
buf.emit_p(PSTR("$F\r\n"
|
||||
"<h3>Server node configuration</h3>"
|
||||
"<form>"
|
||||
"<p>"
|
||||
"Freq band <input type=text name=b value='$D' size=1> (4, 8, or 9)<br>"
|
||||
"Net group <input type=text name=g value='$D' size=3> (1..250)<br>"
|
||||
"Collect mode: <input type=checkbox name=c value='1' $S> "
|
||||
"(don't send ACKs)<br><br>"
|
||||
"UDP Port <input type=text name=p value='$D' size=5> (1024..30000)"
|
||||
"</p>"
|
||||
"<input type=submit value=Set>"
|
||||
"</form>"), okHeader, config.band, config.group,
|
||||
config.collect ? "CHECKED" : "",
|
||||
config.port);
|
||||
}
|
||||
|
||||
static void sendPage (const char* data, BufferFiller& buf) {
|
||||
// pick up submitted data, if present
|
||||
const char* p = strstr(data, "b=");
|
||||
byte d = getIntArg(data, "d");
|
||||
if (data[6] == '?' && p != 0 && 0 <= d && d <= 31) {
|
||||
// prepare to send data as soon as possible in loop()
|
||||
outDest = d & RF12_HDR_MASK ? RF12_HDR_DST | d : 0;
|
||||
outCount = 0;
|
||||
// convert the input string to a number of decimal data bytes in outBuf
|
||||
++p;
|
||||
while (*p != 0 && *p != '&') {
|
||||
outBuf[outCount] = 0;
|
||||
while ('0' <= *++p && *p <= '9')
|
||||
outBuf[outCount] = 10 * outBuf[outCount] + (*p - '0');
|
||||
++outCount;
|
||||
}
|
||||
#if SERIAL
|
||||
Serial.print("Send to ");
|
||||
Serial.print(outDest, DEC);
|
||||
Serial.print(':');
|
||||
for (byte i = 0; i < outCount; ++i) {
|
||||
Serial.print(' ');
|
||||
Serial.print(outBuf[i], DEC);
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
// redirect to home page
|
||||
buf.emit_p(PSTR(
|
||||
"HTTP/1.0 302 found\r\n"
|
||||
"Location: /\r\n"
|
||||
"\r\n"));
|
||||
return;
|
||||
}
|
||||
// else show a send form
|
||||
buf.emit_p(PSTR("$F\r\n"
|
||||
"<h3>Send a wireless data packet</h3>"
|
||||
"<form>"
|
||||
"<p>"
|
||||
"Data bytes <input type=text name=b size=50> (decimal)<br>"
|
||||
"Destination node <input type=text name=d size=3> "
|
||||
"(1..31, or 0 to broadcast)<br>"
|
||||
"</p>"
|
||||
"<input type=submit value=Send>"
|
||||
"</form>"), okHeader);
|
||||
}
|
||||
|
||||
static void collectTypeLen (word type, word len) {
|
||||
len += 4;
|
||||
collBuf[collPos++] = type >> 8;
|
||||
collBuf[collPos++] = (byte) type;
|
||||
collBuf[collPos++] = len >> 8;
|
||||
collBuf[collPos++] = (byte) len;
|
||||
}
|
||||
|
||||
static void collectStr (word type, const char* data) {
|
||||
word len = strlen(data) + 1;
|
||||
collectTypeLen(type, len);
|
||||
strcpy((char*) collBuf + collPos, data);
|
||||
collPos += len;
|
||||
}
|
||||
|
||||
static void collectPayload (word type) {
|
||||
// Copy the received RF12 data into a as many values as needed.
|
||||
byte num = rf12_len / 8 + 1; // this many values will be needed
|
||||
collectTypeLen(type, 2 + 9 * num);
|
||||
collBuf[collPos++] = 0;
|
||||
collBuf[collPos++] = num;
|
||||
for (byte i = 0; i < num; ++i)
|
||||
collBuf[collPos++] = 0; // counter
|
||||
for (char i = 0; i < 8 * num; ++i) // include -1, i.e. the length byte
|
||||
collBuf[collPos++] = i <= rf12_len ? rf12_data[i-1] : 0;
|
||||
}
|
||||
|
||||
static void forwardToUDP () {
|
||||
static byte destIp[] = { 239,192,74,66 }; // UDP multicast address
|
||||
char buf[10];
|
||||
|
||||
collPos = 0;
|
||||
collectStr(0x0000, "JeeUdp");
|
||||
collectStr(0x0002, "RF12");
|
||||
word mhz = config.band == 4 ? 433 : config.band == 8 ? 868 : 915;
|
||||
sprintf(buf, "%d.%d", mhz, config.group);
|
||||
collectStr(0x0003, buf);
|
||||
collectStr(0x0004, "OK");
|
||||
sprintf(buf, "%d", rf12_hdr);
|
||||
collectStr(0x0005, buf);
|
||||
collectPayload(0x0006);
|
||||
|
||||
ether.sendUdp ((char*) collBuf, collPos, 23456, destIp, config.port);
|
||||
#if SERIAL
|
||||
Serial.println("UDP sent");
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop (){
|
||||
word len = ether.packetReceive();
|
||||
word pos = ether.packetLoop(len);
|
||||
// check if valid tcp data is received
|
||||
if (pos) {
|
||||
bfill = ether.tcpOffset();
|
||||
char* data = (char *) Ethernet::buffer + pos;
|
||||
#if SERIAL
|
||||
Serial.println(data);
|
||||
#endif
|
||||
// receive buf hasn't been clobbered by reply yet
|
||||
if (strncmp("GET / ", data, 6) == 0)
|
||||
homePage(bfill);
|
||||
else if (strncmp("GET /c", data, 6) == 0)
|
||||
configPage(data, bfill);
|
||||
else if (strncmp("GET /s", data, 6) == 0)
|
||||
sendPage(data, bfill);
|
||||
else
|
||||
bfill.emit_p(PSTR(
|
||||
"HTTP/1.0 401 Unauthorized\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"\r\n"
|
||||
"<h1>401 Unauthorized</h1>"));
|
||||
ether.httpServerReply(bfill.position()); // send web page data
|
||||
}
|
||||
|
||||
// RFM12 loop runner, don't report acks
|
||||
if (rf12_recvDone() && rf12_crc == 0 && (rf12_hdr & RF12_HDR_CTL) == 0) {
|
||||
history_rcvd[next_msg][0] = rf12_hdr;
|
||||
for (byte i = 0; i < rf12_len; ++i)
|
||||
if (i < MESSAGE_TRUNC)
|
||||
history_rcvd[next_msg][i+1] = rf12_data[i];
|
||||
history_len[next_msg] = rf12_len < MESSAGE_TRUNC ? rf12_len+1
|
||||
: MESSAGE_TRUNC+1;
|
||||
next_msg = (next_msg + 1) % NUM_MESSAGES;
|
||||
msgs_rcvd = (msgs_rcvd + 1) % 10000;
|
||||
|
||||
if (RF12_WANTS_ACK && !config.collect) {
|
||||
#if SERIAL
|
||||
Serial.println(" -> ack");
|
||||
#endif
|
||||
rf12_sendStart(RF12_ACK_REPLY, 0, 0);
|
||||
}
|
||||
|
||||
forwardToUDP();
|
||||
}
|
||||
|
||||
// send a data packet out if requested
|
||||
if (outCount >= 0 && rf12_canSend()) {
|
||||
rf12_sendStart(outDest, outBuf, outCount, 1);
|
||||
outCount = -1;
|
||||
}
|
||||
}
|
||||
|
||||
144
lib-ext/ethercard.git/examples/SSDP/SSDP.ino
Normal file
144
lib-ext/ethercard.git/examples/SSDP/SSDP.ino
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
#include <EtherCard.h>// |Mac adress|
|
||||
const char SSDP_RESPONSE[] PROGMEM = "HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1200\r\nEXT:\r\nSERVER:Arduino\r\nST: upnp:rootdevice\r\nUSN: uuid:abcdefgh-7dec-11d0-a765-7499692d3040\r\nLOCATION: http://"; //dont forget our mac adress USN: uuid:abcdefgh-7dec-11d0-a765-Mac addr
|
||||
const char SSDP_RESPONSE_XML[] PROGMEM = "/??\r\n\r\n"; // here is the adress of xml file /?? in this exemple but you could use another /upnp.xml\r\n\r\n
|
||||
const char XML_DESCRIP[] PROGMEM = "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n\r\n<?xml version='1.0'?>\r<root xmlns='urn:schemas-upnp-org:device-1-0'><device><deviceType>urn:schemas-upnp-org:device:BinaryLight:1</deviceType><presentationURL>/</presentationURL><friendlyName>Arduino</friendlyName><manufacturer>Fredycpu</manufacturer><manufacturerURL>http://fredycpu.pro</manufacturerURL><serialNumber>1</serialNumber><UDN>uuid:abcdefgh-7dec-11d0-a765-7499692d3040</UDN></device></root> ";
|
||||
const char SSDP_NOTIFY[] PROGMEM = "NOTIFY * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nCACHE-CONTROL: max-age=1200\r\nNT: upnp:rootdevice\r\nUSN: uuid:abcdefga-7dec-11d0-a765-7499692d3040::upnp:rootdevice\r\nNTS: ssdp:alive\r\nSERVER: Arduino UPnP/1.0\r\nLOCATION: http://"; //dont forget our mac adress USN: uuid:abcdefgh-7dec-11d0-a765-Mac addr
|
||||
// in XML_DESCRIP // <deviceType>urn:schemas-upnp-org:device:BinaryLight:1</deviceType> // declare as home automation
|
||||
// in XML_DESCRIP // <friendlyName>Arduino</friendlyName> // declare the name of the service here Arduino
|
||||
// in XML_DESCRIP // <presentationURL>/</presentationURL> // adress of the page who would opened on service double click ,you could use http://ip but if you use dhcp it's better so and dont wase memory
|
||||
// this is the entire protocol, but you can try to use SSDP_NOTIFY as SSDP_RESPONSE with most systems will work and you can free a bit of flash mem.
|
||||
static byte myip[] = {
|
||||
192,168,0,67 };
|
||||
static byte gwip[] = {
|
||||
192,168,0,250 };
|
||||
static byte ssdp[] = {
|
||||
239,255,255,250 };
|
||||
static byte mymac[] = {
|
||||
0x74,0x99,0x69,0x2D,0x30,0x40 }; // if you change it you must update SSDP_RESPONSE and XML_DESCRIP
|
||||
byte Ethernet::buffer[750]; // tcp ip send and receive buffer
|
||||
unsigned long timer=9999;
|
||||
const char pageA[] PROGMEM =
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"\r\n"
|
||||
"<html>"
|
||||
"<head><title>"
|
||||
"multipackets Test"
|
||||
"</title></head>"
|
||||
"<body>"
|
||||
"<a href='/'>Start here</a><br>"
|
||||
"<a href='/test.jpg'>Image test</a><br>"
|
||||
"<h3>packet 1</h3>"
|
||||
"<p><em>"
|
||||
"the first packet send "
|
||||
"</em></p>"
|
||||
;
|
||||
const char pageB[] PROGMEM =
|
||||
"<h3>packet 2</h3>"
|
||||
"<p><em>"
|
||||
"if you read this it mean it works"
|
||||
"</em></p>"
|
||||
;
|
||||
const char pageC[] PROGMEM =
|
||||
"<h3>packet 3</h3>"
|
||||
"<p><em>"
|
||||
"if you read this it mean it works"
|
||||
"</em></p>"
|
||||
;
|
||||
const char pageD[] PROGMEM =
|
||||
"<h3>packet 4</h3>"
|
||||
"<p><em>"
|
||||
"if you read this it mean it works"
|
||||
"</em></p>"
|
||||
;
|
||||
|
||||
void setup(){
|
||||
ether.begin(sizeof Ethernet::buffer, mymac , 10);// 53 for the mega ethernet shield and 10 for normal ethernet shield
|
||||
ether.staticSetup(myip, gwip);
|
||||
ENC28J60::disableMulticast(); //disable multicast filter means enable multicast reception
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
wait:
|
||||
word pos = ether.packetLoop(ether.packetReceive());
|
||||
// check if valid tcp data is received
|
||||
if (pos) {
|
||||
char* data = (char *) Ethernet::buffer + pos;
|
||||
if (strncmp("GET / ", data, 6) == 0) {
|
||||
ether.httpServerReplyAck(); // send ack to the request
|
||||
memcpy_P(ether.tcpOffset(), pageA, sizeof pageA); // send first packet and not send the terminate flag
|
||||
ether.httpServerReply_with_flags(sizeof pageA - 1,TCP_FLAGS_ACK_V);
|
||||
memcpy_P(ether.tcpOffset(), pageB, sizeof pageB); // send second packet and not send the terminate flag
|
||||
ether.httpServerReply_with_flags(sizeof pageB - 1,TCP_FLAGS_ACK_V);
|
||||
memcpy_P(ether.tcpOffset(), pageC, sizeof pageC); // send thirdt packet and not send the terminate flag
|
||||
ether.httpServerReply_with_flags(sizeof pageC - 1,TCP_FLAGS_ACK_V);
|
||||
memcpy_P(ether.tcpOffset(), pageD, sizeof pageD); // send fourth packet and send the terminate flag
|
||||
ether.httpServerReply_with_flags(sizeof pageD - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V);
|
||||
goto wait;
|
||||
}
|
||||
if (strncmp("GET /??", data, 7) == 0) { // description of services (normaly an xml file but here .....)
|
||||
ether.httpServerReplyAck();
|
||||
memcpy_P(Ethernet::buffer + TCP_OPTIONS_P,XML_DESCRIP, sizeof XML_DESCRIP);
|
||||
ether.httpServerReply_with_flags(sizeof XML_DESCRIP - 1 ,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V);
|
||||
goto wait;
|
||||
}
|
||||
if (strncmp("M-SEARCH", data, 8) == 0) { // service discovery request comes here (udp protocol)
|
||||
ssdpresp();
|
||||
goto wait;
|
||||
}
|
||||
}
|
||||
if (((millis()-timer)>50000)||(timer>millis())) {
|
||||
timer=millis();
|
||||
ssdpnotify();
|
||||
}
|
||||
}
|
||||
void ssdpresp() { //response to m-search
|
||||
byte ip_dst[4];
|
||||
unsigned int port_dst=Ethernet::buffer[34]*256+Ethernet::buffer[35];//extract source port of request
|
||||
for( int i=0; i<4;i++) { //extract source IP of request
|
||||
ip_dst[i]=Ethernet::buffer[i+26];
|
||||
}
|
||||
int udppos = UDP_DATA_P;
|
||||
|
||||
EtherCard::udpPrepare(1900,ip_dst,port_dst);
|
||||
memcpy_P(Ethernet::buffer + udppos, SSDP_RESPONSE, sizeof SSDP_RESPONSE);
|
||||
udppos = udppos + sizeof SSDP_RESPONSE-1;
|
||||
addip(udppos);
|
||||
}
|
||||
|
||||
void ssdpnotify() { //Notification
|
||||
int udppos = UDP_DATA_P;
|
||||
EtherCard::udpPrepare(1900,ssdp,1900);
|
||||
memcpy_P(Ethernet::buffer + udppos, SSDP_NOTIFY, sizeof SSDP_NOTIFY);
|
||||
udppos = udppos + sizeof SSDP_NOTIFY-1;
|
||||
addip(udppos);
|
||||
}
|
||||
|
||||
void addip(int udppos) { // add current ip to the request and send it
|
||||
int adr;
|
||||
for(int i=0;i<4;i++) { // extract the current ip of arduino
|
||||
adr = ether.myip[i]/100;
|
||||
if (adr) {
|
||||
Ethernet::buffer[udppos]=adr+48;
|
||||
udppos++;
|
||||
}
|
||||
adr=(ether.myip[i]%100)/10;
|
||||
if (adr) {
|
||||
Ethernet::buffer[udppos]=adr+48;
|
||||
udppos++;
|
||||
}
|
||||
adr=ether.myip[i]%10;
|
||||
Ethernet::buffer[udppos]=adr+48;
|
||||
udppos++;
|
||||
Ethernet::buffer[udppos]=46;
|
||||
udppos++; //"."
|
||||
}
|
||||
udppos--;//erase the last point
|
||||
memcpy_P(Ethernet::buffer + udppos,SSDP_RESPONSE_XML,sizeof SSDP_RESPONSE_XML);
|
||||
udppos = udppos + sizeof SSDP_RESPONSE_XML;
|
||||
udppos--;
|
||||
EtherCard::udpTransmit(udppos-UDP_DATA_P); // send all to the computer who make the request on her ip and port who make the request
|
||||
}
|
||||
|
||||
|
||||
63
lib-ext/ethercard.git/examples/backSoon/backSoon.ino
Normal file
63
lib-ext/ethercard.git/examples/backSoon/backSoon.ino
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// Present a "Will be back soon web page", as stand-in webserver.
|
||||
// 2011-01-30 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
|
||||
|
||||
#include <EtherCard.h>
|
||||
|
||||
#define STATIC 0 // set to 1 to disable DHCP (adjust myip/gwip values below)
|
||||
|
||||
#if STATIC
|
||||
// ethernet interface ip address
|
||||
static byte myip[] = { 192,168,1,200 };
|
||||
// gateway ip address
|
||||
static byte gwip[] = { 192,168,1,1 };
|
||||
#endif
|
||||
|
||||
// ethernet mac address - must be unique on your network
|
||||
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||
|
||||
byte Ethernet::buffer[500]; // tcp/ip send and receive buffer
|
||||
|
||||
const char page[] PROGMEM =
|
||||
"HTTP/1.0 503 Service Unavailable\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Retry-After: 600\r\n"
|
||||
"\r\n"
|
||||
"<html>"
|
||||
"<head><title>"
|
||||
"Service Temporarily Unavailable"
|
||||
"</title></head>"
|
||||
"<body>"
|
||||
"<h3>This service is currently unavailable</h3>"
|
||||
"<p><em>"
|
||||
"The main server is currently off-line.<br />"
|
||||
"Please try again later."
|
||||
"</em></p>"
|
||||
"</body>"
|
||||
"</html>"
|
||||
;
|
||||
|
||||
void setup(){
|
||||
Serial.begin(57600);
|
||||
Serial.println("\n[backSoon]");
|
||||
|
||||
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||
Serial.println( "Failed to access Ethernet controller");
|
||||
#if STATIC
|
||||
ether.staticSetup(myip, gwip);
|
||||
#else
|
||||
if (!ether.dhcpSetup())
|
||||
Serial.println("DHCP failed");
|
||||
#endif
|
||||
|
||||
ether.printIp("IP: ", ether.myip);
|
||||
ether.printIp("GW: ", ether.gwip);
|
||||
ether.printIp("DNS: ", ether.dnsip);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
// wait for an incoming TCP packet, but ignore its contents
|
||||
if (ether.packetLoop(ether.packetReceive())) {
|
||||
memcpy_P(ether.tcpOffset(), page, sizeof page);
|
||||
ether.httpServerReply(sizeof page - 1);
|
||||
}
|
||||
}
|
||||
276
lib-ext/ethercard.git/examples/etherNode/etherNode.ino
Normal file
276
lib-ext/ethercard.git/examples/etherNode/etherNode.ino
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
// Arduino demo sketch for testing RFM12B + ethernet
|
||||
// 2010-05-20 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
|
||||
|
||||
// Listens for RF12 messages and displays valid messages on a webpage
|
||||
// Memory usage exceeds 1K, so use Atmega328 or decrease history/buffers
|
||||
//
|
||||
// This sketch is derived from RF12eth.pde:
|
||||
// May 2010, Andras Tucsni, http://opensource.org/licenses/mit-license.php
|
||||
|
||||
#include <EtherCard.h>
|
||||
#include <JeeLib.h>
|
||||
#include <avr/eeprom.h>
|
||||
|
||||
#define DEBUG 1 // set to 1 to display free RAM on web page
|
||||
#define SERIAL 0 // set to 1 to show incoming requests on serial port
|
||||
|
||||
#define CONFIG_EEPROM_ADDR ((byte*) 0x10)
|
||||
|
||||
// configuration, as stored in EEPROM
|
||||
struct Config {
|
||||
byte band;
|
||||
byte group;
|
||||
byte collect;
|
||||
word refresh;
|
||||
byte valid; // keep this as last byte
|
||||
} config;
|
||||
|
||||
// ethernet interface mac address - must be unique on your network
|
||||
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||
|
||||
// buffer for an outgoing data packet
|
||||
static byte outBuf[RF12_MAXDATA], outDest;
|
||||
static char outCount = -1;
|
||||
|
||||
#define NUM_MESSAGES 10 // Number of messages saved in history
|
||||
#define MESSAGE_TRUNC 15 // Truncate message payload to reduce memory use
|
||||
|
||||
static BufferFiller bfill; // used as cursor while filling the buffer
|
||||
|
||||
static byte history_rcvd[NUM_MESSAGES][MESSAGE_TRUNC+1]; //history record
|
||||
static byte history_len[NUM_MESSAGES]; // # of RF12 messages+header in history
|
||||
static byte next_msg; // pointer to next rf12rcvd line
|
||||
static word msgs_rcvd; // total number of lines received modulo 10,000
|
||||
|
||||
byte Ethernet::buffer[1000]; // tcp/ip send and receive buffer
|
||||
|
||||
static void loadConfig() {
|
||||
for (byte i = 0; i < sizeof config; ++i)
|
||||
((byte*) &config)[i] = eeprom_read_byte(CONFIG_EEPROM_ADDR + i);
|
||||
if (config.valid != 253) {
|
||||
config.valid = 253;
|
||||
config.band = 8;
|
||||
config.group = 1;
|
||||
config.collect = 1;
|
||||
config.refresh = 5;
|
||||
}
|
||||
byte freq = config.band == 4 ? RF12_433MHZ :
|
||||
config.band == 8 ? RF12_868MHZ :
|
||||
RF12_915MHZ;
|
||||
rf12_initialize(31, freq, config.group);
|
||||
}
|
||||
|
||||
static void saveConfig() {
|
||||
for (byte i = 0; i < sizeof config; ++i)
|
||||
eeprom_write_byte(CONFIG_EEPROM_ADDR + i, ((byte*) &config)[i]);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
static int freeRam () {
|
||||
extern int __heap_start, *__brkval;
|
||||
int v;
|
||||
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
|
||||
}
|
||||
#endif
|
||||
|
||||
void setup(){
|
||||
#if SERIAL
|
||||
Serial.begin(57600);
|
||||
Serial.println("\n[etherNode]");
|
||||
#endif
|
||||
loadConfig();
|
||||
|
||||
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||
Serial.println( "Failed to access Ethernet controller");
|
||||
if (!ether.dhcpSetup())
|
||||
Serial.println("DHCP failed");
|
||||
#if SERIAL
|
||||
ether.printIp("IP: ", ether.myip);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char okHeader[] PROGMEM =
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Pragma: no-cache\r\n"
|
||||
;
|
||||
|
||||
static void homePage(BufferFiller& buf) {
|
||||
word mhz = config.band == 4 ? 433 : config.band == 8 ? 868 : 915;
|
||||
buf.emit_p(PSTR("$F\r\n"
|
||||
"<meta http-equiv='refresh' content='$D'/>"
|
||||
"<title>RF12 etherNode - $D MHz, group $D</title>"
|
||||
"RF12 etherNode - $D MHz, group $D "
|
||||
"- <a href='c'>configure</a> - <a href='s'>send packet</a>"
|
||||
"<h3>Last $D messages:</h3>"
|
||||
"<pre>"), okHeader, config.refresh, mhz, config.group,
|
||||
mhz, config.group, NUM_MESSAGES);
|
||||
for (byte i = 0; i < NUM_MESSAGES; ++i) {
|
||||
byte j = (next_msg + i) % NUM_MESSAGES;
|
||||
if (history_len[j] > 0) {
|
||||
word n = msgs_rcvd - NUM_MESSAGES + i;
|
||||
buf.emit_p(PSTR("\n$D$D$D$D: OK"), // hack, to show leading zero's
|
||||
n/1000, (n/100) % 10, (n/10) % 10, n % 10);
|
||||
for (byte k = 0; k < history_len[j]; ++k)
|
||||
buf.emit_p(PSTR(" $D"), history_rcvd[j][k]);
|
||||
}
|
||||
}
|
||||
long t = millis() / 1000;
|
||||
word h = t / 3600;
|
||||
byte m = (t / 60) % 60;
|
||||
byte s = t % 60;
|
||||
buf.emit_p(PSTR(
|
||||
"</pre>"
|
||||
"Uptime is $D$D:$D$D:$D$D"), h/10, h%10, m/10, m%10, s/10, s%10);
|
||||
#if DEBUG
|
||||
buf.emit_p(PSTR(" ($D bytes free)"), freeRam());
|
||||
#endif
|
||||
}
|
||||
|
||||
static int getIntArg(const char* data, const char* key, int value =-1) {
|
||||
char temp[10];
|
||||
if (ether.findKeyVal(data + 7, temp, sizeof temp, key) > 0)
|
||||
value = atoi(temp);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void configPage(const char* data, BufferFiller& buf) {
|
||||
// pick up submitted data, if present
|
||||
if (data[6] == '?') {
|
||||
byte b = getIntArg(data, "b");
|
||||
byte g = getIntArg(data, "g");
|
||||
byte c = getIntArg(data, "c", 0);
|
||||
word r = getIntArg(data, "r");
|
||||
if (1 <= g && g <= 250 && 1 <= r && r <= 3600) {
|
||||
// store values as new settings
|
||||
config.band = b;
|
||||
config.group = g;
|
||||
config.collect = c;
|
||||
config.refresh = r;
|
||||
saveConfig();
|
||||
// re-init RF12 driver
|
||||
loadConfig();
|
||||
// clear history
|
||||
memset(history_len, 0, sizeof history_len);
|
||||
// redirect to the home page
|
||||
buf.emit_p(PSTR(
|
||||
"HTTP/1.0 302 found\r\n"
|
||||
"Location: /\r\n"
|
||||
"\r\n"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// else show a configuration form
|
||||
buf.emit_p(PSTR("$F\r\n"
|
||||
"<h3>Server node configuration</h3>"
|
||||
"<form>"
|
||||
"<p>"
|
||||
"Freq band <input type=text name=b value='$D' size=1> (4, 8, or 9)<br>"
|
||||
"Net group <input type=text name=g value='$D' size=3> (1..250)<br>"
|
||||
"Collect mode: <input type=checkbox name=c value='1' $S> "
|
||||
"Don't send ACKs<br><br>"
|
||||
"Refresh rate <input type=text name=r value='$D' size=4> (1..3600 seconds)"
|
||||
"</p>"
|
||||
"<input type=submit value=Set>"
|
||||
"</form>"), okHeader, config.band, config.group,
|
||||
config.collect ? "CHECKED" : "",
|
||||
config.refresh);
|
||||
}
|
||||
|
||||
static void sendPage(const char* data, BufferFiller& buf) {
|
||||
// pick up submitted data, if present
|
||||
const char* p = strstr(data, "b=");
|
||||
byte d = getIntArg(data, "d");
|
||||
if (data[6] == '?' && p != 0 && 0 <= d && d <= 31) {
|
||||
// prepare to send data as soon as possible in loop()
|
||||
outDest = d & RF12_HDR_MASK ? RF12_HDR_DST | d : 0;
|
||||
outCount = 0;
|
||||
// convert the input string to a number of decimal data bytes in outBuf
|
||||
++p;
|
||||
while (*p != 0 && *p != '&') {
|
||||
outBuf[outCount] = 0;
|
||||
while ('0' <= *++p && *p <= '9')
|
||||
outBuf[outCount] = 10 * outBuf[outCount] + (*p - '0');
|
||||
++outCount;
|
||||
}
|
||||
#if SERIAL
|
||||
Serial.print("Send to ");
|
||||
Serial.print(outDest, DEC);
|
||||
Serial.print(':');
|
||||
for (byte i = 0; i < outCount; ++i) {
|
||||
Serial.print(' ');
|
||||
Serial.print(outBuf[i], DEC);
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
// redirect to home page
|
||||
buf.emit_p(PSTR(
|
||||
"HTTP/1.0 302 found\r\n"
|
||||
"Location: /\r\n"
|
||||
"\r\n"));
|
||||
return;
|
||||
}
|
||||
// else show a send form
|
||||
buf.emit_p(PSTR("$F\r\n"
|
||||
"<h3>Send a wireless data packet</h3>"
|
||||
"<form>"
|
||||
"<p>"
|
||||
"Data bytes <input type=text name=b size=50> (decimal)<br>"
|
||||
"Destination node <input type=text name=d size=3> "
|
||||
"(1..31, or 0 to broadcast)<br>"
|
||||
"</p>"
|
||||
"<input type=submit value=Send>"
|
||||
"</form>"), okHeader);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
word len = ether.packetReceive();
|
||||
word pos = ether.packetLoop(len);
|
||||
// check if valid tcp data is received
|
||||
if (pos) {
|
||||
bfill = ether.tcpOffset();
|
||||
char* data = (char *) Ethernet::buffer + pos;
|
||||
#if SERIAL
|
||||
Serial.println(data);
|
||||
#endif
|
||||
// receive buf hasn't been clobbered by reply yet
|
||||
if (strncmp("GET / ", data, 6) == 0)
|
||||
homePage(bfill);
|
||||
else if (strncmp("GET /c", data, 6) == 0)
|
||||
configPage(data, bfill);
|
||||
else if (strncmp("GET /s", data, 6) == 0)
|
||||
sendPage(data, bfill);
|
||||
else
|
||||
bfill.emit_p(PSTR(
|
||||
"HTTP/1.0 401 Unauthorized\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"\r\n"
|
||||
"<h1>401 Unauthorized</h1>"));
|
||||
ether.httpServerReply(bfill.position()); // send web page data
|
||||
}
|
||||
|
||||
// RFM12 loop runner, don't report acks
|
||||
if (rf12_recvDone() && rf12_crc == 0 && (rf12_hdr & RF12_HDR_CTL) == 0) {
|
||||
history_rcvd[next_msg][0] = rf12_hdr;
|
||||
for (byte i = 0; i < rf12_len; ++i)
|
||||
if (i < MESSAGE_TRUNC)
|
||||
history_rcvd[next_msg][i+1] = rf12_data[i];
|
||||
history_len[next_msg] = rf12_len < MESSAGE_TRUNC ? rf12_len+1
|
||||
: MESSAGE_TRUNC+1;
|
||||
next_msg = (next_msg + 1) % NUM_MESSAGES;
|
||||
msgs_rcvd = (msgs_rcvd + 1) % 10000;
|
||||
|
||||
if (RF12_WANTS_ACK && !config.collect) {
|
||||
#if SERIAL
|
||||
Serial.println(" -> ack");
|
||||
#endif
|
||||
rf12_sendStart(RF12_ACK_REPLY, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// send a data packet out if requested
|
||||
if (outCount >= 0 && rf12_canSend()) {
|
||||
rf12_sendStart(outDest, outBuf, outCount, 1);
|
||||
outCount = -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
// This demo does web requests via DHCP and DNS lookup.
|
||||
// 2011-07-05 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
|
||||
|
||||
#include <EtherCard.h>
|
||||
|
||||
#define REQUEST_RATE 5000 // milliseconds
|
||||
|
||||
// ethernet interface mac address
|
||||
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||
// remote website name
|
||||
const char website[] PROGMEM = "google.com";
|
||||
|
||||
byte Ethernet::buffer[700];
|
||||
static long timer;
|
||||
|
||||
// called when the client request is complete
|
||||
static void my_result_cb (byte status, word off, word len) {
|
||||
Serial.print("<<< reply ");
|
||||
Serial.print(millis() - timer);
|
||||
Serial.println(" ms");
|
||||
Serial.println((const char*) Ethernet::buffer + off);
|
||||
}
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
Serial.println("\n[getDHCPandDNS]");
|
||||
|
||||
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||
Serial.println( "Failed to access Ethernet controller");
|
||||
|
||||
if (!ether.dhcpSetup())
|
||||
Serial.println("DHCP failed");
|
||||
|
||||
ether.printIp("My IP: ", ether.myip);
|
||||
// ether.printIp("Netmask: ", ether.mymask);
|
||||
ether.printIp("GW IP: ", ether.gwip);
|
||||
ether.printIp("DNS IP: ", ether.dnsip);
|
||||
|
||||
if (!ether.dnsLookup(website))
|
||||
Serial.println("DNS failed");
|
||||
ether.printIp("Server: ", ether.hisip);
|
||||
|
||||
timer = - REQUEST_RATE; // start timing out right away
|
||||
}
|
||||
|
||||
void loop () {
|
||||
|
||||
ether.packetLoop(ether.packetReceive());
|
||||
|
||||
if (millis() > timer + REQUEST_RATE) {
|
||||
timer = millis();
|
||||
Serial.println("\n>>> REQ");
|
||||
ether.browseUrl(PSTR("/foo/"), "bar", website, my_result_cb);
|
||||
}
|
||||
}
|
||||
57
lib-ext/ethercard.git/examples/getStaticIP/getStaticIP.ino
Normal file
57
lib-ext/ethercard.git/examples/getStaticIP/getStaticIP.ino
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// This demo does web requests to a fixed IP address, using a fixed gateway.
|
||||
// 2010-11-27 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
|
||||
|
||||
#include <EtherCard.h>
|
||||
|
||||
#define REQUEST_RATE 5000 // milliseconds
|
||||
|
||||
// ethernet interface mac address
|
||||
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||
// ethernet interface ip address
|
||||
static byte myip[] = { 192,168,1,203 };
|
||||
// gateway ip address
|
||||
static byte gwip[] = { 192,168,1,1 };
|
||||
// remote website ip address and port
|
||||
static byte hisip[] = { 74,125,79,99 };
|
||||
// remote website name
|
||||
const char website[] PROGMEM = "google.com";
|
||||
|
||||
byte Ethernet::buffer[300]; // a very small tcp/ip buffer is enough here
|
||||
static long timer;
|
||||
|
||||
// called when the client request is complete
|
||||
static void my_result_cb (byte status, word off, word len) {
|
||||
Serial.print("<<< reply ");
|
||||
Serial.print(millis() - timer);
|
||||
Serial.println(" ms");
|
||||
Serial.println((const char*) Ethernet::buffer + off);
|
||||
}
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
Serial.println("\n[getStaticIP]");
|
||||
|
||||
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||
Serial.println( "Failed to access Ethernet controller");
|
||||
|
||||
ether.staticSetup(myip, gwip);
|
||||
|
||||
ether.copyIp(ether.hisip, hisip);
|
||||
ether.printIp("Server: ", ether.hisip);
|
||||
|
||||
while (ether.clientWaitingGw())
|
||||
ether.packetLoop(ether.packetReceive());
|
||||
Serial.println("Gateway found");
|
||||
|
||||
timer = - REQUEST_RATE; // start timing out right away
|
||||
}
|
||||
|
||||
void loop () {
|
||||
ether.packetLoop(ether.packetReceive());
|
||||
|
||||
if (millis() > timer + REQUEST_RATE) {
|
||||
timer = millis();
|
||||
Serial.println("\n>>> REQ");
|
||||
ether.browseUrl(PSTR("/foo/"), "bar", website, my_result_cb);
|
||||
}
|
||||
}
|
||||
52
lib-ext/ethercard.git/examples/getViaDNS/getViaDNS.ino
Normal file
52
lib-ext/ethercard.git/examples/getViaDNS/getViaDNS.ino
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// This demo does web requests via DNS lookup, using a fixed gateway.
|
||||
// 2010-11-27 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
|
||||
|
||||
#include <EtherCard.h>
|
||||
|
||||
#define REQUEST_RATE 5000 // milliseconds
|
||||
|
||||
// ethernet interface mac address
|
||||
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||
// ethernet interface ip address
|
||||
static byte myip[] = { 192,168,1,203 };
|
||||
// gateway ip address
|
||||
static byte gwip[] = { 192,168,1,1 };
|
||||
// remote website name
|
||||
const char website[] PROGMEM = "google.com";
|
||||
|
||||
byte Ethernet::buffer[300]; // a very small tcp/ip buffer is enough here
|
||||
static long timer;
|
||||
|
||||
// called when the client request is complete
|
||||
static void my_result_cb (byte status, word off, word len) {
|
||||
Serial.print("<<< reply ");
|
||||
Serial.print(millis() - timer);
|
||||
Serial.println(" ms");
|
||||
Serial.println((const char*) Ethernet::buffer + off);
|
||||
}
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
Serial.println("\n[getViaDNS]");
|
||||
|
||||
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||
Serial.println( "Failed to access Ethernet controller");
|
||||
|
||||
ether.staticSetup(myip, gwip);
|
||||
|
||||
if (!ether.dnsLookup(website))
|
||||
Serial.println("DNS failed");
|
||||
ether.printIp("Server: ", ether.hisip);
|
||||
|
||||
timer = - REQUEST_RATE; // start timing out right away
|
||||
}
|
||||
|
||||
void loop () {
|
||||
ether.packetLoop(ether.packetReceive());
|
||||
|
||||
if (millis() > timer + REQUEST_RATE) {
|
||||
timer = millis();
|
||||
Serial.println("\n>>> REQ");
|
||||
ether.browseUrl(PSTR("/foo/"), "bar", website, my_result_cb);
|
||||
}
|
||||
}
|
||||
77
lib-ext/ethercard.git/examples/multipacket/multipacket.ino
Normal file
77
lib-ext/ethercard.git/examples/multipacket/multipacket.ino
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#include <EtherCard.h>
|
||||
#define TCP_FLAGS_FIN_V 1 //as declared in net.h
|
||||
#define TCP_FLAGS_ACK_V 0x10 //as declared in net.h
|
||||
static byte myip[] = { 192,168,0,66 };
|
||||
static byte gwip[] = { 192,168,0,250 };
|
||||
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x39 };
|
||||
byte Ethernet::buffer[900]; // tcp ip send and receive buffer
|
||||
const char pageA[] PROGMEM =
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"\r\n"
|
||||
"<html>"
|
||||
"<head><title>"
|
||||
"multipackets Test"
|
||||
"</title></head>"
|
||||
"<body>"
|
||||
"<a href='/'>Start here</a><br>"
|
||||
"<h3>packet 1</h3>"
|
||||
"<p><em>"
|
||||
"the first packet send "
|
||||
"</em></p>"
|
||||
;
|
||||
const char pageB[] PROGMEM =
|
||||
"<h3>packet 2</h3>"
|
||||
"<p><em>"
|
||||
"if you read this it mean it works"
|
||||
"</em></p>"
|
||||
;
|
||||
const char pageC[] PROGMEM =
|
||||
"<h3>packet 3</h3>"
|
||||
"<p><em>"
|
||||
"if you read this it mean it works"
|
||||
"</em></p>"
|
||||
;
|
||||
const char pageD[] PROGMEM =
|
||||
"<h3>packet 4</h3>"
|
||||
"<p><em>"
|
||||
"if you read this it mean it works"
|
||||
"</em></p>"
|
||||
;
|
||||
const char pageE[] PROGMEM =
|
||||
"<h3>packet 5</h3>"
|
||||
"<p><em>"
|
||||
"this is the last packet"
|
||||
"</em></p>"
|
||||
;
|
||||
|
||||
|
||||
void setup(){
|
||||
ether.begin(sizeof Ethernet::buffer, mymac , 10);// 53 for the mega ethernet shield and 10 for normal ethernet shield
|
||||
ether.staticSetup(myip, gwip);
|
||||
}
|
||||
void loop(){
|
||||
word pos = ether.packetLoop(ether.packetReceive());
|
||||
// check if valid tcp data is received
|
||||
if (pos) {
|
||||
char* data = (char *) Ethernet::buffer + pos;
|
||||
if (strncmp("GET / ", data, 6) == 0) {
|
||||
ether.httpServerReplyAck(); // send ack to the request
|
||||
memcpy_P(ether.tcpOffset(), pageA, sizeof pageA); // send first packet and not send the terminate flag
|
||||
ether.httpServerReply_with_flags(sizeof pageA - 1,TCP_FLAGS_ACK_V);
|
||||
memcpy_P(ether.tcpOffset(), pageB, sizeof pageB); // send second packet and not send the terminate flag
|
||||
ether.httpServerReply_with_flags(sizeof pageB - 1,TCP_FLAGS_ACK_V);
|
||||
memcpy_P(ether.tcpOffset(), pageC, sizeof pageC); // send thirdt packet and not send the terminate flag
|
||||
ether.httpServerReply_with_flags(sizeof pageC - 1,TCP_FLAGS_ACK_V);
|
||||
memcpy_P(ether.tcpOffset(), pageD, sizeof pageD); // send fourth packet and not send the terminate flag
|
||||
ether.httpServerReply_with_flags(sizeof pageD - 1,TCP_FLAGS_ACK_V);
|
||||
memcpy_P(ether.tcpOffset(), pageE, sizeof pageE); // send fiveth packet and send the terminate flag
|
||||
ether.httpServerReply_with_flags(sizeof pageE - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V); }
|
||||
else
|
||||
{
|
||||
ether.httpServerReplyAck(); // send ack to the request
|
||||
memcpy_P(ether.tcpOffset(), pageA, sizeof pageA);//only the first part will sended
|
||||
ether.httpServerReply_with_flags(sizeof pageA - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V);
|
||||
}
|
||||
}
|
||||
}
|
||||
129
lib-ext/ethercard.git/examples/multipacketSD/multipacketSD.ino
Normal file
129
lib-ext/ethercard.git/examples/multipacketSD/multipacketSD.ino
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
// works only with tinyfat library
|
||||
// with SD library packets lost will occurs
|
||||
// don't know why !
|
||||
// tested with arduino mega 1280 and uno
|
||||
// send 240 Megabyte file without packet loss
|
||||
// at 100 kbyte/s
|
||||
// tinyfat read a block of 512 bytes on SD card ,
|
||||
// so the buffer must be 512 + 60 bytes
|
||||
// on the arduino mega with bigger buffer you can adjust
|
||||
// if (cur>=512) { // 512 to 1024 with 1100 bytes buffer
|
||||
|
||||
#include <EtherCard.h>
|
||||
#include <tinyFAT.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#define TCP_FLAGS_FIN_V 1 //as declared in net.h
|
||||
#define TCP_FLAGS_ACK_V 16 //as declared in net.h
|
||||
static byte myip[] = { 192,168,0,66 };
|
||||
static byte gwip[] = { 192,168,0,250 };
|
||||
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x39 };
|
||||
byte Ethernet::buffer[700]; // tcp/ip send and receive buffer
|
||||
unsigned long cur;
|
||||
unsigned long pos;
|
||||
byte res;
|
||||
|
||||
void setup() {
|
||||
// Initialize serial communication at 115200 baud
|
||||
Serial.begin(115200);
|
||||
// Initialize tinyFAT
|
||||
// You might need to select a lower speed than the default SPISPEED_HIGH
|
||||
file.setSSpin(4);
|
||||
res=file.initFAT(0);
|
||||
if (res==NO_ERROR) Serial.println("SD started");
|
||||
ether.begin(sizeof Ethernet::buffer, mymac , 10); //53 on mega ethernet shield 10 on others
|
||||
ether.staticSetup(myip, gwip);
|
||||
Serial.println("ETH started");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
wait:
|
||||
pos = ether.packetLoop(ether.packetReceive());// check if valid tcp data is received
|
||||
if (pos) {
|
||||
char* data = (char *) Ethernet::buffer + pos;
|
||||
cur=0;
|
||||
if (strncmp("GET / ", data, 6) == 0) {// nothing specified
|
||||
sendfiles("index.htm");
|
||||
goto wait;
|
||||
}
|
||||
if (strncmp("GET /", data, 5) == 0) { // serve anything on sd card
|
||||
int i =0;
|
||||
char temp[15]=""; // here will be the name of requested file
|
||||
while (data[i+5]!=32) {temp[i]=data[i+5];i++;}//search the end
|
||||
sendfiles((char*) temp);
|
||||
goto wait;
|
||||
}
|
||||
not_found();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void not_found() { //content not found
|
||||
cur=0;
|
||||
streamfile ("404.hea",TCP_FLAGS_FIN_V);
|
||||
// Serial.println("not found");
|
||||
}
|
||||
|
||||
byte streamfile (char* name , byte lastflag) { //send a file to the buffer
|
||||
if (!file.exists(name)) {return 0;}
|
||||
res=file.openFile(name, FILEMODE_BINARY);
|
||||
int car=512;
|
||||
while (car==512) {
|
||||
car=file.readBinary();
|
||||
for(int i=0;i<car;i++) {
|
||||
cur++;
|
||||
Ethernet::buffer[cur+53]=file.buffer[i];
|
||||
}
|
||||
if (cur>=512) {
|
||||
ether.httpServerReply_with_flags(cur,TCP_FLAGS_ACK_V);
|
||||
cur=0;
|
||||
} else {
|
||||
|
||||
if (lastflag==TCP_FLAGS_FIN_V) {
|
||||
ether.httpServerReply_with_flags(cur,TCP_FLAGS_ACK_V+TCP_FLAGS_FIN_V);
|
||||
}
|
||||
}
|
||||
}
|
||||
file.closeFile();
|
||||
return 1;
|
||||
}
|
||||
|
||||
byte sendfiles(char* name) { // function to find the correct header and send a file
|
||||
ether.httpServerReplyAck();
|
||||
int i =0;
|
||||
char dtype[13]="";
|
||||
while (name[i]!=0) {
|
||||
i++;
|
||||
}//search the end
|
||||
int b=i-1;
|
||||
while ((name[b]!=46)&&(b>0)) {
|
||||
b--;
|
||||
}//search the point
|
||||
int a=b+1;
|
||||
while (a<i) {
|
||||
dtype[a-b-1]=name[a];
|
||||
a++;
|
||||
}
|
||||
dtype[a-b-1]='.';
|
||||
dtype[a-b]='h';
|
||||
dtype[a-b+1]='e';
|
||||
dtype[a-b+2]='a';
|
||||
//Serial.println(dtype); // print the requested header file
|
||||
if (streamfile ((char *)dtype,0)==0) {
|
||||
streamfile ("txt.hea",0);
|
||||
}
|
||||
//Serial.println(name); // print the requested file
|
||||
if (streamfile ((char *)name,TCP_FLAGS_FIN_V)==0) {
|
||||
cur=0;
|
||||
not_found();
|
||||
}
|
||||
/* uncomment this if you want to have printed the ip of the target browser
|
||||
Serial.print("content send to ");
|
||||
for(int i=30; i<34; i++) {
|
||||
Serial.print(Ethernet::buffer[i]);
|
||||
if (i<33) Serial.print(".");
|
||||
}
|
||||
Serial.println(" ");
|
||||
*/
|
||||
}
|
||||
58
lib-ext/ethercard.git/examples/nanether/nanether.ino
Normal file
58
lib-ext/ethercard.git/examples/nanether/nanether.ino
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// Example of EtherCard usage, contributed by Will Rose, 2012-07-05.
|
||||
|
||||
#include <EtherCard.h>
|
||||
|
||||
#define BUF_SIZE 512
|
||||
|
||||
byte mac[] = { 0x00, 0x04, 0xA3, 0x21, 0xCA, 0x38 }; // Nanode MAC address.
|
||||
|
||||
uint8_t ip[] = { 192, 168, 1, 8 }; // The fallback board address.
|
||||
uint8_t dns[] = { 192, 168, 1, 20 }; // The DNS server address.
|
||||
uint8_t gateway[] = { 192, 168, 1, 20 }; // The gateway router address.
|
||||
uint8_t subnet[] = { 255, 255, 255, 0 }; // The subnet mask.
|
||||
byte Ethernet::buffer[BUF_SIZE];
|
||||
byte fixed; // Address fixed, no DHCP
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(57600);
|
||||
delay(2000);
|
||||
|
||||
/* Check that the Ethernet controller exists */
|
||||
Serial.println("Initialising the Ethernet controller");
|
||||
if (ether.begin(sizeof Ethernet::buffer, mac, 8) == 0) {
|
||||
Serial.println( "Ethernet controller NOT initialised");
|
||||
while (true)
|
||||
/* MT */ ;
|
||||
}
|
||||
|
||||
/* Get a DHCP connection */
|
||||
Serial.println("Attempting to get an IP address using DHCP");
|
||||
fixed = false;
|
||||
if (ether.dhcpSetup()) {
|
||||
ether.printIp("Got an IP address using DHCP: ", ether.myip);
|
||||
}
|
||||
/* If DHCP fails, start with a hard-coded address */
|
||||
else {
|
||||
ether.staticSetup(ip, gateway, dns);
|
||||
ether.printIp("DHCP FAILED, using fixed address: ", ether.myip);
|
||||
fixed = true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
word rc;
|
||||
|
||||
/* These function calls are required if ICMP packets are to be accepted */
|
||||
rc = ether.packetLoop(ether.packetReceive());
|
||||
Serial.print("ether.packetLoop() returned ");
|
||||
Serial.println(rc, DEC);
|
||||
|
||||
// For debugging
|
||||
delay(5000);
|
||||
|
||||
return;
|
||||
}
|
||||
279
lib-ext/ethercard.git/examples/noipClient/noipClient.ino
Normal file
279
lib-ext/ethercard.git/examples/noipClient/noipClient.ino
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
// NoIP client sketch for ENC28J60 based Ethernet Shield.
|
||||
// You need a free account from www.no-ip.com
|
||||
//
|
||||
// 1. On NoIP website, create a host of type DNS Host (A)
|
||||
// 2. Insert your host name in noIP_host[] variable
|
||||
// 3. Encode "username:password" in base64 using an online tool like
|
||||
// 4. Paste the encoded string in noIP_auth[] variable
|
||||
//
|
||||
// Contributed by Luca Dentella <luca@dentella.it>
|
||||
// http://www.lucadentella.it/2012/04/28/enc28j60-e-arduino-6/
|
||||
|
||||
|
||||
#include <EtherCard.h>
|
||||
|
||||
// Finite-State Machine states
|
||||
#define STATUS_IDLE 0
|
||||
#define STATUS_WAITING_FOR_PUBLIC_IP 1
|
||||
#define STATUS_NOIP_NEEDS_UPDATE 2
|
||||
#define STATUS_WAITING_FOR_NOIP 3
|
||||
#define STATUS_ERROR 99
|
||||
|
||||
// The sketch will check your public IP every CHECK_IP_INTERVAL ms,
|
||||
// and wait for REQUEST_TIMEOUT ms for a response.
|
||||
// It will retry for maximum of MAX_ATTEMPTS attemps.
|
||||
#define CHECK_IP_INTERVAL 60000
|
||||
#define REQUEST_TIMEOUT 10000
|
||||
#define MAX_ATTEMPTS 3
|
||||
|
||||
// MAC Address of Ethernet Shield
|
||||
static byte mymac[] = {0xDD,0xDD,0xDD,0x00,0x00,0x01};
|
||||
|
||||
// Insert your hostname and authentication string
|
||||
const char noIP_host[] PROGMEM = "myhost.no-ip.info";
|
||||
const char noIP_auth[] PROGMEM = "XXXXXXXXXX";
|
||||
|
||||
// Don't change these ones...
|
||||
const char getIP_web[] PROGMEM = "www.lucadentella.it";
|
||||
const char noIP_web[] PROGMEM = "dynupdate.no-ip.com";
|
||||
|
||||
// Some global variables
|
||||
byte Ethernet::buffer[700];
|
||||
byte getIP_address[4];
|
||||
byte noIP_address[4];
|
||||
byte actual_status;
|
||||
static byte session_id;
|
||||
static uint32_t check_ip_timer;
|
||||
static uint32_t request_timer;
|
||||
int attempt;
|
||||
Stash stash;
|
||||
|
||||
void setup () {
|
||||
|
||||
Serial.begin(57600);
|
||||
Serial.println(F("NoIP Client Demo"));
|
||||
Serial.println();
|
||||
|
||||
if (!ether.begin(sizeof Ethernet::buffer, mymac, 10))
|
||||
Serial.println(F( "Failed to access Ethernet controller"));
|
||||
else
|
||||
Serial.println(F("Ethernet controller initialized"));
|
||||
Serial.println();
|
||||
|
||||
if (!ether.dhcpSetup())
|
||||
Serial.println(F("Failed to get configuration from DHCP"));
|
||||
else
|
||||
Serial.println(F("DHCP configuration done"));
|
||||
|
||||
ether.printIp("IP Address:\t", ether.myip);
|
||||
ether.printIp("Netmask:\t", ether.netmask);
|
||||
ether.printIp("Gateway:\t", ether.gwip);
|
||||
Serial.println();
|
||||
|
||||
actual_status = STATUS_IDLE;
|
||||
attempt = 0;
|
||||
|
||||
// Resolve IP for getIP_web and noIP_web
|
||||
// and store them into global variables
|
||||
if (!ether.dnsLookup(getIP_web)) {
|
||||
Serial.print(F("Unable to resolve IP for "));
|
||||
SerialPrint_P(getIP_web);
|
||||
actual_status = STATUS_ERROR;
|
||||
} else {
|
||||
ether.copyIp(getIP_address, ether.hisip);
|
||||
SerialPrint_P(getIP_web);
|
||||
ether.printIp(" resolved to:\t", ether.hisip);
|
||||
}
|
||||
if (!ether.dnsLookup(noIP_web)) {
|
||||
Serial.print(F("Unable to resolve IP for "));
|
||||
SerialPrint_P(noIP_web);
|
||||
actual_status = STATUS_ERROR;
|
||||
} else {
|
||||
ether.copyIp(noIP_address, ether.hisip);
|
||||
SerialPrint_P(noIP_web);
|
||||
ether.printIp(" resolved to:\t", ether.hisip);
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
|
||||
ether.packetLoop(ether.packetReceive());
|
||||
|
||||
// FSM
|
||||
switch(actual_status) {
|
||||
|
||||
case STATUS_IDLE:
|
||||
checkPublicIP();
|
||||
break;
|
||||
case STATUS_WAITING_FOR_PUBLIC_IP:
|
||||
checkPublicIPResponse();
|
||||
break;
|
||||
case STATUS_NOIP_NEEDS_UPDATE:
|
||||
updateNoIP();
|
||||
break;
|
||||
case STATUS_WAITING_FOR_NOIP:
|
||||
checkNoIPResponse();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void checkPublicIP() {
|
||||
|
||||
if(millis() > check_ip_timer) {
|
||||
|
||||
Serial.print(F("Checking public IP... "));
|
||||
|
||||
// Create a request for GetIP service,
|
||||
// set destination IP and send request saving session_id
|
||||
Stash::prepare(PSTR("GET /demo/getip.php HTTP/1.1" "\r\n" "Host: $F" "\r\n" "\r\n"), getIP_web);
|
||||
ether.copyIp(ether.hisip, getIP_address);
|
||||
session_id = ether.tcpSend();
|
||||
|
||||
// Change FSM state, prepare for timeout and increment attempts counter
|
||||
actual_status = STATUS_WAITING_FOR_PUBLIC_IP;
|
||||
request_timer = millis() + REQUEST_TIMEOUT;
|
||||
attempt++;
|
||||
}
|
||||
}
|
||||
|
||||
void checkPublicIPResponse() {
|
||||
|
||||
String actualIp, dnsIp;
|
||||
|
||||
const char* reply = ether.tcpReply(session_id);
|
||||
|
||||
// We got a valid response
|
||||
if(reply != 0) {
|
||||
|
||||
// Parse response for public IP
|
||||
for(int i = 0; i < strlen(reply) - 189; i++) actualIp = actualIp + reply[187 + i];
|
||||
Serial.println(actualIp);
|
||||
|
||||
// If we can't resolve actual IP for our hostname on NoIP,
|
||||
// return to IDLE state and wait for the next interval
|
||||
if(!ether.dnsLookup(noIP_host)) {
|
||||
Serial.print(F("Unable to resolve actual IP for "));
|
||||
SerialPrint_P(noIP_host);
|
||||
Serial.println();
|
||||
actual_status = STATUS_IDLE;
|
||||
attempt = 0;
|
||||
check_ip_timer = millis() + CHECK_IP_INTERVAL;
|
||||
|
||||
// If we can resolve the IP for our hostname, save it in xxx.xxx.xxx.xxx form
|
||||
// and compare it with our public IP
|
||||
} else {
|
||||
for(int i = 0; i < 4; i++) {
|
||||
dnsIp = dnsIp + String(ether.hisip[i]);
|
||||
if(i < 3) dnsIp = dnsIp + ".";
|
||||
}
|
||||
SerialPrint_P(noIP_host);
|
||||
Serial.print(F(" resolved to "));
|
||||
Serial.println(dnsIp);
|
||||
|
||||
// If they are the same, we can sit down and wait for the next interval
|
||||
if(actualIp.compareTo(dnsIp) == 0) {
|
||||
Serial.println(F("No update needed :)"));
|
||||
actual_status = STATUS_IDLE;
|
||||
attempt = 0;
|
||||
check_ip_timer = millis() + CHECK_IP_INTERVAL;
|
||||
|
||||
// Different? We'd better to update NoIP!
|
||||
} else {
|
||||
Serial.println(F("Update needed :("));
|
||||
actual_status = STATUS_NOIP_NEEDS_UPDATE;
|
||||
attempt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// No valid response? Check for timeout
|
||||
// If we've already sent a max number of requests, return to IDLE state
|
||||
// and wait for the next interval
|
||||
} else {
|
||||
if(millis() > request_timer) {
|
||||
Serial.println(F(" no response :("));
|
||||
actual_status = STATUS_IDLE;
|
||||
if(attempt == MAX_ATTEMPTS) {
|
||||
Serial.println(F("Max number of attempts reached"));
|
||||
attempt = 0;
|
||||
check_ip_timer = millis() + CHECK_IP_INTERVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateNoIP() {
|
||||
|
||||
Serial.print(F("Updating NoIP..."));
|
||||
|
||||
// Create a request for updating NoIP using NoIP API,
|
||||
// set destination IP and send request saving session_id
|
||||
Stash::prepare(PSTR("GET /nic/update?hostname=$F HTTP/1.0" "\r\n"
|
||||
"Host: $F" "\r\n"
|
||||
"Authorization: Basic $F" "\r\n"
|
||||
"User-Agent: NoIP_Client" "\r\n" "\r\n"),
|
||||
noIP_host, noIP_web, noIP_auth);
|
||||
ether.copyIp(ether.hisip, noIP_address);
|
||||
session_id = ether.tcpSend();
|
||||
|
||||
// Wait for response or timeout...
|
||||
actual_status = STATUS_WAITING_FOR_NOIP;
|
||||
request_timer = millis() + REQUEST_TIMEOUT;
|
||||
attempt++;
|
||||
}
|
||||
|
||||
void checkNoIPResponse() {
|
||||
|
||||
const char* reply = ether.tcpReply(session_id);
|
||||
boolean done;
|
||||
|
||||
// We got a valid response...
|
||||
if(reply != 0) {
|
||||
|
||||
// Parse NoIP response looking for status/error codes...
|
||||
if(strstr(reply, "good") != 0) {
|
||||
Serial.println(F(" done!"));
|
||||
done = true;
|
||||
}
|
||||
else if(strstr(reply, "nochg") != 0) {
|
||||
Serial.println(F(" no change required!"));
|
||||
done = true;
|
||||
}
|
||||
else if(strstr(reply, "nohost") != 0) Serial.println(F(" host not found :("));
|
||||
else if(strstr(reply, "badauth") != 0) Serial.println(F(" invalid username or password :("));
|
||||
else if(strstr(reply, "badagent") != 0) Serial.println(F(" agent banned :("));
|
||||
else if(strstr(reply, "!donator") != 0) Serial.println(F(" feature not available for specified username :("));
|
||||
else if(strstr(reply, "abuse") != 0) Serial.println(F(" username blocked due to abuse :("));
|
||||
else Serial.println(F(" generic error :("));
|
||||
|
||||
// Record has been updated? Ok wait for next interval...
|
||||
if(done) {
|
||||
actual_status = STATUS_IDLE;
|
||||
attempt = 0;
|
||||
check_ip_timer = millis() + CHECK_IP_INTERVAL;
|
||||
}
|
||||
|
||||
// No valid response? Check for timeout
|
||||
// If we've already sent a max number of requests, return to IDLE state
|
||||
// and wait for the next interval
|
||||
} else {
|
||||
|
||||
if(millis() > request_timer) {
|
||||
Serial.println(F("No response from NoIP"));
|
||||
if(attempt == MAX_ATTEMPTS) {
|
||||
Serial.println(F("Max number of attempts reached"));
|
||||
actual_status = STATUS_IDLE;
|
||||
attempt = 0;
|
||||
check_ip_timer = millis() + CHECK_IP_INTERVAL;
|
||||
}
|
||||
else
|
||||
actual_status = STATUS_NOIP_NEEDS_UPDATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SerialPrint_P(PGM_P str) {
|
||||
for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.write(c);
|
||||
}
|
||||
62
lib-ext/ethercard.git/examples/pings/pings.ino
Normal file
62
lib-ext/ethercard.git/examples/pings/pings.ino
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// Ping a remote server, also uses DHCP and DNS.
|
||||
// 2011-06-12 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
|
||||
|
||||
#include <EtherCard.h>
|
||||
|
||||
// ethernet interface mac address, must be unique on the LAN
|
||||
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||
|
||||
byte Ethernet::buffer[700];
|
||||
static uint32_t timer;
|
||||
|
||||
// called when a ping comes in (replies to it are automatic)
|
||||
static void gotPinged (byte* ptr) {
|
||||
ether.printIp(">>> ping from: ", ptr);
|
||||
}
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
Serial.println("\n[pings]");
|
||||
|
||||
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||
Serial.println(F("Failed to access Ethernet controller"));
|
||||
if (!ether.dhcpSetup())
|
||||
Serial.println(F("DHCP failed"));
|
||||
|
||||
ether.printIp("IP: ", ether.myip);
|
||||
ether.printIp("GW: ", ether.gwip);
|
||||
|
||||
#if 1
|
||||
// use DNS to locate the IP address we want to ping
|
||||
if (!ether.dnsLookup(PSTR("www.google.com")))
|
||||
Serial.println("DNS failed");
|
||||
#else
|
||||
ether.parseIp(ether.hisip, "74.125.77.99");
|
||||
#endif
|
||||
ether.printIp("SRV: ", ether.hisip);
|
||||
|
||||
// call this to report others pinging us
|
||||
ether.registerPingCallback(gotPinged);
|
||||
|
||||
timer = -9999999; // start timing out right away
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void loop () {
|
||||
word len = ether.packetReceive(); // go receive new packets
|
||||
word pos = ether.packetLoop(len); // respond to incoming pings
|
||||
|
||||
// report whenever a reply to our outgoing ping comes back
|
||||
if (len > 0 && ether.packetLoopIcmpCheckReply(ether.hisip)) {
|
||||
Serial.print(" ");
|
||||
Serial.print((micros() - timer) * 0.001, 3);
|
||||
Serial.println(" ms");
|
||||
}
|
||||
|
||||
// ping a remote server once every few seconds
|
||||
if (micros() - timer >= 5000000) {
|
||||
ether.printIp("Pinging: ", ether.hisip);
|
||||
timer = micros();
|
||||
ether.clientIcmpRequest(ether.hisip);
|
||||
}
|
||||
}
|
||||
43
lib-ext/ethercard.git/examples/rbbb_server/rbbb_server.ino
Normal file
43
lib-ext/ethercard.git/examples/rbbb_server/rbbb_server.ino
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// This is a demo of the RBBB running as webserver with the Ether Card
|
||||
// 2010-05-28 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
|
||||
|
||||
#include <EtherCard.h>
|
||||
|
||||
// ethernet interface mac address, must be unique on the LAN
|
||||
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||
static byte myip[] = { 192,168,1,203 };
|
||||
|
||||
byte Ethernet::buffer[500];
|
||||
BufferFiller bfill;
|
||||
|
||||
void setup () {
|
||||
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||
Serial.println(F("Failed to access Ethernet controller"));
|
||||
ether.staticSetup(myip);
|
||||
}
|
||||
|
||||
static word homePage() {
|
||||
long t = millis() / 1000;
|
||||
word h = t / 3600;
|
||||
byte m = (t / 60) % 60;
|
||||
byte s = t % 60;
|
||||
bfill = ether.tcpOffset();
|
||||
bfill.emit_p(PSTR(
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Pragma: no-cache\r\n"
|
||||
"\r\n"
|
||||
"<meta http-equiv='refresh' content='1'/>"
|
||||
"<title>RBBB server</title>"
|
||||
"<h1>$D$D:$D$D:$D$D</h1>"),
|
||||
h/10, h%10, m/10, m%10, s/10, s%10);
|
||||
return bfill.position();
|
||||
}
|
||||
|
||||
void loop () {
|
||||
word len = ether.packetReceive();
|
||||
word pos = ether.packetLoop(len);
|
||||
|
||||
if (pos) // check if valid tcp data is received
|
||||
ether.httpServerReply(homePage()); // send web page data
|
||||
}
|
||||
118
lib-ext/ethercard.git/examples/stashTest/stashTest.ino
Normal file
118
lib-ext/ethercard.git/examples/stashTest/stashTest.ino
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// Test the offloaded RAM stash mechanism.
|
||||
// 2011-07-10 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
|
||||
|
||||
#include <EtherCard.h>
|
||||
#include <avr/eeprom.h>
|
||||
|
||||
// ethernet interface mac address, must be unique on the LAN
|
||||
byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||
|
||||
byte Ethernet::buffer[700];
|
||||
|
||||
void dumpBlock (const char* msg, byte idx) {
|
||||
Serial.print(msg);
|
||||
Serial.print(" [");
|
||||
Serial.print(idx, DEC);
|
||||
Serial.print("] @ ");
|
||||
Serial.print(Stash::bufs[idx].bnum, DEC);
|
||||
Serial.print(" free ");
|
||||
Serial.print(Stash::freeCount(), DEC);
|
||||
for (byte i = 0; i < 64; ++i) {
|
||||
if (i % 16 == 0)
|
||||
Serial.println();
|
||||
Serial.print(' ');
|
||||
Serial.print(Stash::bufs[idx].bytes[i], DEC);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void dumpStash (const char* msg, void* ptr) {
|
||||
Stash& buf = *(Stash*) ptr;
|
||||
Serial.print(msg);
|
||||
Serial.print(" c");
|
||||
Serial.print(buf.count, DEC);
|
||||
Serial.print(" f");
|
||||
Serial.print(buf.first, DEC);
|
||||
Serial.print(" l");
|
||||
Serial.print(buf.last, DEC);
|
||||
Serial.print(" u");
|
||||
Serial.print(buf.curr, DEC);
|
||||
Serial.print(" o");
|
||||
Serial.print(buf.offs, DEC);
|
||||
Serial.print(" #");
|
||||
Serial.println(buf.size());
|
||||
}
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
Serial.println("\n[stashTest]");
|
||||
ether.begin(sizeof Ethernet::buffer, mymac);
|
||||
|
||||
#if 1
|
||||
Stash buf;
|
||||
dumpStash("> AAA", &buf);
|
||||
byte fd = buf.create();
|
||||
Serial.print("fd ");
|
||||
Serial.println(fd, DEC);
|
||||
dumpStash("> BBB", &buf);
|
||||
dumpBlock("EMPTY", 0);
|
||||
for (char c = 'a'; c <= 'z'; ++c)
|
||||
buf.put(c);
|
||||
for (char c = 'A'; c <= 'Z'; ++c)
|
||||
buf.put(c);
|
||||
dumpBlock("LETTERS", 0);
|
||||
dumpStash("> CCC", &buf);
|
||||
for (char c = '0'; c <= '9'; ++c)
|
||||
buf.put(c);
|
||||
dumpBlock("DIGITS", 0);
|
||||
dumpStash("> DDD", &buf);
|
||||
buf.print(" x = ");
|
||||
buf.println(123.45);
|
||||
dumpBlock("PRINT", 0);
|
||||
dumpStash("> EEE", &buf);
|
||||
buf.load(1, 1);
|
||||
dumpBlock("FIRST", 1);
|
||||
buf.save();
|
||||
buf.load(1, 1);
|
||||
dumpBlock("FLUSHED", 1);
|
||||
dumpStash("> FFF", &buf);
|
||||
for (;;) {
|
||||
char c = buf.get();
|
||||
if (c == 0)
|
||||
break;
|
||||
Serial.print(c);
|
||||
}
|
||||
Serial.println();
|
||||
dumpStash("> GGG", &buf);
|
||||
#endif
|
||||
|
||||
Stash buf2;
|
||||
byte fd2 = buf2.create();
|
||||
buf2.print("<XYZ>");
|
||||
buf2.save();
|
||||
buf2.load(1, fd2);
|
||||
dumpBlock("SECOND", 1);
|
||||
dumpStash("> HHH", &buf2);
|
||||
|
||||
Stash::prepare(PSTR("a $S b $F c $D d $H e"),
|
||||
"123", PSTR("4567"), -12345, fd2);
|
||||
dumpBlock("BUFFER", 0);
|
||||
Serial.println(Stash::length());
|
||||
for (word i = 0, n = Stash::length(); i < n; ++i) {
|
||||
char c;
|
||||
Stash::extract(i, 1, &c);
|
||||
Serial.print(c);
|
||||
}
|
||||
Serial.println();
|
||||
Stash::cleanup();
|
||||
#if 1
|
||||
buf.release();
|
||||
#endif
|
||||
Serial.print("free ");
|
||||
Serial.println(Stash::freeCount(), DEC);
|
||||
Serial.println("DONE");
|
||||
}
|
||||
|
||||
void loop () {
|
||||
// ether.packetLoop(ether.packetReceive());
|
||||
}
|
||||
40
lib-ext/ethercard.git/examples/testDHCP/testDHCP.ino
Normal file
40
lib-ext/ethercard.git/examples/testDHCP/testDHCP.ino
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Arduino demo sketch for testing the DHCP client code
|
||||
//
|
||||
// Original author: Andrew Lindsay
|
||||
// Major rewrite and API overhaul by jcw, 2011-06-07
|
||||
//
|
||||
// Copyright: GPL V2
|
||||
// See http://www.gnu.org/licenses/gpl.html
|
||||
|
||||
#include <EtherCard.h>
|
||||
|
||||
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||
|
||||
byte Ethernet::buffer[700];
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
Serial.println(F("\n[testDHCP]"));
|
||||
|
||||
Serial.print("MAC: ");
|
||||
for (byte i = 0; i < 6; ++i) {
|
||||
Serial.print(mymac[i], HEX);
|
||||
if (i < 5)
|
||||
Serial.print(':');
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||
Serial.println(F("Failed to access Ethernet controller"));
|
||||
|
||||
Serial.println(F("Setting up DHCP"));
|
||||
if (!ether.dhcpSetup())
|
||||
Serial.println(F("DHCP failed"));
|
||||
|
||||
ether.printIp("My IP: ", ether.myip);
|
||||
ether.printIp("Netmask: ", ether.netmask);
|
||||
ether.printIp("GW IP: ", ether.gwip);
|
||||
ether.printIp("DNS IP: ", ether.dnsip);
|
||||
}
|
||||
|
||||
void loop () {}
|
||||
84
lib-ext/ethercard.git/examples/twitter/twitter.ino
Normal file
84
lib-ext/ethercard.git/examples/twitter/twitter.ino
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// Twitter client sketch for ENC28J60 based Ethernet Shield. Uses
|
||||
// arduino-tweet.appspot.com as a OAuth gateway.
|
||||
// Step by step instructions:
|
||||
//
|
||||
// 1. Get a oauth token:
|
||||
// http://arduino-tweet.appspot.com/oauth/twitter/login
|
||||
// 2. Put the token value in the TOKEN define below
|
||||
// 3. Run the sketch!
|
||||
//
|
||||
// WARNING: Don't send more than 1 tweet per minute!
|
||||
// NOTE: Twitter rejects tweets with identical content as dupes (returns 403)
|
||||
|
||||
#include <EtherCard.h>
|
||||
|
||||
// OAUTH key from http://arduino-tweet.appspot.com/
|
||||
#define TOKEN "Insert-your-token-here"
|
||||
|
||||
// ethernet interface mac address, must be unique on the LAN
|
||||
byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||
|
||||
const char website[] PROGMEM = "arduino-tweet.appspot.com";
|
||||
|
||||
static byte session;
|
||||
|
||||
byte Ethernet::buffer[700];
|
||||
Stash stash;
|
||||
|
||||
static void sendToTwitter () {
|
||||
Serial.println("Sending tweet...");
|
||||
byte sd = stash.create();
|
||||
|
||||
const char tweet[] = "@solarkennedy the test Twitter sketch works!";
|
||||
stash.print("token=");
|
||||
stash.print(TOKEN);
|
||||
stash.print("&status=");
|
||||
stash.println(tweet);
|
||||
stash.save();
|
||||
int stash_size = stash.size();
|
||||
|
||||
// Compose the http POST request, taking the headers below and appending
|
||||
// previously created stash in the sd holder.
|
||||
Stash::prepare(PSTR("POST http://$F/update HTTP/1.0" "\r\n"
|
||||
"Host: $F" "\r\n"
|
||||
"Content-Length: $D" "\r\n"
|
||||
"\r\n"
|
||||
"$H"),
|
||||
website, website, stash_size, sd);
|
||||
|
||||
// send the packet - this also releases all stash buffers once done
|
||||
// Save the session ID so we can watch for it in the main loop.
|
||||
session = ether.tcpSend();
|
||||
}
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
Serial.println("\n[Twitter Client]");
|
||||
|
||||
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||
Serial.println(F("Failed to access Ethernet controller"));
|
||||
if (!ether.dhcpSetup())
|
||||
Serial.println(F("DHCP failed"));
|
||||
|
||||
ether.printIp("IP: ", ether.myip);
|
||||
ether.printIp("GW: ", ether.gwip);
|
||||
ether.printIp("DNS: ", ether.dnsip);
|
||||
|
||||
if (!ether.dnsLookup(website))
|
||||
Serial.println(F("DNS failed"));
|
||||
|
||||
ether.printIp("SRV: ", ether.hisip);
|
||||
|
||||
sendToTwitter();
|
||||
}
|
||||
|
||||
void loop () {
|
||||
ether.packetLoop(ether.packetReceive());
|
||||
|
||||
const char* reply = ether.tcpReply(session);
|
||||
if (reply != 0) {
|
||||
Serial.println("Got a response!");
|
||||
Serial.println(reply);
|
||||
}
|
||||
}
|
||||
|
||||
95
lib-ext/ethercard.git/examples/udpListener/udpListener.ino
Normal file
95
lib-ext/ethercard.git/examples/udpListener/udpListener.ino
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// Demonstrates usage of the new udpServer feature.
|
||||
//You can register the same function to multiple ports, and multiple functions to the same port.
|
||||
//
|
||||
// 2013-4-7 Brian Lee <cybexsoft@hotmail.com>
|
||||
|
||||
#include <EtherCard.h>
|
||||
#include <IPAddress.h>
|
||||
|
||||
#define STATIC 0 // set to 1 to disable DHCP (adjust myip/gwip values below)
|
||||
|
||||
#if STATIC
|
||||
// ethernet interface ip address
|
||||
static byte myip[] = { 192,168,0,200 };
|
||||
// gateway ip address
|
||||
static byte gwip[] = { 192,168,0,1 };
|
||||
#endif
|
||||
|
||||
// ethernet mac address - must be unique on your network
|
||||
static byte mymac[] = { 0x70,0x69,0x69,0x2D,0x30,0x31 };
|
||||
|
||||
byte Ethernet::buffer[500]; // tcp/ip send and receive buffer
|
||||
|
||||
//callback that prints received packets to the serial port
|
||||
void udpSerialPrint(word port, byte ip[4], const char *data, word len) {
|
||||
IPAddress src(ip[0], ip[1], ip[2], ip[3]);
|
||||
Serial.println(src);
|
||||
Serial.println(port);
|
||||
Serial.println(data);
|
||||
Serial.println(len);
|
||||
}
|
||||
|
||||
void setup(){
|
||||
Serial.begin(57600);
|
||||
Serial.println(F("\n[backSoon]"));
|
||||
|
||||
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||
Serial.println(F("Failed to access Ethernet controller"));
|
||||
#if STATIC
|
||||
ether.staticSetup(myip, gwip);
|
||||
#else
|
||||
if (!ether.dhcpSetup())
|
||||
Serial.println(F("DHCP failed"));
|
||||
#endif
|
||||
|
||||
ether.printIp("IP: ", ether.myip);
|
||||
ether.printIp("GW: ", ether.gwip);
|
||||
ether.printIp("DNS: ", ether.dnsip);
|
||||
|
||||
//register udpSerialPrint() to port 1337
|
||||
ether.udpServerListenOnPort(&udpSerialPrint, 1337);
|
||||
|
||||
//register udpSerialPrint() to port 42.
|
||||
ether.udpServerListenOnPort(&udpSerialPrint, 42);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
//this must be called for ethercard functions to work.
|
||||
ether.packetLoop(ether.packetReceive());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
//Processing sketch to send test UDP packets.
|
||||
|
||||
import hypermedia.net.*;
|
||||
|
||||
UDP udp; // define the UDP object
|
||||
|
||||
|
||||
void setup() {
|
||||
udp = new UDP( this, 6000 ); // create a new datagram connection on port 6000
|
||||
//udp.log( true ); // <-- printout the connection activity
|
||||
udp.listen( true ); // and wait for incoming message
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
}
|
||||
|
||||
void keyPressed() {
|
||||
String ip = "192.168.0.200"; // the remote IP address
|
||||
int port = 1337; // the destination port
|
||||
|
||||
udp.send("Greetings via UDP!", ip, port ); // the message to send
|
||||
|
||||
}
|
||||
|
||||
void receive( byte[] data ) { // <-- default handler
|
||||
//void receive( byte[] data, String ip, int port ) { // <-- extended handler
|
||||
|
||||
for(int i=0; i < data.length; i++)
|
||||
print(char(data[i]));
|
||||
println();
|
||||
}
|
||||
*/
|
||||
50
lib-ext/ethercard.git/examples/webClient/webClient.ino
Normal file
50
lib-ext/ethercard.git/examples/webClient/webClient.ino
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// Demo using DHCP and DNS to perform a web client request.
|
||||
// 2011-06-08 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
|
||||
|
||||
#include <EtherCard.h>
|
||||
|
||||
// ethernet interface mac address, must be unique on the LAN
|
||||
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||
|
||||
byte Ethernet::buffer[700];
|
||||
static uint32_t timer;
|
||||
|
||||
const char website[] PROGMEM = "www.google.com";
|
||||
|
||||
// called when the client request is complete
|
||||
static void my_callback (byte status, word off, word len) {
|
||||
Serial.println(">>>");
|
||||
Ethernet::buffer[off+300] = 0;
|
||||
Serial.print((const char*) Ethernet::buffer + off);
|
||||
Serial.println("...");
|
||||
}
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
Serial.println(F("\n[webClient]"));
|
||||
|
||||
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||
Serial.println(F("Failed to access Ethernet controller"));
|
||||
if (!ether.dhcpSetup())
|
||||
Serial.println(F("DHCP failed"));
|
||||
|
||||
ether.printIp("IP: ", ether.myip);
|
||||
ether.printIp("GW: ", ether.gwip);
|
||||
ether.printIp("DNS: ", ether.dnsip);
|
||||
|
||||
if (!ether.dnsLookup(website))
|
||||
Serial.println("DNS failed");
|
||||
|
||||
ether.printIp("SRV: ", ether.hisip);
|
||||
}
|
||||
|
||||
void loop () {
|
||||
ether.packetLoop(ether.packetReceive());
|
||||
|
||||
if (millis() > timer) {
|
||||
timer = millis() + 5000;
|
||||
Serial.println();
|
||||
Serial.print("<<< REQ ");
|
||||
ether.browseUrl(PSTR("/foo/"), "bar", website, my_callback);
|
||||
}
|
||||
}
|
||||
139
lib-ext/ethercard.git/examples/xively/xively.ino
Normal file
139
lib-ext/ethercard.git/examples/xively/xively.ino
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
// Simple demo for feeding some random data to Pachube.
|
||||
// 2011-07-08 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
|
||||
|
||||
// Handle returning code and reset ethernet module if needed
|
||||
// 2013-10-22 hneiraf@gmail.com
|
||||
|
||||
#include <EtherCard.h>
|
||||
|
||||
// change these settings to match your own setup
|
||||
#define FEED "000"
|
||||
#define APIKEY "xxx"
|
||||
|
||||
// ethernet interface mac address, must be unique on the LAN
|
||||
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||
|
||||
const char website[] PROGMEM = "api.xively.com";
|
||||
|
||||
byte Ethernet::buffer[350];
|
||||
uint32_t timer;
|
||||
Stash stash;
|
||||
byte session;
|
||||
|
||||
//timing variable
|
||||
int res = 0;
|
||||
|
||||
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
Serial.println("\n[Xively example]");
|
||||
|
||||
//Initialize Ethernet
|
||||
initialize_ethernet();
|
||||
}
|
||||
|
||||
|
||||
void loop () {
|
||||
|
||||
//if correct answer is not received then re-initialize ethernet module
|
||||
if (res > 220){
|
||||
initialize_ethernet();
|
||||
}
|
||||
|
||||
res = res + 1;
|
||||
|
||||
ether.packetLoop(ether.packetReceive());
|
||||
|
||||
//200 res = 10 seconds (50ms each res)
|
||||
if (res == 200) {
|
||||
|
||||
|
||||
//Generate random info
|
||||
float demo = random(0,500);
|
||||
word one = random(0,500);
|
||||
String msje;
|
||||
|
||||
if (demo < 250){
|
||||
msje = "low";
|
||||
}
|
||||
else{
|
||||
msje = "high";
|
||||
}
|
||||
|
||||
|
||||
// generate two fake values as payload - by using a separate stash,
|
||||
// we can determine the size of the generated message ahead of time
|
||||
byte sd = stash.create();
|
||||
stash.print("demo,");
|
||||
stash.println(demo);
|
||||
stash.print("one,");
|
||||
stash.println(one);
|
||||
stash.print("mensaje,");
|
||||
stash.println(msje);
|
||||
stash.save();
|
||||
|
||||
//Display data to be sent
|
||||
Serial.println(demo);
|
||||
Serial.println(one);
|
||||
|
||||
|
||||
// generate the header with payload - note that the stash size is used,
|
||||
// and that a "stash descriptor" is passed in as argument using "$H"
|
||||
Stash::prepare(PSTR("PUT http://$F/v2/feeds/$F.csv HTTP/1.0" "\r\n"
|
||||
"Host: $F" "\r\n"
|
||||
"X-PachubeApiKey: $F" "\r\n"
|
||||
"Content-Length: $D" "\r\n"
|
||||
"\r\n"
|
||||
"$H"),
|
||||
website, PSTR(FEED), website, PSTR(APIKEY), stash.size(), sd);
|
||||
|
||||
// send the packet - this also releases all stash buffers once done
|
||||
session = ether.tcpSend();
|
||||
}
|
||||
|
||||
const char* reply = ether.tcpReply(session);
|
||||
|
||||
if (reply != 0) {
|
||||
res = 0;
|
||||
Serial.println(reply);
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void initialize_ethernet(void){
|
||||
for(;;){ // keep trying until you succeed
|
||||
//Reinitialize ethernet module
|
||||
pinMode(5, OUTPUT);
|
||||
Serial.println("Reseting Ethernet...");
|
||||
digitalWrite(5, LOW);
|
||||
delay(1000);
|
||||
digitalWrite(5, HIGH);
|
||||
delay(500);
|
||||
|
||||
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0){
|
||||
Serial.println( "Failed to access Ethernet controller");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ether.dhcpSetup()){
|
||||
Serial.println("DHCP failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
ether.printIp("IP: ", ether.myip);
|
||||
ether.printIp("GW: ", ether.gwip);
|
||||
ether.printIp("DNS: ", ether.dnsip);
|
||||
|
||||
if (!ether.dnsLookup(website))
|
||||
Serial.println("DNS failed");
|
||||
|
||||
ether.printIp("SRV: ", ether.hisip);
|
||||
|
||||
//reset init value
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
123
lib-ext/ethercard.git/net.h
Executable file
123
lib-ext/ethercard.git/net.h
Executable file
|
|
@ -0,0 +1,123 @@
|
|||
// Based on the net.h file from the AVRlib library by Pascal Stang.
|
||||
// Author: Guido Socher
|
||||
// Copyright: GPL V2
|
||||
//
|
||||
// For AVRlib See http://www.procyonengineering.com/
|
||||
// Used with explicit permission of Pascal Stang.
|
||||
//
|
||||
// 2010-05-20 <jc@wippler.nl>
|
||||
|
||||
// notation: _P = position of a field
|
||||
// _V = value of a field
|
||||
|
||||
#ifndef NET_H
|
||||
#define NET_H
|
||||
|
||||
// ******* ETH *******
|
||||
#define ETH_HEADER_LEN 14
|
||||
// values of certain bytes:
|
||||
#define ETHTYPE_ARP_H_V 0x08
|
||||
#define ETHTYPE_ARP_L_V 0x06
|
||||
#define ETHTYPE_IP_H_V 0x08
|
||||
#define ETHTYPE_IP_L_V 0x00
|
||||
// byte positions in the ethernet frame:
|
||||
//
|
||||
// Ethernet type field (2bytes):
|
||||
#define ETH_TYPE_H_P 12
|
||||
#define ETH_TYPE_L_P 13
|
||||
//
|
||||
#define ETH_DST_MAC 0
|
||||
#define ETH_SRC_MAC 6
|
||||
|
||||
|
||||
// ******* ARP *******
|
||||
#define ETH_ARP_OPCODE_REPLY_H_V 0x0
|
||||
#define ETH_ARP_OPCODE_REPLY_L_V 0x02
|
||||
#define ETH_ARP_OPCODE_REQ_H_V 0x0
|
||||
#define ETH_ARP_OPCODE_REQ_L_V 0x01
|
||||
// start of arp header:
|
||||
#define ETH_ARP_P 0xe
|
||||
//
|
||||
#define ETHTYPE_ARP_L_V 0x06
|
||||
// arp.dst.ip
|
||||
#define ETH_ARP_DST_IP_P 0x26
|
||||
// arp.opcode
|
||||
#define ETH_ARP_OPCODE_H_P 0x14
|
||||
#define ETH_ARP_OPCODE_L_P 0x15
|
||||
// arp.src.mac
|
||||
#define ETH_ARP_SRC_MAC_P 0x16
|
||||
#define ETH_ARP_SRC_IP_P 0x1c
|
||||
#define ETH_ARP_DST_MAC_P 0x20
|
||||
#define ETH_ARP_DST_IP_P 0x26
|
||||
|
||||
// ******* IP *******
|
||||
#define IP_HEADER_LEN 20
|
||||
// ip.src
|
||||
#define IP_SRC_P 0x1a
|
||||
#define IP_DST_P 0x1e
|
||||
#define IP_HEADER_LEN_VER_P 0xe
|
||||
#define IP_CHECKSUM_P 0x18
|
||||
#define IP_TTL_P 0x16
|
||||
#define IP_FLAGS_P 0x14
|
||||
#define IP_P 0xe
|
||||
#define IP_TOTLEN_H_P 0x10
|
||||
#define IP_TOTLEN_L_P 0x11
|
||||
|
||||
#define IP_PROTO_P 0x17
|
||||
|
||||
#define IP_PROTO_ICMP_V 1
|
||||
#define IP_PROTO_TCP_V 6
|
||||
// 17=0x11
|
||||
#define IP_PROTO_UDP_V 17
|
||||
// ******* ICMP *******
|
||||
#define ICMP_TYPE_ECHOREPLY_V 0
|
||||
#define ICMP_TYPE_ECHOREQUEST_V 8
|
||||
//
|
||||
#define ICMP_TYPE_P 0x22
|
||||
#define ICMP_CHECKSUM_P 0x24
|
||||
#define ICMP_CHECKSUM_H_P 0x24
|
||||
#define ICMP_CHECKSUM_L_P 0x25
|
||||
#define ICMP_IDENT_H_P 0x26
|
||||
#define ICMP_IDENT_L_P 0x27
|
||||
#define ICMP_DATA_P 0x2a
|
||||
|
||||
// ******* UDP *******
|
||||
#define UDP_HEADER_LEN 8
|
||||
//
|
||||
#define UDP_SRC_PORT_H_P 0x22
|
||||
#define UDP_SRC_PORT_L_P 0x23
|
||||
#define UDP_DST_PORT_H_P 0x24
|
||||
#define UDP_DST_PORT_L_P 0x25
|
||||
//
|
||||
#define UDP_LEN_H_P 0x26
|
||||
#define UDP_LEN_L_P 0x27
|
||||
#define UDP_CHECKSUM_H_P 0x28
|
||||
#define UDP_CHECKSUM_L_P 0x29
|
||||
#define UDP_DATA_P 0x2a
|
||||
|
||||
// ******* TCP *******
|
||||
#define TCP_SRC_PORT_H_P 0x22
|
||||
#define TCP_SRC_PORT_L_P 0x23
|
||||
#define TCP_DST_PORT_H_P 0x24
|
||||
#define TCP_DST_PORT_L_P 0x25
|
||||
// the tcp seq number is 4 bytes 0x26-0x29
|
||||
#define TCP_SEQ_H_P 0x26
|
||||
#define TCP_SEQACK_H_P 0x2a
|
||||
// flags: SYN=2
|
||||
#define TCP_FLAGS_P 0x2f
|
||||
#define TCP_FLAGS_SYN_V 2
|
||||
#define TCP_FLAGS_FIN_V 1
|
||||
#define TCP_FLAGS_RST_V 4
|
||||
#define TCP_FLAGS_PUSH_V 8
|
||||
#define TCP_FLAGS_SYNACK_V 0x12
|
||||
#define TCP_FLAGS_ACK_V 0x10
|
||||
#define TCP_FLAGS_PSHACK_V 0x18
|
||||
// plain len without the options:
|
||||
#define TCP_HEADER_LEN_PLAIN 20
|
||||
#define TCP_HEADER_LEN_P 0x2e
|
||||
#define TCP_WIN_SIZE 0x30
|
||||
#define TCP_CHECKSUM_H_P 0x32
|
||||
#define TCP_CHECKSUM_L_P 0x33
|
||||
#define TCP_OPTIONS_P 0x36
|
||||
//
|
||||
#endif
|
||||
810
lib-ext/ethercard.git/tcpip.cpp
Normal file
810
lib-ext/ethercard.git/tcpip.cpp
Normal file
|
|
@ -0,0 +1,810 @@
|
|||
// IP, ARP, UDP and TCP functions.
|
||||
// Author: Guido Socher
|
||||
// Copyright: GPL V2
|
||||
//
|
||||
// The TCP implementation uses some size optimisations which are valid
|
||||
// only if all data can be sent in one single packet. This is however
|
||||
// not a big limitation for a microcontroller as you will anyhow use
|
||||
// small web-pages. The web server must send the entire web page in one
|
||||
// packet. The client "web browser" as implemented here can also receive
|
||||
// large pages.
|
||||
//
|
||||
// 2010-05-20 <jc@wippler.nl>
|
||||
|
||||
#include "EtherCard.h"
|
||||
#include "net.h"
|
||||
#undef word // arduino nonsense
|
||||
|
||||
#define gPB ether.buffer
|
||||
|
||||
#define PINGPATTERN 0x42
|
||||
|
||||
// Avoid spurious pgmspace warnings - http://forum.jeelabs.net/node/327
|
||||
// See also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734
|
||||
//#undef PROGMEM
|
||||
//#define PROGMEM __attribute__(( section(".progmem.data") ))
|
||||
//#undef PSTR
|
||||
//#define PSTR(s) (__extension__({static prog_char c[] PROGMEM = (s); &c[0];}))
|
||||
|
||||
#define TCPCLIENT_SRC_PORT_H 11 //Source port (MSB) for TCP/IP client connections - hardcode all TCP/IP client connection from ports in range 2816-3071
|
||||
static uint8_t tcpclient_src_port_l=1; // Source port (LSB) for tcp/ip client connections - increments on each TCP/IP request
|
||||
static uint8_t tcp_fd; // a file descriptor, will be encoded into the port
|
||||
static uint8_t tcp_client_state; //TCP connection state: 1=Send SYN, 2=SYN sent awaiting SYN+ACK, 3=Established, 4=Not used, 5=Closing, 6=Closed
|
||||
static uint8_t tcp_client_port_h; // Destination port (MSB) of TCP/IP client connection
|
||||
static uint8_t tcp_client_port_l; // Destination port (LSB) of TCP/IP client connection
|
||||
static uint8_t (*client_tcp_result_cb)(uint8_t,uint8_t,uint16_t,uint16_t); // Pointer to callback function to handle response to current TCP/IP request
|
||||
static uint16_t (*client_tcp_datafill_cb)(uint8_t); //Pointer to callback function to handle payload data in response to current TCP/IP request
|
||||
static uint8_t www_fd; // ID of current http request (only one http request at a time - one of the 8 possible concurrent TCP/IP connections)
|
||||
static void (*client_browser_cb)(uint8_t,uint16_t,uint16_t); // Pointer to callback function to handle result of current HTTP request
|
||||
static const char *client_additionalheaderline; // Pointer to c-string additional http request header info
|
||||
static const char *client_postval;
|
||||
static const char *client_urlbuf; // Pointer to c-string path part of HTTP request URL
|
||||
static const char *client_urlbuf_var; // Pointer to c-string filename part of HTTP request URL
|
||||
static const char *client_hoststr; // Pointer to c-string hostname of current HTTP request
|
||||
static void (*icmp_cb)(uint8_t *ip); // Pointer to callback function for ICMP ECHO response handler (triggers when localhost recieves ping respnse (pong))
|
||||
static uint8_t destmacaddr[6]; // storing both dns server and destination mac addresses, but at different times because both are never needed at same time.
|
||||
static boolean waiting_for_dns_mac = false; //might be better to use bit flags and bitmask operations for these conditions
|
||||
static boolean has_dns_mac = false;
|
||||
static boolean waiting_for_dest_mac = false;
|
||||
static boolean has_dest_mac = false;
|
||||
static uint8_t gwmacaddr[6]; // Hardware (MAC) address of gateway router
|
||||
static uint8_t waitgwmac; // Bitwise flags of gateway router status - see below for states
|
||||
//Define gatweay router ARP statuses
|
||||
#define WGW_INITIAL_ARP 1 // First request, no answer yet
|
||||
#define WGW_HAVE_GW_MAC 2 // Have gateway router MAC
|
||||
#define WGW_REFRESHING 4 // Refreshing but already have gateway MAC
|
||||
#define WGW_ACCEPT_ARP_REPLY 8 // Accept an ARP reply
|
||||
|
||||
static uint16_t info_data_len; // Length of TCP/IP payload
|
||||
static uint8_t seqnum = 0xa; // My initial tcp sequence number
|
||||
static uint8_t result_fd = 123; // Session id of last reply
|
||||
static const char* result_ptr; // Pointer to TCP/IP data
|
||||
static unsigned long SEQ; // TCP/IP sequence number
|
||||
|
||||
#define CLIENTMSS 550
|
||||
#define TCP_DATA_START ((uint16_t)TCP_SRC_PORT_H_P+(gPB[TCP_HEADER_LEN_P]>>4)*4) // Get offset of TCP/IP payload data
|
||||
|
||||
const unsigned char arpreqhdr[] PROGMEM = { 0,1,8,0,6,4,0,1 }; // ARP request header
|
||||
const unsigned char iphdr[] PROGMEM = { 0x45,0,0,0x82,0,0,0x40,0,0x20 }; //IP header
|
||||
const unsigned char ntpreqhdr[] PROGMEM = { 0xE3,0,4,0xFA,0,1,0,0,0,1 }; //NTP request header
|
||||
const uint8_t allOnes[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; // Used for hardware (MAC) and IP broadcast addresses
|
||||
|
||||
static void fill_checksum(uint8_t dest, uint8_t off, uint16_t len,uint8_t type) {
|
||||
const uint8_t* ptr = gPB + off;
|
||||
uint32_t sum = type==1 ? IP_PROTO_UDP_V+len-8 :
|
||||
type==2 ? IP_PROTO_TCP_V+len-8 : 0;
|
||||
while(len >1) {
|
||||
sum += (uint16_t) (((uint32_t)*ptr<<8)|*(ptr+1));
|
||||
ptr+=2;
|
||||
len-=2;
|
||||
}
|
||||
if (len)
|
||||
sum += ((uint32_t)*ptr)<<8;
|
||||
while (sum>>16)
|
||||
sum = (uint16_t) sum + (sum >> 16);
|
||||
uint16_t ck = ~ (uint16_t) sum;
|
||||
gPB[dest] = ck>>8;
|
||||
gPB[dest+1] = ck;
|
||||
}
|
||||
|
||||
static void setMACs (const uint8_t *mac) {
|
||||
EtherCard::copyMac(gPB + ETH_DST_MAC, mac);
|
||||
EtherCard::copyMac(gPB + ETH_SRC_MAC, EtherCard::mymac);
|
||||
}
|
||||
|
||||
static void setMACandIPs (const uint8_t *mac, const uint8_t *dst) {
|
||||
setMACs(mac);
|
||||
EtherCard::copyIp(gPB + IP_DST_P, dst);
|
||||
EtherCard::copyIp(gPB + IP_SRC_P, EtherCard::myip);
|
||||
}
|
||||
|
||||
static uint8_t check_ip_message_is_from(const uint8_t *ip) {
|
||||
return memcmp(gPB + IP_SRC_P, ip, 4) == 0;
|
||||
}
|
||||
|
||||
static boolean is_lan(const uint8_t source[4], const uint8_t destination[4]) {
|
||||
if(source[0] == 0 || destination[0] == 0) {
|
||||
return false;
|
||||
}
|
||||
for(int i = 0; i < 4; i++)
|
||||
if((source[i] & EtherCard::netmask[i]) != (destination[i] & EtherCard::netmask[i])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint8_t eth_type_is_arp_and_my_ip(uint16_t len) {
|
||||
return len >= 41 && gPB[ETH_TYPE_H_P] == ETHTYPE_ARP_H_V &&
|
||||
gPB[ETH_TYPE_L_P] == ETHTYPE_ARP_L_V &&
|
||||
memcmp(gPB + ETH_ARP_DST_IP_P, EtherCard::myip, 4) == 0;
|
||||
}
|
||||
|
||||
static uint8_t eth_type_is_ip_and_my_ip(uint16_t len) {
|
||||
return len >= 42 && gPB[ETH_TYPE_H_P] == ETHTYPE_IP_H_V &&
|
||||
gPB[ETH_TYPE_L_P] == ETHTYPE_IP_L_V &&
|
||||
gPB[IP_HEADER_LEN_VER_P] == 0x45 &&
|
||||
(memcmp(gPB + IP_DST_P, EtherCard::myip, 4) == 0 //not my IP
|
||||
|| (memcmp(gPB + IP_DST_P, EtherCard::broadcastip, 4) == 0) //not subnet broadcast
|
||||
|| (memcmp(gPB + IP_DST_P, allOnes, 4) == 0)); //not global broadcasts
|
||||
//!@todo Handle multicast
|
||||
}
|
||||
|
||||
static void fill_ip_hdr_checksum() {
|
||||
gPB[IP_CHECKSUM_P] = 0;
|
||||
gPB[IP_CHECKSUM_P+1] = 0;
|
||||
gPB[IP_FLAGS_P] = 0x40; // don't fragment
|
||||
gPB[IP_FLAGS_P+1] = 0; // fragement offset
|
||||
gPB[IP_TTL_P] = 64; // ttl
|
||||
fill_checksum(IP_CHECKSUM_P, IP_P, IP_HEADER_LEN,0);
|
||||
}
|
||||
|
||||
static void make_eth_ip() {
|
||||
setMACs(gPB + ETH_SRC_MAC);
|
||||
EtherCard::copyIp(gPB + IP_DST_P, gPB + IP_SRC_P);
|
||||
EtherCard::copyIp(gPB + IP_SRC_P, EtherCard::myip);
|
||||
fill_ip_hdr_checksum();
|
||||
}
|
||||
|
||||
static void step_seq(uint16_t rel_ack_num,uint8_t cp_seq) {
|
||||
uint8_t i;
|
||||
uint8_t tseq;
|
||||
i = 4;
|
||||
while(i>0) {
|
||||
rel_ack_num = gPB[TCP_SEQ_H_P+i-1]+rel_ack_num;
|
||||
tseq = gPB[TCP_SEQACK_H_P+i-1];
|
||||
gPB[TCP_SEQACK_H_P+i-1] = rel_ack_num;
|
||||
if (cp_seq)
|
||||
gPB[TCP_SEQ_H_P+i-1] = tseq;
|
||||
else
|
||||
gPB[TCP_SEQ_H_P+i-1] = 0; // some preset value
|
||||
rel_ack_num = rel_ack_num>>8;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
static void make_tcphead(uint16_t rel_ack_num,uint8_t cp_seq) {
|
||||
uint8_t i = gPB[TCP_DST_PORT_H_P];
|
||||
gPB[TCP_DST_PORT_H_P] = gPB[TCP_SRC_PORT_H_P];
|
||||
gPB[TCP_SRC_PORT_H_P] = i;
|
||||
uint8_t j = gPB[TCP_DST_PORT_L_P];
|
||||
gPB[TCP_DST_PORT_L_P] = gPB[TCP_SRC_PORT_L_P];
|
||||
gPB[TCP_SRC_PORT_L_P] = j;
|
||||
step_seq(rel_ack_num,cp_seq);
|
||||
gPB[TCP_CHECKSUM_H_P] = 0;
|
||||
gPB[TCP_CHECKSUM_L_P] = 0;
|
||||
gPB[TCP_HEADER_LEN_P] = 0x50;
|
||||
}
|
||||
|
||||
static void make_arp_answer_from_request() {
|
||||
setMACs(gPB + ETH_SRC_MAC);
|
||||
gPB[ETH_ARP_OPCODE_H_P] = ETH_ARP_OPCODE_REPLY_H_V;
|
||||
gPB[ETH_ARP_OPCODE_L_P] = ETH_ARP_OPCODE_REPLY_L_V;
|
||||
EtherCard::copyMac(gPB + ETH_ARP_DST_MAC_P, gPB + ETH_ARP_SRC_MAC_P);
|
||||
EtherCard::copyMac(gPB + ETH_ARP_SRC_MAC_P, EtherCard::mymac);
|
||||
EtherCard::copyIp(gPB + ETH_ARP_DST_IP_P, gPB + ETH_ARP_SRC_IP_P);
|
||||
EtherCard::copyIp(gPB + ETH_ARP_SRC_IP_P, EtherCard::myip);
|
||||
EtherCard::packetSend(42);
|
||||
}
|
||||
|
||||
static void make_echo_reply_from_request(uint16_t len) {
|
||||
make_eth_ip();
|
||||
gPB[ICMP_TYPE_P] = ICMP_TYPE_ECHOREPLY_V;
|
||||
if (gPB[ICMP_CHECKSUM_P] > (0xFF-0x08))
|
||||
gPB[ICMP_CHECKSUM_P+1]++;
|
||||
gPB[ICMP_CHECKSUM_P] += 0x08;
|
||||
EtherCard::packetSend(len);
|
||||
}
|
||||
|
||||
void EtherCard::makeUdpReply (const char *data,uint8_t datalen,uint16_t port) {
|
||||
if (datalen>220)
|
||||
datalen = 220;
|
||||
gPB[IP_TOTLEN_H_P] = (IP_HEADER_LEN+UDP_HEADER_LEN+datalen) >>8;
|
||||
gPB[IP_TOTLEN_L_P] = IP_HEADER_LEN+UDP_HEADER_LEN+datalen;
|
||||
make_eth_ip();
|
||||
gPB[UDP_DST_PORT_H_P] = gPB[UDP_SRC_PORT_H_P];
|
||||
gPB[UDP_DST_PORT_L_P] = gPB[UDP_SRC_PORT_L_P];
|
||||
gPB[UDP_SRC_PORT_H_P] = port>>8;
|
||||
gPB[UDP_SRC_PORT_L_P] = port;
|
||||
gPB[UDP_LEN_H_P] = (UDP_HEADER_LEN+datalen) >> 8;
|
||||
gPB[UDP_LEN_L_P] = UDP_HEADER_LEN+datalen;
|
||||
gPB[UDP_CHECKSUM_H_P] = 0;
|
||||
gPB[UDP_CHECKSUM_L_P] = 0;
|
||||
memcpy(gPB + UDP_DATA_P, data, datalen);
|
||||
fill_checksum(UDP_CHECKSUM_H_P, IP_SRC_P, 16 + datalen,1);
|
||||
packetSend(UDP_HEADER_LEN+IP_HEADER_LEN+ETH_HEADER_LEN+datalen);
|
||||
}
|
||||
|
||||
static void make_tcp_synack_from_syn() {
|
||||
gPB[IP_TOTLEN_H_P] = 0;
|
||||
gPB[IP_TOTLEN_L_P] = IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4;
|
||||
make_eth_ip();
|
||||
gPB[TCP_FLAGS_P] = TCP_FLAGS_SYNACK_V;
|
||||
make_tcphead(1,0);
|
||||
gPB[TCP_SEQ_H_P+0] = 0;
|
||||
gPB[TCP_SEQ_H_P+1] = 0;
|
||||
gPB[TCP_SEQ_H_P+2] = seqnum;
|
||||
gPB[TCP_SEQ_H_P+3] = 0;
|
||||
seqnum += 3;
|
||||
gPB[TCP_OPTIONS_P] = 2;
|
||||
gPB[TCP_OPTIONS_P+1] = 4;
|
||||
gPB[TCP_OPTIONS_P+2] = 0x05;
|
||||
gPB[TCP_OPTIONS_P+3] = 0x0;
|
||||
gPB[TCP_HEADER_LEN_P] = 0x60;
|
||||
gPB[TCP_WIN_SIZE] = 0x5; // 1400=0x578
|
||||
gPB[TCP_WIN_SIZE+1] = 0x78;
|
||||
fill_checksum(TCP_CHECKSUM_H_P, IP_SRC_P, 8+TCP_HEADER_LEN_PLAIN+4,2);
|
||||
EtherCard::packetSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4+ETH_HEADER_LEN);
|
||||
}
|
||||
|
||||
static uint16_t get_tcp_data_len() {
|
||||
int16_t i = (((int16_t)gPB[IP_TOTLEN_H_P])<<8)|gPB[IP_TOTLEN_L_P];
|
||||
i -= IP_HEADER_LEN;
|
||||
i -= (gPB[TCP_HEADER_LEN_P]>>4)*4; // generate len in bytes;
|
||||
if (i<=0)
|
||||
i = 0;
|
||||
return (uint16_t)i;
|
||||
}
|
||||
|
||||
static void make_tcp_ack_from_any(int16_t datlentoack,uint8_t addflags) {
|
||||
gPB[TCP_FLAGS_P] = TCP_FLAGS_ACK_V|addflags;
|
||||
if (addflags!=TCP_FLAGS_RST_V && datlentoack==0)
|
||||
datlentoack = 1;
|
||||
make_tcphead(datlentoack,1); // no options
|
||||
uint16_t j = IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN;
|
||||
gPB[IP_TOTLEN_H_P] = j>>8;
|
||||
gPB[IP_TOTLEN_L_P] = j;
|
||||
make_eth_ip();
|
||||
gPB[TCP_WIN_SIZE] = 0x4; // 1024=0x400, 1280=0x500 2048=0x800 768=0x300
|
||||
gPB[TCP_WIN_SIZE+1] = 0;
|
||||
fill_checksum(TCP_CHECKSUM_H_P, IP_SRC_P, 8+TCP_HEADER_LEN_PLAIN,2);
|
||||
EtherCard::packetSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN);
|
||||
}
|
||||
|
||||
static void make_tcp_ack_with_data_noflags(uint16_t dlen) {
|
||||
uint16_t j = IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen;
|
||||
gPB[IP_TOTLEN_H_P] = j>>8;
|
||||
gPB[IP_TOTLEN_L_P] = j;
|
||||
fill_ip_hdr_checksum();
|
||||
gPB[TCP_CHECKSUM_H_P] = 0;
|
||||
gPB[TCP_CHECKSUM_L_P] = 0;
|
||||
fill_checksum(TCP_CHECKSUM_H_P, IP_SRC_P, 8+TCP_HEADER_LEN_PLAIN+dlen,2);
|
||||
EtherCard::packetSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen+ETH_HEADER_LEN);
|
||||
}
|
||||
|
||||
void EtherCard::httpServerReply (uint16_t dlen) {
|
||||
make_tcp_ack_from_any(info_data_len,0); // send ack for http get
|
||||
gPB[TCP_FLAGS_P] = TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V;
|
||||
make_tcp_ack_with_data_noflags(dlen); // send data
|
||||
}
|
||||
|
||||
static void get_seq() { //get the sequence number of packets after an ack from GET
|
||||
SEQ =(((unsigned long)gPB[TCP_SEQ_H_P]*256+gPB[TCP_SEQ_H_P+1])*256+gPB[TCP_SEQ_H_P+2])*256+gPB[TCP_SEQ_H_P+3];
|
||||
} //thanks to mstuetz for the missing (unsigned long)
|
||||
|
||||
static void set_seq() { //set the correct sequence number and calculate the next with the lenght of current packet
|
||||
gPB[TCP_SEQ_H_P]= (SEQ & 0xff000000 ) >> 24;
|
||||
gPB[TCP_SEQ_H_P+1]= (SEQ & 0xff0000 ) >> 16;
|
||||
gPB[TCP_SEQ_H_P+2]= (SEQ & 0xff00 ) >> 8;
|
||||
gPB[TCP_SEQ_H_P+3]= (SEQ & 0xff );
|
||||
}
|
||||
|
||||
void EtherCard::httpServerReplyAck () {
|
||||
make_tcp_ack_from_any(info_data_len,0); // send ack for http get
|
||||
get_seq(); //get the sequence number of packets after an ack from GET
|
||||
}
|
||||
|
||||
void EtherCard::httpServerReply_with_flags (uint16_t dlen , uint8_t flags) {
|
||||
set_seq();
|
||||
gPB[TCP_FLAGS_P] = flags; // final packet
|
||||
make_tcp_ack_with_data_noflags(dlen); // send data
|
||||
SEQ=SEQ+dlen;
|
||||
}
|
||||
|
||||
void EtherCard::clientIcmpRequest(const uint8_t *destip) {
|
||||
if(is_lan(EtherCard::myip, destip)) {
|
||||
setMACandIPs(destmacaddr, destip);
|
||||
} else {
|
||||
setMACandIPs(gwmacaddr, destip);
|
||||
}
|
||||
gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
|
||||
gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
|
||||
memcpy_P(gPB + IP_P,iphdr,9);
|
||||
gPB[IP_TOTLEN_L_P] = 0x54;
|
||||
gPB[IP_PROTO_P] = IP_PROTO_ICMP_V;
|
||||
fill_ip_hdr_checksum();
|
||||
gPB[ICMP_TYPE_P] = ICMP_TYPE_ECHOREQUEST_V;
|
||||
gPB[ICMP_TYPE_P+1] = 0; // code
|
||||
gPB[ICMP_CHECKSUM_H_P] = 0;
|
||||
gPB[ICMP_CHECKSUM_L_P] = 0;
|
||||
gPB[ICMP_IDENT_H_P] = 5; // some number
|
||||
gPB[ICMP_IDENT_L_P] = EtherCard::myip[3]; // last byte of my IP
|
||||
gPB[ICMP_IDENT_L_P+1] = 0; // seq number, high byte
|
||||
gPB[ICMP_IDENT_L_P+2] = 1; // seq number, low byte, we send only 1 ping at a time
|
||||
memset(gPB + ICMP_DATA_P, PINGPATTERN, 56);
|
||||
fill_checksum(ICMP_CHECKSUM_H_P, ICMP_TYPE_P, 56+8,0);
|
||||
packetSend(98);
|
||||
}
|
||||
|
||||
void EtherCard::ntpRequest (uint8_t *ntpip,uint8_t srcport) {
|
||||
if(is_lan(myip, ntpip)) {
|
||||
setMACandIPs(destmacaddr, ntpip);
|
||||
} else {
|
||||
setMACandIPs(gwmacaddr, ntpip);
|
||||
}
|
||||
gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
|
||||
gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
|
||||
memcpy_P(gPB + IP_P,iphdr,9);
|
||||
gPB[IP_TOTLEN_L_P] = 0x4c;
|
||||
gPB[IP_PROTO_P] = IP_PROTO_UDP_V;
|
||||
fill_ip_hdr_checksum();
|
||||
gPB[UDP_DST_PORT_H_P] = 0;
|
||||
gPB[UDP_DST_PORT_L_P] = 0x7b; // ntp = 123
|
||||
gPB[UDP_SRC_PORT_H_P] = 10;
|
||||
gPB[UDP_SRC_PORT_L_P] = srcport; // lower 8 bit of src port
|
||||
gPB[UDP_LEN_H_P] = 0;
|
||||
gPB[UDP_LEN_L_P] = 56; // fixed len
|
||||
gPB[UDP_CHECKSUM_H_P] = 0;
|
||||
gPB[UDP_CHECKSUM_L_P] = 0;
|
||||
memset(gPB + UDP_DATA_P, 0, 48);
|
||||
memcpy_P(gPB + UDP_DATA_P,ntpreqhdr,10);
|
||||
fill_checksum(UDP_CHECKSUM_H_P, IP_SRC_P, 16 + 48,1);
|
||||
packetSend(90);
|
||||
}
|
||||
|
||||
uint8_t EtherCard::ntpProcessAnswer (uint32_t *time,uint8_t dstport_l) {
|
||||
if ((dstport_l && gPB[UDP_DST_PORT_L_P]!=dstport_l) || gPB[UDP_LEN_H_P]!=0 ||
|
||||
gPB[UDP_LEN_L_P]!=56 || gPB[UDP_SRC_PORT_L_P]!=0x7b)
|
||||
return 0;
|
||||
((uint8_t*) time)[3] = gPB[0x52];
|
||||
((uint8_t*) time)[2] = gPB[0x53];
|
||||
((uint8_t*) time)[1] = gPB[0x54];
|
||||
((uint8_t*) time)[0] = gPB[0x55];
|
||||
return 1;
|
||||
}
|
||||
|
||||
void EtherCard::udpPrepare (uint16_t sport, const uint8_t *dip, uint16_t dport) {
|
||||
if(is_lan(myip, dip)) { // this works because both dns mac and destinations mac are stored in same variable - destmacaddr
|
||||
setMACandIPs(destmacaddr, dip); // at different times. The program could have separate variable for dns mac, then here should be
|
||||
} else { // checked if dip is dns ip and separately if dip is hisip and then use correct mac.
|
||||
setMACandIPs(gwmacaddr, dip);
|
||||
}
|
||||
// see http://tldp.org/HOWTO/Multicast-HOWTO-2.html
|
||||
// multicast or broadcast address, https://github.com/jcw/ethercard/issues/59
|
||||
if ((dip[0] & 0xF0) == 0xE0 || *((unsigned long*) dip) == 0xFFFFFFFF)
|
||||
EtherCard::copyMac(gPB + ETH_DST_MAC, allOnes);
|
||||
gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
|
||||
gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
|
||||
memcpy_P(gPB + IP_P,iphdr,9);
|
||||
gPB[IP_TOTLEN_H_P] = 0;
|
||||
gPB[IP_PROTO_P] = IP_PROTO_UDP_V;
|
||||
gPB[UDP_DST_PORT_H_P] = (dport>>8);
|
||||
gPB[UDP_DST_PORT_L_P] = dport;
|
||||
gPB[UDP_SRC_PORT_H_P] = (sport>>8);
|
||||
gPB[UDP_SRC_PORT_L_P] = sport;
|
||||
gPB[UDP_LEN_H_P] = 0;
|
||||
gPB[UDP_CHECKSUM_H_P] = 0;
|
||||
gPB[UDP_CHECKSUM_L_P] = 0;
|
||||
}
|
||||
|
||||
void EtherCard::udpTransmit (uint16_t datalen) {
|
||||
gPB[IP_TOTLEN_H_P] = (IP_HEADER_LEN+UDP_HEADER_LEN+datalen) >> 8;
|
||||
gPB[IP_TOTLEN_L_P] = IP_HEADER_LEN+UDP_HEADER_LEN+datalen;
|
||||
fill_ip_hdr_checksum();
|
||||
gPB[UDP_LEN_H_P] = (UDP_HEADER_LEN+datalen) >>8;
|
||||
gPB[UDP_LEN_L_P] = UDP_HEADER_LEN+datalen;
|
||||
fill_checksum(UDP_CHECKSUM_H_P, IP_SRC_P, 16 + datalen,1);
|
||||
packetSend(UDP_HEADER_LEN+IP_HEADER_LEN+ETH_HEADER_LEN+datalen);
|
||||
}
|
||||
|
||||
void EtherCard::sendUdp (const char *data, uint8_t datalen, uint16_t sport,
|
||||
const uint8_t *dip, uint16_t dport) {
|
||||
udpPrepare(sport, dip, dport);
|
||||
if (datalen>220)
|
||||
datalen = 220;
|
||||
memcpy(gPB + UDP_DATA_P, data, datalen);
|
||||
udpTransmit(datalen);
|
||||
}
|
||||
|
||||
void EtherCard::sendWol (uint8_t *wolmac) {
|
||||
setMACandIPs(allOnes, allOnes);
|
||||
gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
|
||||
gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
|
||||
memcpy_P(gPB + IP_P,iphdr,9);
|
||||
gPB[IP_TOTLEN_L_P] = 0x82;
|
||||
gPB[IP_PROTO_P] = IP_PROTO_UDP_V;
|
||||
fill_ip_hdr_checksum();
|
||||
gPB[UDP_DST_PORT_H_P] = 0;
|
||||
gPB[UDP_DST_PORT_L_P] = 0x9; // wol = normally 9
|
||||
gPB[UDP_SRC_PORT_H_P] = 10;
|
||||
gPB[UDP_SRC_PORT_L_P] = 0x42; // source port does not matter
|
||||
gPB[UDP_LEN_H_P] = 0;
|
||||
gPB[UDP_LEN_L_P] = 110; // fixed len
|
||||
gPB[UDP_CHECKSUM_H_P] = 0;
|
||||
gPB[UDP_CHECKSUM_L_P] = 0;
|
||||
copyMac(gPB + UDP_DATA_P, allOnes);
|
||||
uint8_t pos = UDP_DATA_P;
|
||||
for (uint8_t m = 0; m < 16; ++m) {
|
||||
pos += 6;
|
||||
copyMac(gPB + pos, wolmac);
|
||||
}
|
||||
fill_checksum(UDP_CHECKSUM_H_P, IP_SRC_P, 16 + 102,1);
|
||||
packetSend(pos + 6);
|
||||
}
|
||||
|
||||
// make a arp request
|
||||
static void client_arp_whohas(uint8_t *ip_we_search) {
|
||||
setMACs(allOnes);
|
||||
gPB[ETH_TYPE_H_P] = ETHTYPE_ARP_H_V;
|
||||
gPB[ETH_TYPE_L_P] = ETHTYPE_ARP_L_V;
|
||||
memcpy_P(gPB + ETH_ARP_P,arpreqhdr,8);
|
||||
memset(gPB + ETH_ARP_DST_MAC_P, 0, 6);
|
||||
EtherCard::copyMac(gPB + ETH_ARP_SRC_MAC_P, EtherCard::mymac);
|
||||
EtherCard::copyIp(gPB + ETH_ARP_DST_IP_P, ip_we_search);
|
||||
EtherCard::copyIp(gPB + ETH_ARP_SRC_IP_P, EtherCard::myip);
|
||||
EtherCard::packetSend(42);
|
||||
}
|
||||
|
||||
uint8_t EtherCard::clientWaitingGw () {
|
||||
return !(waitgwmac & WGW_HAVE_GW_MAC);
|
||||
}
|
||||
|
||||
uint8_t EtherCard::clientWaitingDns () {
|
||||
if(is_lan(myip, dnsip))
|
||||
return !has_dns_mac;
|
||||
return !(waitgwmac & WGW_HAVE_GW_MAC);
|
||||
}
|
||||
|
||||
static uint8_t client_store_mac(uint8_t *source_ip, uint8_t *mac) {
|
||||
if (memcmp(gPB + ETH_ARP_SRC_IP_P, source_ip, 4) != 0)
|
||||
return 0;
|
||||
EtherCard::copyMac(mac, gPB + ETH_ARP_SRC_MAC_P);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// static void client_gw_arp_refresh() {
|
||||
// if (waitgwmac & WGW_HAVE_GW_MAC)
|
||||
// waitgwmac |= WGW_REFRESHING;
|
||||
// }
|
||||
|
||||
void EtherCard::setGwIp (const uint8_t *gwipaddr) {
|
||||
delaycnt = 0; //request gateway ARP lookup
|
||||
waitgwmac = WGW_INITIAL_ARP; // causes an arp request in the packet loop
|
||||
copyIp(gwip, gwipaddr);
|
||||
}
|
||||
|
||||
void EtherCard::updateBroadcastAddress()
|
||||
{
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
broadcastip[i] = myip[i] | ~netmask[i];
|
||||
}
|
||||
|
||||
static void client_syn(uint8_t srcport,uint8_t dstport_h,uint8_t dstport_l) {
|
||||
if(is_lan(EtherCard::myip, EtherCard::hisip)) {
|
||||
setMACandIPs(destmacaddr, EtherCard::hisip);
|
||||
} else {
|
||||
setMACandIPs(gwmacaddr, EtherCard::hisip);
|
||||
}
|
||||
gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
|
||||
gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
|
||||
memcpy_P(gPB + IP_P,iphdr,9);
|
||||
gPB[IP_TOTLEN_L_P] = 44; // good for syn
|
||||
gPB[IP_PROTO_P] = IP_PROTO_TCP_V;
|
||||
fill_ip_hdr_checksum();
|
||||
gPB[TCP_DST_PORT_H_P] = dstport_h;
|
||||
gPB[TCP_DST_PORT_L_P] = dstport_l;
|
||||
gPB[TCP_SRC_PORT_H_P] = TCPCLIENT_SRC_PORT_H;
|
||||
gPB[TCP_SRC_PORT_L_P] = srcport; // lower 8 bit of src port
|
||||
memset(gPB + TCP_SEQ_H_P, 0, 8);
|
||||
gPB[TCP_SEQ_H_P+2] = seqnum;
|
||||
seqnum += 3;
|
||||
gPB[TCP_HEADER_LEN_P] = 0x60; // 0x60=24 len: (0x60>>4) * 4
|
||||
gPB[TCP_FLAGS_P] = TCP_FLAGS_SYN_V;
|
||||
gPB[TCP_WIN_SIZE] = 0x3; // 1024 = 0x400 768 = 0x300, initial window
|
||||
gPB[TCP_WIN_SIZE+1] = 0x0;
|
||||
gPB[TCP_CHECKSUM_H_P] = 0;
|
||||
gPB[TCP_CHECKSUM_L_P] = 0;
|
||||
gPB[TCP_CHECKSUM_L_P+1] = 0;
|
||||
gPB[TCP_CHECKSUM_L_P+2] = 0;
|
||||
gPB[TCP_OPTIONS_P] = 2;
|
||||
gPB[TCP_OPTIONS_P+1] = 4;
|
||||
gPB[TCP_OPTIONS_P+2] = (CLIENTMSS>>8);
|
||||
gPB[TCP_OPTIONS_P+3] = (uint8_t) CLIENTMSS;
|
||||
fill_checksum(TCP_CHECKSUM_H_P, IP_SRC_P, 8 +TCP_HEADER_LEN_PLAIN+4,2);
|
||||
// 4 is the tcp mss option:
|
||||
EtherCard::packetSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN+4);
|
||||
}
|
||||
|
||||
uint8_t EtherCard::clientTcpReq (uint8_t (*result_cb)(uint8_t,uint8_t,uint16_t,uint16_t),
|
||||
uint16_t (*datafill_cb)(uint8_t),uint16_t port) {
|
||||
client_tcp_result_cb = result_cb;
|
||||
client_tcp_datafill_cb = datafill_cb;
|
||||
tcp_client_port_h = port>>8;
|
||||
tcp_client_port_l = port;
|
||||
tcp_client_state = 1; // Flag to packetloop to initiate a TCP/IP session by send a syn
|
||||
tcp_fd = (tcp_fd + 1) & 7;
|
||||
return tcp_fd;
|
||||
}
|
||||
|
||||
static uint16_t www_client_internal_datafill_cb(uint8_t fd) {
|
||||
BufferFiller bfill = EtherCard::tcpOffset();
|
||||
if (fd==www_fd) {
|
||||
if (client_postval == 0) {
|
||||
bfill.emit_p(PSTR("GET $F$S HTTP/1.0\r\n"
|
||||
"Host: $F\r\n"
|
||||
"$F\r\n"
|
||||
"\r\n"), client_urlbuf,
|
||||
client_urlbuf_var,
|
||||
client_hoststr, client_additionalheaderline);
|
||||
} else {
|
||||
const char* ahl = client_additionalheaderline;
|
||||
bfill.emit_p(PSTR("POST $F HTTP/1.0\r\n"
|
||||
"Host: $F\r\n"
|
||||
"$F$S"
|
||||
"Accept: */*\r\n"
|
||||
"Content-Length: $D\r\n"
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n"
|
||||
"\r\n"
|
||||
"$S"), client_urlbuf,
|
||||
client_hoststr,
|
||||
ahl != 0 ? ahl : PSTR(""),
|
||||
ahl != 0 ? "\r\n" : "",
|
||||
strlen(client_postval),
|
||||
client_postval);
|
||||
}
|
||||
}
|
||||
return bfill.position();
|
||||
}
|
||||
|
||||
static uint8_t www_client_internal_result_cb(uint8_t fd, uint8_t statuscode, uint16_t datapos, uint16_t len_of_data) {
|
||||
if (fd!=www_fd)
|
||||
(*client_browser_cb)(4,0,0);
|
||||
else if (statuscode==0 && len_of_data>12 && client_browser_cb) {
|
||||
uint8_t f = strncmp("200",(char *)&(gPB[datapos+9]),3) != 0;
|
||||
(*client_browser_cb)(f, ((uint16_t)TCP_SRC_PORT_H_P+(gPB[TCP_HEADER_LEN_P]>>4)*4),len_of_data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EtherCard::browseUrl (const char *urlbuf, const char *urlbuf_varpart, const char *hoststr, void (*callback)(uint8_t,uint16_t,uint16_t)) {
|
||||
browseUrl(urlbuf, urlbuf_varpart, hoststr, PSTR("Accept: text/html"), callback);
|
||||
}
|
||||
|
||||
void EtherCard::browseUrl (const char *urlbuf, const char *urlbuf_varpart, const char *hoststr, const char *additionalheaderline, void (*callback)(uint8_t,uint16_t,uint16_t)) {
|
||||
client_urlbuf = urlbuf;
|
||||
client_urlbuf_var = urlbuf_varpart;
|
||||
client_hoststr = hoststr;
|
||||
client_additionalheaderline = additionalheaderline;
|
||||
client_postval = 0;
|
||||
client_browser_cb = callback;
|
||||
www_fd = clientTcpReq(&www_client_internal_result_cb,&www_client_internal_datafill_cb,hisport);
|
||||
}
|
||||
|
||||
void EtherCard::httpPost (const char *urlbuf, const char *hoststr, const char *additionalheaderline, const char *postval, void (*callback)(uint8_t,uint16_t,uint16_t)) {
|
||||
client_urlbuf = urlbuf;
|
||||
client_hoststr = hoststr;
|
||||
client_additionalheaderline = additionalheaderline;
|
||||
client_postval = postval;
|
||||
client_browser_cb = callback;
|
||||
www_fd = clientTcpReq(&www_client_internal_result_cb,&www_client_internal_datafill_cb,hisport);
|
||||
}
|
||||
|
||||
static uint16_t tcp_datafill_cb(uint8_t fd) {
|
||||
uint16_t len = Stash::length();
|
||||
Stash::extract(0, len, EtherCard::tcpOffset());
|
||||
Stash::cleanup();
|
||||
EtherCard::tcpOffset()[len] = 0;
|
||||
#if SERIAL
|
||||
Serial.print("REQUEST: ");
|
||||
Serial.println(len);
|
||||
Serial.println((char*) EtherCard::tcpOffset());
|
||||
#endif
|
||||
result_fd = 123; // bogus value
|
||||
return len;
|
||||
}
|
||||
|
||||
static uint8_t tcp_result_cb(uint8_t fd, uint8_t status, uint16_t datapos, uint16_t datalen) {
|
||||
if (status == 0) {
|
||||
result_fd = fd; // a valid result has been received, remember its session id
|
||||
result_ptr = (char*) ether.buffer + datapos;
|
||||
// result_ptr[datalen] = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t EtherCard::tcpSend () {
|
||||
www_fd = clientTcpReq(&tcp_result_cb, &tcp_datafill_cb, hisport);
|
||||
return www_fd;
|
||||
}
|
||||
|
||||
const char* EtherCard::tcpReply (uint8_t fd) {
|
||||
if (result_fd != fd)
|
||||
return 0;
|
||||
result_fd = 123; // set to a bogus value to prevent future match
|
||||
return result_ptr;
|
||||
}
|
||||
|
||||
void EtherCard::registerPingCallback (void (*callback)(uint8_t *srcip)) {
|
||||
icmp_cb = callback;
|
||||
}
|
||||
|
||||
uint8_t EtherCard::packetLoopIcmpCheckReply (const uint8_t *ip_monitoredhost) {
|
||||
return gPB[IP_PROTO_P]==IP_PROTO_ICMP_V &&
|
||||
gPB[ICMP_TYPE_P]==ICMP_TYPE_ECHOREPLY_V &&
|
||||
gPB[ICMP_DATA_P]== PINGPATTERN &&
|
||||
check_ip_message_is_from(ip_monitoredhost);
|
||||
}
|
||||
|
||||
uint16_t EtherCard::accept(const uint16_t port, uint16_t plen) {
|
||||
uint16_t pos;
|
||||
|
||||
if (gPB[TCP_DST_PORT_H_P] == (port >> 8) &&
|
||||
gPB[TCP_DST_PORT_L_P] == ((uint8_t) port))
|
||||
{ //Packet targetted at specified port
|
||||
if (gPB[TCP_FLAGS_P] & TCP_FLAGS_SYN_V)
|
||||
make_tcp_synack_from_syn(); //send SYN+ACK
|
||||
else if (gPB[TCP_FLAGS_P] & TCP_FLAGS_ACK_V)
|
||||
{ //This is an acknowledgement to our SYN+ACK so let's start processing that payload
|
||||
info_data_len = get_tcp_data_len();
|
||||
if (info_data_len > 0)
|
||||
{ //Got some data
|
||||
pos = TCP_DATA_START; // TCP_DATA_START is a formula
|
||||
if (pos <= plen - 8)
|
||||
return pos;
|
||||
}
|
||||
else if (gPB[TCP_FLAGS_P] & TCP_FLAGS_FIN_V)
|
||||
make_tcp_ack_from_any(0,0); //No data so close connection
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t EtherCard::packetLoop (uint16_t plen) {
|
||||
uint16_t len;
|
||||
if(using_dhcp) {
|
||||
ether.DhcpStateMachine(plen);
|
||||
}
|
||||
|
||||
if (plen==0) {
|
||||
//Check every 65536 (no-packet) cycles whether we need to retry ARP request for gateway
|
||||
if ((waitgwmac & WGW_INITIAL_ARP || waitgwmac & WGW_REFRESHING) &&
|
||||
delaycnt==0 && isLinkUp()) {
|
||||
client_arp_whohas(gwip);
|
||||
waitgwmac |= WGW_ACCEPT_ARP_REPLY;
|
||||
}
|
||||
delaycnt++;
|
||||
//Initiate TCP/IP session if pending
|
||||
if (tcp_client_state==1 && (waitgwmac & WGW_HAVE_GW_MAC)) { // send a syn
|
||||
tcp_client_state = 2;
|
||||
tcpclient_src_port_l++; // allocate a new port
|
||||
client_syn(((tcp_fd<<5) | (0x1f & tcpclient_src_port_l)),tcp_client_port_h,tcp_client_port_l);
|
||||
}
|
||||
//!@todo this is trying to find mac only once. Need some timeout to make another call if first one doesn't succeed.
|
||||
if(is_lan(myip, dnsip) && !has_dns_mac && !waiting_for_dns_mac) {
|
||||
client_arp_whohas(dnsip);
|
||||
waiting_for_dns_mac = true;
|
||||
}
|
||||
//!@todo this is trying to find mac only once. Need some timeout to make another call if first one doesn't succeed.
|
||||
if(is_lan(myip, hisip) && !has_dest_mac && !waiting_for_dest_mac) {
|
||||
client_arp_whohas(hisip);
|
||||
waiting_for_dest_mac = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (eth_type_is_arp_and_my_ip(plen))
|
||||
{ //Service ARP request
|
||||
if (gPB[ETH_ARP_OPCODE_L_P]==ETH_ARP_OPCODE_REQ_L_V)
|
||||
make_arp_answer_from_request();
|
||||
if (waitgwmac & WGW_ACCEPT_ARP_REPLY && (gPB[ETH_ARP_OPCODE_L_P]==ETH_ARP_OPCODE_REPLY_L_V) && client_store_mac(gwip, gwmacaddr))
|
||||
waitgwmac = WGW_HAVE_GW_MAC;
|
||||
if (!has_dns_mac && waiting_for_dns_mac && client_store_mac(dnsip, destmacaddr)) {
|
||||
has_dns_mac = true;
|
||||
waiting_for_dns_mac = false;
|
||||
}
|
||||
if (!has_dest_mac && waiting_for_dest_mac && client_store_mac(hisip, destmacaddr)) {
|
||||
has_dest_mac = true;
|
||||
waiting_for_dest_mac = false;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (eth_type_is_ip_and_my_ip(plen)==0)
|
||||
{ //Not IP so ignoring
|
||||
//!@todo Add other protocols (and make each optional at compile time)
|
||||
return 0;
|
||||
}
|
||||
if (gPB[IP_PROTO_P]==IP_PROTO_ICMP_V && gPB[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V)
|
||||
{ //Service ICMP echo request (ping)
|
||||
if (icmp_cb)
|
||||
(*icmp_cb)(&(gPB[IP_SRC_P]));
|
||||
make_echo_reply_from_request(plen);
|
||||
return 0;
|
||||
}
|
||||
if (ether.udpServerListening() && gPB[IP_PROTO_P]==IP_PROTO_UDP_V)
|
||||
{ //Call UDP server handler (callback) if one is defined for this packet
|
||||
if(ether.udpServerHasProcessedPacket(plen))
|
||||
return 0; //An UDP server handler (callback) has processed this packet
|
||||
}
|
||||
if (plen<54 && gPB[IP_PROTO_P]!=IP_PROTO_TCP_V )
|
||||
return 0; //Packet flagged as TCP but shorter than minimum TCP packet length
|
||||
if (gPB[TCP_DST_PORT_H_P]==TCPCLIENT_SRC_PORT_H)
|
||||
{ //Source port is in range reserved (by EtherCard) for client TCP/IP connections
|
||||
if (check_ip_message_is_from(hisip)==0)
|
||||
return 0; //Not current TCP/IP connection (only handle one at a time)
|
||||
if (gPB[TCP_FLAGS_P] & TCP_FLAGS_RST_V)
|
||||
{ //TCP reset flagged
|
||||
if (client_tcp_result_cb)
|
||||
(*client_tcp_result_cb)((gPB[TCP_DST_PORT_L_P]>>5)&0x7,3,0,0);
|
||||
tcp_client_state = 5;
|
||||
return 0;
|
||||
}
|
||||
len = get_tcp_data_len();
|
||||
if (tcp_client_state==2)
|
||||
{ //Waiting for SYN-ACK
|
||||
if ((gPB[TCP_FLAGS_P] & TCP_FLAGS_SYN_V) && (gPB[TCP_FLAGS_P] &TCP_FLAGS_ACK_V))
|
||||
{ //SYN and ACK flags set so this is an acknowledgement to our SYN
|
||||
make_tcp_ack_from_any(0,0);
|
||||
gPB[TCP_FLAGS_P] = TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V;
|
||||
if (client_tcp_datafill_cb)
|
||||
len = (*client_tcp_datafill_cb)((gPB[TCP_SRC_PORT_L_P]>>5)&0x7);
|
||||
else
|
||||
len = 0;
|
||||
tcp_client_state = 3;
|
||||
make_tcp_ack_with_data_noflags(len);
|
||||
}
|
||||
else
|
||||
{ //Expecting SYN+ACK so reset and resend SYN
|
||||
tcp_client_state = 1; // retry
|
||||
len++;
|
||||
if (gPB[TCP_FLAGS_P] & TCP_FLAGS_ACK_V)
|
||||
len = 0;
|
||||
make_tcp_ack_from_any(len,TCP_FLAGS_RST_V);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (tcp_client_state==3 && len>0)
|
||||
{ //TCP connection established so read data
|
||||
if (client_tcp_result_cb) {
|
||||
uint16_t tcpstart = TCP_DATA_START; // TCP_DATA_START is a formula
|
||||
if (tcpstart>plen-8)
|
||||
tcpstart = plen-8; // dummy but save
|
||||
uint16_t save_len = len;
|
||||
if (tcpstart+len>plen)
|
||||
save_len = plen-tcpstart;
|
||||
(*client_tcp_result_cb)((gPB[TCP_DST_PORT_L_P]>>5)&0x7,0,tcpstart,save_len); //Call TCP handler (callback) function
|
||||
|
||||
if(persist_tcp_connection)
|
||||
{ //Keep connection alive by sending ACK
|
||||
make_tcp_ack_from_any(len,TCP_FLAGS_PUSH_V);
|
||||
}
|
||||
else
|
||||
{ //Close connection
|
||||
make_tcp_ack_from_any(len,TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V);
|
||||
tcp_client_state = 6;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (tcp_client_state != 5)
|
||||
{ //
|
||||
if (gPB[TCP_FLAGS_P] & TCP_FLAGS_FIN_V) {
|
||||
if(tcp_client_state == 3) {
|
||||
return 0; // In some instances FIN is received *before* DATA. If that is the case, we just return here and keep looking for the data packet
|
||||
}
|
||||
make_tcp_ack_from_any(len+1,TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V);
|
||||
tcp_client_state = 6; // connection terminated
|
||||
} else if (len>0) {
|
||||
make_tcp_ack_from_any(len,0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//If we are here then this is a TCP/IP packet targetted at us and not related to out client connection so accept
|
||||
return accept(hisport, plen);
|
||||
}
|
||||
|
||||
void EtherCard::persistTcpConnection(bool persist) {
|
||||
persist_tcp_connection = persist;
|
||||
}
|
||||
72
lib-ext/ethercard.git/udpserver.cpp
Normal file
72
lib-ext/ethercard.git/udpserver.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// Simple UDP listening server
|
||||
//
|
||||
// Author: Brian Lee
|
||||
//
|
||||
// Copyright: GPL V2
|
||||
// See http://www.gnu.org/licenses/gpl.html
|
||||
|
||||
#include "EtherCard.h"
|
||||
#include "net.h"
|
||||
|
||||
#define gPB ether.buffer
|
||||
|
||||
#define UDPSERVER_MAXLISTENERS 8 //the maximum number of port listeners.
|
||||
|
||||
typedef struct {
|
||||
UdpServerCallback callback;
|
||||
uint16_t port;
|
||||
bool listening;
|
||||
} UdpServerListener;
|
||||
|
||||
UdpServerListener listeners[UDPSERVER_MAXLISTENERS];
|
||||
byte numListeners = 0;
|
||||
|
||||
void EtherCard::udpServerListenOnPort(UdpServerCallback callback, uint16_t port) {
|
||||
if(numListeners < UDPSERVER_MAXLISTENERS)
|
||||
{
|
||||
listeners[numListeners] = (UdpServerListener) {
|
||||
callback, port, true
|
||||
};
|
||||
numListeners++;
|
||||
}
|
||||
}
|
||||
|
||||
void EtherCard::udpServerPauseListenOnPort(uint16_t port) {
|
||||
for(int i = 0; i < numListeners; i++)
|
||||
{
|
||||
if(gPB[UDP_DST_PORT_H_P] == (listeners[i].port >> 8) && gPB[UDP_DST_PORT_L_P] == ((byte) listeners[i].port)) {
|
||||
listeners[i].listening = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EtherCard::udpServerResumeListenOnPort(uint16_t port) {
|
||||
for(int i = 0; i < numListeners; i++)
|
||||
{
|
||||
if(gPB[UDP_DST_PORT_H_P] == (listeners[i].port >> 8) && gPB[UDP_DST_PORT_L_P] == ((byte) listeners[i].port)) {
|
||||
listeners[i].listening = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EtherCard::udpServerListening() {
|
||||
return numListeners > 0;
|
||||
}
|
||||
|
||||
bool EtherCard::udpServerHasProcessedPacket(uint16_t plen) {
|
||||
bool packetProcessed = false;
|
||||
for(int i = 0; i < numListeners; i++)
|
||||
{
|
||||
if(gPB[UDP_DST_PORT_H_P] == (listeners[i].port >> 8) && gPB[UDP_DST_PORT_L_P] == ((byte) listeners[i].port) && listeners[i].listening)
|
||||
{
|
||||
uint16_t datalen = (uint16_t) (gPB[UDP_LEN_H_P] << 8) + gPB[UDP_LEN_L_P] - UDP_HEADER_LEN;
|
||||
listeners[i].callback(
|
||||
listeners[i].port,
|
||||
gPB + IP_SRC_P,
|
||||
(const char *) (gPB + UDP_DATA_P),
|
||||
datalen);
|
||||
packetProcessed = true;
|
||||
}
|
||||
}
|
||||
return packetProcessed;
|
||||
}
|
||||
202
lib-ext/ethercard.git/webutil.cpp
Normal file
202
lib-ext/ethercard.git/webutil.cpp
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
// Some common utilities needed for IP and web applications
|
||||
// Author: Guido Socher
|
||||
// Copyright: GPL V2
|
||||
//
|
||||
// 2010-05-20 <jc@wippler.nl>
|
||||
|
||||
#include "EtherCard.h"
|
||||
|
||||
void EtherCard::copyIp (uint8_t *dst, const uint8_t *src) {
|
||||
memcpy(dst, src, 4);
|
||||
}
|
||||
|
||||
void EtherCard::copyMac (uint8_t *dst, const uint8_t *src) {
|
||||
memcpy(dst, src, 6);
|
||||
}
|
||||
|
||||
void EtherCard::printIp (const char* msg, const uint8_t *buf) {
|
||||
Serial.print(msg);
|
||||
EtherCard::printIp(buf);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void EtherCard::printIp (const __FlashStringHelper *ifsh, const uint8_t *buf) {
|
||||
Serial.print(ifsh);
|
||||
EtherCard::printIp(buf);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void EtherCard::printIp (const uint8_t *buf) {
|
||||
for (uint8_t i = 0; i < 4; ++i) {
|
||||
Serial.print( buf[i], DEC );
|
||||
if (i < 3)
|
||||
Serial.print('.');
|
||||
}
|
||||
}
|
||||
|
||||
// search for a string of the form key=value in
|
||||
// a string that looks like q?xyz=abc&uvw=defgh HTTP/1.1\r\n
|
||||
//
|
||||
// The returned value is stored in strbuf. You must allocate
|
||||
// enough storage for strbuf, maxlen is the size of strbuf.
|
||||
// I.e the value it is declated with: strbuf[5]-> maxlen=5
|
||||
uint8_t EtherCard::findKeyVal (const char *str,char *strbuf, uint8_t maxlen,const char *key)
|
||||
{
|
||||
uint8_t found=0;
|
||||
uint8_t i=0;
|
||||
const char *kp;
|
||||
kp=key;
|
||||
while(*str && *str!=' ' && *str!='\n' && found==0) {
|
||||
if (*str == *kp) {
|
||||
kp++;
|
||||
if (*kp == '\0') {
|
||||
str++;
|
||||
kp=key;
|
||||
if (*str == '=') {
|
||||
found=1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
kp=key;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
if (found==1) {
|
||||
// copy the value to a buffer and terminate it with '\0'
|
||||
while(*str && *str!=' ' && *str!='\n' && *str!='&' && i<maxlen-1) {
|
||||
*strbuf=*str;
|
||||
i++;
|
||||
str++;
|
||||
strbuf++;
|
||||
}
|
||||
*strbuf='\0';
|
||||
}
|
||||
// return the length of the value
|
||||
return(i);
|
||||
}
|
||||
|
||||
// convert a single hex digit character to its integer value
|
||||
unsigned char h2int(char c)
|
||||
{
|
||||
if (c >= '0' && c <='9') {
|
||||
return((unsigned char)c - '0');
|
||||
}
|
||||
if (c >= 'a' && c <='f') {
|
||||
return((unsigned char)c - 'a' + 10);
|
||||
}
|
||||
if (c >= 'A' && c <='F') {
|
||||
return((unsigned char)c - 'A' + 10);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
// decode a url string e.g "hello%20joe" or "hello+joe" becomes "hello joe"
|
||||
void EtherCard::urlDecode (char *urlbuf)
|
||||
{
|
||||
char c;
|
||||
char *dst = urlbuf;
|
||||
while ((c = *urlbuf) != 0) {
|
||||
if (c == '+') c = ' ';
|
||||
if (c == '%') {
|
||||
c = *++urlbuf;
|
||||
c = (h2int(c) << 4) | h2int(*++urlbuf);
|
||||
}
|
||||
*dst++ = c;
|
||||
urlbuf++;
|
||||
}
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
// convert a single character to a 2 digit hex str
|
||||
// a terminating '\0' is added
|
||||
void int2h(char c, char *hstr)
|
||||
{
|
||||
hstr[1]=(c & 0xf)+'0';
|
||||
if ((c & 0xf) >9) {
|
||||
hstr[1]=(c & 0xf) - 10 + 'a';
|
||||
}
|
||||
c=(c>>4)&0xf;
|
||||
hstr[0]=c+'0';
|
||||
if (c > 9) {
|
||||
hstr[0]=c - 10 + 'a';
|
||||
}
|
||||
hstr[2]='\0';
|
||||
}
|
||||
|
||||
// there must be enough space in urlbuf. In the worst case that is
|
||||
// 3 times the length of str
|
||||
void EtherCard::urlEncode (char *str,char *urlbuf)
|
||||
{
|
||||
char c;
|
||||
while ((c = *str) != 0) {
|
||||
if (c == ' '||isalnum(c)) {
|
||||
if (c == ' ') {
|
||||
c = '+';
|
||||
}
|
||||
*urlbuf=c;
|
||||
str++;
|
||||
urlbuf++;
|
||||
continue;
|
||||
}
|
||||
*urlbuf='%';
|
||||
urlbuf++;
|
||||
int2h(c,urlbuf);
|
||||
urlbuf++;
|
||||
urlbuf++;
|
||||
str++;
|
||||
}
|
||||
*urlbuf='\0';
|
||||
}
|
||||
|
||||
// parse a string and extract the IP to bytestr
|
||||
uint8_t EtherCard::parseIp (uint8_t *bytestr,char *str)
|
||||
{
|
||||
char *sptr;
|
||||
uint8_t i=0;
|
||||
sptr=NULL;
|
||||
while(i<4) {
|
||||
bytestr[i]=0;
|
||||
i++;
|
||||
}
|
||||
i=0;
|
||||
while(*str && i<4) {
|
||||
// if a number then start
|
||||
if (sptr==NULL && isdigit(*str)) {
|
||||
sptr=str;
|
||||
}
|
||||
if (*str == '.') {
|
||||
*str ='\0';
|
||||
bytestr[i]=(atoi(sptr)&0xff);
|
||||
i++;
|
||||
sptr=NULL;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
*str ='\0';
|
||||
if (i==3) {
|
||||
bytestr[i]=(atoi(sptr)&0xff);
|
||||
return(0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
// take a byte string and convert it to a human readable display string (base is 10 for ip and 16 for mac addr), len is 4 for IP addr and 6 for mac.
|
||||
void EtherCard::makeNetStr (char *resultstr,uint8_t *bytestr,uint8_t len,char separator,uint8_t base)
|
||||
{
|
||||
uint8_t i=0;
|
||||
uint8_t j=0;
|
||||
while(i<len) {
|
||||
itoa((int)bytestr[i],&resultstr[j],base);
|
||||
// search end of str:
|
||||
while(resultstr[j]) {
|
||||
j++;
|
||||
}
|
||||
resultstr[j]=separator;
|
||||
j++;
|
||||
i++;
|
||||
}
|
||||
j--;
|
||||
resultstr[j]='\0';
|
||||
}
|
||||
|
||||
// end of webutil.c
|
||||
57
lib-ext/narcoleptic/Narcoleptic.cpp
Normal file
57
lib-ext/narcoleptic/Narcoleptic.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Narcoleptic - A sleep library for Arduino
|
||||
* Copyright (C) 2010 Peter Knight (Cathedrow)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/common.h>
|
||||
//#include <util/delay.h>
|
||||
|
||||
#include <avr/wdt.h>
|
||||
#include <avr/sleep.h>
|
||||
#include "Narcoleptic.h"
|
||||
|
||||
SIGNAL(WDT_vect) {
|
||||
wdt_disable();
|
||||
wdt_reset();
|
||||
WDTCSR &= ~_BV(WDIE);
|
||||
}
|
||||
|
||||
void NarcolepticClass::sleep(uint8_t wdt_period) {
|
||||
wdt_enable(wdt_period);
|
||||
wdt_reset();
|
||||
WDTCSR |= _BV(WDIE);
|
||||
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
|
||||
sleep_mode();
|
||||
wdt_disable();
|
||||
WDTCSR &= ~_BV(WDIE);
|
||||
}
|
||||
|
||||
void NarcolepticClass::delay(int milliseconds) {
|
||||
while (milliseconds >= 8000) { sleep(WDTO_8S); milliseconds -= 8000; }
|
||||
if (milliseconds >= 4000) { sleep(WDTO_4S); milliseconds -= 4000; }
|
||||
if (milliseconds >= 2000) { sleep(WDTO_2S); milliseconds -= 2000; }
|
||||
if (milliseconds >= 1000) { sleep(WDTO_1S); milliseconds -= 1000; }
|
||||
if (milliseconds >= 500) { sleep(WDTO_500MS); milliseconds -= 500; }
|
||||
if (milliseconds >= 250) { sleep(WDTO_250MS); milliseconds -= 250; }
|
||||
if (milliseconds >= 125) { sleep(WDTO_120MS); milliseconds -= 120; }
|
||||
if (milliseconds >= 64) { sleep(WDTO_60MS); milliseconds -= 60; }
|
||||
if (milliseconds >= 32) { sleep(WDTO_30MS); milliseconds -= 30; }
|
||||
if (milliseconds >= 16) { sleep(WDTO_15MS); milliseconds -= 15; }
|
||||
}
|
||||
|
||||
NarcolepticClass Narcoleptic;
|
||||
34
lib-ext/narcoleptic/Narcoleptic.h
Normal file
34
lib-ext/narcoleptic/Narcoleptic.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* Narcoleptic - A sleep library for Arduino
|
||||
* Copyright (C) 2010 Peter Knight (Cathedrow)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Narcoleptic_h
|
||||
#define Narcoleptic_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
class NarcolepticClass
|
||||
{
|
||||
public:
|
||||
void delay(int milliseconds);
|
||||
private:
|
||||
void sleep(uint8_t);
|
||||
};
|
||||
extern NarcolepticClass Narcoleptic;
|
||||
|
||||
#endif
|
||||
418
lib-ext/rfm-69.git/Examples/GarageMote/GarageMote.ino
Normal file
418
lib-ext/rfm-69.git/Examples/GarageMote/GarageMote.ino
Normal file
|
|
@ -0,0 +1,418 @@
|
|||
// **********************************************************************************************************
|
||||
// GarageMote garage door controller sketch that works with Moteinos equipped with RFM69W/RFM69HW
|
||||
// Can be adapted to use Moteinos/Arduinos using RFM12B or other RFM69 variants (RFM69CW, RFM69HCW)
|
||||
// http://www.LowPowerLab.com/GarageMote
|
||||
// 2015-02-02 (C) Felix Rusu of http://www.LowPowerLab.com/
|
||||
// **********************************************************************************************************
|
||||
// It uses 2 hall effect sensors (and magnets mounted on the garage belt/chain) to detect the position of the
|
||||
// door, and a small signal relay to be able to toggle the garage opener.
|
||||
// Implementation details are posted at the LowPowerLab blog
|
||||
// Door status is reported via RFM69 to a base Moteino, and visually on the onboard Moteino LED:
|
||||
// - solid ON - door is in open position
|
||||
// - solid OFF - door is in closed position
|
||||
// - blinking - door is not in either open/close position
|
||||
// - pulsing - door is in motion
|
||||
// **********************************************************************************
|
||||
// License
|
||||
// **********************************************************************************
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will
|
||||
// be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
// implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
// PARTICULAR PURPOSE. See the GNU General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// Public License along with this program.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Licence can be viewed at
|
||||
// http://www.gnu.org/licenses/gpl-3.0.txt
|
||||
//
|
||||
// Please maintain this license information along with authorship
|
||||
// and copyright notices in any redistribution of this code
|
||||
// ***************************************************************************************************************************
|
||||
//#define WEATHERSHIELD //uncomment if WeatherShield is present to report temp/humidity/pressure periodically
|
||||
// ***************************************************************************************************************************
|
||||
#include <RFM69.h> //get it here: http://github.com/lowpowerlab/rfm69
|
||||
#include <SPIFlash.h> //get it here: http://github.com/lowpowerlab/spiflash
|
||||
#include <WirelessHEX69.h> //get it here: https://github.com/LowPowerLab/WirelessProgramming
|
||||
#include <SPI.h> //comes with Arduino IDE (www.arduino.cc)
|
||||
|
||||
#ifdef WEATHERSHIELD
|
||||
#include <SFE_BMP180.h> //get it here: https://github.com/LowPowerLab/SFE_BMP180
|
||||
#include <SI7021.h> //get it here: https://github.com/LowPowerLab/SI7021
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
//*****************************************************************************************************************************
|
||||
// ADJUST THE SETTINGS BELOW DEPENDING ON YOUR HARDWARE/TRANSCEIVER SETTINGS/REQUIREMENTS
|
||||
//*****************************************************************************************************************************
|
||||
#define GATEWAYID 1
|
||||
#define NODEID 11
|
||||
#define NETWORKID 250
|
||||
//#define FREQUENCY RF69_433MHZ
|
||||
//#define FREQUENCY RF69_868MHZ
|
||||
#define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ)
|
||||
//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
|
||||
#define ENCRYPTKEY "sampleEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less!
|
||||
|
||||
#define HALLSENSOR1 A0
|
||||
#define HALLSENSOR1_EN 4
|
||||
#define HALLSENSOR2 A1
|
||||
#define HALLSENSOR2_EN 5
|
||||
|
||||
#define RELAYPIN1 6
|
||||
#define RELAYPIN2 7
|
||||
#define RELAY_PULSE_MS 250 //just enough that the opener will pick it up
|
||||
|
||||
#define DOOR_MOVEMENT_TIME 14000 // this has to be at least as long as the max between [door opening time, door closing time]
|
||||
// my door opens and closes in about 12s
|
||||
#define STATUS_CHANGE_MIN 1500 // this has to be at least as long as the delay
|
||||
// between a opener button press and door movement start
|
||||
// most garage doors will start moving immediately (within half a second)
|
||||
//*****************************************************************************************************************************
|
||||
#define WEATHERSENDDELAY 300000 // send WeatherShield data every so often (ms). Ie 300000 ~ 5 min
|
||||
//*****************************************************************************************************************************
|
||||
#define HALLSENSOR_OPENSIDE 0
|
||||
#define HALLSENSOR_CLOSEDSIDE 1
|
||||
|
||||
#define STATUS_CLOSED 0
|
||||
#define STATUS_CLOSING 1
|
||||
#define STATUS_OPENING 2
|
||||
#define STATUS_OPEN 3
|
||||
#define STATUS_UNKNOWN 4
|
||||
|
||||
#define LED 9 //pin connected to onboard LED
|
||||
#define LED_PULSE_PERIOD 5000 //5s seems good value for pulsing/blinking (not too fast/slow)
|
||||
#define SERIAL_BAUD 115200
|
||||
#define SERIAL_EN //comment out if you don't want any serial output
|
||||
|
||||
#ifdef SERIAL_EN
|
||||
#define DEBUG(input) {Serial.print(input); delay(1);}
|
||||
#define DEBUGln(input) {Serial.println(input); delay(1);}
|
||||
#else
|
||||
#define DEBUG(input);
|
||||
#define DEBUGln(input);
|
||||
#endif
|
||||
|
||||
#ifdef WEATHERSHIELD
|
||||
SI7021 weatherShield_SI7021;
|
||||
SFE_BMP180 weatherShield_BMP180;
|
||||
#endif
|
||||
|
||||
//function prototypes
|
||||
void setStatus(byte newSTATUS, boolean reportStatus=true);
|
||||
boolean hallSensorRead(byte which);
|
||||
void pulseRelay();
|
||||
boolean reportStatus();
|
||||
|
||||
//global program variables
|
||||
byte STATUS;
|
||||
unsigned long lastStatusTimestamp=0;
|
||||
unsigned long ledPulseTimestamp=0;
|
||||
unsigned long lastWeatherSent=0;
|
||||
byte lastRequesterNodeID=GATEWAYID;
|
||||
int ledPulseValue=0;
|
||||
boolean ledPulseDirection=false; //false=down, true=up
|
||||
RFM69 radio;
|
||||
char* Pstr = "123.45";
|
||||
char sendBuf[30];
|
||||
SPIFlash flash(8, 0xEF30); //WINDBOND 4MBIT flash chip on CS pin D8 (default for Moteino)
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
pinMode(HALLSENSOR1, INPUT);
|
||||
pinMode(HALLSENSOR2, INPUT);
|
||||
pinMode(HALLSENSOR1_EN, OUTPUT);
|
||||
pinMode(HALLSENSOR2_EN, OUTPUT);
|
||||
pinMode(RELAYPIN1, OUTPUT);
|
||||
pinMode(RELAYPIN2, OUTPUT);
|
||||
pinMode(LED, OUTPUT);
|
||||
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
#ifdef IS_RFM69HW
|
||||
radio.setHighPower(); //uncomment only for RFM69HW!
|
||||
#endif
|
||||
radio.encrypt(ENCRYPTKEY);
|
||||
|
||||
char buff[50];
|
||||
sprintf(buff, "GarageMote : %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
|
||||
DEBUGln(buff);
|
||||
|
||||
if (hallSensorRead(HALLSENSOR_OPENSIDE)==true)
|
||||
setStatus(STATUS_OPEN);
|
||||
if (hallSensorRead(HALLSENSOR_CLOSEDSIDE)==true)
|
||||
setStatus(STATUS_CLOSED);
|
||||
else setStatus(STATUS_UNKNOWN);
|
||||
|
||||
#ifdef WEATHERSHIELD
|
||||
//initialize weather shield sensors
|
||||
weatherShield_SI7021.begin();
|
||||
if (weatherShield_BMP180.begin())
|
||||
{ DEBUGln("BMP180 init success"); }
|
||||
else { DEBUGln("BMP180 init fail\n"); }
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long doorPulseCount = 0;
|
||||
char input;
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (Serial.available())
|
||||
input = Serial.read();
|
||||
|
||||
if (input=='r')
|
||||
{
|
||||
DEBUGln("Relay test...");
|
||||
pulseRelay();
|
||||
input = 0;
|
||||
}
|
||||
|
||||
// UNKNOWN => OPEN/CLOSED
|
||||
if (STATUS == STATUS_UNKNOWN && millis()-(lastStatusTimestamp)>STATUS_CHANGE_MIN)
|
||||
{
|
||||
if (hallSensorRead(HALLSENSOR_OPENSIDE)==true)
|
||||
setStatus(STATUS_OPEN);
|
||||
if (hallSensorRead(HALLSENSOR_CLOSEDSIDE)==true)
|
||||
setStatus(STATUS_CLOSED);
|
||||
}
|
||||
|
||||
// OPEN => CLOSING
|
||||
if (STATUS == STATUS_OPEN && millis()-(lastStatusTimestamp)>STATUS_CHANGE_MIN)
|
||||
{
|
||||
if (hallSensorRead(HALLSENSOR_OPENSIDE)==false)
|
||||
setStatus(STATUS_CLOSING);
|
||||
}
|
||||
|
||||
// CLOSED => OPENING
|
||||
if (STATUS == STATUS_CLOSED && millis()-(lastStatusTimestamp)>STATUS_CHANGE_MIN)
|
||||
{
|
||||
if (hallSensorRead(HALLSENSOR_CLOSEDSIDE)==false)
|
||||
setStatus(STATUS_OPENING);
|
||||
}
|
||||
|
||||
// OPENING/CLOSING => OPEN (when door returns to open due to obstacle or toggle action)
|
||||
// => CLOSED (when door closes normally from OPEN)
|
||||
// => UNKNOWN (when more time passes than normally would for a door up/down movement)
|
||||
if ((STATUS == STATUS_OPENING || STATUS == STATUS_CLOSING) && millis()-(lastStatusTimestamp)>STATUS_CHANGE_MIN)
|
||||
{
|
||||
if (hallSensorRead(HALLSENSOR_OPENSIDE)==true)
|
||||
setStatus(STATUS_OPEN);
|
||||
else if (hallSensorRead(HALLSENSOR_CLOSEDSIDE)==true)
|
||||
setStatus(STATUS_CLOSED);
|
||||
else if (millis()-(lastStatusTimestamp)>DOOR_MOVEMENT_TIME)
|
||||
setStatus(STATUS_UNKNOWN);
|
||||
}
|
||||
|
||||
if (radio.receiveDone())
|
||||
{
|
||||
byte newStatus=STATUS;
|
||||
boolean reportStatusRequest=false;
|
||||
lastRequesterNodeID = radio.SENDERID;
|
||||
DEBUG('[');DEBUG(radio.SENDERID);DEBUG("] ");
|
||||
for (byte i = 0; i < radio.DATALEN; i++)
|
||||
DEBUG((char)radio.DATA[i]);
|
||||
|
||||
if (radio.DATALEN==3)
|
||||
{
|
||||
//check for an OPEN/CLOSE/STATUS request
|
||||
if (radio.DATA[0]=='O' && radio.DATA[1]=='P' && radio.DATA[2]=='N')
|
||||
{
|
||||
if (millis()-(lastStatusTimestamp) > STATUS_CHANGE_MIN && (STATUS == STATUS_CLOSED || STATUS == STATUS_CLOSING || STATUS == STATUS_UNKNOWN))
|
||||
newStatus = STATUS_OPENING;
|
||||
//else radio.Send(requester, "INVALID", 7);
|
||||
}
|
||||
if (radio.DATA[0]=='C' && radio.DATA[1]=='L' && radio.DATA[2]=='S')
|
||||
{
|
||||
if (millis()-(lastStatusTimestamp) > STATUS_CHANGE_MIN && (STATUS == STATUS_OPEN || STATUS == STATUS_OPENING || STATUS == STATUS_UNKNOWN))
|
||||
newStatus = STATUS_CLOSING;
|
||||
//else radio.Send(requester, "INVALID", 7);
|
||||
}
|
||||
if (radio.DATA[0]=='S' && radio.DATA[1]=='T' && radio.DATA[2]=='S')
|
||||
{
|
||||
reportStatusRequest = true;
|
||||
}
|
||||
}
|
||||
|
||||
// wireless programming token check
|
||||
// DO NOT REMOVE, or GarageMote will not be wirelessly programmable any more!
|
||||
CheckForWirelessHEX(radio, flash, true);
|
||||
|
||||
//first send any ACK to request
|
||||
DEBUG(" [RX_RSSI:");DEBUG(radio.RSSI);DEBUG("]");
|
||||
if (radio.ACKRequested())
|
||||
{
|
||||
radio.sendACK();
|
||||
DEBUG(" - ACK sent.");
|
||||
}
|
||||
|
||||
//now take care of the request, if not invalid
|
||||
if (STATUS != newStatus)
|
||||
{
|
||||
pulseRelay();
|
||||
setStatus(newStatus);
|
||||
}
|
||||
if (reportStatusRequest)
|
||||
{
|
||||
reportStatus();
|
||||
}
|
||||
|
||||
DEBUGln();
|
||||
}
|
||||
|
||||
//use LED to visually indicate STATUS
|
||||
if (STATUS == STATUS_OPEN || STATUS == STATUS_CLOSED) //solid ON/OFF
|
||||
{
|
||||
digitalWrite(LED, STATUS == STATUS_OPEN ? LOW : HIGH);
|
||||
}
|
||||
if (STATUS == STATUS_OPENING || STATUS == STATUS_CLOSING) //pulse
|
||||
{
|
||||
if (millis()-(ledPulseTimestamp) > LED_PULSE_PERIOD/256)
|
||||
{
|
||||
ledPulseValue = ledPulseDirection ? ledPulseValue + LED_PULSE_PERIOD/256 : ledPulseValue - LED_PULSE_PERIOD/256;
|
||||
|
||||
if (ledPulseDirection && ledPulseValue > 255)
|
||||
{
|
||||
ledPulseDirection=false;
|
||||
ledPulseValue = 255;
|
||||
}
|
||||
else if (!ledPulseDirection && ledPulseValue < 0)
|
||||
{
|
||||
ledPulseDirection=true;
|
||||
ledPulseValue = 0;
|
||||
}
|
||||
|
||||
analogWrite(LED, ledPulseValue);
|
||||
ledPulseTimestamp = millis();
|
||||
}
|
||||
}
|
||||
if (STATUS == STATUS_UNKNOWN) //blink
|
||||
{
|
||||
if (millis()-(ledPulseTimestamp) > LED_PULSE_PERIOD/20)
|
||||
{
|
||||
ledPulseDirection = !ledPulseDirection;
|
||||
digitalWrite(LED, ledPulseDirection ? HIGH : LOW);
|
||||
ledPulseTimestamp = millis();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WEATHERSHIELD
|
||||
if (millis()-lastWeatherSent > WEATHERSENDDELAY)
|
||||
{
|
||||
lastWeatherSent = millis();
|
||||
double P = getPressure();
|
||||
P*=0.0295333727; //transform to inHg
|
||||
dtostrf(P, 3,2, Pstr);
|
||||
sprintf(sendBuf, "F:%d H:%d P:%s", weatherShield_SI7021.getFahrenheitHundredths(), weatherShield_SI7021.getHumidityPercent(), Pstr);
|
||||
byte sendLen = strlen(sendBuf);
|
||||
radio.send(GATEWAYID, sendBuf, sendLen);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//returns TRUE if magnet is next to sensor, FALSE if magnet is away
|
||||
boolean hallSensorRead(byte which)
|
||||
{
|
||||
//while(millis()-lastStatusTimestamp<STATUS_CHANGE_MIN);
|
||||
digitalWrite(which ? HALLSENSOR2_EN : HALLSENSOR1_EN, HIGH); //turn sensor ON
|
||||
delay(1); //wait a little
|
||||
byte reading = digitalRead(which ? HALLSENSOR2 : HALLSENSOR1);
|
||||
digitalWrite(which ? HALLSENSOR2_EN : HALLSENSOR1_EN, LOW); //turn sensor OFF
|
||||
return reading==0;
|
||||
}
|
||||
|
||||
void setStatus(byte newSTATUS, boolean reportStatusRequest)
|
||||
{
|
||||
if (STATUS != newSTATUS) lastStatusTimestamp = millis();
|
||||
STATUS = newSTATUS;
|
||||
DEBUGln(STATUS==STATUS_CLOSED ? "CLOSED" : STATUS==STATUS_CLOSING ? "CLOSING" : STATUS==STATUS_OPENING ? "OPENING" : STATUS==STATUS_OPEN ? "OPEN" : "UNKNOWN");
|
||||
if (reportStatusRequest)
|
||||
reportStatus();
|
||||
}
|
||||
|
||||
boolean reportStatus()
|
||||
{
|
||||
if (lastRequesterNodeID == 0) return false;
|
||||
char buff[10];
|
||||
sprintf(buff, STATUS==STATUS_CLOSED ? "CLOSED" : STATUS==STATUS_CLOSING ? "CLOSING" : STATUS==STATUS_OPENING ? "OPENING" : STATUS==STATUS_OPEN ? "OPEN" : "UNKNOWN");
|
||||
byte len = strlen(buff);
|
||||
return radio.sendWithRetry(lastRequesterNodeID, buff, len);
|
||||
}
|
||||
|
||||
void pulseRelay()
|
||||
{
|
||||
digitalWrite(RELAYPIN1, HIGH);
|
||||
digitalWrite(RELAYPIN2, HIGH);
|
||||
delay(RELAY_PULSE_MS);
|
||||
digitalWrite(RELAYPIN1, LOW);
|
||||
digitalWrite(RELAYPIN2, LOW);
|
||||
}
|
||||
|
||||
void Blink(byte PIN, byte DELAY_MS)
|
||||
{
|
||||
pinMode(PIN, OUTPUT);
|
||||
digitalWrite(PIN,HIGH);
|
||||
delay(DELAY_MS);
|
||||
digitalWrite(PIN,LOW);
|
||||
}
|
||||
|
||||
#ifdef WEATHERSHIELD
|
||||
double getPressure()
|
||||
{
|
||||
char status;
|
||||
double T,P,p0,a;
|
||||
// If you want sea-level-compensated pressure, as used in weather reports,
|
||||
// you will need to know the altitude at which your measurements are taken.
|
||||
// We're using a constant called ALTITUDE in this sketch:
|
||||
|
||||
// If you want to measure altitude, and not pressure, you will instead need
|
||||
// to provide a known baseline pressure. This is shown at the end of the sketch.
|
||||
// You must first get a temperature measurement to perform a pressure reading.
|
||||
// Start a temperature measurement:
|
||||
// If request is successful, the number of ms to wait is returned.
|
||||
// If request is unsuccessful, 0 is returned.
|
||||
status = weatherShield_BMP180.startTemperature();
|
||||
if (status != 0)
|
||||
{
|
||||
// Wait for the measurement to complete:
|
||||
delay(status);
|
||||
|
||||
// Retrieve the completed temperature measurement:
|
||||
// Note that the measurement is stored in the variable T.
|
||||
// Function returns 1 if successful, 0 if failure.
|
||||
status = weatherShield_BMP180.getTemperature(T);
|
||||
if (status != 0)
|
||||
{
|
||||
// Start a pressure measurement:
|
||||
// The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait).
|
||||
// If request is successful, the number of ms to wait is returned.
|
||||
// If request is unsuccessful, 0 is returned.
|
||||
status = weatherShield_BMP180.startPressure(3);
|
||||
if (status != 0)
|
||||
{
|
||||
// Wait for the measurement to complete:
|
||||
delay(status);
|
||||
|
||||
// Retrieve the completed pressure measurement:
|
||||
// Note that the measurement is stored in the variable P.
|
||||
// Note also that the function requires the previous temperature measurement (T).
|
||||
// (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.)
|
||||
// Function returns 1 if successful, 0 if failure.
|
||||
status = weatherShield_BMP180.getPressure(P,T);
|
||||
if (status != 0)
|
||||
{
|
||||
return P;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
132
lib-ext/rfm-69.git/Examples/GarageMote_base/GarageMote_base.ino
Normal file
132
lib-ext/rfm-69.git/Examples/GarageMote_base/GarageMote_base.ino
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
// **********************************************************************************************************
|
||||
// GarageMote garage door controller base receiver sketch that works with Moteinos equipped with HopeRF RFM69W/RFM69HW
|
||||
// Can be adapted to use Moteinos using RFM12B
|
||||
// This is the sketch for the base, not the controller itself, and meant as another example on how to use a
|
||||
// Moteino as a gateway/base/receiver
|
||||
// 2013-09-13 (C) felix@lowpowerlab.com, http://www.LowPowerLab.com
|
||||
// **********************************************************************************************************
|
||||
// Creative Commons Attrib Share-Alike License
|
||||
// You are free to use/extend this code/library but please abide with the CCSA license:
|
||||
// http://creativecommons.org/licenses/by-sa/3.0/
|
||||
// **********************************************************************************************************
|
||||
|
||||
#include <RFM69.h>
|
||||
#include <SPI.h>
|
||||
#include <SPIFlash.h>
|
||||
|
||||
//*****************************************************************************************************************************
|
||||
// ADJUST THE SETTINGS BELOW DEPENDING ON YOUR HARDWARE/SITUATION!
|
||||
//*****************************************************************************************************************************
|
||||
#define NODEID 1
|
||||
#define GARAGENODEID 99
|
||||
#define NETWORKID 100
|
||||
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
|
||||
//#define FREQUENCY RF69_433MHZ
|
||||
//#define FREQUENCY RF69_868MHZ
|
||||
#define FREQUENCY RF69_915MHZ
|
||||
#define ENCRYPTKEY "sampleEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less!
|
||||
//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
|
||||
#define LED 9
|
||||
#define SERIAL_BAUD 115200
|
||||
#define ACK_TIME 30 // # of ms to wait for an ack
|
||||
//*****************************************************************************************************************************
|
||||
|
||||
RFM69 radio;
|
||||
SPIFlash flash(8, 0xEF30); //EF40 for 16mbit windbond chip
|
||||
byte readSerialLine(char* input, char endOfLineChar=10, byte maxLength=64, uint16_t timeout=50);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
delay(10);
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
#ifdef IS_RFM69HW
|
||||
radio.setHighPower(); //must include only for RFM69HW!
|
||||
#endif
|
||||
radio.encrypt(ENCRYPTKEY);
|
||||
char buff[50];
|
||||
sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
|
||||
Serial.println(buff);
|
||||
if (flash.initialize())
|
||||
Serial.println("SPI Flash Init OK!");
|
||||
else
|
||||
Serial.println("SPI Flash Init FAIL! (is chip present?)");
|
||||
}
|
||||
|
||||
byte ackCount=0;
|
||||
byte inputLen=0;
|
||||
char input[64];
|
||||
void loop() {
|
||||
//process any serial input
|
||||
inputLen = readSerialLine(input);
|
||||
|
||||
if (inputLen >= 6)
|
||||
{
|
||||
if (input[0]=='G' && input[1]=='R' && input[2]=='G' && input[3]=='O' && input[4]=='P' && input[5]=='N')
|
||||
{
|
||||
Serial.print("OPN ... ");
|
||||
if (radio.sendWithRetry(GARAGENODEID, "OPN", 3))
|
||||
Serial.println("ok ... ");
|
||||
else Serial.println("nothing ... ");
|
||||
}
|
||||
if (input[0]=='G' && input[1]=='R' && input[2]=='G' && input[3]=='C' && input[4]=='L' && input[5]=='S')
|
||||
{
|
||||
Serial.print("CLS ... ");
|
||||
if (radio.sendWithRetry(GARAGENODEID, "CLS", 3))
|
||||
Serial.println("ok ... ");
|
||||
else Serial.println("nothing ... ");
|
||||
}
|
||||
if (input[0]=='G' && input[1]=='R' && input[2]=='G' && input[3]=='S' && input[4]=='T' && input[5]=='S')
|
||||
{
|
||||
Serial.print("STS ... ");
|
||||
if (radio.sendWithRetry(GARAGENODEID, "STS", 3))
|
||||
Serial.println("ok ... ");
|
||||
else Serial.println("nothing ... ");
|
||||
}
|
||||
|
||||
//if (input == 'i')
|
||||
//{
|
||||
// Serial.print("DeviceID: ");
|
||||
// word jedecid = flash.readDeviceId();
|
||||
// Serial.println(jedecid, HEX);
|
||||
//}
|
||||
}
|
||||
|
||||
if (radio.receiveDone())
|
||||
{
|
||||
Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] ");
|
||||
for (byte i = 0; i < radio.DATALEN; i++)
|
||||
Serial.print((char)radio.DATA[i]);
|
||||
Serial.print(" [RSSI:");Serial.print(radio.RSSI);Serial.print("]");
|
||||
|
||||
if (radio.ACKRequested())
|
||||
{
|
||||
byte theNodeID = radio.SENDERID;
|
||||
radio.sendACK();
|
||||
Serial.print("[ACK-sent]");
|
||||
}
|
||||
Serial.println();
|
||||
Blink(LED,3);
|
||||
}
|
||||
}
|
||||
|
||||
void Blink(byte PIN, int DELAY_MS)
|
||||
{
|
||||
pinMode(PIN, OUTPUT);
|
||||
digitalWrite(PIN,HIGH);
|
||||
delay(DELAY_MS);
|
||||
digitalWrite(PIN,LOW);
|
||||
}
|
||||
|
||||
// reads a line feed (\n) terminated line from the serial stream
|
||||
// returns # of bytes read, up to 255
|
||||
// timeout in ms, will timeout and return after so long
|
||||
byte readSerialLine(char* input, char endOfLineChar, byte maxLength, uint16_t timeout)
|
||||
{
|
||||
byte inputLen = 0;
|
||||
Serial.setTimeout(timeout);
|
||||
inputLen = Serial.readBytesUntil(endOfLineChar, input, maxLength);
|
||||
input[inputLen]=0;//null-terminate it
|
||||
Serial.setTimeout(0);
|
||||
//Serial.println();
|
||||
return inputLen;
|
||||
}
|
||||
173
lib-ext/rfm-69.git/Examples/Gateway/Gateway.ino
Normal file
173
lib-ext/rfm-69.git/Examples/Gateway/Gateway.ino
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
// Sample RFM69 receiver/gateway sketch, with ACK and optional encryption
|
||||
// Passes through any wireless received messages to the serial port & responds to ACKs
|
||||
// It also looks for an onboard FLASH chip, if present
|
||||
// Library and code by Felix Rusu - felix@lowpowerlab.com
|
||||
// Get the RFM69 and SPIFlash library at: https://github.com/LowPowerLab/
|
||||
|
||||
#include <RFM69.h> //get it here: https://www.github.com/lowpowerlab/rfm69
|
||||
#include <SPI.h>
|
||||
#include <SPIFlash.h> //get it here: https://www.github.com/lowpowerlab/spiflash
|
||||
|
||||
#define NODEID 1 //unique for each node on same network
|
||||
#define NETWORKID 100 //the same on all nodes that talk to each other
|
||||
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
|
||||
#define FREQUENCY RF69_433MHZ
|
||||
//#define FREQUENCY RF69_868MHZ
|
||||
//#define FREQUENCY RF69_915MHZ
|
||||
#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
|
||||
//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
|
||||
#define ACK_TIME 30 // max # of ms to wait for an ack
|
||||
#define SERIAL_BAUD 115200
|
||||
|
||||
#ifdef __AVR_ATmega1284P__
|
||||
#define LED 15 // Moteino MEGAs have LEDs on D15
|
||||
#define FLASH_SS 23 // and FLASH SS on D23
|
||||
#else
|
||||
#define LED 9 // Moteinos have LEDs on D9
|
||||
#define FLASH_SS 8 // and FLASH SS on D8
|
||||
#endif
|
||||
|
||||
RFM69 radio;
|
||||
SPIFlash flash(FLASH_SS, 0xEF30); //EF30 for 4mbit Windbond chip (W25X40CL)
|
||||
bool promiscuousMode = false; //set to 'true' to sniff all packets on the same network
|
||||
|
||||
void setup() {
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
delay(10);
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
#ifdef IS_RFM69HW
|
||||
radio.setHighPower(); //only for RFM69HW!
|
||||
#endif
|
||||
radio.encrypt(ENCRYPTKEY);
|
||||
radio.promiscuous(promiscuousMode);
|
||||
//radio.setFrequency(919000000);
|
||||
char buff[50];
|
||||
sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
|
||||
Serial.println(buff);
|
||||
if (flash.initialize())
|
||||
{
|
||||
Serial.print("SPI Flash Init OK. Unique MAC = [");
|
||||
flash.readUniqueId();
|
||||
for (byte i=0;i<8;i++)
|
||||
{
|
||||
Serial.print(flash.UNIQUEID[i], HEX);
|
||||
if (i!=8) Serial.print(':');
|
||||
}
|
||||
Serial.println(']');
|
||||
|
||||
//alternative way to read it:
|
||||
//byte* MAC = flash.readUniqueId();
|
||||
//for (byte i=0;i<8;i++)
|
||||
//{
|
||||
// Serial.print(MAC[i], HEX);
|
||||
// Serial.print(' ');
|
||||
//}
|
||||
|
||||
}
|
||||
else
|
||||
Serial.println("SPI Flash Init FAIL! (is chip present?)");
|
||||
}
|
||||
|
||||
byte ackCount=0;
|
||||
uint32_t packetCount = 0;
|
||||
void loop() {
|
||||
//process any serial input
|
||||
if (Serial.available() > 0)
|
||||
{
|
||||
char input = Serial.read();
|
||||
if (input == 'r') //d=dump all register values
|
||||
radio.readAllRegs();
|
||||
if (input == 'E') //E=enable encryption
|
||||
radio.encrypt(ENCRYPTKEY);
|
||||
if (input == 'e') //e=disable encryption
|
||||
radio.encrypt(null);
|
||||
if (input == 'p')
|
||||
{
|
||||
promiscuousMode = !promiscuousMode;
|
||||
radio.promiscuous(promiscuousMode);
|
||||
Serial.print("Promiscuous mode ");Serial.println(promiscuousMode ? "on" : "off");
|
||||
}
|
||||
|
||||
if (input == 'd') //d=dump flash area
|
||||
{
|
||||
Serial.println("Flash content:");
|
||||
int counter = 0;
|
||||
|
||||
while(counter<=256){
|
||||
Serial.print(flash.readByte(counter++), HEX);
|
||||
Serial.print('.');
|
||||
}
|
||||
while(flash.busy());
|
||||
Serial.println();
|
||||
}
|
||||
if (input == 'D')
|
||||
{
|
||||
Serial.print("Deleting Flash chip ... ");
|
||||
flash.chipErase();
|
||||
while(flash.busy());
|
||||
Serial.println("DONE");
|
||||
}
|
||||
if (input == 'i')
|
||||
{
|
||||
Serial.print("DeviceID: ");
|
||||
word jedecid = flash.readDeviceId();
|
||||
Serial.println(jedecid, HEX);
|
||||
}
|
||||
if (input == 't')
|
||||
{
|
||||
byte temperature = radio.readTemperature(-1); // -1 = user cal factor, adjust for correct ambient
|
||||
byte fTemp = 1.8 * temperature + 32; // 9/5=1.8
|
||||
Serial.print( "Radio Temp is ");
|
||||
Serial.print(temperature);
|
||||
Serial.print("C, ");
|
||||
Serial.print(fTemp); //converting to F loses some resolution, obvious when C is on edge between 2 values (ie 26C=78F, 27C=80F)
|
||||
Serial.println('F');
|
||||
}
|
||||
}
|
||||
|
||||
if (radio.receiveDone())
|
||||
{
|
||||
Serial.print("#[");
|
||||
Serial.print(++packetCount);
|
||||
Serial.print(']');
|
||||
Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] ");
|
||||
if (promiscuousMode)
|
||||
{
|
||||
Serial.print("to [");Serial.print(radio.TARGETID, DEC);Serial.print("] ");
|
||||
}
|
||||
for (byte i = 0; i < radio.DATALEN; i++)
|
||||
Serial.print((char)radio.DATA[i]);
|
||||
Serial.print(" [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]");
|
||||
|
||||
if (radio.ACKRequested())
|
||||
{
|
||||
byte theNodeID = radio.SENDERID;
|
||||
radio.sendACK();
|
||||
Serial.print(" - ACK sent.");
|
||||
|
||||
// When a node requests an ACK, respond to the ACK
|
||||
// and also send a packet requesting an ACK (every 3rd one only)
|
||||
// This way both TX/RX NODE functions are tested on 1 end at the GATEWAY
|
||||
if (ackCount++%3==0)
|
||||
{
|
||||
Serial.print(" Pinging node ");
|
||||
Serial.print(theNodeID);
|
||||
Serial.print(" - ACK...");
|
||||
delay(3); //need this when sending right after reception .. ?
|
||||
if (radio.sendWithRetry(theNodeID, "ACK TEST", 8, 0)) // 0 = only 1 attempt, no retries
|
||||
Serial.print("ok!");
|
||||
else Serial.print("nothing");
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
Blink(LED,3);
|
||||
}
|
||||
}
|
||||
|
||||
void Blink(byte PIN, int DELAY_MS)
|
||||
{
|
||||
pinMode(PIN, OUTPUT);
|
||||
digitalWrite(PIN,HIGH);
|
||||
delay(DELAY_MS);
|
||||
digitalWrite(PIN,LOW);
|
||||
}
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
// Sample RFM69 sender/node sketch for mailbox motion sensor
|
||||
// http://www.lowpowerlab.com/mailbox
|
||||
// PIR motion sensor connected to D3 (INT1)
|
||||
// When RISE happens on D3, the sketch transmits a "MOTION" msg to receiver Moteino and goes back to sleep
|
||||
// It then wakes up every 32 seconds and sends a message indicating when the last
|
||||
// motion event happened (days, hours, minutes, seconds ago) and the battery level
|
||||
// In sleep mode, Moteino + PIR motion sensor use about ~78uA
|
||||
// Make sure you adjust the settings in the configuration section below !!!
|
||||
|
||||
// **********************************************************************************
|
||||
// Copyright Felix Rusu, LowPowerLab.com
|
||||
// Library and code by Felix Rusu - felix@lowpowerlab.com
|
||||
// Get the RFM69 and SPIFlash library at: https://github.com/LowPowerLab/
|
||||
// **********************************************************************************
|
||||
// License
|
||||
// **********************************************************************************
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will
|
||||
// be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
// implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
// PARTICULAR PURPOSE. See the GNU General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// Public License along with this program.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Licence can be viewed at
|
||||
// http://www.gnu.org/licenses/gpl-3.0.txt
|
||||
//
|
||||
// Please maintain this license information along with authorship
|
||||
// and copyright notices in any redistribution of this code
|
||||
// **********************************************************************************
|
||||
|
||||
#include <RFM69.h> //get it here: https://github.com/LowPowerLab/RFM69
|
||||
#include <SPI.h> //get it here: https://github.com/LowPowerLab/SPIFlash
|
||||
#include <LowPower.h> //get library from: https://github.com/LowPowerLab/LowPower
|
||||
//writeup here: http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/
|
||||
|
||||
//*********************************************************************************************
|
||||
// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE *************
|
||||
//*********************************************************************************************
|
||||
#define NODEID 55 //unique for each node on same network
|
||||
#define NETWORKID 250 //the same on all nodes that talk to each other
|
||||
#define GATEWAYID 1
|
||||
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
|
||||
//#define FREQUENCY RF69_433MHZ
|
||||
//#define FREQUENCY RF69_868MHZ
|
||||
#define FREQUENCY RF69_915MHZ
|
||||
#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
|
||||
#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
|
||||
#define SENDEVERYXLOOPS 4 //each loop sleeps 8 seconds, so send status message every this many loops (default "4" = 32 seconds)
|
||||
//*********************************************************************************************
|
||||
|
||||
#define MOTIONPIN 1 //hardware interrupt 1 (D3)
|
||||
#define BATTERYSENSE A7 //through 1Meg+470Kohm and 0.1uF cap from battery VCC - this ratio divides the voltage to bring it below 3.3V where it is scaled to a readable range
|
||||
#define LED 9 // Moteinos have LEDs on D9
|
||||
//#define BLINK_EN //uncomment to make LED flash when messages are sent, leave out if you want low power
|
||||
|
||||
#define SERIAL_BAUD 115200
|
||||
//#define SERIAL_EN //uncomment this line to enable serial IO debug messages, leave out if you want low power
|
||||
#ifdef SERIAL_EN
|
||||
#define DEBUG(input) {Serial.print(input); delay(1);}
|
||||
#define DEBUGln(input) {Serial.println(input); delay(1);}
|
||||
#else
|
||||
#define DEBUG(input);
|
||||
#define DEBUGln(input);
|
||||
#endif
|
||||
|
||||
RFM69 radio;
|
||||
volatile boolean motionDetected=false;
|
||||
|
||||
void setup() {
|
||||
#ifdef SERIAL_EN
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
#endif
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
#ifdef IS_RFM69HW
|
||||
radio.setHighPower(); //uncomment only for RFM69HW!
|
||||
#endif
|
||||
radio.encrypt(ENCRYPTKEY);
|
||||
pinMode(MOTIONPIN, INPUT);
|
||||
attachInterrupt(MOTIONPIN, motionIRQ, RISING);
|
||||
char buff[50];
|
||||
sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
|
||||
DEBUGln(buff);
|
||||
}
|
||||
|
||||
void motionIRQ()
|
||||
{
|
||||
motionDetected=true;
|
||||
//DEBUGln("I");
|
||||
}
|
||||
|
||||
char sendBuf[32];
|
||||
byte sendLen;
|
||||
byte sendLoops=0;
|
||||
unsigned long MLO=0; //MailLastOpen (ago, in ms)
|
||||
unsigned long now = 0, time=0, lastSend = 0, temp = 0;
|
||||
|
||||
void loop() {
|
||||
now = millis();
|
||||
int batteryReading = analogRead(BATTERYSENSE);
|
||||
if (motionDetected && time-MLO > 20000) //avoid duplicates in 20second intervals
|
||||
{
|
||||
MLO = time; //save timestamp of event
|
||||
sprintf(sendBuf, "MOTION BAT:%i", batteryReading);
|
||||
sendLen = strlen(sendBuf);
|
||||
if (radio.sendWithRetry(GATEWAYID, sendBuf, sendLen))
|
||||
{
|
||||
DEBUGln(" ok!");
|
||||
#ifdef BLINK_EN
|
||||
Blink(LED,3);
|
||||
#endif
|
||||
}
|
||||
else DEBUGln(" nothing...");
|
||||
radio.sleep();
|
||||
motionDetected=false;
|
||||
}
|
||||
else sendLoops++;
|
||||
|
||||
//send readings every SENDEVERYXLOOPS
|
||||
if (sendLoops>=SENDEVERYXLOOPS)
|
||||
{
|
||||
sendLoops=0;
|
||||
|
||||
char periodO='X', periodC='X';
|
||||
unsigned long lastOpened = (time - MLO) / 1000; //get seconds
|
||||
unsigned long LO = lastOpened;
|
||||
char* MLOstr="LO:99d23h59m";
|
||||
char* BATstr="BAT:1024";
|
||||
char* BATactual="BATA:5.00v";
|
||||
|
||||
if (lastOpened <= 59) periodO = 's'; //1-59 seconds
|
||||
else if (lastOpened <= 3599) { periodO = 'm'; lastOpened/=60; } //1-59 minutes
|
||||
else if (lastOpened <= 259199) { periodO = 'h'; lastOpened/=3600; } // 1-71 hours
|
||||
else if (lastOpened >= 259200) { periodO = 'd'; lastOpened/=86400; } // >=3 days
|
||||
|
||||
if (periodO == 'd')
|
||||
sprintf(MLOstr, "LO:%ldd%ldh", lastOpened, (LO%86400)/3600);
|
||||
else if (periodO == 'h')
|
||||
sprintf(MLOstr, "LO:%ldh%ldm", lastOpened, (LO%3600)/60);
|
||||
else sprintf(MLOstr, "LO:%ld%c", lastOpened, periodO);
|
||||
|
||||
//sprintf(BATstr, "BAT:%i", batteryReading);
|
||||
float battV = ((float)batteryReading * 3.3 * 9)/(1023*2.976);
|
||||
dtostrf(battV, 3,2, BATactual);
|
||||
sprintf(sendBuf, "%s BAT:%sv", MLOstr, BATactual);
|
||||
sendLen = strlen(sendBuf);
|
||||
radio.send(GATEWAYID, sendBuf, sendLen);
|
||||
radio.sleep();
|
||||
DEBUG(sendBuf); DEBUG(" ("); DEBUG(sendLen); DEBUGln(")");
|
||||
lastSend = time;
|
||||
#ifdef BLINK_EN
|
||||
Blink(LED, 5);
|
||||
#endif
|
||||
delay(10); motionDetected=false; //fix PIR false positive glitch
|
||||
}
|
||||
|
||||
DEBUGln("LOOP");
|
||||
time = time + 8000 + millis()-now + 480; //correct millis() resonator drift, may need to be tweaked to be accurate
|
||||
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
|
||||
}
|
||||
|
||||
void Blink(byte PIN, int DELAY_MS)
|
||||
{
|
||||
pinMode(PIN, OUTPUT);
|
||||
digitalWrite(PIN,HIGH);
|
||||
delay(DELAY_MS);
|
||||
digitalWrite(PIN,LOW);
|
||||
}
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
// *************************************************************************************************************
|
||||
// MightyBoost control sample sketch
|
||||
// *************************************************************************************************************
|
||||
// Copyright Felix Rusu (2014), felix@lowpowerlab.com
|
||||
// http://lowpowerlab.com/
|
||||
// *************************************************************************************************************
|
||||
// License
|
||||
// *************************************************************************************************************
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will
|
||||
// be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
// implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
// PARTICULAR PURPOSE. See the GNU General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// Public License along with this program; if not, write
|
||||
// to the Free Software Foundation, Inc.,
|
||||
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// Licence can be viewed at
|
||||
// http://www.fsf.org/licenses/gpl.txt
|
||||
//
|
||||
// Please maintain this license information along with authorship
|
||||
// and copyright notices in any redistribution of this code
|
||||
// *************************************************************************************************************
|
||||
// MightyBoost is a smart backup PSU controllable by Moteino, and this sketch is a sample control sketch to run
|
||||
// MightyBoost in this mode.
|
||||
// http://moteino.com
|
||||
// http://github.com/lowpowerlab
|
||||
// Be sure to check back for code updates and patches
|
||||
// *************************************************************************************************************
|
||||
// This sketch will provide control over the essential features of MightyBoost:
|
||||
// - provide switched 5V power to a sensitive load like RaspberryPi which should not lose power instantly
|
||||
// - Control the "5V*" output via Moteino+PowerButton (momentary tactile)
|
||||
// - Monitor input supply and switch to battery backup when external power is lost
|
||||
// - Monitor battery voltage and issue a shutdown signal when battery runs low
|
||||
// This sketch may be extended to include integration with other LowPowerLab automation products
|
||||
// *************************************************************************************************************
|
||||
#define LED 5 // LED pin, should be analog for fading effect (PWM)
|
||||
#define BUTTON 3 // Power button pin
|
||||
#define SIG_REQUESTHALT 6 // Signal to Pi to ask for a shutdown
|
||||
#define SIG_OKTOCUTOFF A0 // Signal from Pi that it's OK to cutoff power
|
||||
// !!NOTE!! Originally this was D7 but it was moved to A0 at least temporarily.
|
||||
// On MightyBoost R1 you need to connect D7 and A0 with a jumper wire.
|
||||
// The explanation for this is given here: http://lowpowerlab.com/mightyboost/#source
|
||||
#define OUTPUT_5V 4 // HIGH on this pin will switch the "5V*" output ON
|
||||
#define BATTERYSENSE A7 // Sense VBAT_COND signal (when powered externally should read ~3.25v/3.3v (1000-1023), when external power is cutoff it should start reading around 2.85v/3.3v * 1023 ~= 880 (ratio given by 10k+4.7K divider from VBAT_COND = 1.47 multiplier)
|
||||
// hence the actual input voltage = analogRead(A7) * 0.00322 (3.3v/1024) * 1.47 (10k+4.7k voltage divider ratio)
|
||||
// when plugged in this should be 4.80v, nothing to worry about
|
||||
// when on battery power this should decrease from 4.15v (fully charged Lipoly) to 3.3v (discharged Lipoly)
|
||||
// trigger a shutdown to the target device once voltage is around 3.4v to allow 30sec safe shutdown
|
||||
#define LOWBATTERYTHRESHOLD 3.7 // a shutdown will be triggered to the target device when battery voltage drops below this (Volts)
|
||||
|
||||
#define ButtonHoldTime 1800 // Button must be hold this many mseconds before a shutdown sequence is started (should be much less than PIForceShutdownDelay)
|
||||
#define PIShutdownDelay_Min 6000 // will start checking the SIG_OKTOCUTOFF line after this long
|
||||
#define PIShutdownDelay_Max 38000 // window of time in which SIG_OKTOCUTOFF is expected to go HIGH
|
||||
// should be at least 3000 more than Min
|
||||
// if nothing happens after this window, if button is
|
||||
// still pressed, force cutoff power, otherwise switch back to normal ON state
|
||||
#define PIForceShutdownDelay 6500 // when SIG_OKTOCUTOFF==0 (PI in unknown state): if button is held
|
||||
// for this long, force shutdown (this should be less than PIShutdownDelay_Max)
|
||||
#define ShutdownFINALDELAY 4000 // after shutdown signal is received, delay for this long
|
||||
// to allow all PI LEDs to stop activity (pulse LED faster)
|
||||
|
||||
#define PRINTPERIOD 1000
|
||||
|
||||
int lastValidReading = 1;
|
||||
unsigned long lastValidReadingTime = 0;
|
||||
unsigned long now=0;
|
||||
int PowerState = 0;
|
||||
long lastPeriod = -1;
|
||||
float systemVoltage = 5;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
pinMode(BUTTON, INPUT_PULLUP);
|
||||
pinMode(SIG_OKTOCUTOFF, INPUT);
|
||||
pinMode(SIG_REQUESTHALT, OUTPUT);
|
||||
pinMode(LED, OUTPUT);
|
||||
pinMode(OUTPUT_5V, OUTPUT);
|
||||
pinMode(A7, INPUT);
|
||||
digitalWrite(SIG_REQUESTHALT, LOW);//added after sudden shutdown quirks, DO NOT REMOVE!
|
||||
digitalWrite(OUTPUT_5V, LOW);//added after sudden shutdown quirks, DO NOT REMOVE!
|
||||
}
|
||||
|
||||
void loop() {
|
||||
int reading = digitalRead(BUTTON);
|
||||
now = millis();
|
||||
digitalWrite(SIG_REQUESTHALT, LOW);//added after sudden shutdown quirks, DO NOT REMOVE!
|
||||
|
||||
boolean batteryLow = systemVoltage < LOWBATTERYTHRESHOLD;
|
||||
|
||||
if (batteryLow || reading != lastValidReading && now - lastValidReadingTime > 200) {
|
||||
lastValidReading = reading;
|
||||
lastValidReadingTime = now;
|
||||
//((PowerState==0 && ()) || (PowerState==1 && (now - lastValidReadingTime > ButtonHoldTime)))
|
||||
if (batteryLow || reading == 0)
|
||||
{
|
||||
//make sure the button is held down for at least 'ButtonHoldTime' before taking action (this is to avoid accidental button presses and consequently Pi shutdowns)
|
||||
now = millis();
|
||||
while (!batteryLow && (PowerState == 1 && millis()-now < ButtonHoldTime)) { delay(10); if (digitalRead(BUTTON) != 0) return; }
|
||||
|
||||
//SIG_OKTOCUTOFF must be HIGH when Pi is ON. During boot, this will take a while to happen (till it executes the "shutdowncheck" script
|
||||
//so I dont want to cutoff power before it had a chance to fully boot up
|
||||
//if (batteryLow || (PowerState == 1 && digitalRead(SIG_OKTOCUTOFF)==1))
|
||||
if (batteryLow || (PowerState == 1 && analogRead(SIG_OKTOCUTOFF)>800))
|
||||
{
|
||||
// signal Pi to shutdown
|
||||
digitalWrite(SIG_REQUESTHALT, HIGH);
|
||||
|
||||
//now wait for the Pi to signal back
|
||||
now = millis();
|
||||
float in, out;
|
||||
boolean forceShutdown = true;
|
||||
|
||||
while (millis()-now < PIShutdownDelay_Max)
|
||||
{
|
||||
if (in > 6.283) in = 0;
|
||||
in += .00628;
|
||||
|
||||
out = sin(in) * 127.5 + 127.5;
|
||||
analogWrite(LED,out);
|
||||
delayMicroseconds(1500);
|
||||
|
||||
//account for force-shutdown action (if button held for PIForceShutdownDelay, then force shutdown regardless)
|
||||
if (millis()-now <= (PIForceShutdownDelay-ButtonHoldTime) && digitalRead(BUTTON) != 0)
|
||||
forceShutdown = false;
|
||||
if (millis()-now >= (PIForceShutdownDelay-ButtonHoldTime) && forceShutdown)
|
||||
{
|
||||
PowerState = 0;
|
||||
digitalWrite(LED, PowerState); //turn off LED to indicate power is being cutoff
|
||||
digitalWrite(OUTPUT_5V, PowerState); //digitalWrite(LED, PowerState);
|
||||
break;
|
||||
}
|
||||
|
||||
if (millis() - now > PIShutdownDelay_Min)
|
||||
{
|
||||
// Pi signaling OK to turn off
|
||||
//if (digitalRead(SIG_OKTOCUTOFF) == 0)
|
||||
if (analogRead(SIG_OKTOCUTOFF) < 800)
|
||||
{
|
||||
PowerState = 0;
|
||||
digitalWrite(LED, PowerState); //turn off LED to indicate power is being cutoff
|
||||
|
||||
//delay(3500); //takes about 3sec between SIG_OKTOCUTOFF going LOW and Pi LEDs activity to stop
|
||||
now = millis();
|
||||
while (millis()-now < ShutdownFINALDELAY)
|
||||
{
|
||||
if (in > 6.283) in = 0;
|
||||
in += .00628;
|
||||
|
||||
out = sin(in) * 127.5 + 127.5;
|
||||
analogWrite(LED,out);
|
||||
delayMicroseconds(300);
|
||||
}
|
||||
|
||||
digitalWrite(OUTPUT_5V, PowerState); //digitalWrite(LED, PowerState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// last chance: if power still on but button still pressed, force cutoff power
|
||||
if (PowerState == 1 && digitalRead(BUTTON) == 0)
|
||||
{
|
||||
PowerState = 0;
|
||||
digitalWrite(OUTPUT_5V, PowerState);
|
||||
}
|
||||
|
||||
digitalWrite(SIG_REQUESTHALT, LOW);
|
||||
}
|
||||
//else if (PowerState == 1 && digitalRead(SIG_OKTOCUTOFF)==0)
|
||||
else if (PowerState == 1 && analogRead(SIG_OKTOCUTOFF)<800)
|
||||
{
|
||||
now = millis();
|
||||
unsigned long now2 = millis();
|
||||
int analogstep = 255 / ((PIForceShutdownDelay-ButtonHoldTime)/100); //every 500ms decrease LED intensity
|
||||
while (digitalRead(BUTTON) == 0)
|
||||
{
|
||||
if (millis()-now2 > 100)
|
||||
{
|
||||
analogWrite(LED, 255 - ((millis()-now)/100)*analogstep);
|
||||
now2 = millis();
|
||||
}
|
||||
if (millis()-now > PIForceShutdownDelay-ButtonHoldTime)
|
||||
{
|
||||
//TODO: add blinking here to signal final shutdown delay
|
||||
PowerState = 0;
|
||||
digitalWrite(OUTPUT_5V, PowerState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (PowerState == 0)
|
||||
{
|
||||
PowerState = 1;
|
||||
digitalWrite(OUTPUT_5V, PowerState); //digitalWrite(LED, PowerState);
|
||||
}
|
||||
}
|
||||
|
||||
digitalWrite(LED, PowerState);
|
||||
}
|
||||
|
||||
int currPeriod = millis()/PRINTPERIOD;
|
||||
if (currPeriod != lastPeriod)
|
||||
{
|
||||
lastPeriod=currPeriod;
|
||||
Serial.print("VIN: ");
|
||||
systemVoltage = analogRead(BATTERYSENSE) * 0.00322 * 1.47;
|
||||
Serial.print(systemVoltage);
|
||||
if (systemVoltage > 4.3)
|
||||
Serial.println(" (plugged in)");
|
||||
else Serial.println(" (running from battery!)");
|
||||
}
|
||||
}
|
||||
150
lib-ext/rfm-69.git/Examples/MotionMote/MotionMote.ino
Normal file
150
lib-ext/rfm-69.git/Examples/MotionMote/MotionMote.ino
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
// Sample RFM69 sender/node sketch for the MotionMote
|
||||
// http://lowpowerlab.com/motion
|
||||
// PIR motion sensor connected to D3 (INT1)
|
||||
// When RISE happens on D3, the sketch transmits a "MOTION" msg to receiver Moteino and goes back to sleep
|
||||
// In sleep mode, Moteino + PIR motion sensor use about ~78uA
|
||||
// Get the RFM69 and SPIFlash library at: https://github.com/LowPowerLab/
|
||||
// Make sure you adjust the settings in the configuration section below !!!
|
||||
|
||||
// **********************************************************************************
|
||||
// Copyright Felix Rusu, LowPowerLab.com
|
||||
// Library and code by Felix Rusu - felix@lowpowerlab.com
|
||||
// **********************************************************************************
|
||||
// License
|
||||
// **********************************************************************************
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will
|
||||
// be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
// implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
// PARTICULAR PURPOSE. See the GNU General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// Public License along with this program.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Licence can be viewed at
|
||||
// http://www.gnu.org/licenses/gpl-3.0.txt
|
||||
//
|
||||
// Please maintain this license information along with authorship
|
||||
// and copyright notices in any redistribution of this code
|
||||
// **********************************************************************************
|
||||
|
||||
#include <RFM69.h> //get it here: https://www.github.com/lowpowerlab/rfm69
|
||||
#include <SPI.h>
|
||||
#include <LowPower.h> //get library from: https://github.com/lowpowerlab/lowpower
|
||||
//writeup here: http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/
|
||||
|
||||
//*********************************************************************************************
|
||||
// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE *************
|
||||
//*********************************************************************************************
|
||||
#define NODEID 88 //unique for each node on same network
|
||||
#define NETWORKID 100 //the same on all nodes that talk to each other
|
||||
#define GATEWAYID 1
|
||||
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
|
||||
//#define FREQUENCY RF69_433MHZ
|
||||
//#define FREQUENCY RF69_868MHZ
|
||||
#define FREQUENCY RF69_915MHZ
|
||||
#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
|
||||
//#define IS_RFM69HW //uncomment only for RFM69HW! Remove/comment if you have RFM69W!
|
||||
//*********************************************************************************************
|
||||
|
||||
#define ACK_TIME 30 // max # of ms to wait for an ack
|
||||
#define ONBOARDLED 9 // Moteinos have LEDs on D9
|
||||
#define EXTLED 5 // MotionOLEDMote has an external LED on D5
|
||||
#define BATT_MONITOR A7 // Sense VBAT_COND signal (when powered externally should read ~3.25v/3.3v (1000-1023), when external power is cutoff it should start reading around 2.85v/3.3v * 1023 ~= 880 (ratio given by 10k+4.7K divider from VBAT_COND = 1.47 multiplier)
|
||||
#define BATT_CYCLES 30 //read and report battery voltage every this many wakeup cycles (ex 30cycles * 8sec sleep = 240sec/4min)
|
||||
#define MOTIONPIN 1 //hardware interrupt 1 (D3)
|
||||
|
||||
//#define SERIAL_EN //comment this out when deploying to an installed SM to save a few KB of sketch size
|
||||
#define SERIAL_BAUD 115200
|
||||
#ifdef SERIAL_EN
|
||||
#define DEBUG(input) {Serial.print(input); delay(1);}
|
||||
#define DEBUGln(input) {Serial.println(input); delay(1);}
|
||||
#else
|
||||
#define DEBUG(input);
|
||||
#define DEBUGln(input);
|
||||
#endif
|
||||
|
||||
RFM69 radio;
|
||||
volatile boolean motionDetected=false;
|
||||
float batteryVolts = 5;
|
||||
char* BATstr="BAT:5.00v";
|
||||
char sendBuf[32];
|
||||
byte sendLen;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
#ifdef IS_RFM69HW
|
||||
radio.setHighPower(); //uncomment only for RFM69HW!
|
||||
#endif
|
||||
radio.encrypt(ENCRYPTKEY);
|
||||
pinMode(MOTIONPIN, INPUT);
|
||||
attachInterrupt(MOTIONPIN, motionIRQ, RISING);
|
||||
char buff[50];
|
||||
sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
|
||||
DEBUGln(buff);
|
||||
pinMode(ONBOARDLED, OUTPUT);
|
||||
pinMode(EXTLED, OUTPUT);
|
||||
}
|
||||
|
||||
void motionIRQ()
|
||||
{
|
||||
motionDetected=true;
|
||||
}
|
||||
|
||||
byte batteryReportCycles=0;
|
||||
void loop() {
|
||||
checkBattery();
|
||||
if (motionDetected)
|
||||
{
|
||||
digitalWrite(EXTLED, HIGH);
|
||||
sprintf(sendBuf, "MOTION BAT:%sv", BATstr);
|
||||
sendLen = strlen(sendBuf);
|
||||
|
||||
if (radio.sendWithRetry(GATEWAYID, sendBuf, sendLen))
|
||||
{
|
||||
DEBUG("MOTION ACK:OK! RSSI:");
|
||||
DEBUG(radio.RSSI);
|
||||
batteryReportCycles = 0;
|
||||
}
|
||||
else DEBUG("MOTION ACK:NOK...");
|
||||
|
||||
DEBUG(" VIN: ");
|
||||
DEBUGln(BATstr);
|
||||
|
||||
radio.sleep();
|
||||
digitalWrite(EXTLED, LOW);
|
||||
}
|
||||
else if (batteryReportCycles == BATT_CYCLES)
|
||||
{
|
||||
sprintf(sendBuf, "BAT:%sv", BATstr);
|
||||
sendLen = strlen(sendBuf);
|
||||
radio.send(GATEWAYID, sendBuf, sendLen);
|
||||
radio.sleep();
|
||||
batteryReportCycles=0;
|
||||
}
|
||||
motionDetected=false; //do NOT move this after the SLEEP line below or motion will never be detected
|
||||
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
|
||||
batteryReportCycles++;
|
||||
}
|
||||
|
||||
byte cycleCount=BATT_CYCLES;
|
||||
void checkBattery()
|
||||
{
|
||||
if (cycleCount++ == BATT_CYCLES) //only read battery every BATT_CYCLES sleep cycles
|
||||
{
|
||||
unsigned int readings=0;
|
||||
for (byte i=0; i<10; i++) //take 10 samples, and average
|
||||
readings+=analogRead(BATT_MONITOR);
|
||||
batteryVolts = (readings / 10.0) * 0.00322 * 1.42;
|
||||
dtostrf(batteryVolts, 3,2, BATstr); //update the BATStr which gets sent every BATT_CYCLES or along with the MOTION message
|
||||
cycleCount = 0;
|
||||
}
|
||||
}
|
||||
68
lib-ext/rfm-69.git/Examples/MotionMote/OLD/MotionMote.ino
Normal file
68
lib-ext/rfm-69.git/Examples/MotionMote/OLD/MotionMote.ino
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// Sample RFM69 sender/node sketch for motion sensor
|
||||
// PIR motion sensor connected to D3 (INT1)
|
||||
// When RISE happens on D3, the sketch transmits a "MOTION" msg to receiver Moteino and goes back to sleep
|
||||
// In sleep mode, Moteino + PIR motion sensor use about ~78uA
|
||||
// Library and code by Felix Rusu - felix@lowpowerlab.com
|
||||
// Get the RFM69 and SPIFlash library at: https://github.com/LowPowerLab/
|
||||
|
||||
#include <RFM69.h> //get it here: https://www.github.com/lowpowerlab/rfm69
|
||||
#include <SPI.h> //get it here: https://github.com/lowpowerlab/spiflash
|
||||
#include <LowPower.h> //get library from: https://github.com/LowPowerLab/LowPower
|
||||
|
||||
#define NODEID 18 //unique for each node on same network
|
||||
#define NETWORKID 100 //the same on all nodes that talk to each other
|
||||
#define GATEWAYID 1
|
||||
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
|
||||
//#define FREQUENCY RF69_433MHZ
|
||||
//#define FREQUENCY RF69_868MHZ
|
||||
#define FREQUENCY RF69_915MHZ
|
||||
#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
|
||||
//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
|
||||
#define ACK_TIME 30 // max # of ms to wait for an ack
|
||||
#define LED 9 // Moteinos have LEDs on D9
|
||||
#define SERIAL_BAUD 115200
|
||||
#define MOTIONPIN 1 //hardware interrupt 1 (D3)
|
||||
|
||||
RFM69 radio;
|
||||
volatile boolean motionDetected=false;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
#ifdef IS_RFM69HW
|
||||
radio.setHighPower(); //uncomment only for RFM69HW!
|
||||
#endif
|
||||
radio.encrypt(ENCRYPTKEY);
|
||||
attachInterrupt(MOTIONPIN, motionIRQ, RISING);
|
||||
char buff[50];
|
||||
sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
|
||||
Serial.println(buff);
|
||||
}
|
||||
|
||||
void motionIRQ()
|
||||
{
|
||||
motionDetected=true;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (motionDetected)
|
||||
{
|
||||
if (radio.sendWithRetry(GATEWAYID, "MOTION", 6))
|
||||
{
|
||||
Serial.println(" ok!");
|
||||
Blink(LED,3);
|
||||
}
|
||||
else Serial.println(" nothing...");
|
||||
motionDetected=false;
|
||||
}
|
||||
radio.sleep();
|
||||
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
|
||||
}
|
||||
|
||||
void Blink(byte PIN, int DELAY_MS)
|
||||
{
|
||||
pinMode(PIN, OUTPUT);
|
||||
digitalWrite(PIN,HIGH);
|
||||
delay(DELAY_MS);
|
||||
digitalWrite(PIN,LOW);
|
||||
}
|
||||
BIN
lib-ext/rfm-69.git/Examples/MotionMote/OLD/MotionMote.jpg
Normal file
BIN
lib-ext/rfm-69.git/Examples/MotionMote/OLD/MotionMote.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
|
|
@ -0,0 +1,26 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="141.7mm" height="110.7mm" viewBox = " 0 0 502.087027 392.244417" >
|
||||
<!-- Front-->
|
||||
<g transform="translate(22.5000185, 22.5000185) " >
|
||||
<polygon style="stroke:#000000; fill:none; stroke-width:0.90000074" points="0, 0 24.80317, 0 24.80317, 10.62993 49.60634, 10.62993 49.60634, 0 74.40951000000001, 0 74.40951000000001, 10.62993 99.21268, 10.62993 99.21268, 0 124.01585, 0 124.01585, 29.2323075 113.38592, 29.2323075 113.38592, 58.464615 124.01585, 58.464615 124.01585, 79.724475 113.38592, 79.724475 113.38592, 108.9567825 124.01585, 108.9567825 124.01585, 138.18909 99.21268, 138.18909 99.21268, 127.55915999999999 74.40951000000001, 127.55915999999999 74.40951000000001, 138.18909 49.60634, 138.18909 49.60634, 127.55915999999999 24.80317, 127.55915999999999 24.80317, 138.18909 0, 138.18909 0, 108.9567825 10.62993, 108.9567825 10.62993, 79.724475 0, 79.724475 0, 58.464615 10.62993, 58.464615 10.62993, 29.2323075 0, 29.2323075 "/>
|
||||
</g>
|
||||
<!-- Back-->
|
||||
<g transform="translate(146.5158685, 22.5000185) " >
|
||||
<polygon style="stroke:#000000; fill:none; stroke-width:0.90000074" points="0, 0 24.80317, 0 24.80317, 10.62993 49.60634, 10.62993 49.60634, 0 74.40951000000001, 0 74.40951000000001, 10.62993 99.21268, 10.62993 99.21268, 0 124.01585, 0 124.01585, 29.2323075 113.38592, 29.2323075 113.38592, 58.464615 124.01585, 58.464615 124.01585, 79.724475 113.38592, 79.724475 113.38592, 108.9567825 124.01585, 108.9567825 124.01585, 138.18909 99.21268, 138.18909 99.21268, 127.55915999999999 74.40951000000001, 127.55915999999999 74.40951000000001, 138.18909 49.60634, 138.18909 49.60634, 127.55915999999999 24.80317, 127.55915999999999 24.80317, 138.18909 0, 138.18909 0, 108.9567825 10.62993, 108.9567825 10.62993, 79.724475 0, 79.724475 0, 58.464615 10.62993, 58.464615 10.62993, 29.2323075 0, 29.2323075 "/>
|
||||
</g>
|
||||
<!-- Left-->
|
||||
<g transform="translate(270.53171849999995, 22.5000185) " >
|
||||
<polygon style="stroke:#000000; fill:none; stroke-width:0.90000074" points="10.62993, 0 36.3189275, 0 36.3189275, 10.62993 72.637855, 10.62993 72.637855, 0 93.897715, 0 93.897715, 10.62993 115.15757500000001, 10.62993 115.15757500000001, 0 136.417435, 0 136.417435, 10.62993 172.73636249999998, 10.62993 172.73636249999998, 0 198.42535999999998, 0 198.42535999999998, 29.2323075 209.05528999999999, 29.2323075 209.05528999999999, 58.464615 198.42535999999998, 58.464615 198.42535999999998, 79.724475 209.05528999999999, 79.724475 209.05528999999999, 108.9567825 198.42535999999998, 108.9567825 198.42536, 138.18909 172.73636249999998, 138.18909 172.73636249999998, 127.55915999999999 136.417435, 127.55915999999999 136.417435, 138.18909 115.15757500000001, 138.18909 115.15757500000001, 127.55915999999999 93.897715, 127.55915999999999 93.897715, 138.18909 72.637855, 138.18909 72.637855, 127.55915999999999 36.3189275, 127.55915999999999 36.3189275, 138.18909 10.62993, 138.18909 10.62993, 108.9567825 0, 108.9567825 0, 79.724475 10.62993, 79.724475 10.62993, 58.464615 0, 58.464615 0, 29.2323075 10.62993, 29.2323075 "/>
|
||||
</g>
|
||||
<!-- Right-->
|
||||
<g transform="translate(270.53171849999995, 160.6891085) " >
|
||||
<polygon style="stroke:#000000; fill:none; stroke-width:0.90000074" points="10.62993, 0 36.3189275, 0 36.3189275, 10.62993 72.637855, 10.62993 72.637855, 0 93.897715, 0 93.897715, 10.62993 115.15757500000001, 10.62993 115.15757500000001, 0 136.417435, 0 136.417435, 10.62993 172.73636249999998, 10.62993 172.73636249999998, 0 198.42535999999998, 0 198.42535999999998, 29.2323075 209.05528999999999, 29.2323075 209.05528999999999, 58.464615 198.42535999999998, 58.464615 198.42535999999998, 79.724475 209.05528999999999, 79.724475 209.05528999999999, 108.9567825 198.42535999999998, 108.9567825 198.42536, 138.18909 172.73636249999998, 138.18909 172.73636249999998, 127.55915999999999 136.417435, 127.55915999999999 136.417435, 138.18909 115.15757500000001, 138.18909 115.15757500000001, 127.55915999999999 93.897715, 127.55915999999999 93.897715, 138.18909 72.637855, 138.18909 72.637855, 127.55915999999999 36.3189275, 127.55915999999999 36.3189275, 138.18909 10.62993, 138.18909 10.62993, 108.9567825 0, 108.9567825 0, 79.724475 10.62993, 79.724475 10.62993, 58.464615 0, 58.464615 0, 29.2323075 10.62993, 29.2323075 "/>
|
||||
</g>
|
||||
<!-- Top-->
|
||||
<g transform="translate(22.5000185, 160.6891085) " >
|
||||
<polygon style="stroke:#000000; fill:none; stroke-width:0.90000074" points="10.62993, 10.62993 24.80317, 10.62993 24.80317, 0 49.60634, 0 49.60634, 10.62993 74.40951000000001, 10.62993 74.40951000000001, 0 99.21268, 0 99.21268, 10.62993 113.38592, 10.62993 113.38592, 36.3189275 124.01585, 36.3189275 124.01585, 72.637855 113.38592, 72.637855 113.38592, 93.897715 124.01585, 93.897715 124.01585, 115.15757500000001 113.38592, 115.15757500000001 113.38592, 136.417435 124.01585, 136.417435 124.01585, 172.73636249999998 113.38592, 172.73636249999998 113.38592, 198.42535999999998 99.21268, 198.42535999999998 99.21268, 209.05528999999999 74.40951000000001, 209.05528999999999 74.40951000000001, 198.42535999999998 49.60634, 198.42535999999998 49.60634, 209.05528999999999 24.80317, 209.05528999999999 24.80317, 198.42535999999998 10.62993, 198.42536 10.62993, 172.73636249999998 0, 172.73636249999998 0, 136.417435 10.62993, 136.417435 10.62993, 115.15757500000001 0, 115.15757500000001 0, 93.897715 10.62993, 93.897715 10.62993, 72.637855 0, 72.637855 0, 36.3189275 10.62993, 36.3189275 "/>
|
||||
<circle cx="62.007925" cy="77.95282" r="39.8622375" style="stroke:#000000;stroke-width:0.90000074;fill:none" />
|
||||
</g>
|
||||
<!-- Bottom-->
|
||||
<g transform="translate(146.5158685, 160.6891085) " >
|
||||
<polygon style="stroke:#000000; fill:none; stroke-width:0.90000074" points="10.62993, 10.62993 24.80317, 10.62993 24.80317, 0 49.60634, 0 49.60634, 10.62993 74.40951000000001, 10.62993 74.40951000000001, 0 99.21268, 0 99.21268, 10.62993 113.38592, 10.62993 113.38592, 36.3189275 124.01585, 36.3189275 124.01585, 72.637855 113.38592, 72.637855 113.38592, 93.897715 124.01585, 93.897715 124.01585, 115.15757500000001 113.38592, 115.15757500000001 113.38592, 136.417435 124.01585, 136.417435 124.01585, 172.73636249999998 113.38592, 172.73636249999998 113.38592, 198.42535999999998 99.21268, 198.42535999999998 99.21268, 209.05528999999999 74.40951000000001, 209.05528999999999 74.40951000000001, 198.42535999999998 49.60634, 198.42535999999998 49.60634, 209.05528999999999 24.80317, 209.05528999999999 24.80317, 198.42535999999998 10.62993, 198.42536 10.62993, 172.73636249999998 0, 172.73636249999998 0, 136.417435 10.62993, 136.417435 10.62993, 115.15757500000001 0, 115.15757500000001 0, 93.897715 10.62993, 93.897715 10.62993, 72.637855 0, 72.637855 0, 36.3189275 10.62993, 36.3189275 "/>
|
||||
</g></svg>
|
||||
|
After Width: | Height: | Size: 6.6 KiB |
172
lib-ext/rfm-69.git/Examples/Node/Node.ino
Normal file
172
lib-ext/rfm-69.git/Examples/Node/Node.ino
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
// Sample RFM69 sender/node sketch, with ACK and optional encryption
|
||||
// Sends periodic messages of increasing length to gateway (id=1)
|
||||
// It also looks for an onboard FLASH chip, if present
|
||||
// Library and code by Felix Rusu - felix@lowpowerlab.com
|
||||
// Get the RFM69 and SPIFlash library at: https://github.com/LowPowerLab/
|
||||
|
||||
#include <RFM69.h> //get it here: https://www.github.com/lowpowerlab/rfm69
|
||||
#include <SPI.h>
|
||||
#include <SPIFlash.h> //get it here: https://www.github.com/lowpowerlab/spiflash
|
||||
|
||||
#define NODEID 2 //unique for each node on same network
|
||||
#define NETWORKID 100 //the same on all nodes that talk to each other
|
||||
#define GATEWAYID 1
|
||||
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
|
||||
#define FREQUENCY RF69_433MHZ
|
||||
//#define FREQUENCY RF69_868MHZ
|
||||
//#define FREQUENCY RF69_915MHZ
|
||||
#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
|
||||
//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
|
||||
#define ACK_TIME 30 // max # of ms to wait for an ack
|
||||
#ifdef __AVR_ATmega1284P__
|
||||
#define LED 15 // Moteino MEGAs have LEDs on D15
|
||||
#define FLASH_SS 23 // and FLASH SS on D23
|
||||
#else
|
||||
#define LED 9 // Moteinos have LEDs on D9
|
||||
#define FLASH_SS 8 // and FLASH SS on D8
|
||||
#endif
|
||||
|
||||
#define SERIAL_BAUD 115200
|
||||
|
||||
int TRANSMITPERIOD = 150; //transmit a packet to gateway so often (in ms)
|
||||
char payload[] = "123 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
char buff[20];
|
||||
byte sendSize=0;
|
||||
boolean requestACK = false;
|
||||
SPIFlash flash(FLASH_SS, 0xEF30); //EF30 for 4mbit Windbond chip (W25X40CL)
|
||||
RFM69 radio;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
#ifdef IS_RFM69HW
|
||||
radio.setHighPower(); //uncomment only for RFM69HW!
|
||||
#endif
|
||||
radio.encrypt(ENCRYPTKEY);
|
||||
//radio.setFrequency(919000000); //set frequency to some custom frequency
|
||||
char buff[50];
|
||||
sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
|
||||
Serial.println(buff);
|
||||
|
||||
if (flash.initialize())
|
||||
{
|
||||
Serial.print("SPI Flash Init OK ... UniqueID (MAC): ");
|
||||
flash.readUniqueId();
|
||||
for (byte i=0;i<8;i++)
|
||||
{
|
||||
Serial.print(flash.UNIQUEID[i], HEX);
|
||||
Serial.print(' ');
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
else
|
||||
Serial.println("SPI Flash Init FAIL! (is chip present?)");
|
||||
}
|
||||
|
||||
long lastPeriod = 0;
|
||||
void loop() {
|
||||
//process any serial input
|
||||
if (Serial.available() > 0)
|
||||
{
|
||||
char input = Serial.read();
|
||||
if (input >= 48 && input <= 57) //[0,9]
|
||||
{
|
||||
TRANSMITPERIOD = 100 * (input-48);
|
||||
if (TRANSMITPERIOD == 0) TRANSMITPERIOD = 1000;
|
||||
Serial.print("\nChanging delay to ");
|
||||
Serial.print(TRANSMITPERIOD);
|
||||
Serial.println("ms\n");
|
||||
}
|
||||
|
||||
if (input == 'r') //d=dump register values
|
||||
radio.readAllRegs();
|
||||
//if (input == 'E') //E=enable encryption
|
||||
// radio.encrypt(KEY);
|
||||
//if (input == 'e') //e=disable encryption
|
||||
// radio.encrypt(null);
|
||||
|
||||
if (input == 'd') //d=dump flash area
|
||||
{
|
||||
Serial.println("Flash content:");
|
||||
uint16_t counter = 0;
|
||||
|
||||
Serial.print("0-256: ");
|
||||
while(counter<=256){
|
||||
Serial.print(flash.readByte(counter++), HEX);
|
||||
Serial.print('.');
|
||||
}
|
||||
while(flash.busy());
|
||||
Serial.println();
|
||||
}
|
||||
if (input == 'e')
|
||||
{
|
||||
Serial.print("Erasing Flash chip ... ");
|
||||
flash.chipErase();
|
||||
while(flash.busy());
|
||||
Serial.println("DONE");
|
||||
}
|
||||
if (input == 'i')
|
||||
{
|
||||
Serial.print("DeviceID: ");
|
||||
word jedecid = flash.readDeviceId();
|
||||
Serial.println(jedecid, HEX);
|
||||
}
|
||||
}
|
||||
|
||||
//check for any received packets
|
||||
if (radio.receiveDone())
|
||||
{
|
||||
Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] ");
|
||||
for (byte i = 0; i < radio.DATALEN; i++)
|
||||
Serial.print((char)radio.DATA[i]);
|
||||
Serial.print(" [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]");
|
||||
|
||||
if (radio.ACKRequested())
|
||||
{
|
||||
radio.sendACK();
|
||||
Serial.print(" - ACK sent");
|
||||
}
|
||||
Blink(LED,3);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
int currPeriod = millis()/TRANSMITPERIOD;
|
||||
if (currPeriod != lastPeriod)
|
||||
{
|
||||
lastPeriod=currPeriod;
|
||||
|
||||
//send FLASH id
|
||||
if(sendSize==0)
|
||||
{
|
||||
sprintf(buff, "FLASH_MEM_ID:0x%X", flash.readDeviceId());
|
||||
byte buffLen=strlen(buff);
|
||||
if (radio.sendWithRetry(GATEWAYID, buff, buffLen))
|
||||
Serial.print(" ok!");
|
||||
else Serial.print(" nothing...");
|
||||
//sendSize = (sendSize + 1) % 31;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print("Sending[");
|
||||
Serial.print(sendSize);
|
||||
Serial.print("]: ");
|
||||
for(byte i = 0; i < sendSize; i++)
|
||||
Serial.print((char)payload[i]);
|
||||
|
||||
if (radio.sendWithRetry(GATEWAYID, payload, sendSize))
|
||||
Serial.print(" ok!");
|
||||
else Serial.print(" nothing...");
|
||||
}
|
||||
sendSize = (sendSize + 1) % 31;
|
||||
Serial.println();
|
||||
Blink(LED,3);
|
||||
}
|
||||
}
|
||||
|
||||
void Blink(byte PIN, int DELAY_MS)
|
||||
{
|
||||
pinMode(PIN, OUTPUT);
|
||||
digitalWrite(PIN,HIGH);
|
||||
delay(DELAY_MS);
|
||||
digitalWrite(PIN,LOW);
|
||||
}
|
||||
242
lib-ext/rfm-69.git/Examples/OLEDMote/OLEDMote.ino
Normal file
242
lib-ext/rfm-69.git/Examples/OLEDMote/OLEDMote.ino
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
// Sample RFM69 sketch for the MotionOLED mote containing the OLED
|
||||
// Displays any messages on the network on the OLED display and beeps the buzzer every time a message is received
|
||||
// The side button will step through 10 past received messages
|
||||
// Library and code by Felix Rusu - felix@lowpowerlab.com
|
||||
// Get libraries at: https://github.com/LowPowerLab/
|
||||
// Make sure you adjust the settings in the configuration section below !!!
|
||||
|
||||
// **********************************************************************************
|
||||
// Copyright Felix Rusu, LowPowerLab.com
|
||||
// Library and code by Felix Rusu - felix@lowpowerlab.com
|
||||
// **********************************************************************************
|
||||
// License
|
||||
// **********************************************************************************
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will
|
||||
// be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
// implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
// PARTICULAR PURPOSE. See the GNU General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// Public License along with this program.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Licence can be viewed at
|
||||
// http://www.gnu.org/licenses/gpl-3.0.txt
|
||||
//
|
||||
// Please maintain this license information along with authorship
|
||||
// and copyright notices in any redistribution of this code
|
||||
// **********************************************************************************
|
||||
|
||||
#include <RFM69.h> //get it here: https://www.github.com/lowpowerlab/rfm69
|
||||
#include <SPI.h>
|
||||
#include <LowPower.h> //get library from: https://github.com/lowpowerlab/lowpower
|
||||
#include "U8glib.h" //get library from: https://code.google.com/p/u8glib/
|
||||
|
||||
//*********************************************************************************************
|
||||
// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE *************
|
||||
//*********************************************************************************************
|
||||
#define NODEID 122 //unique for each node on same network
|
||||
#define NETWORKID 100 //the same on all nodes that talk to each other
|
||||
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
|
||||
//#define FREQUENCY RF69_433MHZ
|
||||
//#define FREQUENCY RF69_868MHZ
|
||||
#define FREQUENCY RF69_915MHZ
|
||||
#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
|
||||
#define IS_RFM69HW //uncomment only for RFM69HW! Remove/comment if you have RFM69W!
|
||||
//*********************************************************************************************
|
||||
|
||||
#define SERIAL_BAUD 115200
|
||||
#define LED 5 // Moteinos have LEDs on D9, but for MotionMote we are using the external led on D5
|
||||
#define BUZZER 6
|
||||
#define BUTTON_INT 1 //user button on interrupt 1
|
||||
#define BUTTON_PIN 3 //user button on interrupt 1
|
||||
|
||||
RFM69 radio;
|
||||
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE); // I2C / TWI SSD1306 OLED 128x64
|
||||
bool promiscuousMode = true; //set to 'true' to sniff all packets on the same network
|
||||
|
||||
void setup() {
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
#ifdef IS_RFM69HW
|
||||
radio.setHighPower(); //only for RFM69HW!
|
||||
#endif
|
||||
radio.encrypt(ENCRYPTKEY);
|
||||
radio.promiscuous(promiscuousMode);
|
||||
char buff[50];
|
||||
sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
|
||||
Serial.println(buff);
|
||||
pinMode(BUZZER, OUTPUT);
|
||||
|
||||
//configure OLED
|
||||
u8g.setRot180(); //flip screen
|
||||
// assign default color value
|
||||
if ( u8g.getMode() == U8G_MODE_R3G3B2 )
|
||||
u8g.setColorIndex(255); // white
|
||||
else if ( u8g.getMode() == U8G_MODE_GRAY2BIT )
|
||||
u8g.setColorIndex(3); // max intensity
|
||||
else if ( u8g.getMode() == U8G_MODE_BW )
|
||||
u8g.setColorIndex(1); // pixel on
|
||||
else if ( u8g.getMode() == U8G_MODE_HICOLOR )
|
||||
u8g.setHiColorByRGB(255,255,255);
|
||||
u8g.begin();
|
||||
Serial.flush();
|
||||
pinMode(BUTTON_PIN, INPUT_PULLUP);
|
||||
attachInterrupt(BUTTON_INT, handleButton, FALLING);
|
||||
}
|
||||
|
||||
#define FLAG_INTERRUPT 0x01
|
||||
volatile int mainEventFlags = 0;
|
||||
boolean buttonPressed = false;
|
||||
void handleButton()
|
||||
{
|
||||
mainEventFlags |= FLAG_INTERRUPT;
|
||||
}
|
||||
|
||||
byte ackCount=0;
|
||||
|
||||
#define MSG_MAX_LEN 17 //OLED 1 line max # of chars (16 + EOL)
|
||||
#define HISTORY_LEN 10 //hold this many past messages
|
||||
typedef struct {
|
||||
char data[MSG_MAX_LEN];
|
||||
int rssi;
|
||||
byte from;
|
||||
} Message;
|
||||
Message * messageHistory = new Message[HISTORY_LEN];
|
||||
|
||||
byte lastMessageIndex = HISTORY_LEN;
|
||||
byte currMessageIndex = HISTORY_LEN;
|
||||
byte historyLength = 0;
|
||||
void loop() {
|
||||
if (mainEventFlags & FLAG_INTERRUPT)
|
||||
{
|
||||
LowPower.powerDown(SLEEP_30MS, ADC_OFF, BOD_ON);
|
||||
mainEventFlags &= ~FLAG_INTERRUPT;
|
||||
if (!digitalRead(BUTTON_PIN)) {
|
||||
buttonPressed=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonPressed)
|
||||
{
|
||||
buttonPressed = false;
|
||||
Beep(10, false);
|
||||
|
||||
//save non-ACK messages in a circular buffer
|
||||
if (!radio.ACK_RECEIVED && historyLength > 1) //only care if at least 2 messages saved. if only 1 message it should be displayed already
|
||||
{
|
||||
if (currMessageIndex==0)
|
||||
currMessageIndex=historyLength-1;
|
||||
else currMessageIndex--;
|
||||
|
||||
//Serial.print("HIST currIndex/histLen=");Serial.print(currMessageIndex+1);Serial.print("/");Serial.print(historyLength);
|
||||
//Serial.print(" - ");
|
||||
//Serial.println(messageHistory[currMessageIndex].data);
|
||||
|
||||
u8g.firstPage();
|
||||
do {
|
||||
draw(messageHistory[currMessageIndex].data, messageHistory[currMessageIndex].rssi, messageHistory[currMessageIndex].from, true);
|
||||
} while(u8g.nextPage());
|
||||
//delay(10); //give OLED time to draw?
|
||||
}
|
||||
}
|
||||
|
||||
if (radio.receiveDone())
|
||||
{
|
||||
Serial.print('[');Serial.print(radio.SENDERID);Serial.print("] ");
|
||||
if (promiscuousMode)
|
||||
Serial.print("to [");Serial.print(radio.TARGETID);Serial.print("] ");
|
||||
|
||||
Serial.print((char*)radio.DATA);
|
||||
Serial.print(" [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]");
|
||||
Serial.println();
|
||||
|
||||
saveToHistory((char *)radio.DATA, radio.RSSI, radio.SENDERID);
|
||||
Blink(LED,3);
|
||||
Beep(20, true);
|
||||
u8g.firstPage();
|
||||
do {
|
||||
draw((char*)radio.DATA, radio.RSSI, radio.SENDERID, false);
|
||||
} while(u8g.nextPage());
|
||||
//delay(10); //give OLED time to draw?
|
||||
}
|
||||
radio.receiveDone();
|
||||
Serial.flush();
|
||||
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_ON);
|
||||
}
|
||||
|
||||
float batteryVolts = 5;
|
||||
char* BATstr="BAT:5.00v";
|
||||
void draw(char * data, int rssi, byte from, boolean isHist) {
|
||||
char buff[20];
|
||||
// graphic commands to redraw the complete screen should be placed here
|
||||
u8g.setFont(u8g_font_unifont);
|
||||
u8g.drawStr( 0, 10, data);
|
||||
sprintf(buff, "ID:%d", from);
|
||||
u8g.drawStr( 0, 25, buff);
|
||||
sprintf(buff, "RSSI:%d", rssi);
|
||||
u8g.drawStr( 60, 25, buff);
|
||||
|
||||
if (!isHist)
|
||||
{
|
||||
batteryVolts = analogRead(A7) * 0.00322 * 1.42;
|
||||
dtostrf(batteryVolts, 3,2, BATstr);
|
||||
sprintf(buff, "BAT:%sv", BATstr);
|
||||
u8g.drawStr( 0, 55, buff);
|
||||
}
|
||||
}
|
||||
|
||||
void Beep(byte theDelay, boolean both)
|
||||
{
|
||||
if (theDelay > 20) theDelay = 20;
|
||||
tone(BUZZER, 4200); //4200
|
||||
delay(theDelay);
|
||||
noTone(BUZZER);
|
||||
LowPower.powerDown(SLEEP_15MS, ADC_OFF, BOD_ON);
|
||||
if (both)
|
||||
{
|
||||
tone(BUZZER, 4500); //4500
|
||||
delay(theDelay);
|
||||
noTone(BUZZER);
|
||||
}
|
||||
}
|
||||
|
||||
void Blink(byte PIN, int DELAY_MS)
|
||||
{
|
||||
pinMode(PIN, OUTPUT);
|
||||
digitalWrite(PIN,HIGH);
|
||||
delay(DELAY_MS);
|
||||
digitalWrite(PIN,LOW);
|
||||
}
|
||||
|
||||
void saveToHistory(char * msg, int rssi, byte from)
|
||||
{
|
||||
byte length = strlen(msg);
|
||||
byte i = 0;
|
||||
if (lastMessageIndex >=9) lastMessageIndex = 0;
|
||||
else lastMessageIndex++;
|
||||
currMessageIndex = lastMessageIndex;
|
||||
if (historyLength < HISTORY_LEN) historyLength++;
|
||||
|
||||
//Serial.print("HIST SAVE lastIndex=");Serial.print(lastMessageIndex);Serial.print(" strlen=");Serial.print(length);
|
||||
//Serial.print(" msg=[");
|
||||
|
||||
for (; i<(MSG_MAX_LEN-1) && (i < length); i++)
|
||||
{
|
||||
messageHistory[lastMessageIndex].data[i] = msg[i];
|
||||
Serial.print(msg[i]);
|
||||
}
|
||||
//Serial.print("] copied:");
|
||||
messageHistory[lastMessageIndex].data[i] = '\0'; //terminate string
|
||||
//Serial.println((char*)messageHistory[lastMessageIndex].data);
|
||||
|
||||
messageHistory[lastMessageIndex].rssi = rssi;
|
||||
messageHistory[lastMessageIndex].from = from;
|
||||
}
|
||||
146
lib-ext/rfm-69.git/Examples/PiGateway/PiGateway.ino
Normal file
146
lib-ext/rfm-69.git/Examples/PiGateway/PiGateway.ino
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
// **********************************************************************************************************
|
||||
// GarageMote garage door controller base receiver sketch that works with Moteinos equipped with HopeRF RFM69W/RFM69HW
|
||||
// Can be adapted to use Moteinos using RFM12B
|
||||
// This is the sketch for the base, not the controller itself, and meant as another example on how to use a
|
||||
// Moteino as a gateway/base/receiver
|
||||
// 2014-07-14 (C) felix@lowpowerlab.com, http://www.LowPowerLab.com
|
||||
// **********************************************************************************************************
|
||||
// Creative Commons Attrib Share-Alike License
|
||||
// You are free to use/extend this code/library but please abide with the CCSA license:
|
||||
// http://creativecommons.org/licenses/by-sa/4.0/
|
||||
// **********************************************************************************
|
||||
|
||||
#include <RFM69.h> //get it here: http://github.com/lowpowerlab/rfm69
|
||||
#include <SPIFlash.h> //get it here: http://github.com/lowpowerlab/spiflash
|
||||
#include <WirelessHEX69.h> //get it here: https://github.com/LowPowerLab/WirelessProgramming
|
||||
#include <SPI.h> //comes with Arduino IDE (www.arduino.cc)
|
||||
|
||||
//*****************************************************************************************************************************
|
||||
// ADJUST THE SETTINGS BELOW DEPENDING ON YOUR HARDWARE/SITUATION!
|
||||
//*****************************************************************************************************************************
|
||||
#define NODEID 1
|
||||
#define NETWORKID 200
|
||||
#define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ)
|
||||
#define ENCRYPTKEY "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less!
|
||||
#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
|
||||
#define LED 9
|
||||
#define FLASH_CS 8
|
||||
#define SERIAL_BAUD 115200
|
||||
#define SERIAL_EN //comment out if you don't want any serial verbose output
|
||||
#define ACK_TIME 30 // # of ms to wait for an ack
|
||||
//*****************************************************************************************************************************
|
||||
|
||||
#ifdef SERIAL_EN
|
||||
#define DEBUG(input) {Serial.print(input); delay(1);}
|
||||
#define DEBUGln(input) {Serial.println(input); delay(1);}
|
||||
#else
|
||||
#define DEBUG(input);
|
||||
#define DEBUGln(input);
|
||||
#endif
|
||||
|
||||
RFM69 radio;
|
||||
SPIFlash flash(FLASH_CS, 0xEF30); //EF40 for 16mbit windbond chip
|
||||
|
||||
void setup() {
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
delay(10);
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
#ifdef IS_RFM69HW
|
||||
radio.setHighPower(); //uncomment only for RFM69HW!
|
||||
#endif
|
||||
radio.encrypt(ENCRYPTKEY);
|
||||
char buff[50];
|
||||
sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
|
||||
DEBUGln(buff);
|
||||
if (flash.initialize())
|
||||
{
|
||||
DEBUGln("SPI Flash Init OK!");
|
||||
}
|
||||
else
|
||||
DEBUGln("SPI Flash Init FAIL! (is chip present?)");
|
||||
}
|
||||
|
||||
byte ackCount=0;
|
||||
byte inputLen=0;
|
||||
char input[64];
|
||||
byte buff[61];
|
||||
String inputstr;
|
||||
void loop() {
|
||||
inputLen = readSerialLine(input);
|
||||
inputstr = String(input);
|
||||
inputstr.toUpperCase();
|
||||
|
||||
if (inputLen > 0)
|
||||
{
|
||||
if (inputstr.equals("KEY?"))
|
||||
{
|
||||
DEBUG("ENCRYPTKEY:");
|
||||
DEBUG(ENCRYPTKEY);
|
||||
}
|
||||
|
||||
byte targetId = inputstr.toInt(); //extract ID if any
|
||||
byte colonIndex = inputstr.indexOf(":"); //find position of first colon
|
||||
if (targetId > 0) inputstr = inputstr.substring(colonIndex+1); //trim "ID:" if any
|
||||
if (targetId > 0 && targetId != NODEID && targetId != RF69_BROADCAST_ADDR && colonIndex>0 && colonIndex<4 && inputstr.length()>0)
|
||||
{
|
||||
|
||||
inputstr.getBytes(buff, 61);
|
||||
//DEBUGln((char*)buff);
|
||||
//DEBUGln(targetId);
|
||||
//DEBUGln(colonIndex);
|
||||
if (radio.sendWithRetry(targetId, buff, inputstr.length()))
|
||||
{
|
||||
DEBUGln("ACK:OK");
|
||||
}
|
||||
else
|
||||
DEBUGln("ACK:NOK");
|
||||
}
|
||||
}
|
||||
|
||||
if (radio.receiveDone())
|
||||
{
|
||||
int rssi = radio.RSSI;
|
||||
DEBUG('[');DEBUG(radio.SENDERID);DEBUG("] ");
|
||||
if (radio.DATALEN > 0)
|
||||
{
|
||||
for (byte i = 0; i < radio.DATALEN; i++)
|
||||
DEBUG((char)radio.DATA[i]);
|
||||
DEBUG(" [RSSI:");DEBUG(rssi);DEBUG("]");
|
||||
}
|
||||
|
||||
CheckForWirelessHEX(radio, flash, false); //non verbose DEBUG
|
||||
|
||||
if (radio.ACKRequested())
|
||||
{
|
||||
byte theNodeID = radio.SENDERID;
|
||||
radio.sendACK();
|
||||
DEBUG("[ACK-sent]");
|
||||
}
|
||||
DEBUGln();
|
||||
Blink(LED,3);
|
||||
}
|
||||
}
|
||||
|
||||
void Blink(byte PIN, int DELAY_MS)
|
||||
{
|
||||
pinMode(PIN, OUTPUT);
|
||||
digitalWrite(PIN,HIGH);
|
||||
delay(DELAY_MS);
|
||||
digitalWrite(PIN,LOW);
|
||||
}
|
||||
|
||||
//readSerialLine already defined in WirelessHEX69
|
||||
// reads a line feed (\n) terminated line from the serial stream
|
||||
// returns # of bytes read, up to 255
|
||||
// timeout in ms, will timeout and return after so long
|
||||
//byte readSerialLine(char* input, char endOfLineChar=10, byte maxLength=64, uint16_t timeout=10);
|
||||
//byte readSerialLine(char* input, char endOfLineChar, byte maxLength, uint16_t timeout)
|
||||
//{
|
||||
// byte inputLen = 0;
|
||||
// Serial.setTimeout(timeout);
|
||||
// inputLen = Serial.readBytesUntil(endOfLineChar, input, maxLength);
|
||||
// input[inputLen]=0;//null-terminate it
|
||||
// Serial.setTimeout(0);
|
||||
// //Serial.println();
|
||||
// return inputLen;
|
||||
//}
|
||||
186
lib-ext/rfm-69.git/Examples/PiGateway/PiGateway_withLCD.ino
Normal file
186
lib-ext/rfm-69.git/Examples/PiGateway/PiGateway_withLCD.ino
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
// **********************************************************************************************************
|
||||
// GarageMote garage door controller base receiver sketch that works with Moteinos equipped with HopeRF RFM69W/RFM69HW
|
||||
// Can be adapted to use Moteinos using RFM12B
|
||||
// This is the sketch for the base, not the controller itself, and meant as another example on how to use a
|
||||
// Moteino as a gateway/base/receiver
|
||||
// 2014-07-14 (C) felix@lowpowerlab.com, http://www.LowPowerLab.com
|
||||
// **********************************************************************************************************
|
||||
// Creative Commons Attrib Share-Alike License
|
||||
// You are free to use/extend this code/library but please abide with the CCSA license:
|
||||
// http://creativecommons.org/licenses/by-sa/4.0/
|
||||
// **********************************************************************************
|
||||
|
||||
#include <RFM69.h> //get it here: http://github.com/lowpowerlab/rfm69
|
||||
#include <SPIFlash.h> //get it here: http://github.com/lowpowerlab/spiflash
|
||||
#include <WirelessHEX69.h> //get it here: https://github.com/LowPowerLab/WirelessProgramming
|
||||
#include <SPI.h> //comes with Arduino IDE (www.arduino.cc)
|
||||
#include "ST7036.h" //get it from here: https://bitbucket.org/fmalpartida/st7036-display-driver/src/
|
||||
#include "LCD_C0220BiZ.h" //get it from here: https://bitbucket.org/fmalpartida/st7036-display-driver/src/
|
||||
#include <Wire.h> //comes with Arduino
|
||||
|
||||
//*****************************************************************************************************************************
|
||||
// ADJUST THE SETTINGS BELOW DEPENDING ON YOUR HARDWARE/SITUATION!
|
||||
//*****************************************************************************************************************************
|
||||
#define NODEID 1
|
||||
#define NETWORKID 200
|
||||
#define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ)
|
||||
#define ENCRYPTKEY "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less!
|
||||
#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
|
||||
#define LED 9
|
||||
#define FLASH_CS 8
|
||||
#define SERIAL_BAUD 115200
|
||||
#define SERIAL_EN //comment out if you don't want any serial verbose output
|
||||
#define ACK_TIME 30 // # of ms to wait for an ack
|
||||
#define BACKLIGHTPIN 5 //3=R,5=G,6=B
|
||||
//*****************************************************************************************************************************
|
||||
|
||||
#ifdef SERIAL_EN
|
||||
#define DEBUG(input) {Serial.print(input); delay(1);}
|
||||
#define DEBUGln(input) {Serial.println(input); delay(1);}
|
||||
#else
|
||||
#define DEBUG(input);
|
||||
#define DEBUGln(input);
|
||||
#endif
|
||||
|
||||
RFM69 radio;
|
||||
SPIFlash flash(FLASH_CS, 0xEF30); //EF40 for 16mbit windbond chip
|
||||
|
||||
//initialize LCD
|
||||
ST7036 lcd = ST7036(2, 20, 0x78, BACKLIGHTPIN); //row count, column count, I2C addr, pin for backlight PWM
|
||||
byte battChar[8] = {0b00000,0b01110,0b11111,0b11111,0b11111,0b11111,0b11111,0};
|
||||
byte rssiChar[8] = {0b00000,0b00100,0b10101,0b01110,0b00100,0b00100,0b00100,0};
|
||||
|
||||
void setup() {
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
delay(10);
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
#ifdef IS_RFM69HW
|
||||
radio.setHighPower(); //uncomment only for RFM69HW!
|
||||
#endif
|
||||
radio.encrypt(ENCRYPTKEY);
|
||||
char buff[50];
|
||||
sprintf(buff, "\nListening @ %dmhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
|
||||
DEBUGln(buff);
|
||||
if (flash.initialize())
|
||||
{
|
||||
DEBUGln("SPI Flash Init OK!");
|
||||
}
|
||||
else
|
||||
DEBUGln("SPI Flash Init FAIL! (is chip present?)");
|
||||
|
||||
lcd.init();
|
||||
lcd.setContrast(10);
|
||||
lcd.clear();
|
||||
lcd.load_custom_character(0, battChar);
|
||||
lcd.load_custom_character(1, rssiChar);
|
||||
lcd.setCursor(0,0);
|
||||
lcd.print(buff);
|
||||
}
|
||||
|
||||
byte ackCount=0;
|
||||
byte inputLen=0;
|
||||
char input[64];
|
||||
byte buff[61];
|
||||
char LO[20];
|
||||
char BAT[20];
|
||||
char temp[25];
|
||||
String inputstr;
|
||||
void loop() {
|
||||
inputLen = readSerialLine(input, 10, 64, 10); //readSerialLine(char* input, char endOfLineChar=10, byte maxLength=64, uint16_t timeout=10);
|
||||
inputstr = String(input);
|
||||
inputstr.toUpperCase();
|
||||
|
||||
if (inputLen > 0)
|
||||
{
|
||||
if (inputstr.equals("KEY?"))
|
||||
{
|
||||
DEBUG("ENCRYPTKEY:");
|
||||
DEBUG(ENCRYPTKEY);
|
||||
}
|
||||
|
||||
byte targetId = inputstr.toInt(); //extract ID if any
|
||||
byte colonIndex = inputstr.indexOf(":"); //find position of first colon
|
||||
if (targetId > 0) inputstr = inputstr.substring(colonIndex+1); //trim "ID:" if any
|
||||
if (targetId > 0 && targetId != NODEID && targetId != RF69_BROADCAST_ADDR && colonIndex>0 && colonIndex<4 && inputstr.length()>0)
|
||||
{
|
||||
|
||||
inputstr.getBytes(buff, 61);
|
||||
//DEBUGln((char*)buff);
|
||||
//DEBUGln(targetId);
|
||||
//DEBUGln(colonIndex);
|
||||
if (radio.sendWithRetry(targetId, buff, inputstr.length()))
|
||||
{
|
||||
DEBUGln("ACK:OK");
|
||||
}
|
||||
else
|
||||
DEBUGln("ACK:NOK");
|
||||
}
|
||||
}
|
||||
|
||||
if (radio.receiveDone())
|
||||
{
|
||||
int rssi = radio.RSSI;
|
||||
DEBUG('[');DEBUG(radio.SENDERID);DEBUG("] ");
|
||||
if (radio.DATALEN > 0)
|
||||
{
|
||||
for (byte i = 0; i < radio.DATALEN; i++)
|
||||
DEBUG((char)radio.DATA[i]);
|
||||
DEBUG(" [RSSI:");DEBUG(rssi);DEBUG("]");
|
||||
}
|
||||
|
||||
CheckForWirelessHEX(radio, flash, false); //non verbose DEBUG
|
||||
|
||||
if (radio.ACKRequested())
|
||||
{
|
||||
byte theNodeID = radio.SENDERID;
|
||||
radio.sendACK();
|
||||
DEBUG("[ACK-sent]");
|
||||
}
|
||||
DEBUGln();
|
||||
Blink(LED,3);
|
||||
|
||||
lcd.clear();
|
||||
lcd.setCursor(0,0);
|
||||
|
||||
//if (radio.DATALEN < RF69_MAX_DATA_LEN) radio.DATA[radio.DATALEN]=0;
|
||||
byte matches = sscanf((const char*)radio.DATA, "%s BAT:%s", LO, BAT);
|
||||
if (matches==2)
|
||||
{
|
||||
lcd.print(LO);
|
||||
lcd.setCursor(0,14);
|
||||
lcd.print(char(0));
|
||||
lcd.setCursor(0,15);
|
||||
lcd.print(BAT);
|
||||
}
|
||||
else lcd.print((const char*)radio.DATA);
|
||||
|
||||
lcd.setCursor(1,14);
|
||||
lcd.print(char(1));
|
||||
lcd.setCursor(1,16);
|
||||
lcd.print(rssi);
|
||||
}
|
||||
}
|
||||
|
||||
void Blink(byte PIN, int DELAY_MS)
|
||||
{
|
||||
pinMode(PIN, OUTPUT);
|
||||
digitalWrite(PIN,HIGH);
|
||||
delay(DELAY_MS);
|
||||
digitalWrite(PIN,LOW);
|
||||
}
|
||||
|
||||
//readSerialLine already defined in WirelessHEX69
|
||||
// reads a line feed (\n) terminated line from the serial stream
|
||||
// returns # of bytes read, up to 255
|
||||
// timeout in ms, will timeout and return after so long
|
||||
//byte readSerialLine(char* input, char endOfLineChar=10, byte maxLength=64, uint16_t timeout=10);
|
||||
//byte readSerialLine(char* input, char endOfLineChar, byte maxLength, uint16_t timeout)
|
||||
//{
|
||||
// byte inputLen = 0;
|
||||
// Serial.setTimeout(timeout);
|
||||
// inputLen = Serial.readBytesUntil(endOfLineChar, input, maxLength);
|
||||
// input[inputLen]=0;//null-terminate it
|
||||
// Serial.setTimeout(0);
|
||||
// //Serial.println();
|
||||
// return inputLen;
|
||||
//}
|
||||
139
lib-ext/rfm-69.git/Examples/Struct_receive/Struct_receive.ino
Normal file
139
lib-ext/rfm-69.git/Examples/Struct_receive/Struct_receive.ino
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
#include <RFM69.h>
|
||||
#include <SPI.h>
|
||||
#include <SPIFlash.h>
|
||||
|
||||
#define NODEID 1
|
||||
#define NETWORKID 100
|
||||
#define FREQUENCY RF69_433MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ)
|
||||
#define KEY "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less!
|
||||
#define LED 9
|
||||
#define SERIAL_BAUD 115200
|
||||
#define ACK_TIME 30 // # of ms to wait for an ack
|
||||
|
||||
RFM69 radio;
|
||||
SPIFlash flash(8, 0xEF30); //EF40 for 16mbit windbond chip
|
||||
bool promiscuousMode = false; //set to 'true' to sniff all packets on the same network
|
||||
|
||||
typedef struct {
|
||||
int nodeId; //store this nodeId
|
||||
unsigned long uptime; //uptime in ms
|
||||
float temp; //temperature maybe?
|
||||
} Payload;
|
||||
Payload theData;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
delay(10);
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
//radio.setHighPower(); //uncomment only for RFM69HW!
|
||||
radio.encrypt(KEY);
|
||||
radio.promiscuous(promiscuousMode);
|
||||
char buff[50];
|
||||
sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
|
||||
Serial.println(buff);
|
||||
if (flash.initialize())
|
||||
Serial.println("SPI Flash Init OK!");
|
||||
else
|
||||
Serial.println("SPI Flash Init FAIL! (is chip present?)");
|
||||
}
|
||||
|
||||
byte ackCount=0;
|
||||
void loop() {
|
||||
//process any serial input
|
||||
if (Serial.available() > 0)
|
||||
{
|
||||
char input = Serial.read();
|
||||
if (input == 'r') //d=dump all register values
|
||||
radio.readAllRegs();
|
||||
if (input == 'E') //E=enable encryption
|
||||
radio.encrypt(KEY);
|
||||
if (input == 'e') //e=disable encryption
|
||||
radio.encrypt(null);
|
||||
if (input == 'p')
|
||||
{
|
||||
promiscuousMode = !promiscuousMode;
|
||||
radio.promiscuous(promiscuousMode);
|
||||
Serial.print("Promiscuous mode ");Serial.println(promiscuousMode ? "on" : "off");
|
||||
}
|
||||
|
||||
if (input == 'd') //d=dump flash area
|
||||
{
|
||||
Serial.println("Flash content:");
|
||||
int counter = 0;
|
||||
|
||||
while(counter<=256){
|
||||
Serial.print(flash.readByte(counter++), HEX);
|
||||
Serial.print('.');
|
||||
}
|
||||
while(flash.busy());
|
||||
Serial.println();
|
||||
}
|
||||
if (input == 'D')
|
||||
{
|
||||
Serial.print("Deleting Flash chip content... ");
|
||||
flash.chipErase();
|
||||
while(flash.busy());
|
||||
Serial.println("DONE");
|
||||
}
|
||||
if (input == 'i')
|
||||
{
|
||||
Serial.print("DeviceID: ");
|
||||
word jedecid = flash.readDeviceId();
|
||||
Serial.println(jedecid, HEX);
|
||||
}
|
||||
}
|
||||
|
||||
if (radio.receiveDone())
|
||||
{
|
||||
Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] ");
|
||||
Serial.print(" [RX_RSSI:");Serial.print(radio.readRSSI());Serial.print("]");
|
||||
if (promiscuousMode)
|
||||
{
|
||||
Serial.print("to [");Serial.print(radio.TARGETID, DEC);Serial.print("] ");
|
||||
}
|
||||
|
||||
if (radio.DATALEN != sizeof(Payload))
|
||||
Serial.print("Invalid payload received, not matching Payload struct!");
|
||||
else
|
||||
{
|
||||
theData = *(Payload*)radio.DATA; //assume radio.DATA actually contains our struct and not something else
|
||||
Serial.print(" nodeId=");
|
||||
Serial.print(theData.nodeId);
|
||||
Serial.print(" uptime=");
|
||||
Serial.print(theData.uptime);
|
||||
Serial.print(" temp=");
|
||||
Serial.print(theData.temp);
|
||||
}
|
||||
|
||||
if (radio.ACKRequested())
|
||||
{
|
||||
byte theNodeID = radio.SENDERID;
|
||||
radio.sendACK();
|
||||
Serial.print(" - ACK sent.");
|
||||
|
||||
// When a node requests an ACK, respond to the ACK
|
||||
// and also send a packet requesting an ACK (every 3rd one only)
|
||||
// This way both TX/RX NODE functions are tested on 1 end at the GATEWAY
|
||||
if (ackCount++%3==0)
|
||||
{
|
||||
Serial.print(" Pinging node ");
|
||||
Serial.print(theNodeID);
|
||||
Serial.print(" - ACK...");
|
||||
delay(3); //need this when sending right after reception .. ?
|
||||
if (radio.sendWithRetry(theNodeID, "ACK TEST", 8, 0)) // 0 = only 1 attempt, no retries
|
||||
Serial.print("ok!");
|
||||
else Serial.print("nothing");
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
Blink(LED,3);
|
||||
}
|
||||
}
|
||||
|
||||
void Blink(byte PIN, int DELAY_MS)
|
||||
{
|
||||
pinMode(PIN, OUTPUT);
|
||||
digitalWrite(PIN,HIGH);
|
||||
delay(DELAY_MS);
|
||||
digitalWrite(PIN,LOW);
|
||||
}
|
||||
135
lib-ext/rfm-69.git/Examples/Struct_send/Struct_send.ino
Normal file
135
lib-ext/rfm-69.git/Examples/Struct_send/Struct_send.ino
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
#include <RFM69.h>
|
||||
#include <SPI.h>
|
||||
#include <SPIFlash.h>
|
||||
|
||||
#define NODEID 99
|
||||
#define NETWORKID 100
|
||||
#define GATEWAYID 1
|
||||
#define FREQUENCY RF69_433MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ)
|
||||
#define KEY "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less!
|
||||
#define LED 9
|
||||
#define SERIAL_BAUD 115200
|
||||
#define ACK_TIME 30 // # of ms to wait for an ack
|
||||
|
||||
int TRANSMITPERIOD = 300; //transmit a packet to gateway so often (in ms)
|
||||
byte sendSize=0;
|
||||
boolean requestACK = false;
|
||||
SPIFlash flash(8, 0xEF30); //EF40 for 16mbit windbond chip
|
||||
RFM69 radio;
|
||||
|
||||
typedef struct {
|
||||
int nodeId; //store this nodeId
|
||||
unsigned long uptime; //uptime in ms
|
||||
float temp; //temperature maybe?
|
||||
} Payload;
|
||||
Payload theData;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
//radio.setHighPower(); //uncomment only for RFM69HW!
|
||||
radio.encrypt(KEY);
|
||||
char buff[50];
|
||||
sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
|
||||
Serial.println(buff);
|
||||
|
||||
if (flash.initialize())
|
||||
Serial.println("SPI Flash Init OK!");
|
||||
else
|
||||
Serial.println("SPI Flash Init FAIL! (is chip present?)");
|
||||
}
|
||||
|
||||
long lastPeriod = -1;
|
||||
void loop() {
|
||||
//process any serial input
|
||||
if (Serial.available() > 0)
|
||||
{
|
||||
char input = Serial.read();
|
||||
if (input >= 48 && input <= 57) //[0,9]
|
||||
{
|
||||
TRANSMITPERIOD = 100 * (input-48);
|
||||
if (TRANSMITPERIOD == 0) TRANSMITPERIOD = 1000;
|
||||
Serial.print("\nChanging delay to ");
|
||||
Serial.print(TRANSMITPERIOD);
|
||||
Serial.println("ms\n");
|
||||
}
|
||||
|
||||
if (input == 'r') //d=dump register values
|
||||
radio.readAllRegs();
|
||||
//if (input == 'E') //E=enable encryption
|
||||
// radio.encrypt(KEY);
|
||||
//if (input == 'e') //e=disable encryption
|
||||
// radio.encrypt(null);
|
||||
|
||||
if (input == 'd') //d=dump flash area
|
||||
{
|
||||
Serial.println("Flash content:");
|
||||
int counter = 0;
|
||||
|
||||
while(counter<=256){
|
||||
Serial.print(flash.readByte(counter++), HEX);
|
||||
Serial.print('.');
|
||||
}
|
||||
while(flash.busy());
|
||||
Serial.println();
|
||||
}
|
||||
if (input == 'e')
|
||||
{
|
||||
Serial.print("Erasing Flash chip ... ");
|
||||
flash.chipErase();
|
||||
while(flash.busy());
|
||||
Serial.println("DONE");
|
||||
}
|
||||
if (input == 'i')
|
||||
{
|
||||
Serial.print("DeviceID: ");
|
||||
word jedecid = flash.readDeviceId();
|
||||
Serial.println(jedecid, HEX);
|
||||
}
|
||||
}
|
||||
|
||||
//check for any received packets
|
||||
if (radio.receiveDone())
|
||||
{
|
||||
Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] ");
|
||||
for (byte i = 0; i < radio.DATALEN; i++)
|
||||
Serial.print((char)radio.DATA[i]);
|
||||
Serial.print(" [RX_RSSI:");Serial.print(radio.readRSSI());Serial.print("]");
|
||||
|
||||
if (radio.ACKRequested())
|
||||
{
|
||||
radio.sendACK();
|
||||
Serial.print(" - ACK sent");
|
||||
delay(10);
|
||||
}
|
||||
Blink(LED,5);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
int currPeriod = millis()/TRANSMITPERIOD;
|
||||
if (currPeriod != lastPeriod)
|
||||
{
|
||||
//fill in the struct with new values
|
||||
theData.nodeId = NODEID;
|
||||
theData.uptime = millis();
|
||||
theData.temp = 91.23; //it's hot!
|
||||
|
||||
Serial.print("Sending struct (");
|
||||
Serial.print(sizeof(theData));
|
||||
Serial.print(" bytes) ... ");
|
||||
if (radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData)))
|
||||
Serial.print(" ok!");
|
||||
else Serial.print(" nothing...");
|
||||
Serial.println();
|
||||
Blink(LED,3);
|
||||
lastPeriod=currPeriod;
|
||||
}
|
||||
}
|
||||
|
||||
void Blink(byte PIN, int DELAY_MS)
|
||||
{
|
||||
pinMode(PIN, OUTPUT);
|
||||
digitalWrite(PIN,HIGH);
|
||||
delay(DELAY_MS);
|
||||
digitalWrite(PIN,LOW);
|
||||
}
|
||||
191
lib-ext/rfm-69.git/Examples/TxRxBlinky/TxRxBlinky.ino
Normal file
191
lib-ext/rfm-69.git/Examples/TxRxBlinky/TxRxBlinky.ino
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
// ***************************************************************************************
|
||||
// Sample RFM69 sketch for Moteino to illustrate sending and receiving, button interrupts
|
||||
// ***************************************************************************************
|
||||
// When you press the button on the SENDER Moteino, it will send a short message to the
|
||||
// RECEIVER Moteino and wait for an ACK (acknowledgement that message was received) from
|
||||
// the RECEIVER Moteino. If the ACK was received, the SENDER will blink the onboard LED
|
||||
// a few times. The RECEIVER listens to a specific token, and it alternates the onboard LED
|
||||
// state from HIGH to LOW or vice versa whenever this token is received.
|
||||
// ***************************************************************************************
|
||||
// Hardware setup:
|
||||
// ***************************************************************************************
|
||||
// On the sender, hook up a momentary tactile button to D3 like this:
|
||||
// __-__
|
||||
// __| |___
|
||||
// GND ----> BTN ----> D3 (D11 on MoteinoMEGA)
|
||||
// Load this sketch on the RECEIVER with NODEID=RECEIVER (adjust in config section below)
|
||||
// Load this sketch on the SENDER with NODEID=SENDER (adjust in config section below)
|
||||
// RFM69 library and code by Felix Rusu - felix@lowpowerlab.com
|
||||
// Get libraries at: https://github.com/LowPowerLab/
|
||||
// Make sure you adjust the settings in the configuration section below !!!
|
||||
// **********************************************************************************
|
||||
// Copyright Felix Rusu, LowPowerLab.com
|
||||
// Library and code by Felix Rusu - felix@lowpowerlab.com
|
||||
// **********************************************************************************
|
||||
// License
|
||||
// **********************************************************************************
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will
|
||||
// be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
// implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
// PARTICULAR PURPOSE. See the GNU General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// Public License along with this program.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Licence can be viewed at
|
||||
// http://www.gnu.org/licenses/gpl-3.0.txt
|
||||
//
|
||||
// Please maintain this license information along with authorship
|
||||
// and copyright notices in any redistribution of this code
|
||||
// **********************************************************************************
|
||||
|
||||
#include <RFM69.h> //get it here: https://www.github.com/lowpowerlab/rfm69
|
||||
#include <SPI.h>
|
||||
#include <LowPower.h> //get library from: https://github.com/lowpowerlab/lowpower
|
||||
|
||||
//*********************************************************************************************
|
||||
// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE *************
|
||||
//*********************************************************************************************
|
||||
#define NETWORKID 100 //the same on all nodes that talk to each other
|
||||
#define RECEIVER 1 //unique ID of the gateway/receiver
|
||||
#define SENDER 2
|
||||
#define NODEID RECEIVER //change to "SENDER" if this is the sender node (the one with the button)
|
||||
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
|
||||
//#define FREQUENCY RF69_433MHZ
|
||||
//#define FREQUENCY RF69_868MHZ
|
||||
#define FREQUENCY RF69_915MHZ
|
||||
#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
|
||||
#define IS_RFM69HW //uncomment only for RFM69HW! Remove/comment if you have RFM69W!
|
||||
//*********************************************************************************************
|
||||
#define SERIAL_BAUD 115200
|
||||
#ifdef __AVR_ATmega1284P__
|
||||
#define LED 15 // Moteino MEGAs have LEDs on D15
|
||||
#define BUTTON_INT 1 //user button on interrupt 1 (D3)
|
||||
#define BUTTON_PIN 11 //user button on interrupt 1 (D3)
|
||||
#else
|
||||
#define LED 9 // Moteinos have LEDs on D9
|
||||
#define BUTTON_INT 1 //user button on interrupt 1 (D3)
|
||||
#define BUTTON_PIN 3 //user button on interrupt 1 (D3)
|
||||
#endif
|
||||
|
||||
#define LED_GREEN 4 //GREEN LED on the SENDER
|
||||
#define LED_RED 5 //RED LED on the SENDER
|
||||
#define RX_TOGGLE_PIN 7 //GPIO to toggle on the RECEIVER
|
||||
|
||||
RFM69 radio;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
#ifdef IS_RFM69HW
|
||||
radio.setHighPower(); //only for RFM69HW!
|
||||
#endif
|
||||
radio.encrypt(ENCRYPTKEY);
|
||||
char buff[50];
|
||||
sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
|
||||
Serial.println(buff);
|
||||
Serial.flush();
|
||||
pinMode(BUTTON_PIN, INPUT_PULLUP);
|
||||
pinMode(LED, OUTPUT);
|
||||
attachInterrupt(BUTTON_INT, handleButton, FALLING);
|
||||
|
||||
pinMode(LED_GREEN, OUTPUT);
|
||||
pinMode(LED_RED, OUTPUT);
|
||||
pinMode(RX_TOGGLE_PIN, OUTPUT);
|
||||
digitalWrite(LED_GREEN, LOW);
|
||||
digitalWrite(LED_RED, HIGH);
|
||||
}
|
||||
|
||||
//******** THIS IS INTERRUPT BASED DEBOUNCING FOR BUTTON ATTACHED TO D3 (INTERRUPT 1)
|
||||
#define FLAG_INTERRUPT 0x01
|
||||
volatile int mainEventFlags = 0;
|
||||
boolean buttonPressed = false;
|
||||
void handleButton()
|
||||
{
|
||||
mainEventFlags |= FLAG_INTERRUPT;
|
||||
}
|
||||
|
||||
byte LEDSTATE=LOW; //LOW=0
|
||||
void loop() {
|
||||
//******** THIS IS INTERRUPT BASED DEBOUNCING FOR BUTTON ATTACHED TO D3 (INTERRUPT 1)
|
||||
if (mainEventFlags & FLAG_INTERRUPT)
|
||||
{
|
||||
LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_ON);
|
||||
mainEventFlags &= ~FLAG_INTERRUPT;
|
||||
if (!digitalRead(BUTTON_PIN)) {
|
||||
buttonPressed=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonPressed)
|
||||
{
|
||||
Serial.println("Button pressed!");
|
||||
buttonPressed = false;
|
||||
|
||||
if(LEDSTATE==LOW)
|
||||
{
|
||||
LEDSTATE=HIGH;
|
||||
digitalWrite(LED_GREEN, HIGH);
|
||||
digitalWrite(LED_RED, LOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
LEDSTATE=LOW;
|
||||
digitalWrite(LED_GREEN, LOW);
|
||||
digitalWrite(LED_RED, HIGH);
|
||||
}
|
||||
|
||||
if (radio.sendWithRetry(RECEIVER, "Hi", 2)) //target node Id, message as string or byte array, message length
|
||||
Blink(LED, 40, 3); //blink LED 3 times, 40ms between blinks
|
||||
}
|
||||
|
||||
//check if something was received (could be an interrupt from the radio)
|
||||
if (radio.receiveDone())
|
||||
{
|
||||
//print message received to serial
|
||||
Serial.print('[');Serial.print(radio.SENDERID);Serial.print("] ");
|
||||
Serial.print((char*)radio.DATA);
|
||||
Serial.print(" [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]");
|
||||
Serial.println();
|
||||
|
||||
//check if received message is 2 bytes long, and check if the message is specifically "Hi"
|
||||
if (radio.DATALEN==2 && radio.DATA[0]=='H' && radio.DATA[1]=='i')
|
||||
{
|
||||
if(LEDSTATE==LOW)
|
||||
LEDSTATE=HIGH;
|
||||
else LEDSTATE=LOW;
|
||||
digitalWrite(LED, LEDSTATE);
|
||||
digitalWrite(RX_TOGGLE_PIN, LEDSTATE);
|
||||
}
|
||||
|
||||
//check if sender wanted an ACK
|
||||
if (radio.ACKRequested())
|
||||
{
|
||||
radio.sendACK();
|
||||
Serial.print(" - ACK sent");
|
||||
}
|
||||
}
|
||||
|
||||
radio.receiveDone(); //put radio in RX mode
|
||||
Serial.flush(); //make sure all serial data is clocked out before sleeping the MCU
|
||||
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_ON); //sleep Moteino in low power mode (to save battery)
|
||||
}
|
||||
|
||||
void Blink(byte PIN, byte DELAY_MS, byte loops)
|
||||
{
|
||||
for (byte i=0; i<loops; i++)
|
||||
{
|
||||
digitalWrite(PIN,HIGH);
|
||||
delay(DELAY_MS);
|
||||
digitalWrite(PIN,LOW);
|
||||
delay(DELAY_MS);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
// **********************************************************************************
|
||||
// This sketch is an example of how wireless programming can be achieved with a Moteino
|
||||
// that was loaded with a custom 1k bootloader (DualOptiboot) that is capable of loading
|
||||
// a new sketch from an external SPI flash chip
|
||||
// This is the GATEWAY node, it does not need a custom Optiboot nor any external FLASH memory chip
|
||||
// (ONLY the target node will need those)
|
||||
// The sketch includes logic to receive the new sketch from the serial port (from a host computer) and
|
||||
// transmit it wirelessly to the target node
|
||||
// The handshake protocol that receives the sketch from the serial port
|
||||
// is handled by the SPIFLash/WirelessHEX69 library, which also relies on the RFM69 library
|
||||
// These libraries and custom 1k Optiboot bootloader for the target node are at: http://github.com/lowpowerlab
|
||||
// **********************************************************************************
|
||||
// Copyright Felix Rusu, LowPowerLab.com
|
||||
// Library and code by Felix Rusu - felix@lowpowerlab.com
|
||||
// **********************************************************************************
|
||||
// License
|
||||
// **********************************************************************************
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will
|
||||
// be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
// implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
// PARTICULAR PURPOSE. See the GNU General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// Public License along with this program.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Licence can be viewed at
|
||||
// http://www.gnu.org/licenses/gpl-3.0.txt
|
||||
//
|
||||
// Please maintain this license information along with authorship
|
||||
// and copyright notices in any redistribution of this code
|
||||
// **********************************************************************************
|
||||
#include <RFM69.h> //get it here: https://www.github.com/lowpowerlab/rfm69
|
||||
#include <SPI.h>
|
||||
#include <SPIFlash.h> //get it here: https://www.github.com/lowpowerlab/spiflash
|
||||
#include <WirelessHEX69.h> //get it here: https://github.com/LowPowerLab/WirelessProgramming/tree/master/WirelessHEX69
|
||||
|
||||
#define NODEID 254 //this node's ID, should be unique among nodes on this NETWORKID
|
||||
#define NETWORKID 250 //what network this node is on
|
||||
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
|
||||
//#define FREQUENCY RF69_433MHZ
|
||||
//#define FREQUENCY RF69_868MHZ
|
||||
#define FREQUENCY RF69_915MHZ
|
||||
#define ENCRYPTKEY "sampleEncryptKey" //(16 bytes of your choice - keep the same on all encrypted nodes)
|
||||
//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
|
||||
|
||||
#define SERIAL_BAUD 115200
|
||||
#define ACK_TIME 50 // # of ms to wait for an ack
|
||||
#define TIMEOUT 3000
|
||||
|
||||
#ifdef __AVR_ATmega1284P__
|
||||
#define LED 15 // Moteino MEGAs have LEDs on D15
|
||||
#else
|
||||
#define LED 9 // Moteinos hsave LEDs on D9
|
||||
#endif
|
||||
|
||||
RFM69 radio;
|
||||
char c = 0;
|
||||
char input[64]; //serial input buffer
|
||||
byte targetID=0;
|
||||
|
||||
void setup(){
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
radio.encrypt(ENCRYPTKEY); //OPTIONAL
|
||||
#ifdef IS_RFM69HW
|
||||
radio.setHighPower(); //only for RFM69HW!
|
||||
#endif
|
||||
Serial.println("Start wireless gateway...");
|
||||
}
|
||||
|
||||
void loop(){
|
||||
byte inputLen = readSerialLine(input, 10, 64, 100); //readSerialLine(char* input, char endOfLineChar=10, byte maxLength=64, uint16_t timeout=1000);
|
||||
|
||||
if (inputLen==4 && input[0]=='F' && input[1]=='L' && input[2]=='X' && input[3]=='?') {
|
||||
if (targetID==0)
|
||||
Serial.println("TO?");
|
||||
else
|
||||
CheckForSerialHEX((byte*)input, inputLen, radio, targetID, TIMEOUT, ACK_TIME, true);
|
||||
}
|
||||
else if (inputLen>3 && inputLen<=6 && input[0]=='T' && input[1]=='O' && input[2]==':')
|
||||
{
|
||||
byte newTarget=0;
|
||||
for (byte i = 3; i<inputLen; i++) //up to 3 characters for target ID
|
||||
if (input[i] >=48 && input[i]<=57)
|
||||
newTarget = newTarget*10+input[i]-48;
|
||||
else
|
||||
{
|
||||
newTarget=0;
|
||||
break;
|
||||
}
|
||||
if (newTarget>0)
|
||||
{
|
||||
targetID = newTarget;
|
||||
Serial.print("TO:");
|
||||
Serial.print(newTarget);
|
||||
Serial.println(":OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(input);
|
||||
Serial.print(":INV");
|
||||
}
|
||||
}
|
||||
else if (inputLen>0) { //just echo back
|
||||
Serial.print("SERIAL IN > ");Serial.println(input);
|
||||
}
|
||||
|
||||
if (radio.receiveDone())
|
||||
{
|
||||
for (byte i = 0; i < radio.DATALEN; i++)
|
||||
Serial.print((char)radio.DATA[i]);
|
||||
|
||||
if (radio.ACK_REQUESTED)
|
||||
{
|
||||
radio.sendACK();
|
||||
Serial.print(" - ACK sent");
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
Blink(LED,5); //heartbeat
|
||||
}
|
||||
|
||||
void Blink(byte PIN, int DELAY_MS)
|
||||
{
|
||||
pinMode(PIN, OUTPUT);
|
||||
digitalWrite(PIN,HIGH);
|
||||
delay(DELAY_MS);
|
||||
digitalWrite(PIN,LOW);
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
// **********************************************************************************
|
||||
// This sketch is an example of how wireless programming can be achieved with a Moteino
|
||||
// that was loaded with a custom 1k bootloader (DualOptiboot) that is capable of loading
|
||||
// a new sketch from an external SPI flash chip
|
||||
// The sketch includes logic to receive the new sketch 'over-the-air' and store it in
|
||||
// the FLASH chip, then restart the Moteino so the bootloader can continue the job of
|
||||
// actually reflashing the internal flash memory from the external FLASH memory chip flash image
|
||||
// The handshake protocol that receives the sketch wirelessly by means of the RFM69 radio
|
||||
// is handled by the SPIFLash/WirelessHEX69 library, which also relies on the RFM69 library
|
||||
// These libraries and custom 1k Optiboot bootloader are at: http://github.com/lowpowerlab
|
||||
// **********************************************************************************
|
||||
// Copyright Felix Rusu, LowPowerLab.com
|
||||
// Library and code by Felix Rusu - felix@lowpowerlab.com
|
||||
// **********************************************************************************
|
||||
// License
|
||||
// **********************************************************************************
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will
|
||||
// be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
// implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
// PARTICULAR PURPOSE. See the GNU General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// Public License along with this program.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Licence can be viewed at
|
||||
// http://www.gnu.org/licenses/gpl-3.0.txt
|
||||
//
|
||||
// Please maintain this license information along with authorship
|
||||
// and copyright notices in any redistribution of this code
|
||||
// **********************************************************************************
|
||||
#include <RFM69.h> //get it here: https://www.github.com/lowpowerlab/rfm69
|
||||
#include <SPI.h>
|
||||
#include <SPIFlash.h> //get it here: https://www.github.com/lowpowerlab/spiflash
|
||||
#include <avr/wdt.h>
|
||||
#include <WirelessHEX69.h> //get it here: https://github.com/LowPowerLab/WirelessProgramming/tree/master/WirelessHEX69
|
||||
|
||||
#define NODEID 123 // node ID used for this unit
|
||||
#define NETWORKID 250
|
||||
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
|
||||
//#define FREQUENCY RF69_433MHZ
|
||||
//#define FREQUENCY RF69_868MHZ
|
||||
#define FREQUENCY RF69_915MHZ
|
||||
//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
|
||||
#define SERIAL_BAUD 115200
|
||||
#define ACK_TIME 30 // # of ms to wait for an ack
|
||||
#define ENCRYPTKEY "sampleEncryptKey" //(16 bytes of your choice - keep the same on all encrypted nodes)
|
||||
#define BLINKPERIOD 500
|
||||
|
||||
#ifdef __AVR_ATmega1284P__
|
||||
#define LED 15 // Moteino MEGAs have LEDs on D15
|
||||
#define FLASH_SS 23 // and FLASH SS on D23
|
||||
#else
|
||||
#define LED 9 // Moteinos hsave LEDs on D9
|
||||
#define FLASH_SS 8 // and FLASH SS on D8
|
||||
#endif
|
||||
|
||||
RFM69 radio;
|
||||
char input = 0;
|
||||
long lastPeriod = -1;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// flash(SPI_CS, MANUFACTURER_ID)
|
||||
// SPI_CS - CS pin attached to SPI flash chip (8 in case of Moteino)
|
||||
// MANUFACTURER_ID - OPTIONAL, 0x1F44 for adesto(ex atmel) 4mbit flash
|
||||
// 0xEF30 for windbond 4mbit flash
|
||||
// 0xEF40 for windbond 16/64mbit flash
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
SPIFlash flash(FLASH_SS, 0xEF30); //EF30 for windbond 4mbit flash
|
||||
|
||||
void setup(){
|
||||
pinMode(LED, OUTPUT);
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||||
radio.encrypt(ENCRYPTKEY); //OPTIONAL
|
||||
#ifdef IS_RFM69HW
|
||||
radio.setHighPower(); //only for RFM69HW!
|
||||
#endif
|
||||
Serial.print("Start node...");
|
||||
|
||||
if (flash.initialize())
|
||||
Serial.println("SPI Flash Init OK!");
|
||||
else
|
||||
Serial.println("SPI Flash Init FAIL!");
|
||||
}
|
||||
|
||||
void loop(){
|
||||
// This part is optional, useful for some debugging.
|
||||
// Handle serial input (to allow basic DEBUGGING of FLASH chip)
|
||||
// ie: display first 256 bytes in FLASH, erase chip, write bytes at first 10 positions, etc
|
||||
if (Serial.available() > 0) {
|
||||
input = Serial.read();
|
||||
if (input == 'd') //d=dump first page
|
||||
{
|
||||
Serial.println("Flash content:");
|
||||
int counter = 0;
|
||||
|
||||
while(counter<=256){
|
||||
Serial.print(flash.readByte(counter++), HEX);
|
||||
Serial.print('.');
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
else if (input == 'e')
|
||||
{
|
||||
Serial.print("Erasing Flash chip ... ");
|
||||
flash.chipErase();
|
||||
while(flash.busy());
|
||||
Serial.println("DONE");
|
||||
}
|
||||
else if (input == 'i')
|
||||
{
|
||||
Serial.print("DeviceID: ");
|
||||
Serial.println(flash.readDeviceId(), HEX);
|
||||
}
|
||||
else if (input == 'r')
|
||||
{
|
||||
Serial.print("Rebooting");
|
||||
resetUsingWatchdog(true);
|
||||
}
|
||||
else if (input == 'R')
|
||||
{
|
||||
Serial.print("RFM69 registers:");
|
||||
radio.readAllRegs();
|
||||
}
|
||||
else if (input >= 48 && input <= 57) //0-9
|
||||
{
|
||||
Serial.print("\nWriteByte("); Serial.print(input); Serial.print(")");
|
||||
flash.writeByte(input-48, millis()%2 ? 0xaa : 0xbb);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for existing RF data, potentially for a new sketch wireless upload
|
||||
// For this to work this check has to be done often enough to be
|
||||
// picked up when a GATEWAY is trying hard to reach this node for a new sketch wireless upload
|
||||
if (radio.receiveDone())
|
||||
{
|
||||
Serial.print("Got [");
|
||||
Serial.print(radio.SENDERID);
|
||||
Serial.print(':');
|
||||
Serial.print(radio.DATALEN);
|
||||
Serial.print("] > ");
|
||||
for (byte i = 0; i < radio.DATALEN; i++)
|
||||
Serial.print((char)radio.DATA[i], HEX);
|
||||
Serial.println();
|
||||
CheckForWirelessHEX(radio, flash, true);
|
||||
Serial.println();
|
||||
}
|
||||
//else Serial.print('.');
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Real sketch code here, let's blink the onboard LED
|
||||
if ((int)(millis()/BLINKPERIOD) > lastPeriod)
|
||||
{
|
||||
lastPeriod++;
|
||||
digitalWrite(LED, lastPeriod%2);
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
674
lib-ext/rfm-69.git/License.txt
Normal file
674
lib-ext/rfm-69.git/License.txt
Normal file
|
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
60
lib-ext/rfm-69.git/README.md
Normal file
60
lib-ext/rfm-69.git/README.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
RFM69 Library
|
||||
----------------
|
||||
By Felix Rusu (felix@lowpowerlab.com)
|
||||
<br/>
|
||||
RFM69 library for RFM69W, RFM69HW, RFM69CW, RFM69HCW (semtech SX1231, SX1231H)
|
||||
|
||||
##License
|
||||
GPL 3.0, please see the License.txt file
|
||||
|
||||
|
||||
##Features
|
||||
Among others, this is a set of features implemented in this library:
|
||||
|
||||
- easy to use API with a few simple functions for basic usage
|
||||
- 255 possible nodes on 256 possible networks
|
||||
- 61 bytes max message length (limited to 61 to support AES hardware encryption)
|
||||
- customizable transmit power (32 levels) for low-power transmission control
|
||||
- sleep function for power saving
|
||||
- automatic ACKs with the sendWithRetry() function
|
||||
- hardware 128bit AES encryption
|
||||
- hardware preamble, synch recognition and CRC check
|
||||
- digital RSSI can be read at any time with readRSSI()
|
||||
- interrupt driven
|
||||
- tested on [Moteino R3, R4, R4-USB (ATMega328p)](http://lowpowerlab.com/shop/Moteino-R4)
|
||||
- works with RFM69W, RFM69HW, RFM69CW, RFM69HCW, Semtech SX1231/SX1231H transceivers
|
||||
- promiscuous mode allows any node to listen to any packet on same network
|
||||
|
||||
I consider this an initial beta release, it could contain bugs, but the provided Gateway and Node examples should work out of the box. Please let me know if you find issues.
|
||||
|
||||
###Installation
|
||||
Copy the content of this library in the "Arduino/libraries/RFM69" folder.
|
||||
<br />
|
||||
To find your Arduino folder go to File>Preferences in the Arduino IDE.
|
||||
<br/>
|
||||
See [this tutorial](http://learn.adafruit.com/arduino-tips-tricks-and-techniques/arduino-libraries) on Arduino libraries.
|
||||
|
||||
###MISC / possible issues
|
||||
- The library and examples are continuously improved as bugs and stability issues are discovered. Be sure to check back often for changes.
|
||||
- Moteino boards are loaded with fuses that will delay startup. This means that other boards like Duemilanove/UNO might need a delay() in the setup() function before doing anything - to allow the transceiver to power up.
|
||||
|
||||
###Sample usage
|
||||
- [Node](https://github.com/LowPowerLab/RFM69/blob/master/Examples/Node/Node.ino)
|
||||
- [Gateway](https://github.com/LowPowerLab/RFM69/blob/master/Examples/Gateway/Gateway.ino)
|
||||
|
||||
##Blog writeup
|
||||
http://lowpowerlab.com/blog/2013/06/20/rfm69-library/
|
||||
|
||||
##Why
|
||||
- I have spent a lot of time developing this library for RFM69W/HW transceivers. I made it open source because I believe a lot of people can benefit from this new powerful transceiver. I hope people will also contribute and build on my work
|
||||
- I have long researched alternative transceivers for RFM12B which is still an excellent transceiver but it is much lower output power and has limited built in features which need to be implemented in firmware (PREAMBLE, SYNC, CRC, packet engine, encryption etc).
|
||||
- I wanted a transceiver that could still be very small, easy to use, but have the longer range that I wanted
|
||||
- RFM69 comes in 2 variants that have the same layout/connections: RFM69W (13dBm, 45mA TX) and RFM69HW (20dBm, 130mA TX)
|
||||
|
||||
##RFM69W range
|
||||
- I have tested open-air range on these transceivers (the W only) in various combinations.
|
||||
- I am happy to say that a range of upwards of 350m can be achieved. I went to local parks and in very large parking spaces and I ran out of space, so more than 350m is possible. Some users reported upwards of 500m by lowering the bitrate, and a forum user reported 1.5miles at 1.2Kbps: see http://lowpowerlab.com/forum/index.php/topic,112.msg288.html and http://lowpowerlab.com/moteino/#antennas
|
||||
- The caveat with these higher RF power units is that they need more DC power when they transmit. For battery powered motes, you will need to keep them powered down and only transmit periodically. Use the sleep() function to put the radios in low power mode and use the [LowPower](https://github.com/rocketscream/Low-Power) or [Narcoleptic](https://code.google.com/p/narcoleptic/) libraries to power down your arduino
|
||||
|
||||
##License
|
||||
GPL 3.0. See License.txt file.
|
||||
498
lib-ext/rfm-69.git/RFM69.cpp
Normal file
498
lib-ext/rfm-69.git/RFM69.cpp
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
// **********************************************************************************
|
||||
// Driver definition for HopeRF RFM69W/RFM69HW/RFM69CW/RFM69HCW, Semtech SX1231/1231H
|
||||
// **********************************************************************************
|
||||
// Copyright Felix Rusu (2014), felix@lowpowerlab.com
|
||||
// http://lowpowerlab.com/
|
||||
// **********************************************************************************
|
||||
// License
|
||||
// **********************************************************************************
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will
|
||||
// be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
// implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
// PARTICULAR PURPOSE. See the GNU General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// Public License along with this program.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Licence can be viewed at
|
||||
// http://www.gnu.org/licenses/gpl-3.0.txt
|
||||
//
|
||||
// Please maintain this license information along with authorship
|
||||
// and copyright notices in any redistribution of this code
|
||||
// **********************************************************************************
|
||||
#include <RFM69.h>
|
||||
#include <RFM69registers.h>
|
||||
#include <SPI.h>
|
||||
|
||||
volatile uint8_t RFM69::DATA[RF69_MAX_DATA_LEN];
|
||||
volatile uint8_t RFM69::_mode; // current transceiver state
|
||||
volatile uint8_t RFM69::DATALEN;
|
||||
volatile uint8_t RFM69::SENDERID;
|
||||
volatile uint8_t RFM69::TARGETID; // should match _address
|
||||
volatile uint8_t RFM69::PAYLOADLEN;
|
||||
volatile uint8_t RFM69::ACK_REQUESTED;
|
||||
volatile uint8_t RFM69::ACK_RECEIVED; // should be polled immediately after sending a packet with ACK request
|
||||
volatile int16_t RFM69::RSSI; // most accurate RSSI during reception (closest to the reception)
|
||||
RFM69* RFM69::selfPointer;
|
||||
|
||||
bool RFM69::initialize(uint8_t freqBand, uint8_t nodeID, uint8_t networkID)
|
||||
{
|
||||
const uint8_t CONFIG[][2] =
|
||||
{
|
||||
/* 0x01 */ { REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY },
|
||||
/* 0x02 */ { REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00 }, // no shaping
|
||||
/* 0x03 */ { REG_BITRATEMSB, RF_BITRATEMSB_55555}, // default: 4.8 KBPS
|
||||
/* 0x04 */ { REG_BITRATELSB, RF_BITRATELSB_55555},
|
||||
/* 0x05 */ { REG_FDEVMSB, RF_FDEVMSB_50000}, // default: 5KHz, (FDEV + BitRate / 2 <= 500KHz)
|
||||
/* 0x06 */ { REG_FDEVLSB, RF_FDEVLSB_50000},
|
||||
|
||||
/* 0x07 */ { REG_FRFMSB, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFMSB_315 : (freqBand==RF69_433MHZ ? RF_FRFMSB_433 : (freqBand==RF69_868MHZ ? RF_FRFMSB_868 : RF_FRFMSB_915))) },
|
||||
/* 0x08 */ { REG_FRFMID, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFMID_315 : (freqBand==RF69_433MHZ ? RF_FRFMID_433 : (freqBand==RF69_868MHZ ? RF_FRFMID_868 : RF_FRFMID_915))) },
|
||||
/* 0x09 */ { REG_FRFLSB, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFLSB_315 : (freqBand==RF69_433MHZ ? RF_FRFLSB_433 : (freqBand==RF69_868MHZ ? RF_FRFLSB_868 : RF_FRFLSB_915))) },
|
||||
|
||||
// looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm
|
||||
// +17dBm and +20dBm are possible on RFM69HW
|
||||
// +13dBm formula: Pout = -18 + OutputPower (with PA0 or PA1**)
|
||||
// +17dBm formula: Pout = -14 + OutputPower (with PA1 and PA2)**
|
||||
// +20dBm formula: Pout = -11 + OutputPower (with PA1 and PA2)** and high power PA settings (section 3.3.7 in datasheet)
|
||||
///* 0x11 */ { REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | RF_PALEVEL_OUTPUTPOWER_11111},
|
||||
///* 0x13 */ { REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95 }, // over current protection (default is 95mA)
|
||||
|
||||
// RXBW defaults are { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_5} (RxBw: 10.4KHz)
|
||||
/* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2 }, // (BitRate < 2 * RxBw)
|
||||
//for BR-19200: /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 },
|
||||
/* 0x25 */ { REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01 }, // DIO0 is the only IRQ we're using
|
||||
/* 0x26 */ { REG_DIOMAPPING2, RF_DIOMAPPING2_CLKOUT_OFF }, // DIO5 ClkOut disable for power saving
|
||||
/* 0x28 */ { REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN }, // writing to this bit ensures that the FIFO & status flags are reset
|
||||
/* 0x29 */ { REG_RSSITHRESH, 220 }, // must be set to dBm = (-Sensitivity / 2), default is 0xE4 = 228 so -114dBm
|
||||
///* 0x2D */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE } // default 3 preamble bytes 0xAAAAAA
|
||||
/* 0x2E */ { REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0 },
|
||||
/* 0x2F */ { REG_SYNCVALUE1, 0x2D }, // attempt to make this compatible with sync1 byte of RFM12B lib
|
||||
/* 0x30 */ { REG_SYNCVALUE2, networkID }, // NETWORK ID
|
||||
/* 0x37 */ { REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF },
|
||||
/* 0x38 */ { REG_PAYLOADLENGTH, 66 }, // in variable length mode: the max frame size, not used in TX
|
||||
///* 0x39 */ { REG_NODEADRS, nodeID }, // turned off because we're not using address filtering
|
||||
/* 0x3C */ { REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE }, // TX on FIFO not empty
|
||||
/* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_2BITS | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent)
|
||||
//for BR-19200: /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent)
|
||||
/* 0x6F */ { REG_TESTDAGC, RF_DAGC_IMPROVED_LOWBETA0 }, // run DAGC continuously in RX mode for Fading Margin Improvement, recommended default for AfcLowBetaOn=0
|
||||
{255, 0}
|
||||
};
|
||||
|
||||
digitalWrite(_slaveSelectPin, HIGH);
|
||||
pinMode(_slaveSelectPin, OUTPUT);
|
||||
SPI.begin();
|
||||
|
||||
do writeReg(REG_SYNCVALUE1, 0xAA); while (readReg(REG_SYNCVALUE1) != 0xAA);
|
||||
do writeReg(REG_SYNCVALUE1, 0x55); while (readReg(REG_SYNCVALUE1) != 0x55);
|
||||
|
||||
for (uint8_t i = 0; CONFIG[i][0] != 255; i++)
|
||||
writeReg(CONFIG[i][0], CONFIG[i][1]);
|
||||
|
||||
// Encryption is persistent between resets and can trip you up during debugging.
|
||||
// Disable it during initialization so we always start from a known state.
|
||||
encrypt(0);
|
||||
|
||||
setHighPower(_isRFM69HW); // called regardless if it's a RFM69W or RFM69HW
|
||||
setMode(RF69_MODE_STANDBY);
|
||||
while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady
|
||||
attachInterrupt(_interruptNum, RFM69::isr0, RISING);
|
||||
|
||||
selfPointer = this;
|
||||
_address = nodeID;
|
||||
return true;
|
||||
}
|
||||
|
||||
// return the frequency (in Hz)
|
||||
uint32_t RFM69::getFrequency()
|
||||
{
|
||||
return RF69_FSTEP * (((uint32_t) readReg(REG_FRFMSB) << 16) + ((uint16_t) readReg(REG_FRFMID) << 8) + readReg(REG_FRFLSB));
|
||||
}
|
||||
|
||||
// set the frequency (in Hz)
|
||||
void RFM69::setFrequency(uint32_t freqHz)
|
||||
{
|
||||
uint8_t oldMode = _mode;
|
||||
if (oldMode == RF69_MODE_TX) {
|
||||
setMode(RF69_MODE_RX);
|
||||
}
|
||||
freqHz /= RF69_FSTEP; // divide down by FSTEP to get FRF
|
||||
writeReg(REG_FRFMSB, freqHz >> 16);
|
||||
writeReg(REG_FRFMID, freqHz >> 8);
|
||||
writeReg(REG_FRFLSB, freqHz);
|
||||
if (oldMode == RF69_MODE_RX) {
|
||||
setMode(RF69_MODE_SYNTH);
|
||||
}
|
||||
setMode(oldMode);
|
||||
}
|
||||
|
||||
void RFM69::setMode(uint8_t newMode)
|
||||
{
|
||||
if (newMode == _mode)
|
||||
return;
|
||||
|
||||
switch (newMode) {
|
||||
case RF69_MODE_TX:
|
||||
writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_TRANSMITTER);
|
||||
if (_isRFM69HW) setHighPowerRegs(true);
|
||||
break;
|
||||
case RF69_MODE_RX:
|
||||
writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_RECEIVER);
|
||||
if (_isRFM69HW) setHighPowerRegs(false);
|
||||
break;
|
||||
case RF69_MODE_SYNTH:
|
||||
writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SYNTHESIZER);
|
||||
break;
|
||||
case RF69_MODE_STANDBY:
|
||||
writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_STANDBY);
|
||||
break;
|
||||
case RF69_MODE_SLEEP:
|
||||
writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SLEEP);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// we are using packet mode, so this check is not really needed
|
||||
// but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode
|
||||
while (_mode == RF69_MODE_SLEEP && (readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady
|
||||
|
||||
_mode = newMode;
|
||||
}
|
||||
|
||||
void RFM69::sleep() {
|
||||
setMode(RF69_MODE_SLEEP);
|
||||
}
|
||||
|
||||
void RFM69::setAddress(uint8_t addr)
|
||||
{
|
||||
_address = addr;
|
||||
writeReg(REG_NODEADRS, _address);
|
||||
}
|
||||
|
||||
void RFM69::setNetwork(uint8_t networkID)
|
||||
{
|
||||
writeReg(REG_SYNCVALUE2, networkID);
|
||||
}
|
||||
|
||||
// set output power: 0 = min, 31 = max
|
||||
// this results in a "weaker" transmitted signal, and directly results in a lower RSSI at the receiver
|
||||
void RFM69::setPowerLevel(uint8_t powerLevel)
|
||||
{
|
||||
_powerLevel = powerLevel;
|
||||
writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0xE0) | (_powerLevel > 31 ? 31 : _powerLevel));
|
||||
}
|
||||
|
||||
bool RFM69::canSend()
|
||||
{
|
||||
if (_mode == RF69_MODE_RX && PAYLOADLEN == 0 && readRSSI() < CSMA_LIMIT) // if signal stronger than -100dBm is detected assume channel activity
|
||||
{
|
||||
setMode(RF69_MODE_STANDBY);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RFM69::send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK)
|
||||
{
|
||||
writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks
|
||||
uint32_t now = millis();
|
||||
while (!canSend() && millis() - now < RF69_CSMA_LIMIT_MS) receiveDone();
|
||||
sendFrame(toAddress, buffer, bufferSize, requestACK, false);
|
||||
}
|
||||
|
||||
// to increase the chance of getting a packet across, call this function instead of send
|
||||
// and it handles all the ACK requesting/retrying for you :)
|
||||
// The only twist is that you have to manually listen to ACK requests on the other side and send back the ACKs
|
||||
// The reason for the semi-automaton is that the lib is interrupt driven and
|
||||
// requires user action to read the received data and decide what to do with it
|
||||
// replies usually take only 5..8ms at 50kbps@915MHz
|
||||
bool RFM69::sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, uint8_t retries, uint8_t retryWaitTime) {
|
||||
uint32_t sentTime;
|
||||
for (uint8_t i = 0; i <= retries; i++)
|
||||
{
|
||||
send(toAddress, buffer, bufferSize, true);
|
||||
sentTime = millis();
|
||||
while (millis() - sentTime < retryWaitTime)
|
||||
{
|
||||
if (ACKReceived(toAddress))
|
||||
{
|
||||
//Serial.print(" ~ms:"); Serial.print(millis() - sentTime);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//Serial.print(" RETRY#"); Serial.println(i + 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// should be polled immediately after sending a packet with ACK request
|
||||
bool RFM69::ACKReceived(uint8_t fromNodeID) {
|
||||
if (receiveDone())
|
||||
return (SENDERID == fromNodeID || fromNodeID == RF69_BROADCAST_ADDR) && ACK_RECEIVED;
|
||||
return false;
|
||||
}
|
||||
|
||||
// check whether an ACK was requested in the last received packet (non-broadcasted packet)
|
||||
bool RFM69::ACKRequested() {
|
||||
return ACK_REQUESTED && (TARGETID != RF69_BROADCAST_ADDR);
|
||||
}
|
||||
|
||||
// should be called immediately after reception in case sender wants ACK
|
||||
void RFM69::sendACK(const void* buffer, uint8_t bufferSize) {
|
||||
uint8_t sender = SENDERID;
|
||||
int16_t _RSSI = RSSI; // save payload received RSSI value
|
||||
writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks
|
||||
uint32_t now = millis();
|
||||
while (!canSend() && millis() - now < RF69_CSMA_LIMIT_MS) receiveDone();
|
||||
sendFrame(sender, buffer, bufferSize, false, true);
|
||||
RSSI = _RSSI; // restore payload RSSI
|
||||
}
|
||||
|
||||
void RFM69::sendFrame(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK, bool sendACK)
|
||||
{
|
||||
setMode(RF69_MODE_STANDBY); // turn off receiver to prevent reception while filling fifo
|
||||
while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady
|
||||
writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00); // DIO0 is "Packet Sent"
|
||||
if (bufferSize > RF69_MAX_DATA_LEN) bufferSize = RF69_MAX_DATA_LEN;
|
||||
|
||||
// control byte
|
||||
uint8_t CTLbyte = 0x00;
|
||||
if (sendACK)
|
||||
CTLbyte = 0x80;
|
||||
else if (requestACK)
|
||||
CTLbyte = 0x40;
|
||||
|
||||
// write to FIFO
|
||||
select();
|
||||
SPI.transfer(REG_FIFO | 0x80);
|
||||
SPI.transfer(bufferSize + 3);
|
||||
SPI.transfer(toAddress);
|
||||
SPI.transfer(_address);
|
||||
SPI.transfer(CTLbyte);
|
||||
|
||||
for (uint8_t i = 0; i < bufferSize; i++)
|
||||
SPI.transfer(((uint8_t*) buffer)[i]);
|
||||
unselect();
|
||||
|
||||
// no need to wait for transmit mode to be ready since its handled by the radio
|
||||
setMode(RF69_MODE_TX);
|
||||
uint32_t txStart = millis();
|
||||
while (digitalRead(_interruptPin) == 0 && millis() - txStart < RF69_TX_LIMIT_MS); // wait for DIO0 to turn HIGH signalling transmission finish
|
||||
//while (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PACKETSENT == 0x00); // wait for ModeReady
|
||||
setMode(RF69_MODE_STANDBY);
|
||||
}
|
||||
|
||||
void RFM69::interruptHandler() {
|
||||
//pinMode(4, OUTPUT);
|
||||
//digitalWrite(4, 1);
|
||||
if (_mode == RF69_MODE_RX && (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY))
|
||||
{
|
||||
//RSSI = readRSSI();
|
||||
setMode(RF69_MODE_STANDBY);
|
||||
select();
|
||||
SPI.transfer(REG_FIFO & 0x7F);
|
||||
PAYLOADLEN = SPI.transfer(0);
|
||||
PAYLOADLEN = PAYLOADLEN > 66 ? 66 : PAYLOADLEN; // precaution
|
||||
TARGETID = SPI.transfer(0);
|
||||
if(!(_promiscuousMode || TARGETID == _address || TARGETID == RF69_BROADCAST_ADDR) // match this node's address, or broadcast address or anything in promiscuous mode
|
||||
|| PAYLOADLEN < 3) // address situation could receive packets that are malformed and don't fit this libraries extra fields
|
||||
{
|
||||
PAYLOADLEN = 0;
|
||||
unselect();
|
||||
receiveBegin();
|
||||
//digitalWrite(4, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
DATALEN = PAYLOADLEN - 3;
|
||||
SENDERID = SPI.transfer(0);
|
||||
uint8_t CTLbyte = SPI.transfer(0);
|
||||
|
||||
ACK_RECEIVED = CTLbyte & 0x80; // extract ACK-received flag
|
||||
ACK_REQUESTED = CTLbyte & 0x40; // extract ACK-requested flag
|
||||
|
||||
for (uint8_t i = 0; i < DATALEN; i++)
|
||||
{
|
||||
DATA[i] = SPI.transfer(0);
|
||||
}
|
||||
if (DATALEN < RF69_MAX_DATA_LEN) DATA[DATALEN] = 0; // add null at end of string
|
||||
unselect();
|
||||
setMode(RF69_MODE_RX);
|
||||
}
|
||||
RSSI = readRSSI();
|
||||
//digitalWrite(4, 0);
|
||||
}
|
||||
|
||||
void RFM69::isr0() { selfPointer->interruptHandler(); }
|
||||
|
||||
void RFM69::receiveBegin() {
|
||||
DATALEN = 0;
|
||||
SENDERID = 0;
|
||||
TARGETID = 0;
|
||||
PAYLOADLEN = 0;
|
||||
ACK_REQUESTED = 0;
|
||||
ACK_RECEIVED = 0;
|
||||
RSSI = 0;
|
||||
if (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY)
|
||||
writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks
|
||||
writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01); // set DIO0 to "PAYLOADREADY" in receive mode
|
||||
setMode(RF69_MODE_RX);
|
||||
}
|
||||
|
||||
bool RFM69::receiveDone() {
|
||||
//ATOMIC_BLOCK(ATOMIC_FORCEON)
|
||||
//{
|
||||
noInterrupts(); // re-enabled in unselect() via setMode() or via receiveBegin()
|
||||
if (_mode == RF69_MODE_RX && PAYLOADLEN > 0)
|
||||
{
|
||||
setMode(RF69_MODE_STANDBY); // enables interrupts
|
||||
return true;
|
||||
}
|
||||
else if (_mode == RF69_MODE_RX) // already in RX no payload yet
|
||||
{
|
||||
interrupts(); // explicitly re-enable interrupts
|
||||
return false;
|
||||
}
|
||||
receiveBegin();
|
||||
return false;
|
||||
//}
|
||||
}
|
||||
|
||||
// To enable encryption: radio.encrypt("ABCDEFGHIJKLMNOP");
|
||||
// To disable encryption: radio.encrypt(null) or radio.encrypt(0)
|
||||
// KEY HAS TO BE 16 bytes !!!
|
||||
void RFM69::encrypt(const char* key) {
|
||||
setMode(RF69_MODE_STANDBY);
|
||||
if (key != 0)
|
||||
{
|
||||
select();
|
||||
SPI.transfer(REG_AESKEY1 | 0x80);
|
||||
for (uint8_t i = 0; i < 16; i++)
|
||||
SPI.transfer(key[i]);
|
||||
unselect();
|
||||
}
|
||||
writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFE) | (key ? 1 : 0));
|
||||
}
|
||||
|
||||
int16_t RFM69::readRSSI(bool forceTrigger) {
|
||||
int16_t rssi = 0;
|
||||
if (forceTrigger)
|
||||
{
|
||||
// RSSI trigger not needed if DAGC is in continuous mode
|
||||
writeReg(REG_RSSICONFIG, RF_RSSI_START);
|
||||
while ((readReg(REG_RSSICONFIG) & RF_RSSI_DONE) == 0x00); // wait for RSSI_Ready
|
||||
}
|
||||
rssi = -readReg(REG_RSSIVALUE);
|
||||
rssi >>= 1;
|
||||
return rssi;
|
||||
}
|
||||
|
||||
uint8_t RFM69::readReg(uint8_t addr)
|
||||
{
|
||||
select();
|
||||
SPI.transfer(addr & 0x7F);
|
||||
uint8_t regval = SPI.transfer(0);
|
||||
unselect();
|
||||
return regval;
|
||||
}
|
||||
|
||||
void RFM69::writeReg(uint8_t addr, uint8_t value)
|
||||
{
|
||||
select();
|
||||
SPI.transfer(addr | 0x80);
|
||||
SPI.transfer(value);
|
||||
unselect();
|
||||
}
|
||||
|
||||
// select the transceiver
|
||||
void RFM69::select() {
|
||||
noInterrupts();
|
||||
// save current SPI settings
|
||||
_SPCR = SPCR;
|
||||
_SPSR = SPSR;
|
||||
// set RFM69 SPI settings
|
||||
SPI.setDataMode(SPI_MODE0);
|
||||
SPI.setBitOrder(MSBFIRST);
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV4); // decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present
|
||||
digitalWrite(_slaveSelectPin, LOW);
|
||||
}
|
||||
|
||||
// UNselect the transceiver chip
|
||||
void RFM69::unselect() {
|
||||
digitalWrite(_slaveSelectPin, HIGH);
|
||||
// restore SPI settings to what they were before talking to RFM69
|
||||
SPCR = _SPCR;
|
||||
SPSR = _SPSR;
|
||||
interrupts();
|
||||
}
|
||||
|
||||
// ON = disable filtering to capture all frames on network
|
||||
// OFF = enable node/broadcast filtering to capture only frames sent to this/broadcast address
|
||||
void RFM69::promiscuous(bool onOff) {
|
||||
_promiscuousMode = onOff;
|
||||
//writeReg(REG_PACKETCONFIG1, (readReg(REG_PACKETCONFIG1) & 0xF9) | (onOff ? RF_PACKET1_ADRSFILTERING_OFF : RF_PACKET1_ADRSFILTERING_NODEBROADCAST));
|
||||
}
|
||||
|
||||
void RFM69::setHighPower(bool onOff) {
|
||||
_isRFM69HW = onOff;
|
||||
writeReg(REG_OCP, _isRFM69HW ? RF_OCP_OFF : RF_OCP_ON);
|
||||
if (_isRFM69HW) // turning ON
|
||||
writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0x1F) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON); // enable P1 & P2 amplifier stages
|
||||
else
|
||||
writeReg(REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | _powerLevel); // enable P0 only
|
||||
}
|
||||
|
||||
void RFM69::setHighPowerRegs(bool onOff) {
|
||||
writeReg(REG_TESTPA1, onOff ? 0x5D : 0x55);
|
||||
writeReg(REG_TESTPA2, onOff ? 0x7C : 0x70);
|
||||
}
|
||||
|
||||
void RFM69::setCS(uint8_t newSPISlaveSelect) {
|
||||
_slaveSelectPin = newSPISlaveSelect;
|
||||
digitalWrite(_slaveSelectPin, HIGH);
|
||||
pinMode(_slaveSelectPin, OUTPUT);
|
||||
}
|
||||
|
||||
// for debugging
|
||||
void RFM69::readAllRegs()
|
||||
{
|
||||
uint8_t regVal;
|
||||
|
||||
for (uint8_t regAddr = 1; regAddr <= 0x4F; regAddr++)
|
||||
{
|
||||
select();
|
||||
SPI.transfer(regAddr & 0x7F); // send address + r/w bit
|
||||
regVal = SPI.transfer(0);
|
||||
unselect();
|
||||
|
||||
Serial.print(regAddr, HEX);
|
||||
Serial.print(" - ");
|
||||
Serial.print(regVal,HEX);
|
||||
Serial.print(" - ");
|
||||
Serial.println(regVal,BIN);
|
||||
}
|
||||
unselect();
|
||||
}
|
||||
|
||||
uint8_t RFM69::readTemperature(uint8_t calFactor) // returns centigrade
|
||||
{
|
||||
setMode(RF69_MODE_STANDBY);
|
||||
writeReg(REG_TEMP1, RF_TEMP1_MEAS_START);
|
||||
while ((readReg(REG_TEMP1) & RF_TEMP1_MEAS_RUNNING));
|
||||
return ~readReg(REG_TEMP2) + COURSE_TEMP_COEF + calFactor; // 'complement' corrects the slope, rising temp = rising val
|
||||
} // COURSE_TEMP_COEF puts reading in the ballpark, user can add additional correction
|
||||
|
||||
void RFM69::rcCalibration()
|
||||
{
|
||||
writeReg(REG_OSC1, RF_OSC1_RCCAL_START);
|
||||
while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00);
|
||||
}
|
||||
143
lib-ext/rfm-69.git/RFM69.h
Normal file
143
lib-ext/rfm-69.git/RFM69.h
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
// **********************************************************************************
|
||||
// Driver definition for HopeRF RFM69W/RFM69HW/RFM69CW/RFM69HCW, Semtech SX1231/1231H
|
||||
// **********************************************************************************
|
||||
// Copyright Felix Rusu (2014), felix@lowpowerlab.com
|
||||
// http://lowpowerlab.com/
|
||||
// **********************************************************************************
|
||||
// License
|
||||
// **********************************************************************************
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will
|
||||
// be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
// implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
// PARTICULAR PURPOSE. See the GNU General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// Public License along with this program.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Licence can be viewed at
|
||||
// http://www.gnu.org/licenses/gpl-3.0.txt
|
||||
//
|
||||
// Please maintain this license information along with authorship
|
||||
// and copyright notices in any redistribution of this code
|
||||
// **********************************************************************************
|
||||
#ifndef RFM69_h
|
||||
#define RFM69_h
|
||||
#include <Arduino.h> // assumes Arduino IDE v1.0 or greater
|
||||
|
||||
#define RF69_MAX_DATA_LEN 61 // to take advantage of the built in AES/CRC we want to limit the frame size to the internal FIFO size (66 bytes - 3 bytes overhead - 2 bytes crc)
|
||||
#define RF69_SPI_CS SS // SS is the SPI slave select pin, for instance D10 on ATmega328
|
||||
|
||||
// INT0 on AVRs should be connected to RFM69's DIO0 (ex on ATmega328 it's D2, on ATmega644/1284 it's D2)
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
#define RF69_IRQ_PIN 2
|
||||
#define RF69_IRQ_NUM 0
|
||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
|
||||
#define RF69_IRQ_PIN 2
|
||||
#define RF69_IRQ_NUM 2
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
#define RF69_IRQ_PIN 3
|
||||
#define RF69_IRQ_NUM 0
|
||||
#endif
|
||||
|
||||
|
||||
#define CSMA_LIMIT -90 // upper RX signal sensitivity threshold in dBm for carrier sense access
|
||||
#define RF69_MODE_SLEEP 0 // XTAL OFF
|
||||
#define RF69_MODE_STANDBY 1 // XTAL ON
|
||||
#define RF69_MODE_SYNTH 2 // PLL ON
|
||||
#define RF69_MODE_RX 3 // RX MODE
|
||||
#define RF69_MODE_TX 4 // TX MODE
|
||||
|
||||
// available frequency bands
|
||||
#define RF69_315MHZ 31 // non trivial values to avoid misconfiguration
|
||||
#define RF69_433MHZ 43
|
||||
#define RF69_868MHZ 86
|
||||
#define RF69_915MHZ 91
|
||||
|
||||
#define null 0
|
||||
#define COURSE_TEMP_COEF -90 // puts the temperature reading in the ballpark, user can fine tune the returned value
|
||||
#define RF69_BROADCAST_ADDR 255
|
||||
#define RF69_CSMA_LIMIT_MS 1000
|
||||
#define RF69_TX_LIMIT_MS 1000
|
||||
#define RF69_FSTEP 61.03515625 // == FXOSC / 2^19 = 32MHz / 2^19 (p13 in datasheet)
|
||||
|
||||
class RFM69 {
|
||||
public:
|
||||
static volatile uint8_t DATA[RF69_MAX_DATA_LEN]; // recv/xmit buf, including header & crc bytes
|
||||
static volatile uint8_t DATALEN;
|
||||
static volatile uint8_t SENDERID;
|
||||
static volatile uint8_t TARGETID; // should match _address
|
||||
static volatile uint8_t PAYLOADLEN;
|
||||
static volatile uint8_t ACK_REQUESTED;
|
||||
static volatile uint8_t ACK_RECEIVED; // should be polled immediately after sending a packet with ACK request
|
||||
static volatile int16_t RSSI; // most accurate RSSI during reception (closest to the reception)
|
||||
static volatile uint8_t _mode; // should be protected?
|
||||
|
||||
RFM69(uint8_t slaveSelectPin=RF69_SPI_CS, uint8_t interruptPin=RF69_IRQ_PIN, bool isRFM69HW=false, uint8_t interruptNum=RF69_IRQ_NUM) {
|
||||
_slaveSelectPin = slaveSelectPin;
|
||||
_interruptPin = interruptPin;
|
||||
_interruptNum = interruptNum;
|
||||
_mode = RF69_MODE_STANDBY;
|
||||
_promiscuousMode = false;
|
||||
_powerLevel = 31;
|
||||
_isRFM69HW = isRFM69HW;
|
||||
}
|
||||
|
||||
bool initialize(uint8_t freqBand, uint8_t ID, uint8_t networkID=1);
|
||||
void setAddress(uint8_t addr);
|
||||
void setNetwork(uint8_t networkID);
|
||||
bool canSend();
|
||||
void send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK=false);
|
||||
bool sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, uint8_t retries=2, uint8_t retryWaitTime=40); // 40ms roundtrip req for 61byte packets
|
||||
bool receiveDone();
|
||||
bool ACKReceived(uint8_t fromNodeID);
|
||||
bool ACKRequested();
|
||||
void sendACK(const void* buffer = "", uint8_t bufferSize=0);
|
||||
uint32_t getFrequency();
|
||||
void setFrequency(uint32_t freqHz);
|
||||
void encrypt(const char* key);
|
||||
void setCS(uint8_t newSPISlaveSelect);
|
||||
int16_t readRSSI(bool forceTrigger=false);
|
||||
void promiscuous(bool onOff=true);
|
||||
void setHighPower(bool onOFF=true); // has to be called after initialize() for RFM69HW
|
||||
void setPowerLevel(uint8_t level); // reduce/increase transmit power level
|
||||
void sleep();
|
||||
uint8_t readTemperature(uint8_t calFactor=0); // get CMOS temperature (8bit)
|
||||
void rcCalibration(); // calibrate the internal RC oscillator for use in wide temperature variations - see datasheet section [4.3.5. RC Timer Accuracy]
|
||||
|
||||
// allow hacking registers by making these public
|
||||
uint8_t readReg(uint8_t addr);
|
||||
void writeReg(uint8_t addr, uint8_t val);
|
||||
void readAllRegs();
|
||||
|
||||
protected:
|
||||
static void isr0();
|
||||
void virtual interruptHandler();
|
||||
void sendFrame(uint8_t toAddress, const void* buffer, uint8_t size, bool requestACK=false, bool sendACK=false);
|
||||
|
||||
static RFM69* selfPointer;
|
||||
uint8_t _slaveSelectPin;
|
||||
uint8_t _interruptPin;
|
||||
uint8_t _interruptNum;
|
||||
uint8_t _address;
|
||||
bool _promiscuousMode;
|
||||
uint8_t _powerLevel;
|
||||
bool _isRFM69HW;
|
||||
uint8_t _SPCR;
|
||||
uint8_t _SPSR;
|
||||
|
||||
void receiveBegin();
|
||||
void setMode(uint8_t mode);
|
||||
void setHighPowerRegs(bool onOff);
|
||||
void select();
|
||||
void unselect();
|
||||
};
|
||||
|
||||
#endif
|
||||
1109
lib-ext/rfm-69.git/RFM69registers.h
Normal file
1109
lib-ext/rfm-69.git/RFM69registers.h
Normal file
File diff suppressed because it is too large
Load diff
54
lib-ext/rfm-69.git/keywords.txt
Normal file
54
lib-ext/rfm-69.git/keywords.txt
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map for RFM69
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Instances (KEYWORD2)
|
||||
#######################################
|
||||
RFM69 KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
initialize KEYWORD2
|
||||
setAddress KEYWORD2
|
||||
canSend KEYWORD2
|
||||
send KEYWORD2
|
||||
sendWithRetry KEYWORD2
|
||||
receiveDone KEYWORD2
|
||||
ACKReceived KEYWORD2
|
||||
sendACK KEYWORD2
|
||||
setFrequency KEYWORD2
|
||||
getFrequency KEYWORD2
|
||||
encrypt KEYWORD2
|
||||
setCS KEYWORD2
|
||||
readRSSI KEYWORD2
|
||||
promiscuous KEYWORD2
|
||||
setHighPower KEYWORD2
|
||||
CryptFunction KEYWORD2
|
||||
sleep KEYWORD2
|
||||
readReg KEYWORD2
|
||||
writeReg KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
RF69_315MHZ LITERAL1
|
||||
RF69_433MHZ LITERAL1
|
||||
RF69_868MHZ LITERAL1
|
||||
RF69_915MHZ LITERAL1
|
||||
#######################################
|
||||
# Variables/Volatiles (LITERAL2)
|
||||
#######################################
|
||||
DATA LITERAL2
|
||||
DATALEN LITERAL2
|
||||
SENDERID LITERAL2
|
||||
TARGETID LITERAL2
|
||||
PAYLOADLEN LITERAL2
|
||||
ACK_REQUESTED LITERAL2
|
||||
ACK_RECEIVED LITERAL2
|
||||
RSSI LITERAL2
|
||||
12
lib-ext/rfm-69.git/library.json
Normal file
12
lib-ext/rfm-69.git/library.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "RFM69",
|
||||
"keywords": "rf, radio, wireless, spi",
|
||||
"description": "RFM69 library for RFM69W, RFM69HW, RFM69CW, RFM69HCW (semtech SX1231, SX1231H)",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/LowPowerLab/RFM69.git"
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms": "atmelavr"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue