From cf232b1baae7b69ca5948a75a7ff967a90a93baf Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 12 Oct 2015 18:48:28 +0200 Subject: [PATCH] RS485 transport layer Note this is still untested as I haven't got any RS485 modules. --- libraries/MySensors/MyConfig.h | 16 +- libraries/MySensors/MySensor.h | 13 +- libraries/MySensors/core/MyTransportRS485.cpp | 320 ++++++++++++++++++ .../drivers/AltSoftSerial/AltSoftSerial.cpp | 317 +++++++++++++++++ .../drivers/AltSoftSerial/AltSoftSerial.h | 75 ++++ .../MySensors/drivers/AltSoftSerial/README.md | 9 + .../config/AltSoftSerial_Boards.h | 138 ++++++++ .../config/AltSoftSerial_Timers.h | 174 ++++++++++ .../AltSoftSerial/config/known_boards.h | 103 ++++++ .../AltSoftSerial/config/known_timers.h | 106 ++++++ .../AltSoftSerial/examples/Test/Test.pde | 38 +++ .../drivers/AltSoftSerial/keywords.txt | 4 + .../GatewaySerialRS485/GatewaySerialRS485.ino | 100 ++++++ .../MotionSensorRS485/MotionSensorRS485.ino | 89 +++++ .../examples/ParkingSensor/ParkingSensor.ino | 3 +- libraries/MySensors/keywords.txt | 3 + 16 files changed, 1499 insertions(+), 9 deletions(-) create mode 100644 libraries/MySensors/core/MyTransportRS485.cpp create mode 100644 libraries/MySensors/drivers/AltSoftSerial/AltSoftSerial.cpp create mode 100644 libraries/MySensors/drivers/AltSoftSerial/AltSoftSerial.h create mode 100644 libraries/MySensors/drivers/AltSoftSerial/README.md create mode 100644 libraries/MySensors/drivers/AltSoftSerial/config/AltSoftSerial_Boards.h create mode 100644 libraries/MySensors/drivers/AltSoftSerial/config/AltSoftSerial_Timers.h create mode 100644 libraries/MySensors/drivers/AltSoftSerial/config/known_boards.h create mode 100644 libraries/MySensors/drivers/AltSoftSerial/config/known_timers.h create mode 100644 libraries/MySensors/drivers/AltSoftSerial/examples/Test/Test.pde create mode 100644 libraries/MySensors/drivers/AltSoftSerial/keywords.txt create mode 100644 libraries/MySensors/examples/GatewaySerialRS485/GatewaySerialRS485.ino create mode 100644 libraries/MySensors/examples/MotionSensorRS485/MotionSensorRS485.ino diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index f8b0108..736b11d 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -53,11 +53,11 @@ * Radio selection and node config ***********************************/ -// Selecting radio transport is optional (for a gateway node). +// Selecting uplink transport layer is optional (for a gateway node). //#define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 - +//#define MY_RS485 // Node id defaults to AUTO (tries to fetch id from controller) #ifndef MY_NODE_ID @@ -233,6 +233,18 @@ #define MY_SIGNING_SOFT_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 #endif +/********************************** +* RS485 Driver Defaults +***********************************/ + +#ifndef MY_RS485_BAUD_RATE +#define MY_RS485_BAUD_RATE 9600 +#endif + +#ifndef MY_RS485_MAX_MESSAGE_LENGTH +#define MY_RS485_MAX_MESSAGE_LENGTH 40 +#endif + /********************************** * NRF24L01 Driver Defaults ***********************************/ diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 04f2611..11c8d64 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -34,7 +34,7 @@ #endif // Enable radio "feature" if one of the radio types was enabled -#if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) +#if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RS485) #define MY_RADIO_FEATURE #endif @@ -140,7 +140,7 @@ // RADIO -#if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) +#if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RS485) // SOFTSPI #ifdef MY_SOFTSPI #if defined(ARDUINO_ARCH_ESP8266) @@ -155,8 +155,8 @@ #include "drivers/SPIFlash/SPIFlash.cpp" #endif #include "core/MyTransport.cpp" - #if defined(MY_RADIO_NRF24) && defined(MY_RADIO_RFM69) - #error Only one radio driver can be activated + #if (defined(MY_RADIO_NRF24) && defined(MY_RADIO_RFM69)) || (defined(MY_RADIO_NRF24) && defined(MY_RS485)) || (defined(MY_RADIO_RFM69) && defined(MY_RS485)) + #error Only one forward link driver can be activated #endif #if defined(MY_RADIO_NRF24) #if defined(MY_RF24_ENABLE_ENCRYPTION) @@ -164,6 +164,9 @@ #endif #include "drivers/RF24/RF24.cpp" #include "core/MyTransportNRF24.cpp" + #elif defined(MY_RS485) + #include "drivers/AltSoftSerial/AltSoftSerial.cpp" + #include "core/MyTransportRS485.cpp" #elif defined(MY_RADIO_RFM69) #include "drivers/RFM69/RFM69.cpp" #include "core/MyTransportRFM69.cpp" @@ -184,7 +187,7 @@ #endif #if !defined(MY_GATEWAY_FEATURE) && !defined(MY_RADIO_FEATURE) - #error No radio or gateway feature activated. This means nowhere to send messages! Pretty pointless. + #error No forward link or gateway feature activated. This means nowhere to send messages! Pretty pointless. #endif diff --git a/libraries/MySensors/core/MyTransportRS485.cpp b/libraries/MySensors/core/MyTransportRS485.cpp new file mode 100644 index 0000000..68eeec5 --- /dev/null +++ b/libraries/MySensors/core/MyTransportRS485.cpp @@ -0,0 +1,320 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * ------------------------------------------------------------------------------- + * + * Copyright (c) 2013, Majenko Technologies and S.J.Hoeksma + * Copyright (c) 2015, LeoDesigner + * https://github.com/leodesigner/mysensors-serial-transport + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those + * of the authors and should not be interpreted as representing official policies, + * either expressed or implied, of Majenko Technologies. + ********************************************************************************/ + +// transport(Serial,0,-1); // serial port, node, dePin (-1 disabled) + +// Serial Transport + + +#include "MyConfig.h" +#include "MyTransport.h" +#include + + +#if defined(ARDUINO) && ARDUINO >= 100 +#include +#else +#include +#endif + +#include "MyTransport.h" + +// We only use SYS_PACK in this application +#define ICSC_SYS_PACK 0x58 + +// Receiving header information +char _header[6]; + +// Reception state machine control and storage variables +unsigned char _recPhase; +unsigned char _recPos; +unsigned char _recCommand; +unsigned char _recLen; +unsigned char _recStation; +unsigned char _recSender; +unsigned char _recCS; +unsigned char _recCalcCS; + +AltSoftSerial _dev; + + +unsigned char _nodeId; +char _data[MY_RS485_MAX_MESSAGE_LENGTH]; +uint8_t _packet_len; +unsigned char _packet_from; +bool _packet_received; + +// Packet wrapping characters, defined in standard ASCII table +#define SOH 1 +#define STX 2 +#define ETX 3 +#define EOT 4 + + + +//Reset the state machine and release the data pointer +void _serialReset(){ + _recPhase = 0; + _recPos = 0; + _recLen = 0; + _recCommand = 0; + _recCS = 0; + _recCalcCS = 0; +} + +// This is the main reception state machine. Progress through the states +// is keyed on either special control characters, or counted number of bytes +// received. If all the data is in the right format, and the calculated +// checksum matches the received checksum, AND the destination station is +// our station ID, then look for a registered command that matches the +// command code. If all the above is true, execute the command's +// function. +boolean _serialProcess() +{ + char inch; + unsigned char i; + if (!_dev.available()) return false; + + while(_dev.available()) { + inch = _dev.read(); + + switch(_recPhase) { + + // Case 0 looks for the header. Bytes arrive in the serial interface and get + // shifted through a header buffer. When the start and end characters in + // the buffer match the SOH/STX pair, and the destination station ID matches + // our ID, save the header information and progress to the next state. + case 0: + memcpy(&_header[0],&_header[1],5); + _header[5] = inch; + if ((_header[0] == SOH) && (_header[5] == STX) && (_header[1] != _header[2])) { + _recCalcCS = 0; + _recStation = _header[1]; + _recSender = _header[2]; + _recCommand = _header[3]; + _recLen = _header[4]; + + for (i=1; i<=4; i++) { + _recCalcCS += _header[i]; + } + _recPhase = 1; + _recPos = 0; + + //Check if we should process this message + //We reject the message if we are the sender + //We reject if we are not the receiver and message is not a broadcast + if ((_recSender == _nodeId) || + (_recStation != _nodeId && + _recStation != BROADCAST_ADDRESS)) { + _dev.print(" wrongid: "); + _dev.print(_recStation); + _dev.print(" - "); + _dev.println(_nodeId); + _serialReset(); + break; + } + + if (_recLen == 0) { + _recPhase = 2; + } + + } + break; + + // Case 1 receives the data portion of the packet. Read in "_recLen" number + // of bytes and store them in the _data array. + case 1: + _data[_recPos++] = inch; + _recCalcCS += inch; + if (_recPos == _recLen) { + _recPhase = 2; + } + break; + + // After the data comes a single ETX character. Do we have it? If not, + // reset the state machine to default and start looking for a new header. + case 2: + // Packet properly terminated? + if (inch == ETX) { + _recPhase = 3; + } else { + _serialReset(); + } + break; + + // Next comes the checksum. We have already calculated it from the incoming + // data, so just store the incoming checksum byte for later. + case 3: + _recCS = inch; + _recPhase = 4; + break; + + // The final state - check the last character is EOT and that the checksum matches. + // If that test passes, then look for a valid command callback to execute. + // Execute it if found. + case 4: + if (inch == EOT) { + if (_recCS == _recCalcCS) { + // First, check for system level commands. It is possible + // to register your own callback as well for system level + // commands which will be called after the system default + // hook. + + switch (_recCommand) { + case ICSC_SYS_PACK: + _packet_from = _recSender; + _packet_len = _recLen; + _packet_received = true; + break; + } + } + } + //Clear the data + _serialReset(); + //Return true, we have processed one command + return true; + break; + } + } + return true; +} + +bool transportSend(uint8_t to, const void* data, uint8_t len) +{ + const char *datap = static_cast(data); + unsigned char i; + unsigned char cs = 0; + unsigned char del; + + // This is how many times to try and transmit before failing. + unsigned char timeout = 10; + + // Let's start out by looking for a collision. If there has been anything seen in + // the last millisecond, then wait for a random time and check again. + + while (_serialProcess()) { + del = rand() % 20; + for (i = 0; i < del; i++) { + delay(1); + _serialProcess(); + } + timeout--; + if (timeout == 0) { + // Failed to transmit!!! + return false; + } + } + + // Start of header by writing multiple SOH + for(byte w=0;w<1;w++) _dev.write(SOH); + _dev.write(to); // Destination address + cs += to; + _dev.write(_nodeId); // Source address + cs += _nodeId; + _dev.write(ICSC_SYS_PACK); // Command code + cs += ICSC_SYS_PACK; + _dev.write(len); // Length of text + cs += len; + _dev.write(STX); // Start of text + for(i=0; i= TX_BUFFER_SIZE) head = 0; + while (tx_buffer_tail == head) ; // wait until space in buffer + intr_state = SREG; + cli(); + if (tx_state) { + tx_buffer[head] = b; + tx_buffer_head = head; + } else { + tx_state = 1; + tx_byte = b; + tx_bit = 0; + ENABLE_INT_COMPARE_A(); + CONFIG_MATCH_CLEAR(); + SET_COMPARE_A(GET_TIMER_COUNT() + 16); + } + SREG = intr_state; +} + + +ISR(COMPARE_A_INTERRUPT) +{ + uint8_t state, byte, bit, head, tail; + uint16_t target; + + state = tx_state; + byte = tx_byte; + target = GET_COMPARE_A(); + while (state < 9) { + target += ticks_per_bit; + bit = byte & 1; + byte >>= 1; + state++; + if (bit != tx_bit) { + if (bit) { + CONFIG_MATCH_SET(); + } else { + CONFIG_MATCH_CLEAR(); + } + SET_COMPARE_A(target); + tx_bit = bit; + tx_byte = byte; + tx_state = state; + // TODO: how to detect timing_error? + return; + } + } + if (state == 9) { + tx_state = 10; + CONFIG_MATCH_SET(); + SET_COMPARE_A(target + ticks_per_bit); + return; + } + head = tx_buffer_head; + tail = tx_buffer_tail; + if (head == tail) { + tx_state = 0; + CONFIG_MATCH_NORMAL(); + DISABLE_INT_COMPARE_A(); + } else { + tx_state = 1; + if (++tail >= TX_BUFFER_SIZE) tail = 0; + tx_buffer_tail = tail; + tx_byte = tx_buffer[tail]; + tx_bit = 0; + CONFIG_MATCH_CLEAR(); + SET_COMPARE_A(target + ticks_per_bit); + // TODO: how to detect timing_error? + } +} + +void AltSoftSerial::flushOutput(void) +{ + while (tx_state) /* wait */ ; +} + + +/****************************************/ +/** Reception **/ +/****************************************/ + + +ISR(CAPTURE_INTERRUPT) +{ + uint8_t state, bit, head; + uint16_t capture, target; + int16_t offset; + + capture = GET_INPUT_CAPTURE(); + bit = rx_bit; + if (bit) { + CONFIG_CAPTURE_FALLING_EDGE(); + rx_bit = 0; + } else { + CONFIG_CAPTURE_RISING_EDGE(); + rx_bit = 0x80; + } + state = rx_state; + if (state == 0) { + if (!bit) { + SET_COMPARE_B(capture + rx_stop_ticks); + ENABLE_INT_COMPARE_B(); + rx_target = capture + ticks_per_bit + ticks_per_bit/2; + rx_state = 1; + } + } else { + target = rx_target; + while (1) { + offset = capture - target; + if (offset < 0) break; + rx_byte = (rx_byte >> 1) | rx_bit; + target += ticks_per_bit; + state++; + if (state >= 9) { + DISABLE_INT_COMPARE_B(); + head = rx_buffer_head + 1; + if (head >= RX_BUFFER_SIZE) head = 0; + if (head != rx_buffer_tail) { + rx_buffer[head] = rx_byte; + rx_buffer_head = head; + } + CONFIG_CAPTURE_FALLING_EDGE(); + rx_bit = 0; + rx_state = 0; + return; + } + } + rx_target = target; + rx_state = state; + } + //if (GET_TIMER_COUNT() - capture > ticks_per_bit) AltSoftSerial::timing_error = true; +} + +ISR(COMPARE_B_INTERRUPT) +{ + uint8_t head, state, bit; + + DISABLE_INT_COMPARE_B(); + CONFIG_CAPTURE_FALLING_EDGE(); + state = rx_state; + bit = rx_bit ^ 0x80; + while (state < 9) { + rx_byte = (rx_byte >> 1) | bit; + state++; + } + head = rx_buffer_head + 1; + if (head >= RX_BUFFER_SIZE) head = 0; + if (head != rx_buffer_tail) { + rx_buffer[head] = rx_byte; + rx_buffer_head = head; + } + rx_state = 0; + CONFIG_CAPTURE_FALLING_EDGE(); + rx_bit = 0; +} + + + +int AltSoftSerial::read(void) +{ + uint8_t head, tail, out; + + head = rx_buffer_head; + tail = rx_buffer_tail; + if (head == tail) return -1; + if (++tail >= RX_BUFFER_SIZE) tail = 0; + out = rx_buffer[tail]; + rx_buffer_tail = tail; + return out; +} + +int AltSoftSerial::peek(void) +{ + uint8_t head, tail; + + head = rx_buffer_head; + tail = rx_buffer_tail; + if (head == tail) return -1; + return rx_buffer[tail]; +} + +int AltSoftSerial::available(void) +{ + uint8_t head, tail; + + head = rx_buffer_head; + tail = rx_buffer_tail; + if (head >= tail) return head - tail; + return RX_BUFFER_SIZE + head - tail; +} + +void AltSoftSerial::flushInput(void) +{ + rx_buffer_head = rx_buffer_tail; +} + + +#ifdef ALTSS_USE_FTM0 +void ftm0_isr(void) +{ + uint32_t flags = FTM0_STATUS; + FTM0_STATUS = 0; + if (flags & (1<<5)) altss_capture_interrupt(); + if (flags & (1<<6)) altss_compare_a_interrupt(); + if (flags & (1<<0)) altss_compare_b_interrupt(); +} +#endif + diff --git a/libraries/MySensors/drivers/AltSoftSerial/AltSoftSerial.h b/libraries/MySensors/drivers/AltSoftSerial/AltSoftSerial.h new file mode 100644 index 0000000..1e86e50 --- /dev/null +++ b/libraries/MySensors/drivers/AltSoftSerial/AltSoftSerial.h @@ -0,0 +1,75 @@ +/* An Alternative Software Serial Library + * http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html + * Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef AltSoftSerial_h +#define AltSoftSerial_h + +#include + +#if ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#include "pins_arduino.h" +#endif + +#if defined(__arm__) && defined(CORE_TEENSY) +#define ALTSS_BASE_FREQ F_BUS +#else +#define ALTSS_BASE_FREQ F_CPU +#endif + +class AltSoftSerial : public Stream +{ +public: + AltSoftSerial() { } + ~AltSoftSerial() { end(); } + static void begin(uint32_t baud) { init((ALTSS_BASE_FREQ + baud / 2) / baud); } + static void end(); + int peek(); + int read(); + int available(); +#if ARDUINO >= 100 + size_t write(uint8_t byte) { writeByte(byte); return 1; } + void flush() { flushOutput(); } +#else + void write(uint8_t byte) { writeByte(byte); } + void flush() { flushInput(); } +#endif + using Print::write; + static void flushInput(); + static void flushOutput(); + // for drop-in compatibility with NewSoftSerial, rxPin & txPin ignored + //AltSoftSerial(uint8_t rxPin, uint8_t txPin, bool inverse = false) { } + bool listen() { return false; } + bool isListening() { return true; } + bool overflow() { bool r = timing_error; timing_error = false; return r; } + static int library_version() { return 1; } + static void enable_timer0(bool) { } + static bool timing_error; +private: + static void init(uint32_t cycles_per_bit); + static void writeByte(uint8_t byte); +}; + +#endif diff --git a/libraries/MySensors/drivers/AltSoftSerial/README.md b/libraries/MySensors/drivers/AltSoftSerial/README.md new file mode 100644 index 0000000..35c290d --- /dev/null +++ b/libraries/MySensors/drivers/AltSoftSerial/README.md @@ -0,0 +1,9 @@ +#AltSoftSerial Library# + +Improved software emulated serial, using hardware timers for precise signal +timing and availability of CPU time for other libraries to respond to interrupts +during data AltSoftSerial data transmission and reception. + +http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html + +![AltSoftSerial on Teensy 2.0](http://www.pjrc.com/teensy/td_libs_AltSoftSerial_2.jpg) diff --git a/libraries/MySensors/drivers/AltSoftSerial/config/AltSoftSerial_Boards.h b/libraries/MySensors/drivers/AltSoftSerial/config/AltSoftSerial_Boards.h new file mode 100644 index 0000000..1ccbf68 --- /dev/null +++ b/libraries/MySensors/drivers/AltSoftSerial/config/AltSoftSerial_Boards.h @@ -0,0 +1,138 @@ +/* An Alternative Software Serial Library + * http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html + * Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +// Teensy 2.0 +// +#if defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY) + + //#define ALTSS_USE_TIMER1 + //#define INPUT_CAPTURE_PIN 22 // receive + //#define OUTPUT_COMPARE_A_PIN 14 // transmit + //#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM + //#define OUTPUT_COMPARE_C_PIN 4 // unusable PWM + + #define ALTSS_USE_TIMER3 + #define INPUT_CAPTURE_PIN 10 // receive + #define OUTPUT_COMPARE_A_PIN 9 // transmit + + + +// Teensy++ 2.0 +// +#elif defined(__AVR_AT90USB1286__) && defined(CORE_TEENSY) + + #define ALTSS_USE_TIMER1 + #define INPUT_CAPTURE_PIN 4 // receive + #define OUTPUT_COMPARE_A_PIN 25 // transmit + #define OUTPUT_COMPARE_B_PIN 26 // unusable PWM + #define OUTPUT_COMPARE_C_PIN 27 // unusable PWM + + //#define ALTSS_USE_TIMER3 + //#define INPUT_CAPTURE_PIN 17 // receive + //#define OUTPUT_COMPARE_A_PIN 16 // transmit + //#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM + //#define OUTPUT_COMPARE_C_PIN 14 // unusable PWM + + +// Teensy 3.0 & 3.1 +// +#elif defined(__MK20DX128__) || defined(__MK20DX256__) + #define ALTSS_USE_FTM0 + #define INPUT_CAPTURE_PIN 20 // receive (FTM0_CH5) + #define OUTPUT_COMPARE_A_PIN 21 // transmit (FTM0_CH6) + #define OUTPUT_COMPARE_B_PIN 22 // unusable PWM (FTM0_CH0) + #define OUTPUT_COMPARE_C_PIN 23 // PWM usable fixed freq + #define OUTPUT_COMPARE_D_PIN 5 // PWM usable fixed freq + #define OUTPUT_COMPARE_E_PIN 6 // PWM usable fixed freq + #define OUTPUT_COMPARE_F_PIN 9 // PWM usable fixed freq + #define OUTPUT_COMPARE_G_PIN 10 // PWM usable fixed freq + + +// Wiring-S +// +#elif defined(__AVR_ATmega644P__) && defined(WIRING) + + #define ALTSS_USE_TIMER1 + #define INPUT_CAPTURE_PIN 6 // receive + #define OUTPUT_COMPARE_A_PIN 5 // transmit + #define OUTPUT_COMPARE_B_PIN 4 // unusable PWM + + + +// Arduino Uno, Duemilanove, LilyPad, etc +// +#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) + + #define ALTSS_USE_TIMER1 + #define INPUT_CAPTURE_PIN 8 // receive + #define OUTPUT_COMPARE_A_PIN 9 // transmit + #define OUTPUT_COMPARE_B_PIN 10 // unusable PWM + + +// Arduino Leonardo & Yun (from Cristian Maglie) +// +#elif defined(ARDUINO_AVR_YUN) || defined(ARDUINO_AVR_LEONARDO) || defined(__AVR_ATmega32U4__) + + //#define ALTSS_USE_TIMER1 + //#define INPUT_CAPTURE_PIN 4 // receive + //#define OUTPUT_COMPARE_A_PIN 9 // transmit + //#define OUTPUT_COMPARE_B_PIN 10 // unusable PWM + //#define OUTPUT_COMPARE_C_PIN 11 // unusable PWM + + #define ALTSS_USE_TIMER3 + #define INPUT_CAPTURE_PIN 13 // receive + #define OUTPUT_COMPARE_A_PIN 5 // transmit + + +// Arduino Mega +// +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + + //#define ALTSS_USE_TIMER4 + //#define INPUT_CAPTURE_PIN 49 // receive + //#define OUTPUT_COMPARE_A_PIN 6 // transmit + //#define OUTPUT_COMPARE_B_PIN 7 // unusable PWM + //#define OUTPUT_COMPARE_C_PIN 8 // unusable PWM + + #define ALTSS_USE_TIMER5 + #define INPUT_CAPTURE_PIN 48 // receive + #define OUTPUT_COMPARE_A_PIN 46 // transmit + #define OUTPUT_COMPARE_B_PIN 45 // unusable PWM + #define OUTPUT_COMPARE_C_PIN 44 // unusable PWM + + + +// Sanguino +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) + #define ALTSS_USE_TIMER1 + #define INPUT_CAPTURE_PIN 14 // receive + #define OUTPUT_COMPARE_A_PIN 13 // transmit + #define OUTPUT_COMPARE_B_PIN 12 // unusable PWM + + +// Unknown board +#else +#error "Please define your board timer and pins" +#endif + diff --git a/libraries/MySensors/drivers/AltSoftSerial/config/AltSoftSerial_Timers.h b/libraries/MySensors/drivers/AltSoftSerial/config/AltSoftSerial_Timers.h new file mode 100644 index 0000000..4270cd8 --- /dev/null +++ b/libraries/MySensors/drivers/AltSoftSerial/config/AltSoftSerial_Timers.h @@ -0,0 +1,174 @@ +/* An Alternative Software Serial Library + * http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html + * Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#if defined(ALTSS_USE_TIMER1) + #define CONFIG_TIMER_NOPRESCALE() (TIMSK1 = 0, TCCR1A = 0, TCCR1B = (1< + +// AltSoftSerial always uses these pins: +// +// Board Transmit Receive PWM Unusable +// ----- -------- ------- ------------ +// Teensy 3.0 & 3.1 21 20 22 +// Teensy 2.0 9 10 (none) +// Teensy++ 2.0 25 4 26, 27 +// Arduino Uno 9 8 10 +// Arduino Leonardo 5 13 (none) +// Arduino Mega 46 48 44, 45 +// Wiring-S 5 6 4 +// Sanguino 13 14 12 + +AltSoftSerial altSerial; + +void setup() { + Serial.begin(9600); + while (!Serial) ; // wait for Arduino Serial Monitor to open + Serial.println("AltSoftSerial Test Begin"); + altSerial.begin(9600); + altSerial.println("Hello World"); +} + +void loop() { + char c; + + if (Serial.available()) { + c = Serial.read(); + altSerial.print(c); + } + if (altSerial.available()) { + c = altSerial.read(); + Serial.print(c); + } +} + diff --git a/libraries/MySensors/drivers/AltSoftSerial/keywords.txt b/libraries/MySensors/drivers/AltSoftSerial/keywords.txt new file mode 100644 index 0000000..f2bf10d --- /dev/null +++ b/libraries/MySensors/drivers/AltSoftSerial/keywords.txt @@ -0,0 +1,4 @@ +AltSoftSerial KEYWORD1 +active KEYWORD2 +overflow KEYWORD2 +library_version KEYWORD2 diff --git a/libraries/MySensors/examples/GatewaySerialRS485/GatewaySerialRS485.ino b/libraries/MySensors/examples/GatewaySerialRS485/GatewaySerialRS485.ino new file mode 100644 index 0000000..b058d83 --- /dev/null +++ b/libraries/MySensors/examples/GatewaySerialRS485/GatewaySerialRS485.ino @@ -0,0 +1,100 @@ + /** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * The RS485 Gateway prints data received from sensors on the serial link. + * The gateway accepts input on seral which will be sent out on + * the RS485 link. + * + * Wire connections (OPTIONAL): + * - Inclusion button should be connected between digital pin 3 and GND + * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series + * + * LEDs (OPTIONAL): + * - To use the feature, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h + * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved + * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly + * - ERR (red) - fast blink on error during transmission error or recieve crc error + * + * The gateway uses AltSoftSerial to handle two serial links + * on one Arduino. Use the following pins for RS485 link + * + * Board Transmit Receive PWM Unusable + * ----- -------- ------- ------------ + * Teensy 3.0 & 3.1 21 20 22 + * Teensy 2.0 9 10 (none) + * Teensy++ 2.0 25 4 26, 27 + * Arduino Uno 9 8 10 + * Arduino Leonardo 5 13 (none) + * Arduino Mega 46 48 44, 45 + * Wiring-S 5 6 4 + * Sanguino 13 14 12 + * + */ + +// Enable debug prints to serial monitor +#define MY_DEBUG + +// Enable RS485 transport layer +#define MY_RS485 + +// Set RS485 baud rate to use +#define MY_RS485_BAUD_RATE 9600 + +// Enable serial gateway +#define MY_GATEWAY_SERIAL + +// Flash leds on rx/tx/err +#define MY_LEDS_BLINKING_FEATURE +// Set blinking period +#define MY_DEFAULT_LED_BLINK_PERIOD 300 + +// Enable inclusion mode +#define MY_INCLUSION_MODE_FEATURE +// Enable Inclusion mode button on gateway +#define MY_INCLUSION_BUTTON_FEATURE +// Set inclusion mode duration (in seconds) +#define MY_INCLUSION_MODE_DURATION 60 +// Digital pin used for inclusion mode button +#define MY_INCLUSION_MODE_BUTTON_PIN 3 + +#define MY_DEFAULT_ERR_LED_PIN 7 // Error led pin +#define MY_DEFAULT_RX_LED_PIN 8 // Receive led pin +#define MY_DEFAULT_TX_LED_PIN 9 // the PCB, on board LED + +#include +#include + +void setup() { + // Setup locally attached sensors +} + +void presentation() { + // Present locally attached sensors +} + +void loop() { + // Send locally attached sensor data here +} + + + + + diff --git a/libraries/MySensors/examples/MotionSensorRS485/MotionSensorRS485.ino b/libraries/MySensors/examples/MotionSensorRS485/MotionSensorRS485.ino new file mode 100644 index 0000000..dab57b7 --- /dev/null +++ b/libraries/MySensors/examples/MotionSensorRS485/MotionSensorRS485.ino @@ -0,0 +1,89 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * + * DESCRIPTION + * This is an example of sensors using RS485 as transport layer + * + * Motion Sensor example using HC-SR501 + * http://www.mysensors.org/build/motion + * + * The transport uses AltSoftSerial to handle two serial links + * on one Arduino. Use the following pins for RS485 link + * + * Board Transmit Receive PWM Unusable + * ----- -------- ------- ------------ + * Teensy 3.0 & 3.1 21 20 22 + * Teensy 2.0 9 10 (none) + * Teensy++ 2.0 25 4 26, 27 + * Arduino Uno 9 8 10 + * Arduino Leonardo 5 13 (none) + * Arduino Mega 46 48 44, 45 + * Wiring-S 5 6 4 + * Sanguino 13 14 12 * + * + */ + + +// Enable RS485 transport layer +#define MY_RS485 + +// Set RS485 baud rate to use +#define MY_RS485_BAUD_RATE 9600 + +#include +#include + +unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds) +#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your motion sensor. (Only 2 and 3 generates interrupt!) +#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway) +#define CHILD_ID 1 // Id of the sensor child + +// Initialize motion message +MyMessage msg(CHILD_ID, V_TRIPPED); + +void setup() +{ + pinMode(DIGITAL_INPUT_SENSOR, INPUT); // sets the motion sensor digital pin as input +} + +void presentation() { + // Send the sketch version information to the gateway and Controller + sendSketchInfo("Motion Sensor", "1.0"); + + // Register all sensors to gw (they will be created as child devices) + present(CHILD_ID, S_MOTION); +} + +void loop() +{ + // Read digital motion value + boolean tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH; + + Serial.println(tripped); + send(msg.set(tripped?"1":"0")); // Send tripped value to gw + + // Sleep until interrupt comes in on motion sensor. Send update every two minute. + sleep(INTERRUPT,CHANGE, SLEEP_TIME); +} + + diff --git a/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino b/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino index 9d617f3..77ec7d0 100644 --- a/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino +++ b/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino @@ -68,7 +68,7 @@ // Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest // example for more information on possible values. -Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, NEO_PIN, NEO_GRB + NEO_KHZ400); +Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, NEO_PIN, NEO_GRB + NEO_KHZ800); NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance. @@ -107,7 +107,6 @@ void presentation() { void loop() { unsigned long now = millis(); - unsigned int fullDist = (sonar.ping_median() / US_ROUNDTRIP_CM); // Serial.println(fullDist); int displayDist = min(fullDist, MAX_DISTANCE); diff --git a/libraries/MySensors/keywords.txt b/libraries/MySensors/keywords.txt index 2b6614c..522dbd5 100644 --- a/libraries/MySensors/keywords.txt +++ b/libraries/MySensors/keywords.txt @@ -96,3 +96,6 @@ MY_ESP8266_PASSWORD LITERAL1 MY_IP_GATEWAY_ADDRESS LITERAL1 MY_IP_SUBNET_ADDRESS LITERAL1 MY_W5100_SPI_EN LITERAL1 +MY_RS485 LITERAL1 +MY_RS485_BAUD_RATE LITERAL1 +MY_RS485_MAX_MESSAGE_LENGTH LITERAL1 \ No newline at end of file