Skip to content

Commit

Permalink
Initial commit of the LLAPSerial library
Browse files Browse the repository at this point in the history
  • Loading branch information
dpslwk committed Apr 8, 2013
0 parents commit 9b9c7e3
Show file tree
Hide file tree
Showing 6 changed files with 416 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .gitignore
@@ -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
22 changes: 22 additions & 0 deletions Examples/LLAPSensor/LLAPSensor.ino
@@ -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
}
}




73 changes: 73 additions & 0 deletions Examples/LLAP_DHT22/LLAP_DHT22.ino
@@ -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();
}
}
269 changes: 269 additions & 0 deletions LLAPSerial.cpp
@@ -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

0 comments on commit 9b9c7e3

Please sign in to comment.