/* ===== pfod Command for Menu_1 ==== pfodApp msg {.} --> {,<+4>~Garage Door Pulse Testing`0~V1|A`7~Pulse time ~ sec`10`1~1~0.1~|B<+3>~Pulse Start/Stop|C`7~Pause time ~ sec`10`1~1~0.1~|D<+3>~Start - Pause - Stop|E`0~Output is ~~Low\High~t} */ /** Select Teensy3.2 as the board to compile this sketch use Teensy 3.x Feather Adapter and Adafruit LoRa Radio FeatherWing - RFM95W On RF9x Feather Wing wire RST to pin A, CS to pin B and IRQ to pin C NOTE!! Teensy uses pin 13 as SPI SCK so DO NOT try and drive the Teensy LED as that will interfer with the SPI connection to the Radio chip */ /* (c)2014-2018 Forward Computing and Control Pty. Ltd. NSW Australia, www.forward.com.au This code is not warranted to be fit for any purpose. You may only use it at your own risk. This generated code may be freely used for both private and commercial use provided this copyright is maintained. */ #include #include // download the libraries from http://www.forward.com.au/pfod/pfodParserLibraries/index.html // pfodParser.zip V3.29+ contains pfodParser, pfodSecurity, pfodBLEBufferedSerial, pfodSMS and pfodRadio #include #include int swap01(int); // method prototype for slider end swaps // uncomment the following to get debug output to Serial #define DEBUG // use last byte of LoRa address as nodeID (need to check it is unique in this situation) const uint8_t NODE_ID = 0xb6; // this node's address, the server address for clients to connect to // Change to 434.0 or other frequency, must match the TX's, pfodClient's, freq! AND must match the range allowed in your country. #define RF95_FREQ 915.0 // add your pfod Password here for 128bit security // eg "b0Ux9akSiwKkwCtcnjTnpWp" but generate your own key, "" means no pfod password #define pfodSecurityCode "" // see http://www.forward.com.au/pfod/ArduinoWiFi_simple_pfodDevice/index.html for more information and an example // and QR image key generator. // ====================== // used to suppress warning #define pfod_MAYBE_UNUSED(x) (void)(x) //==================================== pfodRHDriver ================ // The class to interface with the low lever radio driver. Must extend from pfodRadioDrive interface // class implementation is at the bottom of this file. class pfodRHDriver : public pfodRadioDriver { public: pfodRHDriver(RHGenericDriver* _driver); // RHGenericDriver is the low lever RadioHead class used to talk to the radio module bool init(); int16_t lastRssi(); int getMode(); uint8_t getMaxMessageLength(); void setThisAddress(uint8_t addr); bool receive(uint8_t* buf, uint8_t* len); bool send(const uint8_t* data, uint8_t len); uint8_t headerTo(); uint8_t headerFrom(); uint8_t headerId(); uint8_t headerFlags(); void setHeaderTo(uint8_t to); void setHeaderFrom(uint8_t from); void setHeaderId(uint8_t id); void setHeaderFlags(uint8_t flags); private: RHGenericDriver* driver; }; //============= end of pfodRHDriver header /* Teensy 3.x w/wing */ // on RF9x wing wire RST to A, CS to B and IRQ to C #define RFM95_RST 9 // "A" #define RFM95_CS 10 // "B" #define RFM95_INT 4 // "C" // MISO, SCK, MOSI hardwired to the correct pins on the Radio feather wing // MOSI: pin 11 MISO: pin 12 SCK: pin 13 <<<< NOTE DO NOT DRIVE THE LED!! // Singleton instance of the low level radio driver RH_RF95 driver(RFM95_CS, RFM95_INT); pfodRHDriver pfodDriver(&driver); // create the pfodRadioDriver class pfodRadio radio(&pfodDriver, NODE_ID); // the high level pfod radio driver class pfodSecurity parser(""); // create a parser with menu version string to handle the pfod messages const int SLIDER_MULIPLIER = 100; // 0.1 to 1sec // give the board pins names, if you change the pin number here you will change the pin controlled int cmd_A_var = 1; // name the variable for 'Pulse time' int cmd_C_var = 10; // name the variable for 'Pause time' unsigned long cmd_E_pulseStartTime = 0; // the time when cmd_E pulse started bool cmd_E_pulseRunning = false; // true when cmd_E pulse running unsigned long cmd_E_PULSE_LENGTH = 100; // 0.1 secs this will updated by the slider const int cmd_E_pin = 6; // pin driving relay const int LED = 13; unsigned long pauseStartTime = 0; // the time when cmd_E pulse started bool pauseRunning = false; // true when cmd_E pulse running unsigned long PAUSE_LENGTH = 1000; // 1 secs this will updated by the slider bool startPauseStopRunning = false; bool timerRunning() { return cmd_E_pulseRunning || startPauseStopRunning; } // the setup routine runs once on reset: void setup() { #ifdef DEBUG Serial.begin(115200); delay(100); for (int i = 10; i > 0; i--) { Serial.print(i); Serial.print(' '); delay(500); } Serial.println(); Serial.println("Drive Board LED and relay (pin 6)"); Serial.println(); #endif cmd_E_PULSE_LENGTH = cmd_A_var * SLIDER_MULIPLIER; PAUSE_LENGTH = cmd_C_var * SLIDER_MULIPLIER; pinMode(cmd_E_pin, OUTPUT); // output for relay is initially LOW, digitalWrite(cmd_E_pin, LOW); // set output pinMode(LED, OUTPUT); // output for LED is initially LOW, digitalWrite(LED, LOW); // set output // setup radio driver #ifdef DEBUG //radio.setDebugStream(&Serial); // need to enable DEBUG in pfodRadio.cpp file as well //parser.setDebugStream(&Serial); // need to enable DEBUG in pfodSecurity.cpp file as well #endif driver.setPromiscuous(false); // only accept our address from low level driver pinMode(RFM95_RST, OUTPUT); digitalWrite(RFM95_RST, HIGH); // manual radio reset digitalWrite(RFM95_RST, LOW); delay(10); digitalWrite(RFM95_RST, HIGH); delay(10); while (!radio.init()) { #ifdef DEBUG // Serial.println("LoRa radio init failed"); #endif while (1); } #ifdef DEBUG Serial.println("LoRa radio init OK!"); #endif // setup LoRa radio // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM if (!driver.setFrequency(RF95_FREQ)) { while (1); } driver.setTxPower(23, false); // set max Tx power driver.setModemConfig(RH_RF95::Bw125Cr45Sf128); // default ~683 bytes/sec radio.listen(); // set as server listening for msg address to NODE_ID parser.connect(&radio, F(pfodSecurityCode)); // connect the parser to the i/o stream // <<<<<<<<< Your extra setup code goes here } // the loop routine runs over and over again forever: void loop() { uint8_t cmd = parser.parse(); // parse incoming data from connection // parser returns non-zero when a pfod command is fully parsed if (cmd != 0) { // have parsed a complete msg { to } #ifdef DEBUG Serial.print("Received Cmd:'"); Serial.print((char)cmd); Serial.print("' LastRSSI:"); Serial.println(driver.lastRssi()); #endif uint8_t* pfodFirstArg = parser.getFirstArg(); // may point to \0 if no arguments in this msg. pfod_MAYBE_UNUSED(pfodFirstArg); // may not be used, just suppress warning long pfodLongRtn; // used for parsing long return arguments, if any pfod_MAYBE_UNUSED(pfodLongRtn); // may not be used, just suppress warning if ('.' == cmd) { // pfodApp has connected and sent {.} , it is asking for the main menu if (!parser.isRefresh()) { sendMainMenu(); // send back the menu designed } else { sendMainMenuUpdate(); // menu is cached just send update } // now handle commands returned from button/sliders } else if ('A' == cmd) { // user moved PWM slider -- 'Pulse time' ranges from 1 to 10 // in the main Menu of Menu_1 parser.parseLong(pfodFirstArg, &pfodLongRtn); // parse first arg as a long cmd_A_var = (int)pfodLongRtn; // set variable //set the pulse time cmd_E_PULSE_LENGTH = cmd_A_var * SLIDER_MULIPLIER; // 100 to 1000 mS i.e. 0.1 to 1sec sendMainMenuUpdate(); // always send back a pfod msg otherwise pfodApp will disconnect. } else if ('B' == cmd) { // user pressed -- 'Pulse Start/Stop' // in the main Menu of Menu_1 if (!timerRunning()) { startPulse(); } parser.print(F("{}")); // change this return as needed. // always send back a pfod msg otherwise pfodApp will disconnect. } else if ('C' == cmd) { // user moved PWM slider -- 'Pause time' // in the main Menu of Menu_1 parser.parseLong(pfodFirstArg, &pfodLongRtn); // parse first arg as a long cmd_C_var = (int)pfodLongRtn; // set variable PAUSE_LENGTH = cmd_C_var * SLIDER_MULIPLIER; // 100 to 1000 mS i.e. 0.1 to 1sec sendMainMenuUpdate(); // always send back a pfod msg otherwise pfodApp will disconnect. } else if ('D' == cmd) { // user pressed -- 'Start - Pause - Stop' // in the main Menu of Menu_1 if (!timerRunning()) { startPauseStopRunning = true; startPulse(); } parser.print(F("{}")); // change this return as needed. // always send back a pfod msg otherwise pfodApp will disconnect. } else if ('!' == cmd) { // CloseConnection command closeConnection(parser.getPfodAppStream()); } else { // unknown command parser.print(F("{}")); // always send back a pfod msg otherwise pfodApp will disconnect. } } cmd_E_checkPulse(); checkPause(); } void closeConnection(Stream *io) { // nothing special here } void startPulse() { #ifdef DEBUG Serial.print("Pulse Start:"); Serial.println(millis()); #endif digitalWrite(cmd_E_pin, HIGH); // set output on digitalWrite(LED, HIGH); // set LED on cmd_E_pulseStartTime = millis(); // high pulse cmd_E_pulseRunning = true; } void cmd_E_checkPulse() { if (cmd_E_pulseRunning && ((millis() - cmd_E_pulseStartTime) > cmd_E_PULSE_LENGTH)) { #ifdef DEBUG Serial.print(" End:"); Serial.println(millis()); #endif cmd_E_pulseRunning = false; // timer finished digitalWrite(cmd_E_pin, LOW); // update output pin off digitalWrite(LED, LOW); // set LED off if (startPauseStopRunning) { startPause(); } else { #ifdef DEBUG Serial.println(); // finished #endif } } } void startPause() { #ifdef DEBUG Serial.print("PAUSE Start:"); Serial.println(millis()); #endif pauseStartTime = millis(); // high pulse pauseRunning = true; } void checkPause() { if (pauseRunning && ((millis() - pauseStartTime) > PAUSE_LENGTH)) { #ifdef DEBUG Serial.print(" End:"); Serial.println(millis()); #endif pauseRunning = false; // timer finished if (startPauseStopRunning) { startPauseStopRunning = false; // stop after next pulse startPulse(); } } } void sendMainMenu() { // !! Remember to change the parser version string // every time you edit this method parser.print(F("{,")); // start a Menu screen pfod message // send menu background, format, prompt, refresh and version parser.print(F("<+4>~Garage Door\nPulse Testing`0")); parser.sendVersion(); // send the menu version // send menu items parser.print(F("|A")); parser.print('`'); parser.print(cmd_A_var); // output the current value parser.print(F("~Pulse time ~ sec`10`1~1~0.1~")); parser.print(F("|B<+3>")); parser.print(F("~Pulse Start/Stop")); parser.print(F("|C")); parser.print('`'); parser.print(cmd_C_var); // output the current value parser.print(F("~Pause time ~ sec`10`1~1~0.1~")); parser.print(F("|D<+3>")); parser.print(F("~Start - Pause - Stop")); parser.print(F("}")); // close pfod message } void sendMainMenuUpdate() { parser.print(F("{;")); // start an Update Menu pfod message // send menu items parser.print(F("|A")); parser.print('`'); parser.print(cmd_A_var); // output the current value parser.print(F("|C")); parser.print('`'); parser.print(cmd_C_var); // output the current value parser.print(F("}")); // close pfod message // ============ end of menu =========== } // implementation of pfodRHDriver pfodRHDriver::pfodRHDriver(RHGenericDriver * _driver) { driver = _driver; } bool pfodRHDriver::init() { return driver->init(); } int16_t pfodRHDriver::lastRssi() { return driver->lastRssi(); } int pfodRHDriver::getMode() { return driver->mode(); } uint8_t pfodRHDriver::getMaxMessageLength() { return driver->maxMessageLength(); // it is important this is set } void pfodRHDriver::setThisAddress(uint8_t addr) { driver->setThisAddress(addr); } bool pfodRHDriver::receive(uint8_t* buf, uint8_t* len) { return driver->recv(buf, len); } bool pfodRHDriver::send(const uint8_t* data, uint8_t len) { return driver->send(data, len); } uint8_t pfodRHDriver::headerTo() { return driver->headerTo(); } uint8_t pfodRHDriver::headerFrom() { return driver->headerFrom(); } uint8_t pfodRHDriver::headerId() { return driver->headerId(); } uint8_t pfodRHDriver::headerFlags() { return driver->headerFlags(); } void pfodRHDriver::setHeaderTo(uint8_t to) { driver->setHeaderTo(to); } void pfodRHDriver::setHeaderFrom(uint8_t from) { driver->setHeaderFrom(from); } void pfodRHDriver::setHeaderId(uint8_t id) { driver->setHeaderId(id); } void pfodRHDriver::setHeaderFlags(uint8_t flags) { driver->setHeaderFlags(flags, 0xff); } // end of pfodRHDriver implementation int swap01(int in) { return (in == 0) ? 1 : 0; } // ============= end generated code =========