Refactor RaspberryPi port
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
#############################################################################
|
||||
#
|
||||
# Makefile for MySensors
|
||||
#
|
||||
# Description:
|
||||
# ------------
|
||||
# use make all and make install to install the gateway
|
||||
#
|
||||
|
||||
CONFIG_FILE=Makefile.inc
|
||||
|
||||
include $(CONFIG_FILE)
|
||||
|
||||
GATEWAY=examples_RPi/MySGateway
|
||||
GATEWAY_SOURCES=examples_RPi/MySGateway.cpp
|
||||
GATEWAY_OBJECTS=$(patsubst %.cpp,%.o,$(GATEWAY_SOURCES))
|
||||
DEPS+=$(patsubst %.cpp,%.d,$(GATEWAY_SOURCES))
|
||||
|
||||
CINCLUDE=-I. -I./core -I./drivers/Linux -I$(RF24H_LIB_DIR)
|
||||
|
||||
.PHONY: all gateway cleanconfig clean install uninstall force
|
||||
|
||||
all: $(GATEWAY)
|
||||
|
||||
# Gateway Build
|
||||
$(GATEWAY): $(GATEWAY_OBJECTS)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(GATEWAY_OBJECTS)
|
||||
|
||||
# Include all .d files
|
||||
-include $(DEPS)
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) $(CINCLUDE) -MMD -c -o $@ $<
|
||||
|
||||
# clear configuration files
|
||||
cleanconfig:
|
||||
@echo "[Cleaning configuration]"
|
||||
rm -rf $(CONFIG_FILE)
|
||||
|
||||
# clear build files
|
||||
clean:
|
||||
@echo "[Cleaning]"
|
||||
rm -rf build $(GATEWAY_OBJECTS) $(GATEWAY) $(DEPS)
|
||||
|
||||
$(CONFIG_FILE):
|
||||
@echo "[Running configure]"
|
||||
@./configure --no-clean
|
||||
|
||||
install: all install-gateway install-initscripts
|
||||
|
||||
install-gateway:
|
||||
@echo "Installing $(GATEWAY) to $(GATEWAY_DIR)"
|
||||
@install -m 0755 $(GATEWAY) $(GATEWAY_DIR)
|
||||
|
||||
install-initscripts:
|
||||
if [[ `systemctl` =~ -\.mount ]]; then \
|
||||
install -m0644 initscripts/mysgateway.systemd /etc/systemd/system/mysgateway.service && \
|
||||
sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/systemd/system/mysgateway.service && \
|
||||
systemctl daemon-reload; \
|
||||
elif [[ -f /etc/init.d/cron && ! -h /etc/init.d/cron ]]; then \
|
||||
install -m0755 initscripts/mysgateway.sysvinit /etc/init.d/mysgateway && \
|
||||
sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/init.d/mysgateway; \
|
||||
fi
|
||||
+17
-8
@@ -413,7 +413,7 @@
|
||||
#elif defined(RASPBERRYPI_ARCH)
|
||||
#include <RF24.h>
|
||||
#include <RF24_config.h>
|
||||
#ifdef __PI_BPLUS
|
||||
#ifdef __RPI_BPLUS
|
||||
#define MY_RF24_CE_PIN RPI_BPLUS_GPIO_J8_22
|
||||
#define MY_RF24_CS_PIN RPI_BPLUS_GPIO_J8_24
|
||||
#else
|
||||
@@ -716,25 +716,34 @@
|
||||
#endif
|
||||
|
||||
/**************************************
|
||||
* RaspberryPi Settings
|
||||
* Linux Settings
|
||||
***************************************/
|
||||
|
||||
/**
|
||||
* @def MY_RASPBERRYPI_TTY_NAME
|
||||
* @def MY_LINUX_TTY_NAME
|
||||
* @brief Set the name of predictable tty
|
||||
*/
|
||||
#ifndef MY_RASPBERRYPI_TTY_NAME
|
||||
#define MY_RASPBERRYPI_TTY_NAME /dev/ttyMySensorsGateway
|
||||
#ifndef MY_LINUX_TTY_NAME
|
||||
#define MY_LINUX_TTY_NAME "/dev/ttyMySensorsGateway"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def MY_RASPBERRYPI_TTY_GROUPNAME
|
||||
* @def MY_LINUX_TTY_GROUPNAME
|
||||
* @brief Set the group name for the raw tty
|
||||
*/
|
||||
#ifndef MY_RASPBERRYPI_TTY_GROUPNAME
|
||||
#define MY_RASPBERRYPI_TTY_GROUPNAME tty
|
||||
#ifndef MY_LINUX_TTY_GROUPNAME
|
||||
#define MY_LINUX_TTY_GROUPNAME tty
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def MY_LINUX_CONFIG_FILE
|
||||
* @brief Set the filepath for the gateway config file
|
||||
*
|
||||
* For now the configuration file is only used to store the emulated eeprom state
|
||||
*/
|
||||
#ifndef MY_LINUX_CONFIG_FILE
|
||||
#define MY_LINUX_CONFIG_FILE "/etc/MySensorGateway.cfg"
|
||||
#endif
|
||||
|
||||
// Doxygen specific constructs, not included when built normally
|
||||
// This is used to enable disabled macros/definitions to be included in the documentation as well.
|
||||
|
||||
+24
-45
@@ -52,6 +52,10 @@
|
||||
#define MY_NODE_TYPE "NODE"
|
||||
#endif
|
||||
|
||||
#if defined(MY_GATEWAY_RASPBERRYPI)
|
||||
#define MY_GATEWAY_LINUX
|
||||
#endif
|
||||
|
||||
// Enable radio "feature" if one of the radio types was enabled
|
||||
#if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RS485)
|
||||
#define MY_RADIO_FEATURE
|
||||
@@ -68,7 +72,7 @@
|
||||
#elif defined(ARDUINO_ARCH_AVR)
|
||||
#include "core/MyHwATMega328.cpp"
|
||||
#elif defined(ARDUINO_ARCH_SAMD)
|
||||
#include "core/MyHwSAMD.cpp"
|
||||
#include "core/MyHwSAMD.cpp"
|
||||
#elif defined(LINUX_ARCH_GENERIC)
|
||||
// Remove PSTR macros from debug prints
|
||||
#undef PSTR
|
||||
@@ -80,6 +84,7 @@
|
||||
#define snprintf_P(...) snprintf( __VA_ARGS__ )
|
||||
#define memcpy_P memcpy
|
||||
#define pgm_read_dword(x) (*x)
|
||||
#define pgm_read_byte_near(x) (*x)
|
||||
#include "core/MyHwLinuxGeneric.cpp"
|
||||
#endif
|
||||
|
||||
@@ -197,7 +202,7 @@
|
||||
#define MY_REPEATER_FEATURE
|
||||
#endif
|
||||
// GATEWAY - COMMON FUNCTIONS
|
||||
// We only support MQTT Client using W5100 and ESP8266 at the moment
|
||||
// We support MQTT Client using W5100, ESP8266 and Linux
|
||||
#if !(defined(MY_CONTROLLER_URL_ADDRESS) || defined(MY_CONTROLLER_IP_ADDRESS))
|
||||
#error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS
|
||||
#endif
|
||||
@@ -208,18 +213,25 @@
|
||||
#if !defined(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX)
|
||||
#error You must specify a topic subscribe prefix MY_MQTT_SUBSCRIBE_TOPIC_PREFIX for this MQTT client
|
||||
#endif
|
||||
#if !defined(MY_MQTT_CLIENT_ID)
|
||||
|
||||
#if !defined(MY_MQTT_CLIENT_ID)
|
||||
#error You must define a unique MY_MQTT_CLIENT_ID for this MQTT client
|
||||
#endif
|
||||
|
||||
#include "drivers/PubSubClient/PubSubClient.cpp"
|
||||
#include "core/MyGatewayTransport.cpp"
|
||||
#include "core/MyProtocolMySensors.cpp"
|
||||
|
||||
#if defined(MY_GATEWAY_LINUX)
|
||||
#include "drivers/Linux/EthernetClient.cpp"
|
||||
#include "drivers/Linux/EthernetServer.cpp"
|
||||
#include "drivers/Linux/IPAddress.cpp"
|
||||
#endif
|
||||
#include "drivers/PubSubClient/PubSubClient.cpp"
|
||||
#include "core/MyGatewayTransportMQTTClient.cpp"
|
||||
#elif defined(MY_GATEWAY_FEATURE)
|
||||
// GATEWAY - COMMON FUNCTIONS
|
||||
#include "core/MyGatewayTransport.cpp"
|
||||
|
||||
// We currently only support one protocol at the moment, enable it.
|
||||
#include "core/MyProtocolMySensors.cpp"
|
||||
|
||||
// GATEWAY - CONFIGURATION
|
||||
@@ -227,9 +239,6 @@
|
||||
// We assume that a gateway having a radio also should act as repeater
|
||||
#define MY_REPEATER_FEATURE
|
||||
#endif
|
||||
#if defined(MY_GATEWAY_RASPBERRYPI)
|
||||
#define MY_GATEWAY_LINUX
|
||||
#endif
|
||||
#if defined(MY_CONTROLLER_IP_ADDRESS)
|
||||
#define MY_GATEWAY_CLIENT_MODE
|
||||
#endif
|
||||
@@ -238,23 +247,16 @@
|
||||
#endif
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
// GATEWAY - ESP8266
|
||||
#if defined(MY_GATEWAY_MQTT_CLIENT)
|
||||
#include "drivers/pubsubclient/src/PubSubClient.cpp"
|
||||
#include "core/MyGatewayTransportMQTTClient.cpp"
|
||||
#else
|
||||
#include "core/MyGatewayTransportEthernet.cpp"
|
||||
#endif
|
||||
#include "core/MyGatewayTransportEthernet.cpp"
|
||||
#elif defined(MY_GATEWAY_LINUX)
|
||||
// GATEWAY - Generic Linux (RaspberryPi, BBB)
|
||||
#include "core/MyGatewayTransportEthernetLinux.cpp"
|
||||
// GATEWAY - Generic Linux (RaspberryPi, BBB, ...)
|
||||
#include "drivers/Linux/EthernetClient.cpp"
|
||||
#include "drivers/Linux/EthernetServer.cpp"
|
||||
#include "drivers/Linux/IPAddress.cpp"
|
||||
#include "core/MyGatewayTransportEthernet.cpp"
|
||||
#elif defined(MY_GATEWAY_W5100)
|
||||
// GATEWAY - W5100
|
||||
#if defined(MY_GATEWAY_MQTT_CLIENT)
|
||||
#include "drivers/pubsubclient/src/PubSubClient.cpp"
|
||||
#include "core/MyGatewayTransportMQTTClient.cpp"
|
||||
#else
|
||||
#include "core/MyGatewayTransportEthernet.cpp"
|
||||
#endif
|
||||
#include "core/MyGatewayTransportEthernet.cpp"
|
||||
#elif defined(MY_GATEWAY_ENC28J60)
|
||||
// GATEWAY - ENC28J60
|
||||
#if defined(MY_USE_UDP)
|
||||
@@ -264,32 +266,9 @@
|
||||
#elif defined(MY_GATEWAY_SERIAL)
|
||||
// GATEWAY - SERIAL
|
||||
#include "core/MyGatewayTransportSerial.cpp"
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// GATEWAY - MQTT
|
||||
#if defined(MY_GATEWAY_MQTT_CLIENT) && !defined(MY_GATEWAY_LINUX)
|
||||
// GATEWAY - COMMON FUNCTIONS
|
||||
// We only support MQTT Client using W5100, ESP8266 or Linux/RasperryPi at the moment
|
||||
#if !(defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_LINUX))
|
||||
#error We only support MQTT Client using W5100, ESP8266 or Linux/RasperryPi at the moment
|
||||
#endif
|
||||
|
||||
#if !(defined(MY_CONTROLLER_URL_ADDRESS) || defined(MY_CONTROLLER_IP_ADDRESS))
|
||||
#error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS
|
||||
#endif
|
||||
|
||||
#if !defined(MY_MQTT_PUBLISH_TOPIC_PREFIX)
|
||||
#error You must specify a topic publish prefix MY_MQTT_PUBLISH_TOPIC_PREFIX for this MQTT client
|
||||
#endif
|
||||
#if !defined(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX)
|
||||
#error You must specify a topic subscribe prefix MY_MQTT_SUBSCRIBE_TOPIC_PREFIX for this MQTT client
|
||||
#endif
|
||||
#if !defined(MY_MQTT_CLIENT_ID)
|
||||
#error You must define a unique MY_MQTT_CLIENT_ID for this MQTT client
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// RADIO
|
||||
#if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RS485)
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
#!/bin/bash
|
||||
# This version is heavily based on the work of mz-fuzzy (https://github.com/mz-fuzzy)
|
||||
# adapted to work with MySensors project.
|
||||
# Original work: https://github.com/TMRh20/RF24/blob/master/configure
|
||||
|
||||
function help {
|
||||
cat <<EOF
|
||||
configure script for MySensors gateway.
|
||||
Options:
|
||||
|
||||
Help:
|
||||
-h, --help print this message
|
||||
|
||||
Driver options:
|
||||
--driver=[SPIDEV|MRAA|RPi|LittleWire]
|
||||
Driver for RF24 library. [configure autodetected]
|
||||
|
||||
Building options:
|
||||
--os=[LINUX|DARWIN] Operating system. [configure autodetected]
|
||||
--soc=[BCM2835|BCM2836|AM33XX|A10|A13|A20|H3]
|
||||
SoC type to be used. [configure autodetected]
|
||||
--cpu-flags=<CXXFLAGS> CPU defining/optimizing flags to be used. [configure autodetected]
|
||||
--extra-cxxflags=<CXXFLAGS> Extra C flags passed to C/C++ compilation. []
|
||||
--extra-ldflags=<LDFLAGS> Extra C flags passed to linking. []
|
||||
--libname=<LIBNAME> Library name. [rf24]
|
||||
--cxx_compiler=<CXX> C++ compiler [arm-linux-gnueabihf-g++][g++]
|
||||
--no-clean Don't clean previous build artifacts.
|
||||
--rf24h-lib-dir RF24 library files directory.
|
||||
|
||||
Installation options:
|
||||
--prefix=<PREFIX> Installation prefix path. [/usr/local]
|
||||
--gateway-dir=<DIR> Gateway files installation directory. [PREFIX/bin]
|
||||
|
||||
MySensors options:
|
||||
--my-debug Enables debug.
|
||||
--my-gateway-type=[ethernet|mqtt]
|
||||
Gateway type, default to ethernet.
|
||||
--my-config-file=<FILE> Config file path. [/etc/MySensorGateway.cfg]
|
||||
--my-rf24-enable Enables RF24 radio.
|
||||
--my-rf24-channel=<0-125> RF channel for the sensor net, 0-125.
|
||||
--my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW]
|
||||
RF24 PA level.
|
||||
--my-controller-url-address=<URL>
|
||||
Controller or MQTT broker url.
|
||||
--my-controller-ip-address=<IP>
|
||||
Controller or MQTT broker ip.
|
||||
Use commas instead of points. Example: 127,0,0,1
|
||||
--my-port Controller or MQTT broker port.
|
||||
--my-mqtt-client-id=<ID> MQTT client id.
|
||||
--my-mqtt-publish-topic-prefix=<PREFIX>
|
||||
MQTT publish topic prefix.
|
||||
--my-mqtt-subscribe-topic-prefix=<PREFIX>
|
||||
MQTT subscribe topic prefix.
|
||||
--my-rf24-irq-pin Pin number connected to nRF24L01 IRQ pin.
|
||||
--my-rx-message-buffer-size Buffer size for incoming messages when using rf24 interrupts.
|
||||
Default set to 20.
|
||||
EOF
|
||||
}
|
||||
|
||||
function die {
|
||||
echo "[ERROR] $1"
|
||||
exit $2
|
||||
}
|
||||
|
||||
function detect_rpi_revision {
|
||||
# get PI Revision from cpuinfo
|
||||
local pirev=$(eval "cat /proc/cpuinfo 2>/dev/null | grep Revision | cut -f 2 -d ':' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$$//'")
|
||||
echo ${pirev}
|
||||
}
|
||||
|
||||
function detect_machine {
|
||||
local cpu=$(eval "uname -m 2>/dev/null")
|
||||
local machine=$(eval "cat /sys/firmware/devicetree/base/model 2>/dev/null")
|
||||
local hardware=$(eval "grep sunxi_platform /sys/class/sunxi_info/sys_info 2>/dev/null | sed 's/^.*: \(.*\)$/\1/'")
|
||||
if [ -z "$hardware" ]; then
|
||||
local hardware=$(eval "grep Hardware /proc/cpuinfo 2>/dev/null | sed 's/^.*: \(.*\)$/\1/'")
|
||||
fi
|
||||
local soc="unknown"
|
||||
local tp="unknown"
|
||||
local rev="unknown"
|
||||
|
||||
if [ -z "$cpu" ]; then
|
||||
cpu="unknown"
|
||||
fi
|
||||
|
||||
case $hardware in
|
||||
BCM2708)
|
||||
soc="BCM2835"
|
||||
if [[ $machine == "Raspberry"* ]]; then
|
||||
tp="RPi"
|
||||
rev=($(detect_rpi_revision))
|
||||
fi
|
||||
;;
|
||||
BCM2709)
|
||||
soc="BCM2836"
|
||||
if [[ $machine == "Raspberry"* ]]; then
|
||||
rev=($(detect_rpi_revision))
|
||||
if [[ $rev == "a02082" || $rev == "a22082" ]]; then
|
||||
tp="RPi3"
|
||||
else
|
||||
tp="Rpi2"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
sun4i|Sun4iw1p1)
|
||||
soc="A10"
|
||||
;;
|
||||
sun5i|Sun4iw2p1)
|
||||
soc="A13"
|
||||
;;
|
||||
Sun4iw2p2)
|
||||
soc="A12"
|
||||
;;
|
||||
Sun4iw2p3)
|
||||
soc="A10s"
|
||||
;;
|
||||
sun6i|Sun8iw1p1)
|
||||
soc="A31"
|
||||
;;
|
||||
Sun8iw1p2)
|
||||
soc="A31s"
|
||||
;;
|
||||
sun7i|Sun8iw2p1)
|
||||
soc="A20"
|
||||
if [[ $machine == "Banana Pi"* ]]; then
|
||||
tp="BananaPi"
|
||||
elif [[ $machine == "Banana Pro"* ]]; then
|
||||
tp="BananaPro"
|
||||
fi
|
||||
;;
|
||||
sun8i|Sun8iw7p1)
|
||||
soc="H3"
|
||||
;;
|
||||
Sun8iw3p1)
|
||||
soc="A23"
|
||||
;;
|
||||
Sun8iw5p1)
|
||||
soc="A33"
|
||||
;;
|
||||
Sun8iw6p1)
|
||||
soc="A83t"
|
||||
;;
|
||||
sun9i|Sun9iw1p1)
|
||||
soc="A80"
|
||||
;;
|
||||
Sun9iw1p2)
|
||||
soc="A80t"
|
||||
;;
|
||||
sun50i|Sun50iw1p1)
|
||||
soc="A64"
|
||||
;;
|
||||
'Generic AM33XX'*)
|
||||
soc="AM33XX"
|
||||
;;
|
||||
*)
|
||||
soc="unknown"
|
||||
esac
|
||||
echo "${soc} ${tp} ${cpu} ${rev}"
|
||||
}
|
||||
|
||||
function gcc_cpu_flags {
|
||||
local soc=$1
|
||||
case $soc in
|
||||
BCM2835)
|
||||
flags="-march=armv6zk -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -DRASPBERRYPI_ARCH"
|
||||
;;
|
||||
BCM2836)
|
||||
flags="-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -DRASPBERRYPI_ARCH"
|
||||
;;
|
||||
AM33XX)
|
||||
flags="-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard"
|
||||
;;
|
||||
A10)
|
||||
flags="-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard"
|
||||
;;
|
||||
A13)
|
||||
flags="-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard"
|
||||
;;
|
||||
A20)
|
||||
flags="-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard"
|
||||
;;
|
||||
H3)
|
||||
flags="-march=armv8-a -mtune=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard"
|
||||
;;
|
||||
*)
|
||||
flags=""
|
||||
esac
|
||||
echo ${flags}
|
||||
}
|
||||
|
||||
params="OS SOC CPUFLAGS CXXFLAGS LDFLAGS PREFIX CXX RF24H_LIB_DIR GATEWAY_DIR"
|
||||
|
||||
for opt do
|
||||
if [ "$opt" = "-h" ] || [ "$opt" = "--help" ]; then
|
||||
help
|
||||
exit 0
|
||||
fi
|
||||
optarg="${opt#*=}"
|
||||
case "$opt" in
|
||||
--os=*)
|
||||
OS="$optarg"
|
||||
;;
|
||||
--soc=*)
|
||||
SOC="$optarg"
|
||||
;;
|
||||
--cpu-flags=*)
|
||||
CPUFLAGS="$optarg"
|
||||
;;
|
||||
--extra-cxxflags=*)
|
||||
CXXFLAGS="$optarg"
|
||||
;;
|
||||
--extra-ldflags=*)
|
||||
LDFLAGS="$optarg"
|
||||
;;
|
||||
--cxx_compiler=*)
|
||||
CXX="$optarg"
|
||||
;;
|
||||
--no-clean*)
|
||||
NO_CLEAN="1"
|
||||
;;
|
||||
--prefix=*)
|
||||
PREFIX="$optarg"
|
||||
;;
|
||||
--rf24h-lib-dir=*)
|
||||
RF24H_LIB_DIR="$optarg"
|
||||
;;
|
||||
--gateway-dir=*)
|
||||
GATEWAY_DIR="$optarg"
|
||||
;;
|
||||
--my-debug*)
|
||||
CXXFLAGS="-DMY_DEBUG $CXXFLAGS"
|
||||
;;
|
||||
--my-gateway-type=*)
|
||||
if [[ ${optarg} == "mqtt" ]]; then
|
||||
LDFLAGS="-lmosquitto $LDFLAGS"
|
||||
CXXFLAGS="-DMY_GATEWAY_MQTT_CLIENT $CXXFLAGS"
|
||||
fi
|
||||
;;
|
||||
--my-config-file=*)
|
||||
CXXFLAGS="-DMY_CONFIG_FILE=${optarg} $CXXFLAGS"
|
||||
;;
|
||||
--my-rf24-enable*)
|
||||
CXXFLAGS="-DMY_RADIO_NRF24 $CXXFLAGS"
|
||||
;;
|
||||
--my-rf24-channel=*)
|
||||
CXXFLAGS="-DMY_RF24_CHANNEL=${optarg} $CXXFLAGS"
|
||||
;;
|
||||
--my-rf24-pa-level=*)
|
||||
CXXFLAGS="-DMY_RF24_PA_LEVEL=${optarg} $CXXFLAGS"
|
||||
;;
|
||||
--my-controller-url-address=*)
|
||||
CXXFLAGS="-DMY_CONTROLLER_URL_ADDRESS=${optarg} $CXXFLAGS"
|
||||
;;
|
||||
--my-controller-ip-address=*)
|
||||
CXXFLAGS="-DMY_CONTROLLER_IP_ADDRESS=${optarg} $CXXFLAGS"
|
||||
;;
|
||||
--my-port=*)
|
||||
CXXFLAGS="-DMY_PORT=${optarg} $CXXFLAGS"
|
||||
;;
|
||||
--my-mqtt-client-id=*)
|
||||
CXXFLAGS="-DMY_MQTT_CLIENT_ID=${optarg} $CXXFLAGS"
|
||||
;;
|
||||
--my-mqtt-publish-topic-prefix=*)
|
||||
CXXFLAGS="-DMY_MQTT_PUBLISH_TOPIC_PREFIX=${optarg} $CXXFLAGS"
|
||||
;;
|
||||
--my-mqtt-subscribe-topic-prefix=*)
|
||||
CXXFLAGS="-DMY_MQTT_SUBSCRIBE_TOPIC_PREFIX=${optarg} $CXXFLAGS"
|
||||
;;
|
||||
--my-rf24-irq-pin=*)
|
||||
CXXFLAGS="-DMY_RF24_IRQ_PIN=${optarg} $CXXFLAGS"
|
||||
;;
|
||||
--my-rx-message-buffer-size=*)
|
||||
CXXFLAGS="-DMY_RX_MESSAGE_BUFFER_SIZE=${optarg} $CXXFLAGS"
|
||||
;;
|
||||
*)
|
||||
echo "[WARNING] Unknown option detected:$opt, ignored"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
PREFIX=${PREFIX:-/usr/local}
|
||||
RF24H_LIB_DIR=${PREFIX}/include/RF24
|
||||
GATEWAY_DIR=${GATEWAY_DIR:-${PREFIX}/bin}
|
||||
CXX=${CXX:-g++}
|
||||
|
||||
if [ -z "${SOC}" ]; then
|
||||
echo "[SECTION] Detecting target machine."
|
||||
info=($(detect_machine))
|
||||
SOC=${info[0]}
|
||||
TYPE=${info[1]}
|
||||
CPU=${info[2]}
|
||||
REV=${info[3]}
|
||||
echo "[OK] machine detected: SoC=${SOC}, Type=${TYPE}, CPU=${CPU}, REV=${REV}."
|
||||
fi
|
||||
|
||||
if [ -z "${CPUFLAGS}" ]; then
|
||||
CPUFLAGS=$(gcc_cpu_flags $SOC)
|
||||
fi
|
||||
|
||||
CXXFLAGS="$CPUFLAGS -Ofast -g -Wall -Wextra -DLINUX_ARCH_GENERIC $CXXFLAGS"
|
||||
|
||||
if [[ $TYPE == "RPi2" || $TYPE == "RPi3" || $REV == "0010" ]]; then
|
||||
CXXFLAGS+="-D__RPI_BPLUS"
|
||||
fi
|
||||
|
||||
LDFLAGS="-pthread -lrf24-bcm $LDFLAGS"
|
||||
|
||||
echo "[SECTION] Saving configuration."
|
||||
echo -n "" > Makefile.inc
|
||||
for param in ${params}; do
|
||||
if [[ ${!param} ]]; then
|
||||
echo "${param}=${!param}" >> Makefile.inc
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "${NO_CLEAN}" ]; then
|
||||
echo "[SECTION] Cleaning previous builds."
|
||||
make clean >/dev/null
|
||||
fi
|
||||
|
||||
|
||||
echo "[OK] Finished."
|
||||
@@ -26,7 +26,7 @@
|
||||
#if defined(MY_IP_ADDRESS)
|
||||
IPAddress _ethernetGatewayIP(MY_IP_ADDRESS);
|
||||
#endif
|
||||
byte _ethernetGatewayMAC[] = { MY_MAC_ADDRESS };
|
||||
uint8_t _ethernetGatewayMAC[] = { MY_MAC_ADDRESS };
|
||||
uint16_t _ethernetGatewayPort = MY_PORT;
|
||||
MyMessage _ethernetMsg;
|
||||
|
||||
@@ -36,8 +36,8 @@ MyMessage _ethernetMsg;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char string[MY_GATEWAY_MAX_RECEIVE_LENGTH];
|
||||
uint8_t idx;
|
||||
char string[MY_GATEWAY_MAX_RECEIVE_LENGTH];
|
||||
uint8_t idx;
|
||||
} inputBuffer;
|
||||
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
@@ -50,7 +50,6 @@ typedef struct
|
||||
IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS);
|
||||
IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS);
|
||||
#endif
|
||||
static bool clientsConnected[MY_GATEWAY_MAX_CLIENTS];
|
||||
#endif
|
||||
|
||||
#if defined(MY_USE_UDP)
|
||||
@@ -60,8 +59,9 @@ typedef struct
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX)
|
||||
static EthernetClient clients[MY_GATEWAY_MAX_CLIENTS];
|
||||
static bool clientsConnected[MY_GATEWAY_MAX_CLIENTS];
|
||||
static inputBuffer inputString[MY_GATEWAY_MAX_CLIENTS];
|
||||
#else
|
||||
static EthernetClient client = EthernetClient();
|
||||
@@ -78,18 +78,18 @@ typedef struct
|
||||
#ifdef MY_W5100_SPI_EN
|
||||
void _w5100_spi_en(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
// Pull up pin
|
||||
pinMode(MY_W5100_SPI_EN, INPUT);
|
||||
digitalWrite(MY_W5100_SPI_EN, HIGH);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ground pin
|
||||
pinMode(MY_W5100_SPI_EN, OUTPUT);
|
||||
digitalWrite(MY_W5100_SPI_EN, LOW);
|
||||
}
|
||||
if (enable)
|
||||
{
|
||||
// Pull up pin
|
||||
pinMode(MY_W5100_SPI_EN, INPUT);
|
||||
digitalWrite(MY_W5100_SPI_EN, HIGH);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ground pin
|
||||
pinMode(MY_W5100_SPI_EN, OUTPUT);
|
||||
digitalWrite(MY_W5100_SPI_EN, LOW);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define _w5100_spi_en(x)
|
||||
@@ -119,7 +119,8 @@ bool gatewayTransportInit() {
|
||||
MY_SERIALDEVICE.print(F("IP: "));
|
||||
MY_SERIALDEVICE.println(WiFi.localIP());
|
||||
#endif
|
||||
|
||||
#elif defined(MY_GATEWAY_LINUX)
|
||||
// Nothing to do here
|
||||
#else
|
||||
#ifdef MY_IP_ADDRESS
|
||||
Ethernet.begin(_ethernetGatewayMAC, _ethernetGatewayIP);
|
||||
@@ -140,8 +141,12 @@ bool gatewayTransportInit() {
|
||||
#ifdef MY_USE_UDP
|
||||
_ethernetServer.begin(_ethernetGatewayPort);
|
||||
#else
|
||||
// we have to use pointers due to the constructor of EthernetServer
|
||||
_ethernetServer.begin();
|
||||
#if defined(MY_GATEWAY_LINUX) && defined(MY_IP_ADDRESS)
|
||||
_ethernetServer.begin(_ethernetGatewayIP);
|
||||
#else
|
||||
// we have to use pointers due to the constructor of EthernetServer
|
||||
_ethernetServer.begin();
|
||||
#endif
|
||||
#endif /* USE_UDP */
|
||||
_w5100_spi_en(false);
|
||||
return true;
|
||||
@@ -152,7 +157,7 @@ bool gatewayTransportSend(MyMessage &message)
|
||||
bool ret = true;
|
||||
char *_ethernetMsg = protocolFormat(message);
|
||||
|
||||
setIndication(INDICATION_GW_TX);
|
||||
setIndication(INDICATION_GW_TX);
|
||||
|
||||
_w5100_spi_en(true);
|
||||
#if defined(MY_CONTROLLER_IP_ADDRESS)
|
||||
@@ -164,16 +169,16 @@ bool gatewayTransportSend(MyMessage &message)
|
||||
#else
|
||||
EthernetClient client;
|
||||
#if defined(MY_CONTROLLER_URL_ADDRESS)
|
||||
if (client.connected() || client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) {
|
||||
#else
|
||||
if (client.connected() || client.connect(_ethernetControllerIP, MY_PORT)) {
|
||||
#endif
|
||||
client.write(_ethernetMsg, strlen(_ethernetMsg));
|
||||
}
|
||||
else {
|
||||
// connecting to the server failed!
|
||||
ret = false;
|
||||
}
|
||||
if (client.connected() || client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) {
|
||||
#else
|
||||
if (client.connected() || client.connect(_ethernetControllerIP, MY_PORT)) {
|
||||
#endif
|
||||
client.write(_ethernetMsg, strlen(_ethernetMsg));
|
||||
}
|
||||
else {
|
||||
// connecting to the server failed!
|
||||
ret = false;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
// Send message to connected clients
|
||||
@@ -195,7 +200,7 @@ bool gatewayTransportSend(MyMessage &message)
|
||||
}
|
||||
|
||||
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX)
|
||||
bool _readFromClient(uint8_t i) {
|
||||
while (clients[i].connected() && clients[i].available()) {
|
||||
char inChar = clients[i].read();
|
||||
@@ -270,7 +275,7 @@ bool gatewayTransportAvailable()
|
||||
|
||||
if (packet_size) {
|
||||
//debug(PSTR("UDP packet available. Size:%d\n"), packet_size);
|
||||
setIndication(INDICATION_GW_RX);
|
||||
setIndication(INDICATION_GW_RX);
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
_ethernetServer.read(inputString[0].string, MY_GATEWAY_MAX_RECEIVE_LENGTH);
|
||||
inputString[0].string[packet_size] = 0;
|
||||
@@ -285,7 +290,7 @@ bool gatewayTransportAvailable()
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX)
|
||||
// ESP8266: Go over list of clients and stop any that are no longer connected.
|
||||
// If the server has a new client connection it will be assigned to a free slot.
|
||||
bool allSlotsOccupied = true;
|
||||
@@ -318,7 +323,7 @@ bool gatewayTransportAvailable()
|
||||
// Loop over clients connect and read available data
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) {
|
||||
if (_readFromClient(i)) {
|
||||
setIndication(INDICATION_GW_RX);
|
||||
setIndication(INDICATION_GW_RX);
|
||||
_w5100_spi_en(false);
|
||||
return true;
|
||||
}
|
||||
@@ -344,7 +349,7 @@ bool gatewayTransportAvailable()
|
||||
client.stop();
|
||||
} else {
|
||||
if (_readFromClient()) {
|
||||
setIndication(INDICATION_GW_RX);
|
||||
setIndication(INDICATION_GW_RX);
|
||||
_w5100_spi_en(false);
|
||||
return true;
|
||||
}
|
||||
@@ -363,7 +368,7 @@ MyMessage& gatewayTransportReceive()
|
||||
}
|
||||
|
||||
|
||||
#if !defined(MY_IP_ADDRESS) && !defined(MY_GATEWAY_ESP8266)
|
||||
#if !defined(MY_IP_ADDRESS) && !defined(MY_GATEWAY_ESP8266) && !defined(MY_GATEWAY_LINUX)
|
||||
void gatewayTransportRenewIP()
|
||||
{
|
||||
/* renew/rebind IP address
|
||||
|
||||
@@ -32,8 +32,10 @@
|
||||
IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS);
|
||||
IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS);
|
||||
#endif
|
||||
#elif defined(MY_GATEWAY_LINUX)
|
||||
// Nothing to do here
|
||||
#else
|
||||
byte _MQTT_clientMAC[] = { MY_MAC_ADDRESS };
|
||||
uint8_t _MQTT_clientMAC[] = { MY_MAC_ADDRESS };
|
||||
#endif
|
||||
|
||||
#if defined(MY_IP_ADDRESS)
|
||||
@@ -46,98 +48,20 @@ static bool _MQTT_connecting = true;
|
||||
static bool _MQTT_available = false;
|
||||
static MyMessage _MQTT_msg;
|
||||
|
||||
uint8_t protocolH2i(char c) {
|
||||
uint8_t i = 0;
|
||||
if (c <= '9')
|
||||
i += c - '0';
|
||||
else if (c >= 'a')
|
||||
i += c - 'a' + 10;
|
||||
else
|
||||
i += c - 'A' + 10;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
bool gatewayTransportSend(MyMessage &message) {
|
||||
if (!_MQTT_client.connected())
|
||||
return false;
|
||||
setIndication(INDICATION_GW_TX);
|
||||
char _fmtBuffer[MY_GATEWAY_MAX_SEND_LENGTH];
|
||||
char _convBuffer[MAX_PAYLOAD * 2 + 1];
|
||||
snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR(MY_MQTT_PUBLISH_TOPIC_PREFIX "/%d/%d/%d/%d/%d"), message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type);
|
||||
debug(PSTR("Sending message on topic: %s\n"), _fmtBuffer);
|
||||
return _MQTT_client.publish(_fmtBuffer, message.getString(_convBuffer));
|
||||
char *topic = protocolFormatMQTTTopic(MY_MQTT_PUBLISH_TOPIC_PREFIX, message);
|
||||
debug(PSTR("Sending message on topic: %s\n"), topic);
|
||||
return _MQTT_client.publish(topic, message.getString(_convBuffer));
|
||||
}
|
||||
|
||||
void incomingMQTT(char* topic, byte* payload, unsigned int length) {
|
||||
void incomingMQTT(char* topic, uint8_t* payload, unsigned int length) {
|
||||
debug(PSTR("Message arrived on topic: %s\n"), topic);
|
||||
char *str, *p;
|
||||
uint8_t i = 0;
|
||||
uint8_t bvalue[MAX_PAYLOAD];
|
||||
uint8_t blen = 0;
|
||||
uint8_t command = 0;
|
||||
for (str = strtok_r(topic, "/", &p); str && i <= 5;
|
||||
str = strtok_r(NULL, "/", &p)) {
|
||||
switch (i) {
|
||||
case 0: {
|
||||
// Topic prefix
|
||||
if (strcmp(str, MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) != 0) {
|
||||
// Message not for us or malformed!
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
// Node id
|
||||
_MQTT_msg.destination = atoi(str);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
// Sensor id
|
||||
_MQTT_msg.sensor = atoi(str);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
// Command type
|
||||
command = atoi(str);
|
||||
mSetCommand(_MQTT_msg, command);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
// Ack flag
|
||||
mSetRequestAck(_MQTT_msg, atoi(str) ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
// Sub type
|
||||
_MQTT_msg.type = atoi(str);
|
||||
// Add payload
|
||||
if (command == C_STREAM) {
|
||||
blen = 0;
|
||||
uint8_t val;
|
||||
while (*payload) {
|
||||
val = protocolH2i(*payload++) << 4;
|
||||
val += protocolH2i(*payload++);
|
||||
bvalue[blen] = val;
|
||||
blen++;
|
||||
}
|
||||
_MQTT_msg.set(bvalue, blen);
|
||||
}
|
||||
else {
|
||||
char* ca;
|
||||
ca = (char *)payload;
|
||||
ca += length;
|
||||
*ca = '\0';
|
||||
_MQTT_msg.set((const char*)payload);
|
||||
}
|
||||
_MQTT_available = true;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
_MQTT_available = protocolMQTTParse(_MQTT_msg, topic, payload, length);
|
||||
}
|
||||
|
||||
|
||||
bool reconnectMQTT() {
|
||||
debug(PSTR("Attempting MQTT connection...\n"));
|
||||
// Attempt to connect
|
||||
@@ -168,6 +92,10 @@ bool gatewayTransportConnect() {
|
||||
}
|
||||
MY_SERIALDEVICE.print("IP: ");
|
||||
MY_SERIALDEVICE.println(WiFi.localIP());
|
||||
#elif defined(MY_GATEWAY_LINUX)
|
||||
#if defined(MY_IP_ADDRESS)
|
||||
//TODO
|
||||
#endif
|
||||
#else
|
||||
#ifdef MY_IP_ADDRESS
|
||||
Ethernet.begin(_MQTT_clientMAC, _MQTT_clientIp);
|
||||
@@ -215,8 +143,6 @@ bool gatewayTransportInit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool gatewayTransportAvailable() {
|
||||
|
||||
if (_MQTT_connecting)
|
||||
@@ -239,6 +165,3 @@ MyMessage & gatewayTransportReceive() {
|
||||
_MQTT_available = false;
|
||||
return _MQTT_msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -57,7 +57,13 @@ do { \
|
||||
// Define these as macros to save valuable space
|
||||
|
||||
#define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value))
|
||||
#define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE)
|
||||
|
||||
#if defined(MY_DISABLED_SERIAL)
|
||||
#define hwInit()
|
||||
#else
|
||||
#define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE)
|
||||
#endif
|
||||
|
||||
#define hwWatchdogReset() wdt_reset()
|
||||
#define hwReboot() wdt_enable(WDTO_15MS); while (1)
|
||||
#define hwMillis() millis()
|
||||
|
||||
+7
-1
@@ -33,7 +33,13 @@
|
||||
// Define these as macros to save valuable space
|
||||
|
||||
#define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value))
|
||||
#define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE); MY_SERIALDEVICE.setDebugOutput(true)
|
||||
|
||||
#if defined(MY_DISABLED_SERIAL)
|
||||
#define hwInit()
|
||||
#else
|
||||
#define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE); MY_SERIALDEVICE.setDebugOutput(true)
|
||||
#endif
|
||||
|
||||
#define hwWatchdogReset() wdt_reset()
|
||||
#define hwReboot() ESP.restart();
|
||||
#define hwMillis() millis()
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* 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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* Full contributor list: https://github.com/mysensors/MySensors/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.
|
||||
*/
|
||||
|
||||
#include "MyHwLinuxGeneric.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
static const char* CONFIG_FILE = MY_LINUX_CONFIG_FILE;
|
||||
static const size_t _length = 1024; // ATMega328 has 1024 bytes
|
||||
static uint8_t _config[_length];
|
||||
static unsigned long millis_at_start;
|
||||
|
||||
bool CheckConfigFile() {
|
||||
struct stat fileInfo;
|
||||
|
||||
if(stat(CONFIG_FILE, &fileInfo) != 0)
|
||||
{
|
||||
//File does not exist. Create it.
|
||||
debug("Config file %s does not exist, creating new config file.\n", CONFIG_FILE);
|
||||
ofstream myFile(CONFIG_FILE, ios::out | ios::binary);
|
||||
if(!myFile)
|
||||
{
|
||||
debug("Unable to create config file %s.\n", CONFIG_FILE);
|
||||
return false;
|
||||
}
|
||||
myFile.write((const char*)_config, _length);
|
||||
myFile.close();
|
||||
}
|
||||
else if(fileInfo.st_size < 0 || (size_t)fileInfo.st_size != _length)
|
||||
{
|
||||
debug("Config file %s is not the correct size of %i. Please remove the file and a new one will be created.\n", CONFIG_FILE, _length);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Read config into local memory.
|
||||
ifstream myFile(CONFIG_FILE, ios::in | ios::binary);
|
||||
if(!myFile)
|
||||
{
|
||||
debug("Unable to open config to file %s for reading.\n", CONFIG_FILE);
|
||||
return false;
|
||||
}
|
||||
myFile.read((char*)_config, _length);
|
||||
myFile.close();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void hwInit()
|
||||
{
|
||||
timeval curTime;
|
||||
|
||||
for (size_t i = 0; i < _length; i++)
|
||||
_config[i] = 0xFF;
|
||||
|
||||
if (!CheckConfigFile())
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
gettimeofday(&curTime, NULL);
|
||||
millis_at_start = curTime.tv_sec;
|
||||
}
|
||||
|
||||
void hwReadConfigBlock(void* buf, void* addr, size_t length)
|
||||
{
|
||||
unsigned long int offs = reinterpret_cast<unsigned long int>(addr);
|
||||
|
||||
if (length && offs + length <= _length) {
|
||||
memcpy(buf, _config+offs, length);
|
||||
}
|
||||
}
|
||||
|
||||
void hwWriteConfigBlock(void* buf, void* addr, size_t length)
|
||||
{
|
||||
unsigned long int offs = reinterpret_cast<unsigned long int>(addr);
|
||||
|
||||
if (length && offs + length <= _length) {
|
||||
memcpy(_config+offs, buf, length);
|
||||
|
||||
ofstream myFile(CONFIG_FILE, ios::out | ios::binary);
|
||||
if(!myFile)
|
||||
{
|
||||
debug("Unable to write config to file %s.\n", CONFIG_FILE);
|
||||
return;
|
||||
}
|
||||
myFile.write((const char*)buf+offs, _length);
|
||||
myFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t hwReadConfig(int adr)
|
||||
{
|
||||
uint8_t value = 0xFF;
|
||||
hwReadConfigBlock(&value, reinterpret_cast<void*>(adr), 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
void hwWriteConfig(int adr, uint8_t value)
|
||||
{
|
||||
uint8_t curr = hwReadConfig(adr);
|
||||
if (curr != value)
|
||||
{
|
||||
hwWriteConfigBlock(&value, reinterpret_cast<void*>(adr), 1);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long hwMillis()
|
||||
{
|
||||
timeval curTime;
|
||||
|
||||
gettimeofday(&curTime, NULL);
|
||||
return ((curTime.tv_sec - millis_at_start) * 1000) + (curTime.tv_usec / 1000);
|
||||
}
|
||||
|
||||
// TODO: Not supported!
|
||||
int8_t hwSleep(unsigned long ms)
|
||||
{
|
||||
(void)ms;
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
// TODO: Not supported!
|
||||
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms)
|
||||
{
|
||||
(void)interrupt;
|
||||
(void)mode;
|
||||
(void)ms;
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
// TODO: Not supported!
|
||||
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms)
|
||||
{
|
||||
(void)interrupt1;
|
||||
(void)mode1;
|
||||
(void)interrupt2;
|
||||
(void)mode2;
|
||||
(void)ms;
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint16_t hwCPUVoltage() {
|
||||
// TODO: Not supported!
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t hwCPUFrequency() {
|
||||
// TODO: Not supported!
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t hwFreeMem() {
|
||||
// TODO: Not supported!
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MY_DEBUG
|
||||
void hwDebugPrint(const char *fmt, ... )
|
||||
{
|
||||
va_list arglist;
|
||||
va_start(arglist, fmt);
|
||||
vprintf(fmt, arglist);
|
||||
va_end(arglist);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* Full contributor list: https://github.com/mysensors/MySensors/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.
|
||||
*/
|
||||
|
||||
#ifndef MyHwLinuxGeneric_h
|
||||
#define MyHwLinuxGeneric_h
|
||||
|
||||
#include "MyHw.h"
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <pthread.h>
|
||||
|
||||
#define MY_SERIALDEVICE Serial
|
||||
|
||||
// Define these as macros (do nothing)
|
||||
#define hwDigitalWrite(__pin, __value)
|
||||
#define hwWatchdogReset()
|
||||
#define hwReboot()
|
||||
|
||||
using namespace std;
|
||||
|
||||
void hwInit();
|
||||
void hwReadConfigBlock(void* buf, void* adr, size_t length);
|
||||
void hwWriteConfigBlock(void* buf, void* adr, size_t length);
|
||||
void hwWriteConfig(int adr, uint8_t value);
|
||||
uint8_t hwReadConfig(int adr);
|
||||
unsigned long hwMillis();
|
||||
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static __inline__ void __hwUnlock(const uint8_t *__s) {
|
||||
pthread_mutex_unlock(&hw_mutex);
|
||||
(void)__s;
|
||||
}
|
||||
|
||||
static __inline__ void __hwLock() {
|
||||
pthread_mutex_lock(&hw_mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__DOXYGEN__)
|
||||
#define ATOMIC_BLOCK_CLEANUP
|
||||
#elif defined(MY_RF24_IRQ_PIN)
|
||||
#define ATOMIC_BLOCK_CLEANUP uint8_t __atomic_loop \
|
||||
__attribute__((__cleanup__( __hwUnlock ))) = 1
|
||||
#endif /* __DOXYGEN__ */
|
||||
|
||||
#if defined(__DOXYGEN__)
|
||||
#define ATOMIC_BLOCK
|
||||
#elif defined(MY_RF24_IRQ_PIN)
|
||||
#define ATOMIC_BLOCK for ( ATOMIC_BLOCK_CLEANUP, __hwLock(); \
|
||||
__atomic_loop ; __atomic_loop = 0 )
|
||||
#endif /* __DOXYGEN__ */
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#define MY_CRITICAL_SECTION ATOMIC_BLOCK
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
// Initialize library and handle sketch functions like we want to
|
||||
|
||||
#include <iostream>
|
||||
#include <signal.h>
|
||||
#include "MySensorsCore.h"
|
||||
|
||||
volatile static int running = 1;
|
||||
|
||||
/*
|
||||
* handler for SIGINT signal
|
||||
*/
|
||||
void handle_sigint(int sig)
|
||||
{
|
||||
running = 0;
|
||||
|
||||
if (sig == SIGINT) {
|
||||
std::cout << "Received SIGINT\n" << std::endl;
|
||||
} else if (sig == SIGTERM) {
|
||||
std::cout << "Received SIGTERM\n" << std::endl;
|
||||
}
|
||||
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
detachInterrupt(MY_RF24_IRQ_PIN);
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
/* register the signal handler */
|
||||
signal(SIGINT, handle_sigint);
|
||||
signal(SIGTERM, handle_sigint);
|
||||
|
||||
_begin(); // Startup MySensors library
|
||||
|
||||
while (running) {
|
||||
_process(); // Process incoming data
|
||||
if (loop) loop(); // Call sketch loop
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -21,7 +21,11 @@
|
||||
#include "MyMessage.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef ARDUINO
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
MyMessage::MyMessage()
|
||||
{
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <Arduino.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "MyConfig.h"
|
||||
#include "MyTransport.h"
|
||||
#include "MyProtocol.h"
|
||||
#include <string.h>
|
||||
|
||||
uint8_t protocolH2i(char c);
|
||||
|
||||
@@ -32,7 +33,6 @@ bool protocolParse(MyMessage &message, char *inputString) {
|
||||
uint8_t blen = 0;
|
||||
int i = 0;
|
||||
uint8_t command = 0;
|
||||
uint8_t ack = 0;
|
||||
|
||||
// Extract command data coming on serial line
|
||||
for (str = strtok_r(inputString, ";", &p); // split using semicolon
|
||||
@@ -51,7 +51,7 @@ bool protocolParse(MyMessage &message, char *inputString) {
|
||||
mSetCommand(message, command);
|
||||
break;
|
||||
case 3: // Should we request ack from destination?
|
||||
ack = atoi(str);
|
||||
mSetRequestAck(message, atoi(str)?1:0);
|
||||
break;
|
||||
case 4: // Data type
|
||||
message.type = atoi(str);
|
||||
@@ -86,8 +86,7 @@ bool protocolParse(MyMessage &message, char *inputString) {
|
||||
|
||||
message.sender = GATEWAY_ADDRESS;
|
||||
message.last = GATEWAY_ADDRESS;
|
||||
mSetRequestAck(message, ack?1:0);
|
||||
mSetAck(message, false);
|
||||
mSetAck(message, false);
|
||||
if (command == C_STREAM)
|
||||
message.set(bvalue, blen);
|
||||
else
|
||||
@@ -110,23 +109,23 @@ char * protocolFormatMQTTSubscribe(const char* prefix) {
|
||||
return _fmtBuffer;
|
||||
}
|
||||
|
||||
void protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsigned int length) {
|
||||
//TODO: Not sure if we should copy the topic and payload into a buffer so we are not modifying original.
|
||||
#ifdef MY_GATEWAY_MQTT_CLIENT
|
||||
bool protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsigned int length) {
|
||||
char *str, *p;
|
||||
uint8_t i = 0;
|
||||
uint8_t bvalue[MAX_PAYLOAD];
|
||||
uint8_t blen = 0;
|
||||
uint8_t command = 0;
|
||||
|
||||
for (str = strtok_r(topic, "/", &p); str && i <= 5;
|
||||
str = strtok_r(NULL, "/", &p)) {
|
||||
switch (i) {
|
||||
case 0: {
|
||||
// Topic prefix
|
||||
//TODO: Should be checking the topic prefix
|
||||
//if (strcmp(str, MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) != 0) {
|
||||
if (strcmp(str, MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) != 0) {
|
||||
// Message not for us or malformed!
|
||||
// return;
|
||||
//}
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
@@ -153,29 +152,41 @@ void protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsign
|
||||
case 5: {
|
||||
// Sub type
|
||||
message.type = atoi(str);
|
||||
// Add payload
|
||||
if (command == C_STREAM) {
|
||||
blen = 0;
|
||||
uint8_t val;
|
||||
while (*payload) {
|
||||
val = protocolH2i(*payload++) << 4;
|
||||
val += protocolH2i(*payload++);
|
||||
bvalue[blen] = val;
|
||||
blen++;
|
||||
}
|
||||
message.set(bvalue, blen);
|
||||
} else {
|
||||
char* ca;
|
||||
ca = (char *) payload;
|
||||
ca += length;
|
||||
*ca = '\0';
|
||||
message.set((const char*) payload);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i != 6)
|
||||
return false;
|
||||
|
||||
message.sender = GATEWAY_ADDRESS;
|
||||
message.last = GATEWAY_ADDRESS;
|
||||
mSetAck(message, false);
|
||||
|
||||
// Add payload
|
||||
if (command == C_STREAM) {
|
||||
blen = 0;
|
||||
uint8_t val;
|
||||
while (*payload) {
|
||||
val = protocolH2i(*payload++) << 4;
|
||||
val += protocolH2i(*payload++);
|
||||
bvalue[blen] = val;
|
||||
blen++;
|
||||
}
|
||||
message.set(bvalue, blen);
|
||||
} else {
|
||||
char* ca;
|
||||
ca = (char *) payload;
|
||||
ca += length;
|
||||
*ca = '\0';
|
||||
message.set((const char*) payload);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t protocolH2i(char c) {
|
||||
uint8_t i = 0;
|
||||
@@ -187,5 +198,3 @@ uint8_t protocolH2i(char c) {
|
||||
i += c - 'A' + 10;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -51,6 +51,10 @@ void _process() {
|
||||
transportProcess();
|
||||
#endif
|
||||
|
||||
#if defined(LINUX_ARCH_GENERIC)
|
||||
// To avoid high cpu usage
|
||||
usleep(10000); // 10ms
|
||||
#endif
|
||||
}
|
||||
|
||||
void _infiniteLoop() {
|
||||
@@ -61,17 +65,17 @@ void _infiniteLoop() {
|
||||
#if defined (MY_LEDS_BLINKING_FEATURE)
|
||||
ledsProcess();
|
||||
#endif
|
||||
#if defined(LINUX_ARCH_GENERIC)
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void _begin() {
|
||||
|
||||
if (preHwInit)
|
||||
preHwInit();
|
||||
|
||||
#if !defined(MY_DISABLED_SERIAL)
|
||||
hwInit();
|
||||
#endif
|
||||
hwInit();
|
||||
|
||||
debug(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",VER=" MYSENSORS_LIBRARY_VERSION "\n"));
|
||||
|
||||
|
||||
@@ -467,7 +467,7 @@ void transportProcessMessage() {
|
||||
// Is message addressed to this node?
|
||||
if (destination == _nc.nodeId) {
|
||||
// prevent buffer overflow by limiting max. possible message length (5 bits=31 bytes max) to MAX_PAYLOAD (25 bytes)
|
||||
mSetLength(_msg, min(mGetLength(_msg),MAX_PAYLOAD));
|
||||
mSetLength(_msg, min(mGetLength(_msg),(uint8_t)MAX_PAYLOAD));
|
||||
// null terminate data
|
||||
_msg.data[mGetLength(_msg)] = 0x00;
|
||||
|
||||
@@ -717,4 +717,4 @@ bool transportSendWrite(uint8_t to, MyMessage &message) {
|
||||
return (ok || to==BROADCAST_ADDRESS);
|
||||
}
|
||||
|
||||
// EOF MyTransport.cpp
|
||||
// EOF MyTransport.cpp
|
||||
|
||||
@@ -19,7 +19,13 @@
|
||||
|
||||
#include "MyConfig.h"
|
||||
#include "MyTransport.h"
|
||||
#include "drivers/RF24/RF24.h"
|
||||
|
||||
#ifdef RASPBERRYPI_ARCH
|
||||
#include "drivers/RF24/RF24_RPi.cpp"
|
||||
#else
|
||||
#include "drivers/RF24/RF24.h"
|
||||
#endif
|
||||
|
||||
#include "drivers/CircularBuffer/CircularBuffer.h"
|
||||
|
||||
#if defined(MY_RF24_ENABLE_ENCRYPTION)
|
||||
|
||||
@@ -57,12 +57,7 @@
|
||||
#include "MyTransport.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
#include "MyTransport.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
#ifndef Arduino_h
|
||||
#define Arduino_h
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef LSBFIRST
|
||||
#define LSBFIRST 0
|
||||
#endif
|
||||
|
||||
#ifndef MSBFIRST
|
||||
#define MSBFIRST 1
|
||||
#endif
|
||||
|
||||
#define abs(x) ((x)>0?(x):-(x))
|
||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#define sq(x) ((x)*(x))
|
||||
|
||||
#define lowByte(w) ((uint8_t) ((w) & 0xff))
|
||||
#define highByte(w) ((uint8_t) ((w) >> 8))
|
||||
|
||||
#define bit(b) (1UL << (b))
|
||||
|
||||
typedef bool boolean;
|
||||
typedef uint8_t byte;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* C++ version 0.4 char* style "itoa":
|
||||
* Written by Lukás Chmela
|
||||
* Released under GPLv3.
|
||||
*/
|
||||
char *itoa(int value, char* result, int base) {
|
||||
// check that the base if valid
|
||||
if (base < 2 || base > 36) { *result = '\0'; return result; }
|
||||
|
||||
char* ptr = result, *ptr1 = result, tmp_char;
|
||||
int tmp_value;
|
||||
|
||||
do {
|
||||
tmp_value = value;
|
||||
value /= base;
|
||||
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
|
||||
} while ( value );
|
||||
|
||||
// Apply negative sign
|
||||
// Apply negative sign
|
||||
if (tmp_value < 0) *ptr++ = '-';
|
||||
*ptr-- = '\0';
|
||||
while(ptr1 < ptr) {
|
||||
tmp_char = *ptr;
|
||||
*ptr--= *ptr1;
|
||||
*ptr1++ = tmp_char;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* C++ version 0.4 char* style "itoa":
|
||||
* Written by Lukás Chmela
|
||||
* Released under GPLv3.
|
||||
*/
|
||||
char *ltoa(long value, char* result, int base) {
|
||||
// check that the base if valid
|
||||
if (base < 2 || base > 36) { *result = '\0'; return result; }
|
||||
|
||||
char* ptr = result, *ptr1 = result, tmp_char;
|
||||
long tmp_value;
|
||||
|
||||
do {
|
||||
tmp_value = value;
|
||||
value /= base;
|
||||
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
|
||||
} while ( value );
|
||||
|
||||
// Apply negative sign
|
||||
if (tmp_value < 0) *ptr++ = '-';
|
||||
*ptr-- = '\0';
|
||||
while(ptr1 < ptr) {
|
||||
tmp_char = *ptr;
|
||||
*ptr--= *ptr1;
|
||||
*ptr1++ = tmp_char;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
char *ultoa(long num, char *str, int radix)
|
||||
{
|
||||
unsigned long value;
|
||||
char *sp = str;
|
||||
char *sp2;
|
||||
|
||||
value = num;
|
||||
|
||||
/* Store sign at start of buffer for negative base-10 values */
|
||||
if (10 == radix && 0 > num) {
|
||||
*sp++ = '-';
|
||||
value = -num;
|
||||
}
|
||||
|
||||
sp2 = sp;
|
||||
|
||||
do {
|
||||
char rem = value % radix;
|
||||
value /= radix;
|
||||
if (10 > rem) {
|
||||
*sp++ = '0' + rem;
|
||||
} else {
|
||||
*sp++ = 'A' + rem - 10;
|
||||
}
|
||||
} while (0 < value);
|
||||
|
||||
/* Mark end of string */
|
||||
*sp-- = 0;
|
||||
|
||||
/* Reverse string contents (excluding sign) in place */
|
||||
while (sp2 < sp) {
|
||||
char tmp = *sp2;
|
||||
*sp2++ = *sp;
|
||||
*sp-- = tmp;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copyright (c) 2012, Peter A. Bigot <bigotp@acm.org>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* * Neither the name of the software nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* 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 HOLDER 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.
|
||||
*/
|
||||
|
||||
char *utoa(int num, char *str, int radix)
|
||||
{
|
||||
unsigned int value;
|
||||
char *sp = str;
|
||||
char *sp2;
|
||||
|
||||
value = num;
|
||||
|
||||
/* Store sign at start of buffer for negative base-10 values */
|
||||
if (10 == radix && 0 > num) {
|
||||
*sp++ = '-';
|
||||
value = -num;
|
||||
}
|
||||
|
||||
sp2 = sp;
|
||||
|
||||
do {
|
||||
char rem = value % radix;
|
||||
value /= radix;
|
||||
if (10 > rem) {
|
||||
*sp++ = '0' + rem;
|
||||
} else {
|
||||
*sp++ = 'A' + rem - 10;
|
||||
}
|
||||
} while (0 < value);
|
||||
|
||||
/* Mark end of string */
|
||||
*sp-- = 0;
|
||||
|
||||
/* Reverse string contents (excluding sign) in place */
|
||||
while (sp2 < sp) {
|
||||
char tmp = *sp2;
|
||||
*sp2++ = *sp;
|
||||
*sp-- = tmp;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
char *dtostrf(float f, int width, int decimals, char *result)
|
||||
{
|
||||
sprintf(result,"%*.*f", width, decimals, f);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Client.h - Base class that provides Client
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Modified by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
|
||||
*/
|
||||
|
||||
#ifndef client_h
|
||||
#define client_h
|
||||
#include "Stream.h"
|
||||
#include "IPAddress.h"
|
||||
|
||||
class Client : public Stream {
|
||||
|
||||
public:
|
||||
virtual int connect(IPAddress ip, uint16_t port) = 0;
|
||||
virtual int connect(const char *host, uint16_t port) = 0;
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
virtual size_t write(const uint8_t *buf, size_t size) = 0;
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int read(uint8_t *buf, size_t size) = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual uint8_t connected() = 0;
|
||||
virtual operator bool() = 0;
|
||||
protected:
|
||||
uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); };
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* 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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* Full contributor list: https://github.com/mysensors/MySensors/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.
|
||||
*
|
||||
* Based on Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include "EthernetClient.h"
|
||||
|
||||
EthernetClient::EthernetClient() : _sock(-1) {
|
||||
}
|
||||
|
||||
EthernetClient::EthernetClient(int sock) : _sock(sock) {
|
||||
}
|
||||
|
||||
int EthernetClient::connect(const char* host, uint16_t port) {
|
||||
int sockfd;
|
||||
struct addrinfo hints, *servinfo, *p;
|
||||
int rv;
|
||||
char s[INET6_ADDRSTRLEN];
|
||||
char port_str[6];
|
||||
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
sprintf(port_str, "%hu", port);
|
||||
if ((rv = getaddrinfo(host, port_str, &hints, &servinfo)) != 0) {
|
||||
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// loop through all the results and connect to the first we can
|
||||
for (p = servinfo; p != NULL; p = p->ai_next) {
|
||||
if ((sockfd = socket(p->ai_family, p->ai_socktype,
|
||||
p->ai_protocol)) == -1) {
|
||||
perror("socket");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (::connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
|
||||
close(sockfd);
|
||||
perror("connect");
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (p == NULL) {
|
||||
fprintf(stderr, "failed to connect\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_sock = sockfd;
|
||||
|
||||
void *addr = &(((struct sockaddr_in*)p->ai_addr)->sin_addr);
|
||||
inet_ntop(p->ai_family, addr, s, sizeof s);
|
||||
ETHERNETCLIENT_DEBUG("connected to %s\n", s);
|
||||
|
||||
freeaddrinfo(servinfo); // all done with this structure
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EthernetClient::connect(IPAddress ip, uint16_t port) {
|
||||
return connect(ip.toString().c_str(), port);
|
||||
}
|
||||
|
||||
size_t EthernetClient::write(uint8_t b) {
|
||||
return write(&b, 1);
|
||||
}
|
||||
|
||||
size_t EthernetClient::write(const uint8_t *buf, size_t size) {
|
||||
int rc = 0;
|
||||
int bytes = 0;
|
||||
|
||||
if (_sock == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (size > 0) {
|
||||
rc = send(_sock, buf + bytes, size, MSG_NOSIGNAL | MSG_DONTWAIT);
|
||||
if (rc == -1) {
|
||||
perror("send");
|
||||
close(_sock);
|
||||
_sock = -1;
|
||||
break;
|
||||
}
|
||||
bytes += rc;
|
||||
size -= rc;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
size_t EthernetClient::write(const char *str) {
|
||||
if (str == NULL) return 0;
|
||||
return write((const uint8_t *)str, strlen(str));
|
||||
}
|
||||
size_t EthernetClient::write(const char *buffer, size_t size) {
|
||||
return write((const uint8_t *)buffer, size);
|
||||
}
|
||||
|
||||
int EthernetClient::available() {
|
||||
int count = 0;
|
||||
|
||||
if (_sock != -1) {
|
||||
ioctl(_sock, FIONREAD, &count);
|
||||
return count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EthernetClient::read() {
|
||||
uint8_t b;
|
||||
if ( recv(_sock, &b, 1, 0) > 0 )
|
||||
{
|
||||
// recv worked
|
||||
return b;
|
||||
} else {
|
||||
// No data available
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int EthernetClient::read(uint8_t *buf, size_t size) {
|
||||
return recv(_sock, buf, size, 0);
|
||||
}
|
||||
|
||||
int EthernetClient::peek() {
|
||||
uint8_t b;
|
||||
|
||||
return recv(_sock, &b, 1, MSG_PEEK | MSG_DONTWAIT);
|
||||
}
|
||||
|
||||
void EthernetClient::flush() {
|
||||
// There isn't much we can do here
|
||||
return;
|
||||
}
|
||||
|
||||
void EthernetClient::stop() {
|
||||
if (_sock == -1)
|
||||
return;
|
||||
|
||||
// attempt to close the connection gracefully (send a FIN to other side)
|
||||
shutdown(_sock, SHUT_RDWR);
|
||||
|
||||
timeval startTime, curTime;
|
||||
gettimeofday(&startTime, NULL);
|
||||
|
||||
// wait up to a second for the connection to close
|
||||
uint8_t s;
|
||||
do {
|
||||
s = status();
|
||||
if (s == ETHERNETCLIENT_W5100_CLOSED)
|
||||
break; // exit the loop
|
||||
usleep(1000);
|
||||
gettimeofday(&curTime, NULL);
|
||||
} while (((curTime.tv_sec - startTime.tv_sec) * 1000000) + (curTime.tv_usec - startTime.tv_usec) < 1000000);
|
||||
|
||||
// if it hasn't closed, close it forcefully
|
||||
if (s != ETHERNETCLIENT_W5100_CLOSED)
|
||||
close(_sock);
|
||||
|
||||
_sock = -1;
|
||||
}
|
||||
|
||||
uint8_t EthernetClient::connected() {
|
||||
if (_sock == -1) return 0;
|
||||
|
||||
if (peek() < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t EthernetClient::status() {
|
||||
if (_sock == -1) return ETHERNETCLIENT_W5100_CLOSED;
|
||||
|
||||
struct tcp_info tcp_info;
|
||||
int tcp_info_length = sizeof(tcp_info);
|
||||
|
||||
if ( getsockopt( _sock, SOL_TCP, TCP_INFO, (void *)&tcp_info, (socklen_t *)&tcp_info_length ) == 0 ) {
|
||||
switch (tcp_info.tcpi_state) {
|
||||
case TCP_ESTABLISHED:
|
||||
return ETHERNETCLIENT_W5100_ESTABLISHED;
|
||||
case TCP_SYN_SENT:
|
||||
return ETHERNETCLIENT_W5100_SYNSENT;
|
||||
case TCP_SYN_RECV:
|
||||
return ETHERNETCLIENT_W5100_SYNRECV;
|
||||
case TCP_FIN_WAIT1:
|
||||
case TCP_FIN_WAIT2:
|
||||
return ETHERNETCLIENT_W5100_FIN_WAIT;
|
||||
case TCP_TIME_WAIT:
|
||||
return TCP_TIME_WAIT;
|
||||
case TCP_CLOSE:
|
||||
return ETHERNETCLIENT_W5100_CLOSED;
|
||||
case TCP_CLOSE_WAIT:
|
||||
return ETHERNETCLIENT_W5100_CLOSING;
|
||||
case TCP_LAST_ACK:
|
||||
return ETHERNETCLIENT_W5100_LAST_ACK;
|
||||
case TCP_LISTEN:
|
||||
return ETHERNETCLIENT_W5100_LISTEN;
|
||||
case TCP_CLOSING:
|
||||
return ETHERNETCLIENT_W5100_CLOSING;
|
||||
}
|
||||
} else {
|
||||
perror("getsockopt");
|
||||
}
|
||||
|
||||
return ETHERNETCLIENT_W5100_CLOSED;
|
||||
}
|
||||
|
||||
// the next function allows us to use the client returned by
|
||||
// EthernetServer::available() as the condition in an if-statement.
|
||||
|
||||
EthernetClient::operator bool() {
|
||||
return _sock != -1;
|
||||
}
|
||||
|
||||
bool EthernetClient::operator==(const EthernetClient& rhs) {
|
||||
return _sock == rhs._sock && _sock != -1 && rhs._sock != -1;
|
||||
}
|
||||
|
||||
uint8_t EthernetClient::getSocketNumber() {
|
||||
return _sock;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* Full contributor list: https://github.com/mysensors/MySensors/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.
|
||||
*
|
||||
* Based on Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved.
|
||||
*/
|
||||
|
||||
#ifndef ethernetclient_h
|
||||
#define ethernetclient_h
|
||||
|
||||
#include "Client.h"
|
||||
#include "IPAddress.h"
|
||||
|
||||
// State codes from W5100 library
|
||||
#define ETHERNETCLIENT_W5100_CLOSED 0x00
|
||||
#define ETHERNETCLIENT_W5100_LISTEN 0x14
|
||||
#define ETHERNETCLIENT_W5100_SYNSENT 0x15
|
||||
#define ETHERNETCLIENT_W5100_SYNRECV 0x16
|
||||
#define ETHERNETCLIENT_W5100_ESTABLISHED 0x17
|
||||
#define ETHERNETCLIENT_W5100_FIN_WAIT 0x18
|
||||
#define ETHERNETCLIENT_W5100_CLOSING 0x1A
|
||||
#define ETHERNETCLIENT_W5100_TIME_WAIT 0x1B
|
||||
#define ETHERNETCLIENT_W5100_CLOSE_WAIT 0x1C
|
||||
#define ETHERNETCLIENT_W5100_LAST_ACK 0x1D
|
||||
|
||||
// debug
|
||||
#if defined(ETHERNETCLIENT_VERBOSE)
|
||||
#define ETHERNETCLIENT_DEBUG(x,...) debug(x, ##__VA_ARGS__)
|
||||
#else
|
||||
#define ETHERNETCLIENT_DEBUG(x,...)
|
||||
#endif
|
||||
|
||||
class EthernetClient : public Client {
|
||||
|
||||
public:
|
||||
EthernetClient();
|
||||
EthernetClient(int sock);
|
||||
|
||||
uint8_t status();
|
||||
virtual int connect(IPAddress ip, uint16_t port);
|
||||
virtual int connect(const char *host, uint16_t port);
|
||||
virtual size_t write(uint8_t);
|
||||
virtual size_t write(const uint8_t *buf, size_t size);
|
||||
size_t write(const char *str);
|
||||
size_t write(const char *buffer, size_t size);
|
||||
virtual int available();
|
||||
virtual int read();
|
||||
virtual int read(uint8_t *buf, size_t size);
|
||||
virtual int peek();
|
||||
virtual void flush();
|
||||
virtual void stop();
|
||||
virtual uint8_t connected();
|
||||
virtual operator bool();
|
||||
virtual bool operator==(const bool value) { return bool() == value; }
|
||||
virtual bool operator!=(const bool value) { return bool() != value; }
|
||||
virtual bool operator==(const EthernetClient&);
|
||||
virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); };
|
||||
uint8_t getSocketNumber();
|
||||
|
||||
friend class EthernetServer;
|
||||
|
||||
private:
|
||||
int _sock;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* Full contributor list: https://github.com/mysensors/MySensors/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.
|
||||
*
|
||||
* Based on Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <cstring>
|
||||
#include <sys/socket.h>
|
||||
#include <pthread.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include "EthernetServer.h"
|
||||
|
||||
struct server_vars {
|
||||
uint16_t port;
|
||||
struct IPAddress address;
|
||||
std::list<int> *new_clients;
|
||||
std::vector<int> *clients;
|
||||
};
|
||||
|
||||
static pthread_mutex_t new_clients_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void *incoming_connections(void *);
|
||||
|
||||
EthernetServer::EthernetServer(uint16_t port) : port(port)
|
||||
{
|
||||
clients.reserve(MY_GATEWAY_MAX_CLIENTS);
|
||||
}
|
||||
|
||||
void EthernetServer::begin()
|
||||
{
|
||||
begin(IPAddress(0,0,0,0));
|
||||
}
|
||||
|
||||
void EthernetServer::begin(IPAddress address)
|
||||
{
|
||||
pthread_t thread_id;
|
||||
pthread_attr_t detached_attr;
|
||||
|
||||
struct server_vars *vars = new struct server_vars;
|
||||
vars->port = port;
|
||||
vars->address = address;
|
||||
vars->new_clients = &new_clients;
|
||||
vars->clients = &clients;
|
||||
|
||||
pthread_attr_init(&detached_attr);
|
||||
pthread_attr_setdetachstate(&detached_attr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_create(&thread_id, &detached_attr, &incoming_connections, vars);
|
||||
}
|
||||
|
||||
void EthernetServer::beginPacket(IPAddress address, uint16_t port)
|
||||
{
|
||||
//TODO: UDP
|
||||
(void)address;
|
||||
(void)port;
|
||||
}
|
||||
|
||||
int EthernetServer::parsePacket()
|
||||
{
|
||||
//TODO: UDP
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool EthernetServer::hasClient()
|
||||
{
|
||||
bool empty;
|
||||
|
||||
pthread_mutex_lock(&new_clients_mutex);
|
||||
empty = new_clients.empty();
|
||||
pthread_mutex_unlock(&new_clients_mutex);
|
||||
|
||||
return !empty;
|
||||
}
|
||||
|
||||
EthernetClient EthernetServer::available()
|
||||
{
|
||||
int sock;
|
||||
|
||||
pthread_mutex_lock(&new_clients_mutex);
|
||||
if (new_clients.empty()) {
|
||||
sock = -1;
|
||||
} else {
|
||||
sock = new_clients.front();
|
||||
new_clients.pop_front();
|
||||
}
|
||||
pthread_mutex_unlock(&new_clients_mutex);
|
||||
|
||||
return EthernetClient(sock);
|
||||
}
|
||||
|
||||
size_t EthernetServer::write(uint8_t b)
|
||||
{
|
||||
return write(&b, 1);
|
||||
}
|
||||
|
||||
size_t EthernetServer::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
size_t n = 0;
|
||||
size_t i = 0;
|
||||
|
||||
pthread_mutex_lock(&clients_mutex);
|
||||
while (i < clients.size()) {
|
||||
EthernetClient client(clients[i]);
|
||||
if (client.connected()) {
|
||||
n += client.write(buffer, size);
|
||||
i++;
|
||||
} else {
|
||||
clients[i] = clients.back();
|
||||
clients.pop_back();
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&clients_mutex);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t EthernetServer::write(const char *str) {
|
||||
if (str == NULL) return 0;
|
||||
return write((const uint8_t *)str, strlen(str));
|
||||
}
|
||||
size_t EthernetServer::write(const char *buffer, size_t size) {
|
||||
return write((const uint8_t *)buffer, size);
|
||||
}
|
||||
|
||||
void *incoming_connections(void* thread_arg)
|
||||
{
|
||||
struct server_vars *vars = (struct server_vars*) thread_arg;
|
||||
int sockfd, new_fd;
|
||||
struct addrinfo hints, *servinfo, *p;
|
||||
struct sockaddr_storage client_addr;
|
||||
socklen_t sin_size;
|
||||
int yes=1;
|
||||
int rv;
|
||||
char ipstr[INET_ADDRSTRLEN];
|
||||
char portstr[6];
|
||||
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
sprintf(portstr, "%d", vars->port);
|
||||
if ((rv = getaddrinfo(vars->address.toString().c_str(), portstr, &hints, &servinfo)) != 0) {
|
||||
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// loop through all the results and bind to the first we can
|
||||
for (p = servinfo; p != NULL; p = p->ai_next) {
|
||||
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
|
||||
perror("socket");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
|
||||
perror("setsockopt");
|
||||
freeaddrinfo(servinfo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
|
||||
close(sockfd);
|
||||
perror("bind");
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (p == NULL) {
|
||||
fprintf(stderr, "failed to bind\n");
|
||||
freeaddrinfo(servinfo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (listen(sockfd, ETHERNETSERVER_BACKLOG) == -1) {
|
||||
perror("listen");
|
||||
freeaddrinfo(servinfo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
freeaddrinfo(servinfo);
|
||||
|
||||
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
|
||||
void *addr = &(ipv4->sin_addr);
|
||||
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
|
||||
ETHERNETSERVER_DEBUG("Listening for connections on %s:%s\n", ipstr, portstr);
|
||||
|
||||
while (1) { // accept() loop
|
||||
sin_size = sizeof client_addr;
|
||||
new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);
|
||||
if (new_fd == -1) {
|
||||
perror("accept");
|
||||
continue;
|
||||
}
|
||||
|
||||
void *addr = &(((struct sockaddr_in*)&client_addr)->sin_addr);
|
||||
inet_ntop(client_addr.ss_family, addr, ipstr, sizeof ipstr);
|
||||
ETHERNETSERVER_DEBUG("New connection from %s\n", ipstr);
|
||||
|
||||
pthread_mutex_lock(&new_clients_mutex);
|
||||
pthread_mutex_lock(&clients_mutex);
|
||||
int connected_clients = vars->new_clients->size() + vars->clients->size();
|
||||
|
||||
if (connected_clients == MY_GATEWAY_MAX_CLIENTS) {
|
||||
pthread_mutex_unlock(&clients_mutex);
|
||||
pthread_mutex_unlock(&new_clients_mutex);
|
||||
ETHERNETSERVER_DEBUG("Max number of ethernet clients reached.");
|
||||
close(new_fd);
|
||||
usleep(5000000);
|
||||
} else {
|
||||
vars->new_clients->push_back(new_fd);
|
||||
vars->clients->push_back(new_fd);
|
||||
pthread_mutex_unlock(&clients_mutex);
|
||||
pthread_mutex_unlock(&new_clients_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
delete vars;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* Full contributor list: https://github.com/mysensors/MySensors/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.
|
||||
*
|
||||
* Based on Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved.
|
||||
*/
|
||||
|
||||
#ifndef ethernetserver_h
|
||||
#define ethernetserver_h
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include "Server.h"
|
||||
#include "EthernetClient.h"
|
||||
|
||||
#ifndef ETHERNETSERVER_BACKLOG
|
||||
#define ETHERNETSERVER_BACKLOG 10
|
||||
#endif
|
||||
|
||||
// debug
|
||||
#if defined(ETHERNETSERVER_VERBOSE)
|
||||
#define ETHERNETSERVER_DEBUG(x,...) debug(x, ##__VA_ARGS__)
|
||||
#else
|
||||
#define ETHERNETSERVER_DEBUG(x,...)
|
||||
#endif
|
||||
|
||||
class EthernetClient;
|
||||
|
||||
class EthernetServer : public Server {
|
||||
|
||||
private:
|
||||
uint16_t port;
|
||||
std::list<int> new_clients;
|
||||
std::vector<int> clients;
|
||||
|
||||
public:
|
||||
EthernetServer(uint16_t);
|
||||
virtual void begin();
|
||||
void begin(IPAddress);
|
||||
void beginPacket(IPAddress, uint16_t);
|
||||
int parsePacket();
|
||||
bool hasClient();
|
||||
EthernetClient available();
|
||||
virtual size_t write(uint8_t);
|
||||
virtual size_t write(const uint8_t *, size_t);
|
||||
size_t write(const char *str);
|
||||
size_t write(const char *buffer, size_t size);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
IPAddress.cpp - Base class that provides IPAddress
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
Modified by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include "IPAddress.h"
|
||||
|
||||
IPAddress::IPAddress() {
|
||||
_address.dword = 0;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) {
|
||||
_address.bytes[0] = first_octet;
|
||||
_address.bytes[1] = second_octet;
|
||||
_address.bytes[2] = third_octet;
|
||||
_address.bytes[3] = fourth_octet;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(uint32_t address) {
|
||||
_address.dword = address;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(const uint8_t *address) {
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
bool IPAddress::fromString(const char *address) {
|
||||
// TODO: add support for "a", "a.b", "a.b.c" formats
|
||||
|
||||
uint16_t acc = 0; // Accumulator
|
||||
uint8_t dots = 0;
|
||||
|
||||
while (*address)
|
||||
{
|
||||
char c = *address++;
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
acc = acc * 10 + (c - '0');
|
||||
if (acc > 255) {
|
||||
// Value out of [0..255] range
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (c == '.')
|
||||
{
|
||||
if (dots == 3) {
|
||||
// Too much dots (there must be 3 dots)
|
||||
return false;
|
||||
}
|
||||
_address.bytes[dots++] = acc;
|
||||
acc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid char
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (dots != 3) {
|
||||
// Too few dots (there must be 3 dots)
|
||||
return false;
|
||||
}
|
||||
_address.bytes[3] = acc;
|
||||
return true;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(const uint8_t *address) {
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
return *this;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(uint32_t address) {
|
||||
_address.dword = address;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IPAddress::operator==(const uint8_t* addr) const {
|
||||
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
|
||||
}
|
||||
|
||||
std::string IPAddress::toString()
|
||||
{
|
||||
char szRet[16];
|
||||
sprintf(szRet,"%u.%u.%u.%u", _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3]);
|
||||
return std::string(szRet);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
IPAddress.h - Base class that provides IPAddress
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
Modified by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
|
||||
*/
|
||||
|
||||
#ifndef IPAddress_h
|
||||
#define IPAddress_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
// A class to make it easier to handle and pass around IP addresses
|
||||
|
||||
// class IPAddress: public Printable {
|
||||
class IPAddress {
|
||||
private:
|
||||
union {
|
||||
uint8_t bytes[4]; // IPv4 address
|
||||
uint32_t dword;
|
||||
} _address;
|
||||
|
||||
// Access the raw byte array containing the address. Because this returns a pointer
|
||||
// to the internal structure rather than a copy of the address this function should only
|
||||
// be used when you know that the usage of the returned uint8_t* will be transient and not
|
||||
// stored.
|
||||
uint8_t* raw_address() {
|
||||
return _address.bytes;
|
||||
}
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
IPAddress();
|
||||
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
|
||||
IPAddress(uint32_t address);
|
||||
IPAddress(const uint8_t *address);
|
||||
|
||||
bool fromString(const char *address);
|
||||
bool fromString(const std::string &address) { return fromString(address.c_str()); }
|
||||
|
||||
// Overloaded cast operator to allow IPAddress objects to be used where a pointer
|
||||
// to a four-byte uint8_t array is expected
|
||||
operator uint32_t() const {
|
||||
return _address.dword;
|
||||
}
|
||||
bool operator==(const IPAddress& addr) const {
|
||||
return _address.dword == addr._address.dword;
|
||||
}
|
||||
bool operator==(uint32_t addr) const {
|
||||
return _address.dword == addr;
|
||||
}
|
||||
bool operator==(const uint8_t* addr) const;
|
||||
|
||||
// Overloaded index operator to allow getting and setting individual octets of the address
|
||||
uint8_t operator[](int index) const {
|
||||
return _address.bytes[index];
|
||||
}
|
||||
uint8_t& operator[](int index) {
|
||||
return _address.bytes[index];
|
||||
}
|
||||
|
||||
// Overloaded copy operators to allow initialisation of IPAddress objects from other types
|
||||
IPAddress& operator=(const uint8_t *address);
|
||||
IPAddress& operator=(uint32_t address);
|
||||
|
||||
std::string toString();
|
||||
|
||||
friend class Client;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Server.h - Base class that provides Server
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef server_h
|
||||
#define server_h
|
||||
|
||||
class Server {
|
||||
public:
|
||||
virtual void begin() =0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef Stream_h
|
||||
#define Stream_h
|
||||
|
||||
class Stream {
|
||||
public:
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
virtual size_t write(const uint8_t *buffer, size_t size) = 0;
|
||||
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* 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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* Full contributor list: https://github.com/mysensors/MySensors/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.
|
||||
*
|
||||
* Based on Olivier Mauti work(RF24.h), copyright (C) 2016 Olivier Mauti <olivier@mysensors.org>
|
||||
*/
|
||||
|
||||
#include "RF24.h"
|
||||
|
||||
// pipes
|
||||
#define BROADCAST_PIPE 1
|
||||
#define NODE_PIPE 2
|
||||
|
||||
// debug
|
||||
#if defined(MY_DEBUG_VERBOSE_RF24)
|
||||
#define RF24_DEBUG(x,...) debug(x, ##__VA_ARGS__)
|
||||
#else
|
||||
#define RF24_DEBUG(x,...)
|
||||
#endif
|
||||
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
typedef void (*RF24_receiveCallbackType)(void);
|
||||
|
||||
void (* RF24_receiveCallback)(void) = NULL;
|
||||
|
||||
static pthread_mutex_t rf24_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
static uint8_t MY_RF24_BASE_ADDR[MY_RF24_ADDR_WIDTH] = { MY_RF24_BASE_RADIO_ID };
|
||||
static uint8_t MY_RF24_NODE_ADDRESS = AUTO;
|
||||
|
||||
RF24 _rf24(MY_RF24_CE_PIN, MY_RF24_CS_PIN);
|
||||
|
||||
static void RF24_startListening(void) {
|
||||
RF24_DEBUG(PSTR("start listening\n"));
|
||||
|
||||
_rf24.startListening();
|
||||
}
|
||||
|
||||
static void RF24_powerDown(void) {
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_lock(&rf24_mutex);
|
||||
#endif
|
||||
_rf24.powerDown();
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_unlock(&rf24_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool RF24_sendMessage( uint8_t recipient, const void* buf, uint8_t len ) {
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_lock(&rf24_mutex);
|
||||
#endif
|
||||
// Make sure radio has powered up
|
||||
_rf24.powerUp();
|
||||
_rf24.stopListening();
|
||||
|
||||
RF24_DEBUG(PSTR("send message to %d, len=%d\n"), recipient,len);
|
||||
|
||||
MY_RF24_BASE_ADDR[0] = recipient;
|
||||
_rf24.openWritingPipe(MY_RF24_BASE_ADDR);
|
||||
bool ok = _rf24.write(buf, len, recipient == BROADCAST_ADDRESS);
|
||||
_rf24.startListening();
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_unlock(&rf24_mutex);
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool RF24_isDataAvailable() {
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_lock(&rf24_mutex);
|
||||
#endif
|
||||
uint8_t pipe_num = 255;
|
||||
_rf24.available(&pipe_num);
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_unlock(&rf24_mutex);
|
||||
#endif
|
||||
return (pipe_num <= 5);
|
||||
}
|
||||
|
||||
static uint8_t RF24_readMessage( void* buf) {
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_lock(&rf24_mutex);
|
||||
#endif
|
||||
uint8_t len = _rf24.getDynamicPayloadSize();
|
||||
_rf24.read(buf, len);
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_unlock(&rf24_mutex);
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
static void RF24_setNodeAddress(uint8_t address) {
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_lock(&rf24_mutex);
|
||||
#endif
|
||||
if (address != AUTO){
|
||||
MY_RF24_NODE_ADDRESS = address;
|
||||
// enable node pipe
|
||||
MY_RF24_BASE_ADDR[0] = MY_RF24_NODE_ADDRESS;
|
||||
_rf24.openReadingPipe(NODE_PIPE, MY_RF24_BASE_ADDR);
|
||||
// enable autoACK on node pipe
|
||||
_rf24.setAutoAck(NODE_PIPE, true);
|
||||
}
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_unlock(&rf24_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t RF24_getNodeID(void) {
|
||||
return MY_RF24_NODE_ADDRESS;
|
||||
}
|
||||
|
||||
bool RF24_sanityCheck(void) {
|
||||
bool ok = true;
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_lock(&rf24_mutex);
|
||||
#endif
|
||||
// detect HW defect ot interrupted SPI line, CE disconnect cannot be detected
|
||||
if (_rf24.getPALevel() != MY_RF24_PA_LEVEL || _rf24.getDataRate() != MY_RF24_DATARATE ||
|
||||
_rf24.getChannel() != MY_RF24_CHANNEL) {
|
||||
ok = false;
|
||||
}
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_unlock(&rf24_mutex);
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
void RF24_irqHandler(void) {
|
||||
if (RF24_receiveCallback) {
|
||||
while (RF24_isDataAvailable()) {
|
||||
RF24_receiveCallback();
|
||||
}
|
||||
} else {
|
||||
// clear RX interrupt
|
||||
bool tx_ok,tx_fail,rx;
|
||||
_rf24.whatHappened(tx_ok,tx_fail,rx);
|
||||
}
|
||||
}
|
||||
|
||||
void RF24_registerReceiveCallback(RF24_receiveCallbackType cb) {
|
||||
RF24_receiveCallback = cb;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool RF24_initialize(void) {
|
||||
// start up the radio library
|
||||
_rf24.begin();
|
||||
// determine whether the hardware is an nRF24L01+ or not
|
||||
if (!_rf24.isPVariant()) {
|
||||
RF24_DEBUG(PSTR("radio hardware not compatible"));
|
||||
return false;
|
||||
}
|
||||
// set CRC
|
||||
_rf24.setCRCLength(RF24_CRC_16);
|
||||
// set address width
|
||||
_rf24.setAddressWidth(MY_RF24_ADDR_WIDTH);
|
||||
// auto retransmit delay 1500us, auto retransmit count 15
|
||||
_rf24.setRetries(5, 15);
|
||||
// channel
|
||||
_rf24.setChannel(MY_RF24_CHANNEL);
|
||||
// PA level
|
||||
_rf24.setPALevel(MY_RF24_PA_LEVEL);
|
||||
// data rate
|
||||
_rf24.setDataRate(MY_RF24_DATARATE);
|
||||
// sanity check
|
||||
#if defined(MY_RF24_SANITY_CHECK)
|
||||
if (!RF24_sanityCheck()) {
|
||||
RF24_DEBUG(PSTR("RF24:Sanity check failed: configuration mismatch! Check wiring, replace module or non-P version\n"));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
// enable Dynamic payload
|
||||
_rf24.enableDynamicPayloads();
|
||||
// enable ACK payload
|
||||
_rf24.enableAckPayload();
|
||||
// disable AA on all pipes, activate when node pipe set
|
||||
_rf24.setAutoAck(false);
|
||||
// all nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages)
|
||||
MY_RF24_BASE_ADDR[0] = BROADCAST_ADDRESS;
|
||||
_rf24.openReadingPipe(BROADCAST_PIPE, MY_RF24_BASE_ADDR);
|
||||
|
||||
//_rf24.printDetails();
|
||||
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
// Mask all interrupts except the receive interrupt
|
||||
_rf24.maskIRQ(1,1,0);
|
||||
|
||||
attachInterrupt(MY_RF24_IRQ_PIN, INT_EDGE_FALLING, RF24_irqHandler);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* 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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyleft (c) 2016, Marcelo Aquino
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
|
||||
// Enable debug prints to monitor
|
||||
#ifndef MY_DEBUG
|
||||
#define MY_DEBUG
|
||||
#endif
|
||||
|
||||
// Config file
|
||||
#ifndef MY_LINUX_CONFIG_FILE
|
||||
#define MY_LINUX_CONFIG_FILE "/etc/MySensorGateway.cfg"
|
||||
#endif
|
||||
|
||||
// Enables and select radio type (if attached)
|
||||
#ifndef MY_RADIO_NRF24
|
||||
#define MY_RADIO_NRF24
|
||||
#endif
|
||||
|
||||
#define MY_GATEWAY_RASPBERRYPI
|
||||
|
||||
// How many clients should be able to connect to this gateway (default 1)
|
||||
#define MY_GATEWAY_MAX_CLIENTS 2
|
||||
|
||||
#ifdef MY_GATEWAY_MQTT_CLIENT
|
||||
// Set MQTT client id
|
||||
#ifndef MY_MQTT_CLIENT_ID
|
||||
#define MY_MQTT_CLIENT_ID "mysensors-1"
|
||||
#endif
|
||||
// MQTT broker ip address.
|
||||
#ifndef MY_CONTROLLER_IP_ADDRESS
|
||||
#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68
|
||||
#endif
|
||||
// The MQTT broker port to to open
|
||||
#ifndef MY_PORT
|
||||
#define MY_PORT 1883
|
||||
#endif
|
||||
|
||||
// Enable these if your MQTT broker requires usenrame/password
|
||||
//#define MY_MQTT_USER "username"
|
||||
//#define MY_MQTT_PASSWORD "password"
|
||||
|
||||
// Set this node's subscribe and publish topic prefix
|
||||
#ifndef MY_MQTT_PUBLISH_TOPIC_PREFIX
|
||||
#define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out"
|
||||
#endif
|
||||
#ifndef MY_MQTT_SUBSCRIBE_TOPIC_PREFIX
|
||||
#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in"
|
||||
#endif
|
||||
#else
|
||||
// Enable MY_IP_ADDRESS here if you want to listen for incoming network
|
||||
// connections on the specified IP address/hostname only
|
||||
//#define MY_IP_ADDRESS 192,168,178,87
|
||||
|
||||
// The port to keep open on node server mode
|
||||
#ifndef MY_PORT
|
||||
#define MY_PORT 5003
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <MySensors.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void setup() {
|
||||
}
|
||||
|
||||
void presentation() {
|
||||
// Present locally attached sensors here
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Send locally attached sensors data here
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
[Unit]
|
||||
Description=MySensors Gateway daemon
|
||||
Requires=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=%gateway_dir%/MySGateway
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,159 @@
|
||||
#! /bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: MySGateway
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: MySensors Gateway
|
||||
# Description: This file should be used to construct scripts to be
|
||||
# placed in /etc/init.d.
|
||||
### END INIT INFO
|
||||
|
||||
# Author: Foo Bar <foobar@baz.org>
|
||||
#
|
||||
# Please remove the "Author" lines above and replace them
|
||||
# with your own name if you copy and modify this script.
|
||||
|
||||
# Do NOT "set -e"
|
||||
|
||||
# PATH should only include /usr/* if it runs after the mountnfs.sh script
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin
|
||||
DESC="MySensors Gateway"
|
||||
NAME=MySGateway
|
||||
DAEMON=%gateway_dir%/$NAME
|
||||
DAEMON_ARGS="-d"
|
||||
PIDFILE=/var/run/$NAME.pid
|
||||
SCRIPTNAME=/etc/init.d/$NAME
|
||||
|
||||
# Exit if the package is not installed
|
||||
[ -x "$DAEMON" ] || exit 0
|
||||
|
||||
# Read configuration variable file if it is present
|
||||
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
|
||||
|
||||
# Load the VERBOSE setting and other rcS variables
|
||||
. /lib/init/vars.sh
|
||||
|
||||
# Define LSB log_* functions.
|
||||
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
|
||||
# and status_of_proc is working.
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
#
|
||||
# Function that starts the daemon/service
|
||||
#
|
||||
do_start()
|
||||
{
|
||||
# Return
|
||||
# 0 if daemon has been started
|
||||
# 1 if daemon was already running
|
||||
# 2 if daemon could not be started
|
||||
start-stop-daemon --start --quiet --exec $DAEMON --test > /dev/null \
|
||||
|| return 1
|
||||
start-stop-daemon --start --quiet --exec $DAEMON -- \
|
||||
$DAEMON_ARGS \
|
||||
|| return 2
|
||||
# Add code here, if necessary, that waits for the process to be ready
|
||||
# to handle requests from services started subsequently which depend
|
||||
# on this one. As a last resort, sleep for some time.
|
||||
}
|
||||
|
||||
#
|
||||
# Function that stops the daemon/service
|
||||
#
|
||||
do_stop()
|
||||
{
|
||||
# Return
|
||||
# 0 if daemon has been stopped
|
||||
# 1 if daemon was already stopped
|
||||
# 2 if daemon could not be stopped
|
||||
# other if a failure occurred
|
||||
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --name $NAME
|
||||
RETVAL="$?"
|
||||
[ "$RETVAL" = 2 ] && return 2
|
||||
# Wait for children to finish too if this is a daemon that forks
|
||||
# and if the daemon is only ever run from this initscript.
|
||||
# If the above conditions are not satisfied then add some other code
|
||||
# that waits for the process to drop all resources that could be
|
||||
# needed by services started subsequently. A last resort is to
|
||||
# sleep for some time.
|
||||
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
|
||||
[ "$?" = 2 ] && return 2
|
||||
# Many daemons don't delete their pidfiles when they exit.
|
||||
rm -f $PIDFILE
|
||||
return "$RETVAL"
|
||||
}
|
||||
|
||||
#
|
||||
# Function that sends a SIGHUP to the daemon/service
|
||||
#
|
||||
do_reload() {
|
||||
#
|
||||
# If the daemon can reload its configuration without
|
||||
# restarting (for example, when it is sent a SIGHUP),
|
||||
# then implement that here.
|
||||
#
|
||||
start-stop-daemon --stop --signal 1 --quiet --name $NAME
|
||||
return 0
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
|
||||
do_start
|
||||
case "$?" in
|
||||
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
|
||||
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
|
||||
esac
|
||||
;;
|
||||
stop)
|
||||
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
|
||||
do_stop
|
||||
case "$?" in
|
||||
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
|
||||
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
|
||||
esac
|
||||
;;
|
||||
status)
|
||||
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
|
||||
;;
|
||||
#reload|force-reload)
|
||||
#
|
||||
# If do_reload() is not implemented then leave this commented out
|
||||
# and leave 'force-reload' as an alias for 'restart'.
|
||||
#
|
||||
#log_daemon_msg "Reloading $DESC" "$NAME"
|
||||
#do_reload
|
||||
#log_end_msg $?
|
||||
#;;
|
||||
restart|force-reload)
|
||||
#
|
||||
# If the "reload" option is implemented then remove the
|
||||
# 'force-reload' alias
|
||||
#
|
||||
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||
do_stop
|
||||
case "$?" in
|
||||
0|1)
|
||||
do_start
|
||||
case "$?" in
|
||||
0) log_end_msg 0 ;;
|
||||
1) log_end_msg 1 ;; # Old process is still running
|
||||
*) log_end_msg 1 ;; # Failed to start
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
# Failed to stop
|
||||
log_end_msg 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
|
||||
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
|
||||
exit 3
|
||||
;;
|
||||
esac
|
||||
|
||||
:
|
||||
Reference in New Issue
Block a user