Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial commit of the LLAPSerial library
- Loading branch information
dpslwk
committed
Apr 8, 2013
0 parents
commit 9b9c7e3
Showing
6 changed files
with
416 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
Examples/LLAPSensor/LLAPSensor.sln | ||
Examples/LLAPSensor/LLAPSensor.suo | ||
Examples/LLAPSensor/LLAPSensor.vcxproj | ||
Examples/LLAPSensor/LLAPSensor.vcxproj.filters | ||
Examples/LLAPSensor/LLAPSensor.vcxproj.user | ||
Examples/LLAPSensor/Visual Micro/.LLAPSensor.vsarduino.h | ||
Examples/LLAPSensor/Visual Micro/Compile.vmps.xml | ||
Examples/LLAPSensor/Visual Micro/Configuration.Debug.vmps.xml | ||
Examples/LLAPSensor/Visual Micro/Upload.vmps.xml | ||
Examples/LLAP_DHT22/LLAP_DHT22.sln | ||
Examples/LLAP_DHT22/LLAP_DHT22.suo | ||
Examples/LLAP_DHT22/LLAP_DHT22.vcxproj | ||
Examples/LLAP_DHT22/LLAP_DHT22.vcxproj.filters | ||
Examples/LLAP_DHT22/LLAP_DHT22.vcxproj.user | ||
Examples/LLAP_DHT22/Visual Micro/.LLAP_DHT22.vsarduino.h | ||
Examples/LLAP_DHT22/Visual Micro/Compile.vmps.xml | ||
Examples/LLAP_DHT22/Visual Micro/Configuration.Debug.vmps.xml | ||
Examples/LLAP_DHT22/Visual Micro/Upload.vmps.xml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
|
||
#include "LLAPSerial.h" // include the library | ||
|
||
void setup() { | ||
// initialise serial: | ||
Serial.begin(9600); | ||
// Initialise the LLAPSerial library | ||
LLAP.init(); | ||
} | ||
|
||
void loop() { | ||
// print the string when a newline arrives: | ||
if (LLAP.bMsgReceived) { | ||
Serial.print("message is:"); | ||
Serial.println(LLAP.sMessage); | ||
LLAP.bMsgReceived = false; // if we do not clear the message flag then message processing will be blocked | ||
} | ||
} | ||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
////////////////////////////////////////////////////////////////////////// | ||
// LLAP temperature and humidity sensor using a DHT22 | ||
// | ||
// Reading temperature or humidity takes about 250 milliseconds! | ||
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) | ||
// | ||
// will work with any Arduino compatible however the target boards are the | ||
// Ciseco XinoRF and RFu-328, for LLAP over radio | ||
// | ||
// | ||
// Uses the Ciseco LLAPSerial library | ||
// Uses the Adafruit DHT library https://github.com/adafruit/DHT-sensor-library | ||
////////////////////////////////////////////////////////////////////////// | ||
|
||
#include <LLAPSerial.h> | ||
#include <DHT.h> | ||
|
||
#define DEVICEID "DH" // this is the LLAP device ID | ||
|
||
#define DHTPIN 2 // what I/O the DHT-22 data pin is connected to | ||
#define DHTTYPE DHT22 // DHT 22 (AM2302) | ||
|
||
// Connect pin 1 (on the left) of the sensor to +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 | ||
|
||
DHT dht(DHTPIN, DHTTYPE); | ||
|
||
void setup() { | ||
Serial.begin(115200); | ||
|
||
pinMode(8,OUTPUT); // switch on the radio | ||
digitalWrite(8,HIGH); | ||
delay(1000); // allow the radio to startup | ||
|
||
LLAP.init(DEVICEID); | ||
|
||
dht.begin(); | ||
|
||
LLAP.sendMessage("STARTED"); | ||
//tst code | ||
Serial.print("ABCDEFGHIJKLMNOPQRSTUVWX"); | ||
Serial.flush(); | ||
} | ||
|
||
void loop() { | ||
// print the string when a newline arrives: | ||
if (LLAP.bMsgReceived) { | ||
Serial.print("message is:"); | ||
Serial.println(LLAP.sMessage); | ||
LLAP.bMsgReceived = false; // if we do not clear the message flag then message processing will be blocked | ||
} | ||
|
||
// every 10 seconds | ||
static unsigned long lastTime = millis(); | ||
if (millis() - lastTime >= 30000) | ||
{ | ||
lastTime = millis(); | ||
int h = dht.readHumidity() * 10; | ||
int t = dht.readTemperature() * 10; | ||
|
||
// check if returns are valid, if they are NaN (not a number) then something went wrong! | ||
if (isnan(t) || isnan(h)) { | ||
LLAP.sendMessage("ERROR"); | ||
} else { | ||
LLAP.sendIntWithDP("HUM",h,1); | ||
//delay(100); | ||
LLAP.sendIntWithDP("TMP",t,1); | ||
} | ||
//Serial.println(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,269 @@ | ||
// | ||
// | ||
// | ||
|
||
#include "LLAPSerial.h" | ||
|
||
/* | ||
const CTable __code Commands[] = { | ||
{9,{'A','C','K','-','-','-','-','-','-'},cmdAck}, // must be the first entry | ||
{0,{'A','P','V','E','R','-','-','-','-'},cmdPVer}, // Protocol version | ||
{0,{'D','E','V','T','Y','P','E','-','-'},cmdDevType}, // Device Type | ||
{0,{'D','E','V','N','A','M','E','-','-'},cmdDevName}, // Device Name | ||
{0,{'H','E','L','L','O','-','-','-','-'},cmdHello}, // Echo | ||
{3,{'S','E','R','#','#','#','#','#','#'},cmdSer}, // Serial Number | ||
{0,{'$','E','R','-','-','-','-','-','-'},cmdSerReset}, // Serial Number | ||
{0,{'F','V','E','R','-','-','-','-','-'},cmdFVer}, // Software revision | ||
{7,{'C','H','D','E','V','I','D','#','#'},cmdDevID}, // Device ID | ||
{5,{'P','A','N','I','D','#','#','#','#'},cmdPanID}, // PANID | ||
{0,{'R','E','B','O','O','T','-','-','-'},cmdReset}, // reset | ||
{7,{'R','E','T','R','I','E','S','#','#'},cmdRetries}, // set # retrys | ||
{4,{'B','A','T','T','-','-','-','-','-'},cmdBatt}, // request battery voltage | ||
{4,{'S','A','V','E','-','-','-','-','-'},cmdSave}, // Save config to flash | ||
#if defined(APSLEEP) // cyclic sleep | ||
{0,{'I','N','T','V','L','#','#','#','#'},cmdInterval}, // SET cyclic sleep interval - 999S - three digits + timescale | ||
// T=mS, S=S, M=mins, H=Hours, D=days | ||
{0,{'C','Y','C','L','E','-','-','-','-'},cmdCyclic}, // activate cyclic sleep | ||
{0,{'W','A','K','E','-','-','-','-','-'},cmdDeactivate}, // deactivate programmed behaviour (cyclic sleep etc) | ||
{5,{'W','A','K','E','C','#','#','#','-'},cmdSetSleepCount}, // set the sleep count until awake is sent | ||
#endif | ||
// allow all device to do a one shot sleep (including DALLAS) | ||
{0,{'S','L','E','E','P','#','#','#','#'},cmdActivate}, // activate Sleeping mode - one shot or sleep until interrupt | ||
*/ | ||
|
||
void LLAPSerial::init() | ||
{ | ||
sMessage.reserve(10); | ||
bMsgReceived = false; | ||
deviceId[0] = '-'; | ||
deviceId[1] = '-'; | ||
} | ||
|
||
void LLAPSerial::init(char* dID) | ||
{ | ||
init(); | ||
bMsgReceived = false; | ||
setDeviceId(dID); | ||
} | ||
|
||
void LLAPSerial::processMessage(){ | ||
//if (LLAP.cMessage[0] != 'a') return; //not needed as already checked | ||
if (cMessage[1] != deviceId[0]) return; | ||
if (cMessage[2] != deviceId[1]) return; | ||
// now we have LLAP.cMessage[3] to LLAP.cMessage[11] as the actual message | ||
if (0 == strncmp_P(&cMessage[3],PSTR("HELLO----"),9)) { | ||
Serial.print(cMessage); // echo the message | ||
} else if (0 == strncmp_P(&cMessage[3],PSTR("CHDEVID"),7)) { | ||
deviceId[0] = cMessage[10]; | ||
deviceId[1] = cMessage[11]; | ||
Serial.print(cMessage); // echo the message | ||
} else { | ||
sMessage = String(&cMessage[3]); // let the main program deal with it | ||
bMsgReceived = true; | ||
} | ||
} | ||
|
||
void LLAPSerial::SerialEvent() | ||
{ | ||
if (bMsgReceived) return; //get out if previous message not yet processed | ||
if (Serial.available() >= 12) { | ||
// get the new byte: | ||
char inChar = (char)Serial.peek(); | ||
if (inChar == 'a') { | ||
for (byte i = 0; i<12; i++) { | ||
inChar = (char)Serial.read(); | ||
cMessage[i] = inChar; | ||
if (i < 11 && Serial.peek() == 'a') { | ||
// out of synch so abort and pick it up next time round | ||
return; | ||
} | ||
} | ||
cMessage[12]=0; | ||
processMessage(); | ||
} | ||
} | ||
} | ||
|
||
void LLAPSerial::sendMessage(String sToSend) | ||
{ | ||
cMessage[0] = 'a'; | ||
cMessage[1] = deviceId[0]; | ||
cMessage[2] = deviceId[1]; | ||
for (byte i = 0; i<9; i++) { | ||
if (i < sToSend.length()) | ||
cMessage[i+3] = sToSend.charAt(i); | ||
else | ||
cMessage[i+3] = '-'; | ||
} | ||
|
||
Serial.print(cMessage); | ||
Serial.flush(); | ||
} | ||
|
||
void LLAPSerial::sendInt(String sToSend, int value) | ||
{ | ||
char cValue[7]; // long enough for -32767 and the trailing zero | ||
itoa(value, cValue,10); | ||
byte cValuePtr = 0; | ||
|
||
cMessage[0] = 'a'; | ||
cMessage[1] = deviceId[0]; | ||
cMessage[2] = deviceId[1]; | ||
for (byte i = 0; i<9; i++) { | ||
if (i < sToSend.length()) | ||
cMessage[i+3] = sToSend.charAt(i); | ||
else if (cValuePtr < 7 && cValue[cValuePtr] !=0) | ||
cMessage[i+3] = cValue[cValuePtr++]; | ||
else | ||
cMessage[i+3] = '-'; | ||
} | ||
|
||
Serial.print(cMessage); | ||
Serial.flush(); | ||
} | ||
|
||
void LLAPSerial::sendIntWithDP(String sToSend, int value, byte decimalPlaces) | ||
{ | ||
char cValue[8]; // long enough for -3276.7 and the trailing zero | ||
byte cValuePtr; | ||
itoa(value, cValue,10); | ||
char* cp = &cValue[strlen(cValue)]; | ||
*(cp+1) = 0; // new terminator | ||
while (decimalPlaces-- && --cp ) | ||
{ | ||
*(cp+1) = *cp; | ||
} | ||
*cp = '.'; | ||
|
||
cMessage[0] = 'a'; | ||
cMessage[1] = deviceId[0]; | ||
cMessage[2] = deviceId[1]; | ||
for (byte i = 0; i<9; i++) { | ||
if (i < sToSend.length()) | ||
cMessage[i+3] = sToSend.charAt(i); | ||
else if (cValuePtr < 7 && cValue[cValuePtr] !=0) | ||
cMessage[i+3] = cValue[cValuePtr++]; | ||
else | ||
cMessage[i+3] = '-'; | ||
} | ||
|
||
Serial.print(cMessage); | ||
Serial.flush(); | ||
} | ||
|
||
void LLAPSerial::setDeviceId(char* cId) | ||
{ | ||
deviceId[0] = cId[0]; | ||
deviceId[1] = cId[1]; | ||
} | ||
|
||
///////////////////////////////////////////////////////////////////////////////////////////////////// | ||
///////////////////////////////////////////////////////////////////////////////////////////////////// | ||
// | ||
// This power-saving code was shamelessly stolen from the Jeelabs library with slight modification. | ||
// see https://github.com/jcw/jeelib | ||
// The watchdog timer is only about 10% accurate - varies between chips | ||
|
||
|
||
#include <avr/sleep.h> | ||
#include <util/atomic.h> | ||
|
||
static volatile byte watchdogCounter; | ||
|
||
void watchdogEvent() { | ||
++watchdogCounter; | ||
} | ||
|
||
ISR(WDT_vect) { watchdogEvent(); } | ||
|
||
|
||
void watchdogInterrupts (char mode) { | ||
// correct for the fact that WDP3 is *not* in bit position 3! | ||
if (mode & bit(3)) | ||
mode ^= bit(3) | bit(WDP3); | ||
// pre-calculate the WDTCSR value, can't do it inside the timed sequence | ||
// we only generate interrupts, no reset | ||
byte wdtcsr = mode >= 0 ? bit(WDIE) | mode : 0; | ||
MCUSR &= ~(1<<WDRF); | ||
ATOMIC_BLOCK(ATOMIC_FORCEON) { | ||
#ifndef WDTCSR | ||
#define WDTCSR WDTCR | ||
#endif | ||
WDTCSR |= (1<<WDCE) | (1<<WDE); // timed sequence | ||
WDTCSR = wdtcsr; | ||
} | ||
} | ||
|
||
/// @see http://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html | ||
void powerDown () { | ||
byte adcsraSave = ADCSRA; | ||
ADCSRA &= ~ bit(ADEN); // disable the ADC | ||
// switch off analog comparator - not in Jeelabs' code | ||
ACSR = ACSR & 0x7F; // note if using it then we need to switch this back on when we wake. | ||
set_sleep_mode(SLEEP_MODE_PWR_DOWN); | ||
ATOMIC_BLOCK(ATOMIC_FORCEON) { | ||
sleep_enable(); | ||
// sleep_bod_disable(); // can't use this - not in my avr-libc version! | ||
#ifdef BODSE | ||
MCUCR = MCUCR | bit(BODSE) | bit(BODS); // timed sequence | ||
MCUCR = (MCUCR & ~ bit(BODSE)) | bit(BODS); | ||
#endif | ||
} | ||
sleep_cpu(); | ||
sleep_disable(); | ||
// re-enable what we disabled | ||
ADCSRA = adcsraSave; | ||
} | ||
|
||
byte LLAPSerial::sleepForaWhile (word msecs) { | ||
byte ok = 1; | ||
word msleft = msecs; | ||
// only slow down for periods longer than the watchdog granularity | ||
while (msleft >= 16) { | ||
char wdp = 0; // wdp 0..9 corresponds to roughly 16..8192 ms | ||
// calc wdp as log2(msleft/16), i.e. loop & inc while next value is ok | ||
for (word m = msleft; m >= 32; m >>= 1) | ||
if (++wdp >= 9) | ||
break; | ||
watchdogCounter = 0; | ||
watchdogInterrupts(wdp); | ||
powerDown(); | ||
watchdogInterrupts(-1); // off | ||
// when interrupted, our best guess is that half the time has passed | ||
word halfms = 8 << wdp; | ||
msleft -= halfms; | ||
if (watchdogCounter == 0) { | ||
ok = 0; // lost some time, but got interrupted | ||
break; | ||
} | ||
msleft -= halfms; | ||
} | ||
// adjust the milli ticks, since we will have missed several | ||
#if defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny85__) || defined (__AVR_ATtiny44__) || defined (__AVR_ATtiny45__) | ||
extern volatile unsigned long millis_timer_millis; | ||
millis_timer_millis += msecs - msleft; | ||
#else | ||
extern volatile unsigned long timer0_millis; | ||
timer0_millis += msecs - msleft; | ||
#endif | ||
return ok; // true if we lost approx the time planned | ||
} | ||
|
||
// End of power-saving code. | ||
// | ||
///////////////////////////////////////////////////////////////////////////////////////////////////// | ||
///////////////////////////////////////////////////////////////////////////////////////////////////// | ||
|
||
/* | ||
SerialEvent occurs whenever a new data comes in the | ||
hardware serial RX. This routine is run between each | ||
time loop() runs, so using delay inside loop can delay | ||
response. Multiple bytes of data may be available. | ||
*/ | ||
void serialEvent() { | ||
LLAP.SerialEvent(); | ||
} | ||
|
||
|
||
LLAPSerial LLAP; // declare the instance | ||
|
Oops, something went wrong.