├── .gitignore ├── LLAPSerial.cpp ├── LLAPSerial.h ├── README.md └── examples ├── LLAPSensor └── LLAPSensor.ino ├── LLAP_DHT22 └── LLAP_DHT22.ino ├── LLAP_PIR └── LLAP_PIR.ino ├── LowPower_LLAP_test_Tx └── LowPower_LLAP_test_Tx.ino ├── VeryLowPower_RFu328_ATSM3 └── VeryLowPower_RFu328_ATSM3.ino └── WIKSketch └── WIKSketch.ino /.gitignore: -------------------------------------------------------------------------------- 1 | Examples/LLAPSensor/LLAPSensor.sln 2 | Examples/LLAPSensor/LLAPSensor.suo 3 | Examples/LLAPSensor/LLAPSensor.vcxproj 4 | Examples/LLAPSensor/LLAPSensor.vcxproj.filters 5 | Examples/LLAPSensor/LLAPSensor.vcxproj.user 6 | Examples/LLAPSensor/Visual Micro/.LLAPSensor.vsarduino.h 7 | Examples/LLAPSensor/Visual Micro/Compile.vmps.xml 8 | Examples/LLAPSensor/Visual Micro/Configuration.Debug.vmps.xml 9 | Examples/LLAPSensor/Visual Micro/Upload.vmps.xml 10 | Examples/LLAP_DHT22/LLAP_DHT22.sln 11 | Examples/LLAP_DHT22/LLAP_DHT22.suo 12 | Examples/LLAP_DHT22/LLAP_DHT22.vcxproj 13 | Examples/LLAP_DHT22/LLAP_DHT22.vcxproj.filters 14 | Examples/LLAP_DHT22/LLAP_DHT22.vcxproj.user 15 | Examples/LLAP_DHT22/Visual Micro/.LLAP_DHT22.vsarduino.h 16 | Examples/LLAP_DHT22/Visual Micro/Compile.vmps.xml 17 | Examples/LLAP_DHT22/Visual Micro/Configuration.Debug.vmps.xml 18 | Examples/LLAP_DHT22/Visual Micro/Upload.vmps.xml 19 | -------------------------------------------------------------------------------- /LLAPSerial.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // 4 | 5 | #include "LLAPSerial.h" 6 | 7 | /* 8 | const CTable __code Commands[] = { 9 | {9,{'A','C','K','-','-','-','-','-','-'},cmdAck}, // must be the first entry 10 | {0,{'A','P','V','E','R','-','-','-','-'},cmdPVer}, // Protocol version 11 | {0,{'D','E','V','T','Y','P','E','-','-'},cmdDevType}, // Device Type 12 | {0,{'D','E','V','N','A','M','E','-','-'},cmdDevName}, // Device Name 13 | {0,{'H','E','L','L','O','-','-','-','-'},cmdHello}, // Echo 14 | {3,{'S','E','R','#','#','#','#','#','#'},cmdSer}, // Serial Number 15 | {0,{'$','E','R','-','-','-','-','-','-'},cmdSerReset}, // Serial Number 16 | {0,{'F','V','E','R','-','-','-','-','-'},cmdFVer}, // Software revision 17 | {7,{'C','H','D','E','V','I','D','#','#'},cmdDevID}, // Device ID 18 | {5,{'P','A','N','I','D','#','#','#','#'},cmdPanID}, // PANID 19 | {0,{'R','E','B','O','O','T','-','-','-'},cmdReset}, // reset 20 | {7,{'R','E','T','R','I','E','S','#','#'},cmdRetries}, // set # retrys 21 | {4,{'B','A','T','T','-','-','-','-','-'},cmdBatt}, // request battery voltage 22 | {4,{'S','A','V','E','-','-','-','-','-'},cmdSave}, // Save config to flash 23 | #if defined(APSLEEP) // cyclic sleep 24 | {0,{'I','N','T','V','L','#','#','#','#'},cmdInterval}, // SET cyclic sleep interval - 999S - three digits + timescale 25 | // T=mS, S=S, M=mins, H=Hours, D=days 26 | {0,{'C','Y','C','L','E','-','-','-','-'},cmdCyclic}, // activate cyclic sleep 27 | {0,{'W','A','K','E','-','-','-','-','-'},cmdDeactivate}, // deactivate programmed behaviour (cyclic sleep etc) 28 | {5,{'W','A','K','E','C','#','#','#','-'},cmdSetSleepCount}, // set the sleep count until awake is sent 29 | #endif 30 | // allow all device to do a one shot sleep (including DALLAS) 31 | {0,{'S','L','E','E','P','#','#','#','#'},cmdActivate}, // activate Sleeping mode - one shot or sleep until interrupt 32 | */ 33 | 34 | void LLAPSerial::init() 35 | { 36 | sMessage.reserve(10); 37 | bMsgReceived = false; 38 | deviceId[0] = '-'; 39 | deviceId[1] = '-'; 40 | } 41 | 42 | void LLAPSerial::init(char* dID) 43 | { 44 | init(); 45 | bMsgReceived = false; 46 | setDeviceId(dID); 47 | cMessage[12]=0; // ensure terminated 48 | } 49 | 50 | void LLAPSerial::processMessage(){ 51 | //if (LLAP.cMessage[0] != 'a') return; //not needed as already checked 52 | if (cMessage[1] != deviceId[0]) return; 53 | if (cMessage[2] != deviceId[1]) return; 54 | // now we have LLAP.cMessage[3] to LLAP.cMessage[11] as the actual message 55 | if (0 == strncmp_P(&cMessage[3],PSTR("HELLO----"),9)) { 56 | Serial.print(cMessage); // echo the message 57 | } else if (0 == strncmp_P(&cMessage[3],PSTR("CHDEVID"),7)) { 58 | if (strchr_P(PSTR("-#@?\\*ABCDEFGHIJKLMNOPQRSTUVWXYZ"), cMessage[10]) != 0 && strchr_P(PSTR("-#@?\\*ABCDEFGHIJKLMNOPQRSTUVWXYZ"), cMessage[11]) != 0) 59 | { 60 | deviceId[0] = cMessage[10]; 61 | deviceId[1] = cMessage[11]; 62 | Serial.print(cMessage); // echo the message 63 | } 64 | } else { 65 | sMessage = String(&cMessage[3]); // let the main program deal with it 66 | bMsgReceived = true; 67 | } 68 | } 69 | 70 | void LLAPSerial::SerialEvent() 71 | { 72 | if (bMsgReceived) return; //get out if previous message not yet processed 73 | if (Serial.available() >= 12) { 74 | // get the new byte: 75 | char inChar = (char)Serial.peek(); 76 | if (inChar == 'a') { 77 | for (byte i = 0; i<12; i++) { 78 | inChar = (char)Serial.read(); 79 | cMessage[i] = inChar; 80 | if (i < 11 && Serial.peek() == 'a') { 81 | // out of synch so abort and pick it up next time round 82 | return; 83 | } 84 | } 85 | cMessage[12]=0; 86 | processMessage(); 87 | } 88 | else 89 | Serial.read(); // throw away the character 90 | } 91 | } 92 | 93 | void LLAPSerial::sendMessage(String sToSend) 94 | { 95 | cMessage[0] = 'a'; 96 | cMessage[1] = deviceId[0]; 97 | cMessage[2] = deviceId[1]; 98 | for (byte i = 0; i<9; i++) { 99 | if (i < sToSend.length()) 100 | cMessage[i+3] = sToSend.charAt(i); 101 | else 102 | cMessage[i+3] = '-'; 103 | } 104 | 105 | Serial.print(cMessage); 106 | Serial.flush(); 107 | } 108 | 109 | void LLAPSerial::sendMessage(char* sToSend) 110 | { 111 | sendMessage(sToSend,NULL); 112 | } 113 | 114 | void LLAPSerial::sendMessage(char* sToSend, char* valueToSend) 115 | { 116 | cMessage[0] = 'a'; 117 | cMessage[1] = deviceId[0]; 118 | cMessage[2] = deviceId[1]; 119 | for (byte i = 0; i<9; i++) { 120 | if (i < strlen(sToSend)) 121 | cMessage[i+3] = sToSend[i]; 122 | else if (i < strlen(sToSend) + strlen(valueToSend)) 123 | cMessage[i+3] = valueToSend[i - strlen(sToSend)]; 124 | else 125 | cMessage[i+3] = '-'; 126 | } 127 | 128 | Serial.print(cMessage); 129 | Serial.flush(); 130 | } 131 | 132 | void LLAPSerial::sendMessage(const __FlashStringHelper *ifsh) 133 | { 134 | sendMessage(ifsh,NULL); 135 | } 136 | 137 | void LLAPSerial::sendMessage(const __FlashStringHelper *ifsh, char* valueToSend) 138 | { 139 | const char PROGMEM *p = (const char PROGMEM *)ifsh; 140 | byte eos = 0; 141 | cMessage[0] = 'a'; 142 | cMessage[1] = deviceId[0]; 143 | cMessage[2] = deviceId[1]; 144 | for (byte i = 0; i<9; i++) { 145 | if (!eos) 146 | { 147 | cMessage[i+3] = pgm_read_byte(p++); 148 | if (!cMessage[i+3]) // end of string 149 | { 150 | eos = i-3; 151 | } 152 | } 153 | if (eos) 154 | { 155 | if (i < eos + strlen(valueToSend)) 156 | cMessage[i+3] = valueToSend[i - eos]; 157 | else 158 | cMessage[i+3] = '-'; 159 | } 160 | } 161 | Serial.print(cMessage); 162 | Serial.flush(); 163 | } 164 | 165 | void LLAPSerial::sendInt(String sToSend, int value) 166 | { 167 | char cValue[7]; // long enough for -32767 and the trailing zero 168 | itoa(value, cValue,10); 169 | byte cValuePtr = 0; 170 | 171 | cMessage[0] = 'a'; 172 | cMessage[1] = deviceId[0]; 173 | cMessage[2] = deviceId[1]; 174 | for (byte i = 0; i<9; i++) { 175 | if (i < sToSend.length()) 176 | cMessage[i+3] = sToSend.charAt(i); 177 | else if (cValuePtr < 7 && cValue[cValuePtr] !=0) 178 | cMessage[i+3] = cValue[cValuePtr++]; 179 | else 180 | cMessage[i+3] = '-'; 181 | } 182 | 183 | Serial.print(cMessage); 184 | Serial.flush(); 185 | } 186 | 187 | void LLAPSerial::sendIntWithDP(String sToSend, int value, byte decimalPlaces) 188 | { 189 | char cValue[8]; // long enough for -3276.7 and the trailing zero 190 | byte cValuePtr=0; 191 | itoa(value, cValue,10); 192 | char* cp = &cValue[strlen(cValue)]; 193 | *(cp+1) = 0; // new terminator 194 | while (decimalPlaces-- && --cp ) 195 | { 196 | *(cp+1) = *cp; 197 | } 198 | *cp = '.'; 199 | 200 | cMessage[0] = 'a'; 201 | cMessage[1] = deviceId[0]; 202 | cMessage[2] = deviceId[1]; 203 | for (byte i = 0; i<9; i++) { 204 | if (i < sToSend.length()) 205 | cMessage[i+3] = sToSend.charAt(i); 206 | else if (cValuePtr < 8 && cValue[cValuePtr] !=0) 207 | cMessage[i+3] = cValue[cValuePtr++]; 208 | else 209 | cMessage[i+3] = '-'; 210 | } 211 | 212 | Serial.print(cMessage); 213 | Serial.flush(); 214 | } 215 | 216 | void LLAPSerial::setDeviceId(char* cId) 217 | { 218 | deviceId[0] = cId[0]; 219 | deviceId[1] = cId[1]; 220 | } 221 | 222 | ///////////////////////////////////////////////////////////////////////////////////////////////////// 223 | ///////////////////////////////////////////////////////////////////////////////////////////////////// 224 | // 225 | // This power-saving code was shamelessly stolen from the Jeelabs library with slight modification. 226 | // see https://github.com/jcw/jeelib 227 | // The watchdog timer is only about 10% accurate - varies between chips 228 | 229 | 230 | #include 231 | #include 232 | 233 | static volatile byte watchdogCounter; 234 | 235 | void watchdogEvent() { 236 | ++watchdogCounter; 237 | } 238 | 239 | ISR(WDT_vect) { watchdogEvent(); } 240 | 241 | 242 | void watchdogInterrupts (char mode) { 243 | // correct for the fact that WDP3 is *not* in bit position 3! 244 | if (mode & bit(3)) 245 | mode ^= bit(3) | bit(WDP3); 246 | // pre-calculate the WDTCSR value, can't do it inside the timed sequence 247 | // we only generate interrupts, no reset 248 | byte wdtcsr = mode >= 0 ? bit(WDIE) | mode : 0; 249 | MCUSR &= ~(1<= 16) { 285 | char wdp = 0; // wdp 0..9 corresponds to roughly 16..8192 ms 286 | // calc wdp as log2(msleft/16), i.e. loop & inc while next value is ok 287 | for (word m = msleft; m >= 32; m >>= 1) 288 | if (++wdp >= 9) 289 | break; 290 | watchdogCounter = 0; 291 | watchdogInterrupts(wdp); 292 | powerDown(); 293 | watchdogInterrupts(-1); // off 294 | // when interrupted, our best guess is that half the time has passed 295 | word halfms = 8 << wdp; 296 | msleft -= halfms; 297 | if (watchdogCounter == 0) { 298 | ok = 0; // lost some time, but got interrupted 299 | break; 300 | } 301 | msleft -= halfms; 302 | } 303 | // adjust the milli ticks, since we will have missed several 304 | #if defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny85__) || defined (__AVR_ATtiny44__) || defined (__AVR_ATtiny45__) 305 | extern volatile unsigned long millis_timer_millis; 306 | millis_timer_millis += msecs - msleft; 307 | #else 308 | extern volatile unsigned long timer0_millis; 309 | timer0_millis += msecs - msleft; 310 | #endif 311 | return ok; // true if we lost approx the time planned 312 | } 313 | 314 | void pin2_isr() 315 | { 316 | sleep_disable(); 317 | detachInterrupt(0); 318 | } 319 | 320 | void pin3_isr() 321 | { 322 | sleep_disable(); 323 | detachInterrupt(1); 324 | } 325 | 326 | void LLAPSerial::sleep(byte pinToWakeOn, byte direction, byte bPullup) // full sleep wake on interrupt - pin is 2 or 3 327 | { 328 | byte adcsraSave = ADCSRA; 329 | ADCSRA &= ~ bit(ADEN); // disable the ADC 330 | // switch off analog comparator - not in Jeelabs' code 331 | ACSR = ACSR & 0x7F; // note if using it then we need to switch this back on when we wake. 332 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); 333 | sleep_enable(); 334 | if (pinToWakeOn == 2) 335 | { 336 | pinMode(2,INPUT); 337 | if (bPullup) digitalWrite(2,HIGH); // enable pullup 338 | attachInterrupt(0, pin2_isr, direction); 339 | } 340 | else 341 | { 342 | pinMode(3,INPUT); 343 | if (bPullup) digitalWrite(3,HIGH); // enable pullup 344 | attachInterrupt(1, pin3_isr, direction); 345 | } 346 | cli(); 347 | // sleep_bod_disable(); // can't use this - not in my avr-libc version! 348 | #ifdef BODSE 349 | MCUCR = MCUCR | bit(BODSE) | bit(BODS); // timed sequence 350 | MCUCR = (MCUCR & ~ bit(BODSE)) | bit(BODS); 351 | #endif 352 | sei(); 353 | sleep_cpu(); // and wait until we are woken 354 | sleep_disable(); 355 | // re-enable what we disabled 356 | ADCSRA = adcsraSave; 357 | } 358 | 359 | // End of power-saving code. 360 | // 361 | ///////////////////////////////////////////////////////////////////////////////////////////////////// 362 | ///////////////////////////////////////////////////////////////////////////////////////////////////// 363 | 364 | /* 365 | SerialEvent occurs whenever a new data comes in the 366 | hardware serial RX. This routine is run between each 367 | time loop() runs, so using delay inside loop can delay 368 | response. Multiple bytes of data may be available. 369 | */ 370 | void serialEvent() { 371 | LLAP.SerialEvent(); 372 | } 373 | 374 | 375 | LLAPSerial LLAP; // declare the instance 376 | 377 | -------------------------------------------------------------------------------- /LLAPSerial.h: -------------------------------------------------------------------------------- 1 | // LLAPSerial.h 2 | 3 | #ifndef _LLAPSERIAL_h 4 | #define _LLAPSERIAL_h 5 | 6 | #if defined(ARDUINO) && ARDUINO >= 100 7 | #include "Arduino.h" 8 | #else 9 | #include "WProgram.h" 10 | #endif 11 | 12 | class LLAPSerial 13 | { 14 | private: 15 | char cMessage[13]; 16 | void processMessage(); 17 | public: 18 | void init(); 19 | void init(char* cI); 20 | char deviceId[2]; 21 | String sMessage; 22 | boolean bMsgReceived; 23 | void SerialEvent(); 24 | void sendMessage(String sToSend); 25 | void sendMessage(char* sToSend); 26 | void sendMessage(char* sToSend, char* valueToSend); 27 | void sendMessage(const __FlashStringHelper *ifsh); 28 | void sendMessage(const __FlashStringHelper *ifsh, char* valueToSend); 29 | void sendInt(String sToSend, int value); 30 | void sendIntWithDP(String sToSend, int value, byte decimalPlaces); 31 | void setDeviceId(char* cId); 32 | byte sleepForaWhile (word msecs); // timed sleep using the watchdog 33 | void sleep(byte pinToWakeOn, byte direction = FALLING, byte bPullup = true); // full sleep woken by pin interrupt 34 | }; 35 | 36 | extern LLAPSerial LLAP; 37 | 38 | #endif 39 | 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This Arduino library is under development, however feel free to try it out. 2 | 3 | It is designed to assist the user in implementing a LLAP device using the Arduino development environment. 4 | 5 | For more infomation see http://openmicros.org/index.php/articles/85-llap-lightweight-local-automation-protocol/266-arduino-llap-library-for-user-devices 6 | 7 | Installing 8 | 9 | * On https://github.com/CisecoPlc/LLAPSerial at the bottom right you will find a button called "dowload zip" 10 | * Extracting this zip will give you a folder called LLAPSerial-master 11 | * Rename this to LLAPSerial 12 | * Move this to your libraries folder inside your arduino sketchbook. On windows this would be something like C:\Users\miles\Documents\Arduino\libraries\LLAPSerial 13 | * Restart the IDE 14 | * Examples can then be found under File->Examples->LLAPSerial 15 | 16 | Please ask any questions on our forums at http://openmicros.org/ 17 | 18 | -------------------------------------------------------------------------------- /examples/LLAPSensor/LLAPSensor.ino: -------------------------------------------------------------------------------- 1 | 2 | #include "LLAPSerial.h" // include the library 3 | 4 | void setup() { 5 | // initialise serial: 6 | Serial.begin(9600); 7 | // Initialise the LLAPSerial library 8 | LLAP.init(); 9 | } 10 | 11 | void loop() { 12 | // print the string when a newline arrives: 13 | if (LLAP.bMsgReceived) { 14 | Serial.print("message is:"); 15 | Serial.println(LLAP.sMessage); 16 | LLAP.bMsgReceived = false; // if we do not clear the message flag then message processing will be blocked 17 | } 18 | } 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/LLAP_DHT22/LLAP_DHT22.ino: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////// 2 | // LLAP temperature and humidity sensor using a DHT22 3 | // 4 | // Reading temperature or humidity takes about 250 milliseconds! 5 | // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) 6 | // 7 | // will work with any Arduino compatible however the target boards are the 8 | // Ciseco XinoRF and RFu-328, for LLAP over radio 9 | // 10 | // 11 | // Uses the Ciseco LLAPSerial library 12 | // Uses the Adafruit DHT library https://github.com/adafruit/DHT-sensor-library 13 | ////////////////////////////////////////////////////////////////////////// 14 | 15 | #include 16 | #include 17 | 18 | #define DEVICEID "DH" // this is the LLAP device ID 19 | 20 | #define DHTPIN 2 // what I/O the DHT-22 data pin is connected to 21 | #define DHTTYPE DHT22 // DHT 22 (AM2302) 22 | 23 | // Connect pin 1 (on the left) of the sensor to +5V 24 | // Connect pin 2 of the sensor to whatever your DHTPIN is 25 | // Connect pin 4 (on the right) of the sensor to GROUND 26 | // Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor 27 | 28 | DHT dht(DHTPIN, DHTTYPE); 29 | 30 | void setup() { 31 | Serial.begin(115200); 32 | pinMode(8,OUTPUT); // switch on the radio 33 | digitalWrite(8,HIGH); 34 | pinMode(4,OUTPUT); // switch on the radio 35 | digitalWrite(4,LOW); // ensure the radio is not sleeping 36 | delay(1000); // allow the radio to startup 37 | LLAP.init(DEVICEID); 38 | 39 | dht.begin(); 40 | 41 | LLAP.sendMessage(F("STARTED")); 42 | 43 | } 44 | 45 | void loop() { 46 | // print the string when a newline arrives: 47 | if (LLAP.bMsgReceived) { 48 | Serial.print(F("msg:")); 49 | Serial.println(LLAP.sMessage); 50 | LLAP.bMsgReceived = false; // if we do not clear the message flag then message processing will be blocked 51 | } 52 | 53 | // every 30 seconds 54 | static unsigned long lastTime = millis(); 55 | if (millis() - lastTime >= 30000) 56 | { 57 | lastTime = millis(); 58 | int h = dht.readHumidity() * 10; 59 | int t = dht.readTemperature() * 10; 60 | // check if returns are valid, if they are NaN (not a number) then something went wrong! 61 | if (isnan(t) || isnan(h)) { 62 | LLAP.sendMessage(F("ERROR")); 63 | } else { 64 | LLAP.sendIntWithDP("HUM",h,1); 65 | //delay(100); 66 | LLAP.sendIntWithDP("TMP",t,1); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /examples/LLAP_PIR/LLAP_PIR.ino: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////// 2 | // RFµ PIR Sensor 3 | // 4 | // 5 | // 6 | // Uses the Ciseco LLAPSerial library 7 | // 8 | // https://code.google.com/p/tinkerit/wiki/SecretVoltmeter 9 | ////////////////////////////////////////////////////////////////////////// 10 | 11 | 12 | #include 13 | 14 | #define DEVICEID "AC" 15 | #define PIR_PIN 2 16 | 17 | #define WAKEC 10 18 | byte battc = 9; 19 | 20 | #define PIRBLOCKTIME 20000 // time in ms to block after a triger 21 | 22 | void setup() { 23 | Serial.begin(115200); 24 | 25 | pinMode(8, OUTPUT); // pin 8 controls the radio 26 | digitalWrite(8, HIGH); // select the radio 27 | 28 | pinMode(4, OUTPUT); // pin 4 controls the radio sleep 29 | digitalWrite(4, LOW); // wake the radio 30 | 31 | delay(450); // allow the radio to startup 32 | LLAP.init(DEVICEID); 33 | 34 | pinMode(PIR_PIN, INPUT); // PIR Input pin 35 | digitalWrite(PIR_PIN, LOW); // no pullup 36 | 37 | LLAP.sendMessage(F("STARTED")); 38 | 39 | } 40 | 41 | 42 | 43 | void loop() { 44 | pinMode(4, INPUT); // sleep the radio 45 | 46 | 47 | LLAP.sleep(PIR_PIN, RISING, false); // deep sleep until PIR causes interupt 48 | battc++; // increase battery count 49 | 50 | pinMode(4, OUTPUT); // wake the radio 51 | 52 | delay(450); // give it time to wake up 53 | 54 | LLAP.sendMessage(F("PIRTRIG")); // the pir trigered send a message 55 | 56 | if (battc >= WAKEC) { // is it time to send a battery reading 57 | battc = 0; 58 | LLAP.sendIntWithDP("BATT", int(readVcc()),3); // read the battery voltage and send 59 | } 60 | pinMode(4, INPUT); // sleep the radio again 61 | LLAP.sleepForaWhile(PIRBLOCKTIME); // sleep for a little while before we go back to listening for the PIR 62 | 63 | } 64 | 65 | long readVcc() { 66 | long result; 67 | // Read 1.1V reference against AVcc 68 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 69 | delay(2); // Wait for Vref to settle 70 | ADCSRA |= _BV(ADSC); // Convert 71 | while (bit_is_set(ADCSRA,ADSC)); 72 | result = ADCL; 73 | result |= ADCH<<8; 74 | result = 1126400L / result; // Back-calculate AVcc in mV 75 | return result; 76 | } 77 | -------------------------------------------------------------------------------- /examples/LowPower_LLAP_test_Tx/LowPower_LLAP_test_Tx.ino: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////// 2 | // Simple RFu SRF LLAP Tx Test example 3 | // 4 | // Works well on RFu328. Issue with Xino RF where the sleep mode disable the USB serial port opperation! 5 | // 6 | // 7 | // Uses the Ciseco LLAPSerial library 8 | // 9 | // Example by Glyn Hudson OpenEnergyMonitor.org June 2013 10 | // Based on LLAP Serial Library and examples from Ciseco 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | #include 14 | 15 | #define DEVICEID "A1" // this is the LLAP device ID 16 | 17 | int i; 18 | float f; 19 | 20 | 21 | void setup() { 22 | Serial.begin(115200); 23 | 24 | pinMode(8,OUTPUT); // switch on the SRF radio 25 | digitalWrite(8,HIGH); 26 | delay(1000); // allow the radio to startup 27 | 28 | //-------------enable SRF sleep mode 2---------------------------------------------- 29 | //http://openmicros.org/index.php/articles/88-ciseco-product-documentation/260-srf-configuration 30 | pinMode(4,OUTPUT); // hardwired XinoRF / RFu328 SRF sleep pin 31 | digitalWrite(4,LOW); // pull sleep pin high - sleep 2 disabled 32 | Serial.print("+++"); // enter AT command mode 33 | delay(1500); // delay 1.5s 34 | Serial.println("ATSM2"); // enable sleep mode 2 <0.5uA 35 | delay(2000); 36 | Serial.println("ATDN"); // exit AT command mode*/ 37 | delay(2000); 38 | //--------------------------------------------------------------------------------- 39 | 40 | LLAP.init(DEVICEID); 41 | LLAP.sendMessage("STARTED"); 42 | //tst code 43 | Serial.print("ABCDEFGHIJKLMNOPQRSTUVWX"); 44 | Serial.flush(); 45 | 46 | 47 | } 48 | 49 | void loop() { 50 | 51 | //LLAP receive code - not used in this low power Tx only example 52 | // print the string when a newline arrives: 53 | //if (LLAP.bMsgReceived) { 54 | // Serial.print("message is:"); 55 | // Serial.println(LLAP.sMessage); 56 | // LLAP.bMsgReceived = false; // if we do not clear the message flag then message processing will be blocked 57 | //} 58 | 59 | //--------Send Test Variables---------------------------------------------------------- 60 | LLAP.sendMessage("TEST0"); 61 | LLAP.sendInt("TEST1",i); //name, int variable 62 | LLAP.sendIntWithDP("Test2", f ,1); //name, float variable, number of DP's 63 | i++; //inc test variables 64 | f=f+0.1; 65 | //------------------------------------------------------------------------------------- 66 | 67 | //-------Put ATmega328 and SRF Radio to sleep------------------------------------------ 68 | delay(10); // allow radio to finish sending 69 | //Serial.println(); 70 | digitalWrite(4, HIGH); // pull sleep pin high to enter SRF sleep 2 71 | LLAP.sleepForaWhile(5000); // sleep ATmega328 for 5s (ms) 72 | digitalWrite(4, LOW); // when ATmega328 wakes up, wake up SRF Radio 73 | delay(10); // allow radio to wake up 74 | //------------------------------------------------------------------------------------- 75 | 76 | } 77 | -------------------------------------------------------------------------------- /examples/VeryLowPower_RFu328_ATSM3/VeryLowPower_RFu328_ATSM3.ino: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // LLAP very low power example - RFu-328 only 4 | // 5 | /////////////////////////////////////////////////////////////////////////////// 6 | // 7 | // Target: Ciseco RFu-328 8 | // version: 0.1 9 | // date: 25 August 2013 10 | // 11 | // copyright/left, limitations to use etc. statement to go here 12 | // 13 | ////////////////////////////////////////////////////////////////////////////// 14 | // 15 | // Reads the voltage at A0 e.g. for moisture sensor 16 | // Connections: 17 | // Probes connected between GND and Analog 0 (A0) 18 | // 10kOhm resistor connected between pin 9 and Analog 0 (A0) 19 | // 20 | ///////////////////////////////////////////////////////////////////////////// 21 | // 22 | // RFu-328 specific AT commands (requires firmware RFu-328 V0.84 or better) 23 | // The following RFu specific AT commands are supported in V0.84 or later 24 | // Added a new sleep mode (ATSM3) Wake after timed interval 25 | // The duration is specified by a new command ATSD, units are mS 26 | // and the range is 32bit (max approx. 49 days) 27 | // e.g. ATSD5265C00 is one day (hex 5265C00 is decimal 86400000) 28 | // ATSD36EE80 is one hour 29 | // ATSD493E0 is five minutes 30 | // This sleep mode can be used to wake the 328 after a timed interval 31 | // by connecting RFu-328 pin 7 to pin 19, D3(INT1) or 20, D2(INT0). 32 | // Using this technique means that a RFu-328 can sleep for a timed 33 | // period consuming about 0.6uA, instead of using the AVR328 watchdog (for timing) 34 | // which uses around 7uA. 35 | // 36 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// 37 | 38 | 39 | #include 40 | 41 | 42 | void setup() 43 | { 44 | Serial.begin(115200); // Start the serial port 45 | 46 | LLAP.init("LP"); // Initialise the LLAPSerial library and the device identity 47 | 48 | pinMode(8, OUTPUT); // pin 8 controls the radio 49 | digitalWrite(8, HIGH); // select the radio 50 | 51 | pinMode(4, OUTPUT); // pin 4 controls the radio sleep 52 | digitalWrite(4, LOW); // wake the radio 53 | 54 | delay(400); // let everything start up 55 | 56 | // set up sleep mode 3 (low = awake) 57 | uint8_t val; 58 | while ((val = setupSRF()) != 5) 59 | { 60 | LLAP.sendInt("ERR",val); // Diagnostic 61 | delay(5000); // try again in 5 seconds 62 | } 63 | 64 | pinMode(9,OUTPUT); 65 | digitalWrite(9,LOW); // No voltage to the sensor 66 | 67 | LLAP.sendMessage(F("STARTED")); // send the usual "started message 68 | } 69 | 70 | void loop() 71 | { 72 | pinMode(4, INPUT); // sleep the radio 73 | 74 | LLAP.sleep(3, RISING, false); // sleep until woken on pin 3, no pullup (low power) 75 | 76 | pinMode(4, OUTPUT); // wake the radio 77 | 78 | digitalWrite(9,HIGH); // provide voltage for the sensor 79 | int moist = analogRead(0); // read sensor and convert to temperature 80 | digitalWrite(9,LOW); // remove voltage from the sensor 81 | LLAP.sendInt("MST",moist); 82 | } 83 | 84 | 85 | ///////////////////////////////////////////////////////// 86 | // SRF AT command handling 87 | ///////////////////////////////////////////////////////// 88 | 89 | uint8_t setupSRF() // set Sleep mode 2 90 | { 91 | if (!enterCommandMode()) // if failed once then try again 92 | { 93 | if (!enterCommandMode()) return 1; 94 | } 95 | //if (!sendCommand("ATSD49E30")) return 2; // 5 minutes 96 | //if (!sendCommand("ATSD4E20")) return 2; // 20 seconds 97 | // if (!sendCommand("ATSD1388")) return 2; // 5 seconds 98 | if (!sendCommand("ATSD3E8")) return 2; // 1 second 99 | if (!sendCommand("ATSM3")) return 3; 100 | if (!sendCommand("ATDN")) return 3; 101 | return 5; 102 | } 103 | 104 | uint8_t enterCommandMode() 105 | { 106 | delay(1200); 107 | Serial.print("+++"); 108 | delay(500); 109 | while (Serial.available()) Serial.read(); // flush serial in 110 | delay(500); 111 | return checkOK(500); 112 | } 113 | 114 | uint8_t sendCommand(char* lpszCommand) 115 | { 116 | Serial.print(lpszCommand); 117 | Serial.write('\r'); 118 | return checkOK(100); 119 | } 120 | 121 | uint8_t checkOK(int timeout) 122 | { 123 | uint32_t time = millis(); 124 | while (millis() - time < timeout) 125 | { 126 | if (Serial.available() >= 3) 127 | { 128 | if (Serial.read() != 'O') continue; 129 | if (Serial.read() != 'K') continue; 130 | if (Serial.read() != '\r') continue; 131 | return 1; 132 | } 133 | } 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /examples/WIKSketch/WIKSketch.ino: -------------------------------------------------------------------------------- 1 | // 2 | // LLAP - Lightweight Local Automation Protocol 3 | // 4 | // Wireless Inventors Kits 5 | // Ciseco Ltd. Copyright 2013 6 | // 7 | 8 | // Changes 9 | // 1.0 Add FVER command 10 | // 11 | #define VERSION "1.0" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #define DEVICETYPE "RASWIK" 18 | #define DEVICEID1 '-' 19 | #define DEVICEID2 '-' 20 | #define EEPROM_DEVICEID1 0 21 | #define EEPROM_DEVICEID2 1 22 | 23 | // inputs 24 | uint8_t inputs[] = {2,3,4,7,10,12,254}; 25 | // analog 26 | uint8_t analogs[] = {0,1,2,3,4,5,254}; 27 | // counter 28 | #define COUNTPIN 4 29 | unsigned int countValue = 0;; 30 | uint8_t countState = 1; 31 | uint32_t countTime; 32 | // interrupt 33 | #define DEBOUNCETIME 150 34 | #define INT1PIN 2 35 | uint8_t int1Value =1; 36 | uint32_t int1Time; 37 | #define INT2PIN 3 38 | uint8_t int2Value =1; 39 | uint32_t int2Time; 40 | // outputs 41 | uint8_t outputs[] = {6,5,11,13,254}; 42 | // pwm 43 | uint8_t pwm[] = {6,5,11,254}; 44 | // servo 45 | #define SERVOPIN 9 46 | Servo myservo; // create servo object to control a servo 47 | 48 | 49 | String msg; // storage for incoming message 50 | String reply; // storage for reply 51 | 52 | void setup() // always called at the start to setup I/Os etc 53 | { 54 | 55 | pinMode(8, OUTPUT); 56 | digitalWrite(8, HIGH); // turn on the radio 57 | Serial.begin(115200); // start the serial port at 115200 baud 58 | 59 | byte i=0; 60 | while (inputs[i] != 254) {pinMode(inputs[i],INPUT); digitalWrite(inputs[i++],HIGH);} 61 | i=0; 62 | while (outputs[i] != 254) pinMode(outputs[i++],OUTPUT); 63 | myservo.attach(SERVOPIN); // attaches the servo pin to the servo object 64 | 65 | String permittedChars = "-#@?\\*ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 66 | char deviceID[2]; 67 | deviceID[0] = EEPROM.read(EEPROM_DEVICEID1); 68 | deviceID[1] = EEPROM.read(EEPROM_DEVICEID2); 69 | 70 | 71 | if (permittedChars.indexOf(deviceID[0]) == -1 || permittedChars.indexOf(deviceID[1]) == -1) 72 | { 73 | deviceID[0] = DEVICEID1; 74 | deviceID[1] = DEVICEID2; 75 | } 76 | 77 | LLAP.init(deviceID); 78 | 79 | LLAP.sendMessage(String("STARTED")); 80 | } 81 | 82 | void loop() // repeatedly called 83 | { 84 | if (LLAP.bMsgReceived) // got a message? 85 | { 86 | msg = LLAP.sMessage; 87 | LLAP.bMsgReceived = false; 88 | reply = msg; 89 | if (msg.compareTo("HELLO----") == 0) 90 | { 91 | ; // just echo the message back 92 | } 93 | else if (msg.compareTo("FVER-----") == 0) 94 | { 95 | reply = reply.substring(0,4) + VERSION; 96 | } 97 | else if (msg.compareTo("DEVTYPE--") == 0) 98 | { 99 | reply = DEVICETYPE; 100 | } 101 | else if (msg.compareTo("SAVE-----") == 0) 102 | { 103 | EEPROM.write(EEPROM_DEVICEID1, LLAP.deviceId[0]); // save the device ID 104 | EEPROM.write(EEPROM_DEVICEID2, LLAP.deviceId[1]); // save the device ID 105 | } 106 | else if (msg.startsWith("SERVO")) 107 | { 108 | msg = msg.substring(5); 109 | int value = msg.toInt(); 110 | if (value >=0 && value <= 180) 111 | myservo.write(value); 112 | else 113 | reply = "TOOLARGE"; 114 | } 115 | else if (msg.startsWith("COUNT")) 116 | { 117 | msg = msg.substring(5); 118 | if (msg.startsWith("-")) 119 | { // read the value 120 | reply = reply.substring(0,5) + countValue; 121 | } 122 | else 123 | { // set the value 124 | int value = msg.toInt(); 125 | if (value >=0 && value <= 9999) 126 | countValue = value; 127 | else 128 | reply = "TOOLARGE"; 129 | } 130 | } 131 | else // it is an action message 132 | { 133 | byte typeOfIO; 134 | byte ioNumber; 135 | typeOfIO = msg.charAt(0); 136 | ioNumber = (msg.charAt(1) - '0') * 10 + msg.charAt(2) - '0'; 137 | msg = msg.substring(3); 138 | if (msg.compareTo("HIGH--") == 0) 139 | { 140 | if (validPin(outputs,ioNumber)) 141 | digitalWrite(ioNumber,HIGH); 142 | else 143 | reply = "NOTOUTPUT"; 144 | } 145 | else if (msg.compareTo("LOW---") == 0) 146 | { 147 | if (validPin(outputs,ioNumber)) 148 | digitalWrite(ioNumber,LOW); 149 | else 150 | reply = "NOTOUTPUT"; 151 | 152 | } 153 | else if (msg.startsWith("PWM")) 154 | { 155 | byte val = ((msg.charAt(3) - '0') * 10 + msg.charAt(4) - '0') * 10 + msg.charAt(5) - '0'; 156 | if (val >=0 && val <= 255) 157 | { 158 | if (validPin(pwm,ioNumber)) 159 | analogWrite(ioNumber,val); 160 | else 161 | reply = "NOTPWM"; 162 | } 163 | else 164 | reply = "TOOLARGE"; 165 | 166 | } 167 | else if (msg.compareTo("READ--") == 0) 168 | { 169 | reply = reply.substring(0,3); 170 | if (typeOfIO == 'A') 171 | { 172 | if (validPin(analogs,ioNumber)) 173 | { 174 | int val = analogRead(ioNumber); 175 | reply = reply + "+" + val; 176 | } 177 | else 178 | reply = "NOTINPUT"; 179 | } 180 | else 181 | { 182 | if (validPin(inputs,ioNumber)) 183 | { 184 | byte val = digitalRead(ioNumber); 185 | if (val) 186 | { 187 | reply = reply + "HIGH"; 188 | } 189 | else 190 | { 191 | reply = reply + "LOW"; 192 | } 193 | } 194 | else 195 | reply = "NOTINPUT"; 196 | } 197 | } 198 | else 199 | reply = "ERROR"; 200 | } 201 | LLAP.sendMessage(reply); 202 | } 203 | else 204 | { 205 | checkForInterruptPin(INT1PIN, &int1Value, &int1Time); 206 | checkForInterruptPin(INT2PIN, &int2Value, &int2Time); 207 | // and increment counter if needed 208 | if (millis() - countTime > DEBOUNCETIME) 209 | { 210 | if (countState && digitalRead(COUNTPIN) == 0) 211 | { 212 | countState = 0; 213 | countValue++; 214 | if (countValue > 9999) countValue = 0; 215 | } 216 | else if (countState == 0 && digitalRead(COUNTPIN)) 217 | { 218 | countState = 1; 219 | } 220 | countTime = millis(); 221 | } 222 | } 223 | } 224 | 225 | boolean validPin(byte* pins, byte pinNumber) 226 | { 227 | byte i = 0; 228 | while (pins[i] != 254) // end of array check numebr 229 | { 230 | if (pins[i++] == pinNumber) 231 | return true; 232 | } 233 | return false; 234 | } 235 | 236 | void checkForInterruptPin(uint8_t intpin, uint8_t* pinvalue, uint32_t* pinTime) 237 | { 238 | // check interrupts 239 | // crude debounce 240 | // once changed don't look for another change until DEBOUNCETIME has elapsed 241 | if (digitalRead(intpin) != *pinvalue && millis() - *pinTime > DEBOUNCETIME) 242 | { 243 | *pinvalue = digitalRead(intpin); 244 | *pinTime = millis(); 245 | reply = "D0"; 246 | reply += intpin; 247 | if (*pinvalue) 248 | { 249 | reply = reply + "HIGH"; 250 | } 251 | else 252 | { 253 | reply = reply + "LOW"; 254 | } 255 | LLAP.sendMessage(reply); 256 | } 257 | } 258 | --------------------------------------------------------------------------------