Code maintenance (#1261)

This commit is contained in:
tekka
2019-01-27 20:58:06 +01:00
committed by GitHub
parent 4d90c5a072
commit 71b06987ab
189 changed files with 221 additions and 217 deletions

View File

@@ -1,80 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 "BCM.h"
#include <stdlib.h>
#include "log.h"
// Declare a single default instance
BCMClass BCM = BCMClass();
uint8_t BCMClass::initialized = 0;
BCMClass::~BCMClass()
{
if (initialized) {
bcm2835_close();
initialized = 0;
}
}
uint8_t BCMClass::init()
{
if (!bcm2835_init()) {
logError("Failed to initialized bcm2835.\n");
exit(1);
}
initialized = 1;
return 1;
}
void BCMClass::pinMode(uint8_t gpio, uint8_t mode)
{
if (!initialized) {
init();
}
bcm2835_gpio_fsel(gpio, mode);
}
void BCMClass::digitalWrite(uint8_t gpio, uint8_t value)
{
if (!initialized) {
init();
}
bcm2835_gpio_write(gpio, value);
// Delay to allow any change in state to be reflected in the LEVn, register bit.
delayMicroseconds(1);
}
uint8_t BCMClass::digitalRead(uint8_t gpio)
{
if (!initialized) {
init();
}
return bcm2835_gpio_lev(gpio);
}
uint8_t BCMClass::isInitialized()
{
return initialized;
}

View File

@@ -1,92 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 BCM_h
#define BCM_h
#include <stdint.h>
#include "bcm2835.h"
#define INPUT BCM2835_GPIO_FSEL_INPT
#define OUTPUT BCM2835_GPIO_FSEL_OUTP
/**
* @brief BCM class
*/
class BCMClass
{
public:
/**
* @brief BCMClass destructor.
*/
~BCMClass();
/**
* @brief Initializes BCM.
*
* @return 1 if successful, else exits the program.
*/
uint8_t init();
/**
* @brief Configures the specified pin to behave either as an input or an output.
*
* @param gpio The GPIO pin number.
* @param mode INPUT or OUTPUT.
*/
void pinMode(uint8_t gpio, uint8_t mode);
/**
* @brief Write a high or a low value for the given pin.
*
* @param gpio The GPIO pin number.
* @param value HIGH or LOW.
*/
void digitalWrite(uint8_t gpio, uint8_t value);
/**
* @brief Reads the value from a specified pin.
*
* @param gpio The GPIO pin number.
* @return HIGH or LOW.
*/
uint8_t digitalRead(uint8_t gpio);
/**
* @brief Returns the same GPIO, no conversion is required.
*
* @param gpio The GPIO pin number.
* @return The GPIO pin number.
*/
inline uint8_t digitalPinToInterrupt(uint8_t gpio);
/**
* @brief Checks if SPI was initialized.
*
* @return 1 if initialized, else 0.
*/
uint8_t isInitialized();
private:
static uint8_t initialized; //!< @brief BCM initialized flag.
};
uint8_t BCMClass::digitalPinToInterrupt(uint8_t gpio)
{
return gpio;
}
extern BCMClass BCM;
#endif

View File

@@ -1,167 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 "RPi.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "log.h"
const static int phys_to_gpio_rev1[41] = {-1, -1, -1, 0, -1, 1, -1, 4, 14, -1, 15, 17, 18, 21, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
const static int phys_to_gpio_rev2[41] = {-1, -1, -1, 2, -1, 3, -1, 4, 14, -1, 15, 17, 18, 27, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, 5, -1, 6, 12, 13, -1, 19, 16, 26, 20, -1, 21};
// Declare a single default instance
RPiClass RPi = RPiClass();
const int* RPiClass::phys_to_gpio = NULL;
void RPiClass::pinMode(uint8_t physPin, uint8_t mode)
{
uint8_t gpioPin;
if (physToGPIO(physPin, &gpioPin) != 0) {
logError("pinMode: invalid pin: %d\n", physPin);
return;
}
BCM.pinMode(gpioPin, mode);
}
void RPiClass::digitalWrite(uint8_t physPin, uint8_t value)
{
uint8_t gpioPin;
if (physToGPIO(physPin, &gpioPin) != 0) {
logError("digitalWrite: invalid pin: %d\n", physPin);
return;
}
BCM.digitalWrite(gpioPin, value);
}
uint8_t RPiClass::digitalRead(uint8_t physPin)
{
uint8_t gpioPin;
if (physToGPIO(physPin, &gpioPin) != 0) {
logError("digitalRead: invalid pin: %d\n", physPin);
return 0;
}
return BCM.digitalRead(gpioPin);
}
uint8_t RPiClass::digitalPinToInterrupt(uint8_t physPin)
{
uint8_t gpioPin;
if (physToGPIO(physPin, &gpioPin) != 0) {
logError("digitalPinToInterrupt: invalid pin: %d\n", physPin);
return 0;
}
return gpioPin;
}
int RPiClass::rpiGpioLayout()
{
/*
* Based on wiringPi Copyright (c) 2012 Gordon Henderson.
*/
FILE *fd;
char line[120];
char *c;
if ((fd = fopen("/proc/cpuinfo", "r")) == NULL) {
return -1;
}
while (fgets(line, 120, fd) != NULL) {
if (strncmp(line, "Revision", 8) == 0) {
fclose(fd);
// Chop trailing CR/NL
for (c = &line[strlen(line) - 1]; (*c == '\n') || (*c == '\r'); --c) {
*c = 0;
}
// Scan to the first character of the revision number
for (c = line; *c; ++c) {
if (*c == ':') {
// Chop spaces
++c;
while (isspace(*c)) {
++c;
}
// Check hex digit at start
if (!isxdigit(*c)) {
return -1;
}
// Check bogus revision line (too small)
if (strlen(c) < 4) {
return -1;
}
// Isolate last 4 characters: (in-case of overvolting or new encoding scheme)
c = c + strlen(c) - 4;
if ((strcmp(c, "0002") == 0) || (strcmp(c, "0003") == 0) ||
(strcmp(c, "0004") == 0) || (strcmp(c, "0005") == 0) ||
(strcmp(c, "0006") == 0) || (strcmp(c, "0007") == 0) ||
(strcmp(c, "0008") == 0) || (strcmp(c, "0009") == 0) ||
(strcmp(c, "000d") == 0) || (strcmp(c, "000e") == 0) ||
(strcmp(c, "000f") == 0)) {
return 1;
} else {
return 2;
}
}
}
}
}
fclose(fd);
return -1;
}
int RPiClass::physToGPIO(uint8_t physPin, uint8_t *gpio)
{
if (phys_to_gpio == NULL) {
if (rpiGpioLayout() == 1) {
// A, B, Rev 1, 1.1
phys_to_gpio = &phys_to_gpio_rev1[0];
} else {
// A2, B2, A+, B+, CM, Pi2, Pi3, Zero
phys_to_gpio = &phys_to_gpio_rev2[0];
}
}
if (gpio == NULL || physPin > 40) {
return -1;
}
int pin = *(phys_to_gpio+physPin);
if (pin == -1) {
return -1;
} else {
*gpio = pin;
}
return 0;
}

View File

@@ -1,82 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 RPi_h
#define RPi_h
#include <stdint.h>
#include "BCM.h"
/**
* @brief RPi class
*/
class RPiClass
{
public:
/**
* @brief Configures the specified pin to behave either as an input or an output.
*
* @param physPin The physical number of the pin.
* @param mode INPUT or OUTPUT.
*/
void pinMode(uint8_t physPin, uint8_t mode);
/**
* @brief Write a high or a low value for the given pin.
*
* @param physPin The physical number of the pin.
* @param value HIGH or LOW.
*/
void digitalWrite(uint8_t physPin, uint8_t value);
/**
* @brief Reads the value from a specified pin.
*
* @param physPin The physical number of the pin.
* @return HIGH or LOW.
*/
uint8_t digitalRead(uint8_t physPin);
/**
* @brief Translate the physical pin number to the GPIO number for use in interrupt.
*
* @param physPin The physical number of the pin.
* @return The GPIO pin number.
*/
uint8_t digitalPinToInterrupt(uint8_t physPin);
/**
* @brief Translate the physical pin number to the GPIO number.
*
* @param physPin The physical number of the pin.
* @param gpio Pointer to write the GPIO pin number when success.
* @return -1 if FAILURE or 0 if SUCCESS.
*/
static int physToGPIO(uint8_t physPin, uint8_t *gpio);
private:
static const int *phys_to_gpio; //!< @brief Pointer to array of GPIO pins numbers.
/**
* @brief Get the gpio layout.
*
* @return The gpio layout number.
*/
static int rpiGpioLayout(void);
};
extern RPiClass RPi;
#endif

View File

@@ -1,110 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard <tmrh20@gmail.com>
*/
#include "SPIBCM.h"
#include <pthread.h>
#include <stdlib.h>
#include "log.h"
static pthread_mutex_t spiMutex = PTHREAD_MUTEX_INITIALIZER;
// Declare a single default instance
SPIBCMClass SPIBCM = SPIBCMClass();
uint8_t SPIBCMClass::initialized = 0;
void SPIBCMClass::begin()
{
if (!initialized) {
if (!BCM.isInitialized()) {
BCM.init();
}
if (!bcm2835_spi_begin()) {
logError("You need root privilege to use SPI.\n");
exit(1);
}
}
initialized++; // reference count
}
void SPIBCMClass::end()
{
if (initialized) {
initialized--;
}
if (!initialized) {
// End the SPI
bcm2835_spi_end();
}
}
void SPIBCMClass::setBitOrder(uint8_t bit_order)
{
bcm2835_spi_setBitOrder(bit_order);
}
void SPIBCMClass::setDataMode(uint8_t data_mode)
{
bcm2835_spi_setDataMode(data_mode);
}
void SPIBCMClass::setClockDivider(uint16_t divider)
{
bcm2835_spi_setClockDivider(divider);
}
void SPIBCMClass::chipSelect(int csn_pin)
{
if (csn_pin == RPI_GPIO_P1_26) {
csn_pin = BCM2835_SPI_CS1;
} else if (csn_pin == RPI_GPIO_P1_24) {
csn_pin = BCM2835_SPI_CS0;
} else {
csn_pin = BCM2835_SPI_CS0;
}
bcm2835_spi_chipSelect(csn_pin);
delayMicroseconds(5);
}
void SPIBCMClass::beginTransaction(SPISettings settings)
{
pthread_mutex_lock(&spiMutex);
setBitOrder(settings.border);
setDataMode(settings.dmode);
setClockDivider(settings.cdiv);
}
void SPIBCMClass::endTransaction()
{
pthread_mutex_unlock(&spiMutex);
}
void SPIBCMClass::usingInterrupt(uint8_t interruptNumber)
{
(void)interruptNumber;
}
void SPIBCMClass::notUsingInterrupt(uint8_t interruptNumber)
{
(void)interruptNumber;
}

View File

@@ -1,262 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard <tmrh20@gmail.com>
*/
#ifndef SPIBCM_h
#define SPIBCM_h
#include <stdio.h>
#include "bcm2835.h"
#include "BCM.h"
#define SPI_HAS_TRANSACTION
#define SPI_CLOCK_BASE 256000000
// SPI Clock divider
#define SPI_CLOCK_DIV1 BCM2835_SPI_CLOCK_DIVIDER_1
#define SPI_CLOCK_DIV2 BCM2835_SPI_CLOCK_DIVIDER_2
#define SPI_CLOCK_DIV4 BCM2835_SPI_CLOCK_DIVIDER_4
#define SPI_CLOCK_DIV8 BCM2835_SPI_CLOCK_DIVIDER_8
#define SPI_CLOCK_DIV16 BCM2835_SPI_CLOCK_DIVIDER_16
#define SPI_CLOCK_DIV32 BCM2835_SPI_CLOCK_DIVIDER_32
#define SPI_CLOCK_DIV64 BCM2835_SPI_CLOCK_DIVIDER_64
#define SPI_CLOCK_DIV128 BCM2835_SPI_CLOCK_DIVIDER_128
#define SPI_CLOCK_DIV256 BCM2835_SPI_CLOCK_DIVIDER_256
#define SPI_CLOCK_DIV512 BCM2835_SPI_CLOCK_DIVIDER_512
#define SPI_CLOCK_DIV1024 BCM2835_SPI_CLOCK_DIVIDER_1024
#define SPI_CLOCK_DIV2048 BCM2835_SPI_CLOCK_DIVIDER_2048
#define SPI_CLOCK_DIV4096 BCM2835_SPI_CLOCK_DIVIDER_4096
#define SPI_CLOCK_DIV8192 BCM2835_SPI_CLOCK_DIVIDER_8192
#define SPI_CLOCK_DIV16384 BCM2835_SPI_CLOCK_DIVIDER_16384
#define SPI_CLOCK_DIV32768 BCM2835_SPI_CLOCK_DIVIDER_32768
#define SPI_CLOCK_DIV65536 BCM2835_SPI_CLOCK_DIVIDER_65536
// SPI Data mode
#define SPI_MODE0 BCM2835_SPI_MODE0
#define SPI_MODE1 BCM2835_SPI_MODE1
#define SPI_MODE2 BCM2835_SPI_MODE2
#define SPI_MODE3 BCM2835_SPI_MODE3
#define LSBFIRST BCM2835_SPI_BIT_ORDER_LSBFIRST
#define MSBFIRST BCM2835_SPI_BIT_ORDER_MSBFIRST
const uint8_t SS = 24;
const uint8_t MOSI = 19;
const uint8_t MISO = 21;
const uint8_t SCK = 23;
/**
* SPISettings class
*/
class SPISettings
{
public:
/**
* @brief SPISettings constructor.
*
* Default clock speed is 8Mhz.
*/
SPISettings()
{
init(SPI_CLOCK_DIV32, MSBFIRST, SPI_MODE0);
}
/**
* @brief SPISettings constructor.
*
* @param clock SPI clock speed in Hz.
* @param bitOrder SPI bit order.
* @param dataMode SPI data mode.
*/
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
{
uint16_t divider;
if (clock >= SPI_CLOCK_BASE) {
divider = SPI_CLOCK_DIV1;
} else if (clock >= SPI_CLOCK_BASE / 2) {
divider = SPI_CLOCK_DIV2;
} else if (clock >= SPI_CLOCK_BASE / 4) {
divider = SPI_CLOCK_DIV4;
} else if (clock >= SPI_CLOCK_BASE / 8) {
divider = SPI_CLOCK_DIV8;
} else if (clock >= SPI_CLOCK_BASE / 16) {
divider = SPI_CLOCK_DIV16;
} else if (clock >= SPI_CLOCK_BASE / 32) {
divider = SPI_CLOCK_DIV32;
} else if (clock >= SPI_CLOCK_BASE / 64) {
divider = SPI_CLOCK_DIV64;
} else if (clock >= SPI_CLOCK_BASE / 128) {
divider = SPI_CLOCK_DIV128;
} else if (clock >= SPI_CLOCK_BASE / 256) {
divider = SPI_CLOCK_DIV256;
} else if (clock >= SPI_CLOCK_BASE / 512) {
divider = SPI_CLOCK_DIV512;
} else if (clock >= SPI_CLOCK_BASE / 1024) {
divider = SPI_CLOCK_DIV1024;
} else if (clock >= SPI_CLOCK_BASE / 2048) {
divider = SPI_CLOCK_DIV2048;
} else if (clock >= SPI_CLOCK_BASE / 4096) {
divider = SPI_CLOCK_DIV4096;
} else if (clock >= SPI_CLOCK_BASE / 8192) {
divider = SPI_CLOCK_DIV8192;
} else if (clock >= SPI_CLOCK_BASE / 16384) {
divider = SPI_CLOCK_DIV16384;
} else if (clock >= SPI_CLOCK_BASE / 32768) {
divider = SPI_CLOCK_DIV32768;
} else if (clock >= SPI_CLOCK_BASE / 65536) {
divider = SPI_CLOCK_DIV65536;
} else {
// Default to 8Mhz
divider = SPI_CLOCK_DIV32;
}
init(divider, bitOrder, dataMode);
}
uint16_t cdiv; //!< @brief SPI clock divider.
uint8_t border; //!< @brief SPI bit order.
uint8_t dmode; //!< @brief SPI data mode.
private:
/**
* @brief Initialized class members.
*
* @param divider SPI clock divider.
* @param bitOrder SPI bit order.
* @param dataMode SPI data mode.
*/
void init(uint16_t divider, uint8_t bitOrder, uint8_t dataMode)
{
cdiv = divider;
border = bitOrder;
dmode = dataMode;
}
friend class SPIBCMClass;
};
/**
* SPIBCM class
*/
class SPIBCMClass
{
public:
/**
* @brief Send and receive a byte.
*
* @param data to send.
* @return byte received.
*/
inline static uint8_t transfer(uint8_t data);
/**
* @brief Send and receive a number of bytes.
*
* @param tbuf Sending buffer.
* @param rbuf Receive buffer.
* @param len Buffer length.
*/
inline static void transfernb(char* tbuf, char* rbuf, uint32_t len);
/**
* @brief Send and receive a number of bytes.
*
* @param buf Buffer to read from and write to.
* @param len Buffer length.
*/
inline static void transfern(char* buf, uint32_t len);
/**
* @brief Start SPI operations.
*/
static void begin();
/**
* @brief End SPI operations.
*/
static void end();
/**
* @brief Sets the SPI bit order.
*
* @param bit_order The desired bit order.
*/
static void setBitOrder(uint8_t bit_order);
/**
* @brief Sets the SPI data mode.
*
* @param data_mode The desired data mode.
*/
static void setDataMode(uint8_t data_mode);
/**
* @brief Sets the SPI clock divider and therefore the SPI clock speed.
*
* @param divider The desired SPI clock divider.
*/
static void setClockDivider(uint16_t divider);
/**
* @brief Sets the chip select pin.
*
* @param csn_pin Specifies the CS pin.
*/
static void chipSelect(int csn_pin);
/**
* @brief Start SPI transaction.
*
* @param settings for SPI.
*/
static void beginTransaction(SPISettings settings);
/**
* @brief End SPI transaction.
*/
static void endTransaction();
/**
* @brief Not implemented.
*
* @param interruptNumber ignored parameter.
*/
static void usingInterrupt(uint8_t interruptNumber);
/**
* @brief Not implemented.
*
* @param interruptNumber ignored parameter.
*/
static void notUsingInterrupt(uint8_t interruptNumber);
private:
static uint8_t initialized; //!< @brief SPI initialized flag.
};
uint8_t SPIBCMClass::transfer(uint8_t data)
{
return bcm2835_spi_transfer(data);
}
void SPIBCMClass::transfernb(char* tbuf, char* rbuf, uint32_t len)
{
bcm2835_spi_transfernb( tbuf, rbuf, len);
}
void SPIBCMClass::transfern(char* buf, uint32_t len)
{
transfernb(buf, buf, len);
}
extern SPIBCMClass SPIBCM;
#endif

View File

@@ -1,213 +0,0 @@
/*
TwoWire.h - TWI/I2C library for Arduino & Wiring
Copyright (c) 2006 Nicholas Zambetti. 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 2012 by Todd Krein (todd@krein.org) to implement repeated starts
Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support
Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support
Modified October 2016 by Marcelo Aquino <marceloaqno@gmail.org> for Raspberry Pi
*/
#include "Wire.h"
#include <stdlib.h>
#include <pthread.h>
#include "bcm2835.h"
#include "log.h"
static pthread_mutex_t i2cMutex = PTHREAD_MUTEX_INITIALIZER;
uint8_t TwoWire::rxBuffer[BUFFER_LENGTH];
uint8_t TwoWire::rxBufferIndex = 0;
uint8_t TwoWire::rxBufferLength = 0;
uint8_t TwoWire::txAddress = 0;
uint8_t TwoWire::txBuffer[BUFFER_LENGTH];
uint8_t TwoWire::txBufferIndex = 0;
uint8_t TwoWire::txBufferLength = 0;
uint8_t TwoWire::transmitting = 0;
void TwoWire::begin()
{
if (!bcm2835_i2c_begin()) {
logError("You need root privilege to use I2C.\n");
exit(1);
}
}
void TwoWire::begin(uint8_t address)
{
begin();
bcm2835_i2c_setSlaveAddress(address);
}
void TwoWire::begin(int address)
{
begin(static_cast<uint8_t>(address));
}
void TwoWire::end()
{
bcm2835_i2c_end();
}
void TwoWire::setClock(uint32_t clock)
{
bcm2835_i2c_set_baudrate(clock);
}
void TwoWire::beginTransmission(uint8_t address)
{
pthread_mutex_lock(&i2cMutex);
// indicate that we are transmitting
transmitting = 1;
// set address of targeted slave
txAddress = address;
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
}
void TwoWire::beginTransmission(int address)
{
beginTransmission(static_cast<uint8_t>(address));
}
uint8_t TwoWire::endTransmission(void)
{
// transmit buffer
bcm2835_i2c_setSlaveAddress(txAddress);
uint8_t ret = bcm2835_i2c_write(reinterpret_cast<const char *>(txBuffer), txBufferLength);
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
// indicate that we are done transmitting
transmitting = 0;
pthread_mutex_unlock(&i2cMutex);
if (ret == BCM2835_I2C_REASON_OK) {
return 0; // success
} else if (ret == BCM2835_I2C_REASON_ERROR_NACK) {
return 3; // error: data send, nack received
}
return 4; // other error
}
size_t TwoWire::requestFrom(uint8_t address, size_t quantity)
{
// clamp to buffer length
if (quantity > BUFFER_LENGTH) {
quantity = BUFFER_LENGTH;
}
rxBufferIndex = 0;
rxBufferLength = 0;
bcm2835_i2c_setSlaveAddress(address);
uint8_t ret = bcm2835_i2c_read(reinterpret_cast<char *>(rxBuffer), quantity);
if (ret == BCM2835_I2C_REASON_OK) {
rxBufferLength = quantity;
}
return rxBufferLength;
}
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
{
return requestFrom(address, static_cast<size_t>(quantity));
}
uint8_t TwoWire::requestFrom(int address, int quantity)
{
return requestFrom(static_cast<uint8_t>(address), static_cast<size_t>(quantity));
}
size_t TwoWire::write(uint8_t data)
{
if (transmitting) {
// in master transmitter mode
// don't bother if buffer is full
if (txBufferLength >= BUFFER_LENGTH) {
setWriteError();
return 0;
}
// put byte in tx buffer
txBuffer[txBufferIndex] = data;
++txBufferIndex;
// update amount in buffer
txBufferLength = txBufferIndex;
return 1;
} else {
return write(&data, 1);
}
}
size_t TwoWire::write(const uint8_t *data, size_t quantity)
{
if (transmitting) {
// in master transmitter mode
for (size_t i = 0; i < quantity; ++i) {
write(data[i]);
}
} else {
uint8_t rc = bcm2835_i2c_write(reinterpret_cast<const char *>(data), quantity);
if (rc != BCM2835_I2C_REASON_OK) {
return 0;
}
}
return quantity;
}
int TwoWire::available()
{
return rxBufferLength - rxBufferIndex;
}
int TwoWire::read()
{
int value = -1;
if (rxBufferIndex < rxBufferLength) {
value = rxBuffer[rxBufferIndex];
++rxBufferIndex;
}
return value;
}
int TwoWire::peek()
{
if (rxBufferIndex < rxBufferLength) {
return rxBuffer[rxBufferIndex];
}
return -1;
}
void TwoWire::flush()
{
rxBufferIndex = 0;
rxBufferLength = 0;
txBufferIndex = 0;
txBufferLength = 0;
}
TwoWire Wire = TwoWire();

View File

@@ -1,94 +0,0 @@
/*
TwoWire.h - TWI/I2C library for Arduino & Wiring
Copyright (c) 2006 Nicholas Zambetti. 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 2012 by Todd Krein (todd@krein.org) to implement repeated starts
Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support
Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support
Modified October 2016 by Marcelo Aquino <marceloaqno@gmail.org> for Raspberry Pi
*/
#ifndef Wire_h
#define Wire_h
#if !DOXYGEN
#include <stdint.h>
#include "Stream.h"
#include "BCM.h"
#define BUFFER_LENGTH 32
class TwoWire : public Stream
{
private:
static uint8_t rxBuffer[];
static uint8_t rxBufferIndex;
static uint8_t rxBufferLength;
static uint8_t txAddress;
static uint8_t txBuffer[];
static uint8_t txBufferIndex;
static uint8_t txBufferLength;
static uint8_t transmitting;
public:
void begin();
void begin(uint8_t address);
void begin(int address);
void end();
void setClock(uint32_t clock);
void beginTransmission(uint8_t address);
void beginTransmission(int address);
uint8_t endTransmission(void);
size_t requestFrom(uint8_t address, size_t size);
uint8_t requestFrom(uint8_t address, uint8_t quantity);
uint8_t requestFrom(int address, int quantity);
size_t write(uint8_t data);
size_t write(const uint8_t *data, size_t quantity);
int available();
int read();
int peek();
void flush();
inline size_t write(unsigned long n)
{
return write((uint8_t)n);
}
inline size_t write(long n)
{
return write((uint8_t)n);
}
inline size_t write(unsigned int n)
{
return write((uint8_t)n);
}
inline size_t write(int n)
{
return write((uint8_t)n);
}
using Print::write;
};
extern TwoWire Wire;
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,115 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 Arduino_h
#define Arduino_h
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <string>
#include <algorithm>
#include "stdlib_noniso.h"
#ifdef LINUX_ARCH_RASPBERRYPI
#include "RPi.h"
#define pinMode(pin, direction) RPi.pinMode(pin, direction)
#define digitalWrite(pin, value) RPi.digitalWrite(pin, value)
#define digitalRead(pin) RPi.digitalRead(pin)
#define digitalPinToInterrupt(pin) RPi.digitalPinToInterrupt(pin)
#else
#include "GPIO.h"
#define pinMode(pin, direction) GPIO.pinMode(pin, direction)
#define digitalWrite(pin, value) GPIO.digitalWrite(pin, value)
#define digitalRead(pin) GPIO.digitalRead(pin)
#define digitalPinToInterrupt(pin) GPIO.digitalPinToInterrupt(pin)
#endif
#include "interrupt.h"
#undef PSTR
#define PSTR(x) (x)
#undef F
#define F(x) (x)
#define PROGMEM __attribute__(( section(".progmem.data") ))
#define vsnprintf_P(...) vsnprintf( __VA_ARGS__ )
#define snprintf_P(...) snprintf( __VA_ARGS__ )
#define memcpy_P memcpy
#define pgm_read_byte(p) (*(p))
#define pgm_read_dword(p) (*(p))
#define pgm_read_byte_near(p) (*(p))
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define TWO_PI 6.283185307179586476925286766559
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.295779513082320876798154814105
#define EULER 2.718281828459045235360287471352
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#define radians(deg) ((deg)*DEG_TO_RAD)
#define degrees(rad) ((rad)*RAD_TO_DEG)
#define sq(x) ((x)*(x))
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
#define lowByte(w) ((uint8_t) ((w) & 0xff))
#define highByte(w) ((uint8_t) ((w) >> 8))
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
#define bit(b) (1UL << (b))
#define GET_MACRO(_0, _1, _2, NAME, ...) NAME
#define random(...) GET_MACRO(_0, ##__VA_ARGS__, randMinMax, randMax, rand)(__VA_ARGS__)
#ifndef delay
#define delay _delay_milliseconds
#endif
#ifndef delayMicroseconds
#define delayMicroseconds _delay_microseconds
#endif
using std::string;
using std::min;
using std::max;
using std::abs;
typedef uint8_t byte;
typedef string String;
typedef char __FlashStringHelper;
void yield(void);
unsigned long millis(void);
unsigned long micros(void);
void _delay_milliseconds(unsigned int millis);
void _delay_microseconds(unsigned int micro);
void randomSeed(unsigned long seed);
long randMax(long howbig);
long randMinMax(long howsmall, long howbig);
#endif

View File

@@ -1,54 +0,0 @@
/*
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"
#if !DOXYGEN
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
#endif

View File

@@ -1,311 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 "EthernetClient.h"
#include <cstdio>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <cstring>
#include <unistd.h>
#include <sys/time.h>
#include <netinet/tcp.h>
#include <errno.h>
#include "log.h"
EthernetClient::EthernetClient() : _sock(-1)
{
}
EthernetClient::EthernetClient(int sock) : _sock(sock)
{
}
int EthernetClient::connect(const char* host, uint16_t port)
{
struct addrinfo hints, *servinfo, *localinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
char port_str[6];
bool use_bind = (_srcip != 0);
close();
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) {
logError("getaddrinfo: %s\n", gai_strerror(rv));
return -1;
}
if (use_bind) {
if ((rv = getaddrinfo(_srcip.toString().c_str(), port_str, &hints, &localinfo)) != 0) {
logError("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 ((_sock = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
logError("socket: %s\n", strerror(errno));
continue;
}
if (use_bind) {
if (::bind(_sock, localinfo->ai_addr, localinfo->ai_addrlen) == -1) {
close();
logError("bind: %s\n", strerror(errno));
return -1;
}
}
if (::connect(_sock, p->ai_addr, p->ai_addrlen) == -1) {
close();
logError("connect: %s\n", strerror(errno));
continue;
}
break;
}
if (p == NULL) {
logError("failed to connect\n");
return -1;
}
void *addr = &(((struct sockaddr_in*)p->ai_addr)->sin_addr);
inet_ntop(p->ai_family, addr, s, sizeof s);
logDebug("connected to %s\n", s);
freeaddrinfo(servinfo); // all done with this structure
if (use_bind) {
freeaddrinfo(localinfo); // 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 bytes = 0;
if (_sock == -1) {
return 0;
}
while (size > 0) {
int rc = send(_sock, buf + bytes, size, MSG_NOSIGNAL | MSG_DONTWAIT);
if (rc == -1) {
logError("send: %s\n", strerror(errno));
close();
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, SIOCINQ, &count);
}
return count;
}
int EthernetClient::read()
{
uint8_t b;
if ( recv(_sock, &b, 1, MSG_DONTWAIT) > 0 ) {
// recv worked
return b;
} else {
// No data available
return -1;
}
}
int EthernetClient::read(uint8_t *buf, size_t bytes)
{
return recv(_sock, buf, bytes, MSG_DONTWAIT);
}
int EthernetClient::peek()
{
uint8_t b;
if (recv(_sock, &b, 1, MSG_PEEK | MSG_DONTWAIT) > 0) {
return b;
} else {
return -1;
}
}
void EthernetClient::flush()
{
int count = 0;
if (_sock != -1) {
while (true) {
ioctl(_sock, SIOCOUTQ, &count);
if (count == 0) {
return;
}
usleep(1000);
}
}
}
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
do {
uint8_t 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);
// free up the socket descriptor
::close(_sock);
_sock = -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;
}
}
return ETHERNETCLIENT_W5100_CLOSED;
}
uint8_t EthernetClient::connected()
{
return status() == ETHERNETCLIENT_W5100_ESTABLISHED || available();
}
void EthernetClient::close()
{
if (_sock != -1) {
::close(_sock);
_sock = -1;
}
}
void EthernetClient::bind(IPAddress ip)
{
_srcip = ip;
}
int EthernetClient::getSocketNumber()
{
return _sock;
}
// 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;
}

View File

@@ -1,211 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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
/**
* EthernetClient class
*/
class EthernetClient : public Client
{
public:
/**
* @brief EthernetClient constructor.
*/
EthernetClient();
/**
* @brief EthernetClient constructor.
*
* @param sock Network socket.
*/
explicit EthernetClient(int sock);
/**
* @brief Initiate a connection with host:port.
*
* @param host name to resolve or a stringified dotted IP address.
* @param port to connect to.
* @return 1 if SUCCESS or -1 if FAILURE.
*/
virtual int connect(const char *host, uint16_t port);
/**
* @brief Initiate a connection with ip:port.
*
* @param ip to connect to.
* @param port to connect to.
* @return 1 if SUCCESS or -1 if FAILURE.
*/
virtual int connect(IPAddress ip, uint16_t port);
/**
* @brief Write a byte.
*
* @param b byte to write.
* @return 0 if FAILURE or 1 if SUCCESS.
*/
virtual size_t write(uint8_t b);
/**
* @brief Write at most 'size' bytes.
*
* @param buf Buffer to read from.
* @param size of the buffer.
* @return 0 if FAILURE or the number of bytes sent.
*/
virtual size_t write(const uint8_t *buf, size_t size);
/**
* @brief Write a null-terminated string.
*
* @param str String to write.
* @return 0 if FAILURE or number of characters sent.
*/
size_t write(const char *str);
/**
* @brief Write at most 'size' characters.
*
* @param buffer to read from.
* @param size of the buffer.
* @return 0 if FAILURE or the number of characters sent.
*/
size_t write(const char *buffer, size_t size);
/**
* @brief Returns the number of bytes available for reading.
*
* @return number of bytes available.
*/
virtual int available();
/**
* @brief Read a byte.
*
* @return -1 if no data, else the first byte available.
*/
virtual int read();
/**
* @brief Read a number of bytes and store in a buffer.
*
* @param buf buffer to write to.
* @param bytes number of bytes to read.
* @return -1 if no data or number of read bytes.
*/
virtual int read(uint8_t *buf, size_t bytes);
/**
* @brief Returns the next byte of the read queue without removing it from the queue.
*
* @return -1 if no data, else the first byte of incoming data available.
*/
virtual int peek();
/**
* @brief Waits until all outgoing bytes in buffer have been sent.
*/
virtual void flush();
/**
* @brief Close the connection gracefully.
*
* Send a FIN and wait 1s for a response. If no response close it forcefully.
*/
virtual void stop();
/**
* @brief Connection status.
*
* @return state according to W5100 library codes.
*/
uint8_t status();
/**
* @brief Whether or not the client is connected.
*
* Note that a client is considered connected if the connection has been closed but
* there is still unread data.
*
* @return 1 if the client is connected, 0 if not.
*/
virtual uint8_t connected();
/**
* @brief Close the connection.
*/
void close();
/**
* @brief Bind the conection to the specified local ip.
*/
void bind(IPAddress ip);
/**
* @brief Get the internal socket file descriptor.
*
* @return an integer, that is the socket number.
*/
int getSocketNumber();
/**
* @brief Overloaded cast operators.
*
* Allow EthernetClient objects to be used where a bool is expected.
*/
virtual operator bool();
/**
* @brief Overloaded cast operators.
*
*/
virtual bool operator==(const bool value)
{
return bool() == value;
}
/**
* @brief Overloaded cast operators.
*
*/
virtual bool operator!=(const bool value)
{
return bool() != value;
}
/**
* @brief Overloaded cast operators.
*
*/
virtual bool operator==(const EthernetClient& rhs);
/**
* @brief Overloaded cast operators.
*
*/
virtual bool operator!=(const EthernetClient& rhs)
{
return !this->operator==(rhs);
};
friend class EthernetServer;
private:
int _sock; //!< @brief Network socket file descriptor.
IPAddress _srcip; //!< @brief Local ip to bind to.
};
#endif

View File

@@ -1,211 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 "EthernetServer.h"
#include <cstdio>
#include <sys/socket.h>
#include <cstring>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include "log.h"
#include "EthernetClient.h"
EthernetServer::EthernetServer(uint16_t port, uint16_t max_clients) : port(port),
max_clients(max_clients), sockfd(-1)
{
clients.reserve(max_clients);
}
void EthernetServer::begin()
{
begin(IPAddress(0,0,0,0));
}
void EthernetServer::begin(IPAddress address)
{
struct addrinfo hints, *servinfo, *p;
int yes=1;
int rv;
char ipstr[INET_ADDRSTRLEN];
char portstr[6];
if (sockfd != -1) {
close(sockfd);
sockfd = -1;
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
sprintf(portstr, "%d", port);
if ((rv = getaddrinfo(address.toString().c_str(), portstr, &hints, &servinfo)) != 0) {
logError("getaddrinfo: %s\n", gai_strerror(rv));
return;
}
// 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) {
logError("socket: %s\n", strerror(errno));
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
logError("setsockopt: %s\n", strerror(errno));
freeaddrinfo(servinfo);
return;
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
logError("bind: %s\n", strerror(errno));
continue;
}
break;
}
if (p == NULL) {
logError("Failed to bind!\n");
freeaddrinfo(servinfo);
return;
}
if (listen(sockfd, ETHERNETSERVER_BACKLOG) == -1) {
logError("listen: %s\n", strerror(errno));
freeaddrinfo(servinfo);
return;
}
freeaddrinfo(servinfo);
fcntl(sockfd, F_SETFL, O_NONBLOCK);
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
void *addr = &(ipv4->sin_addr);
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
logDebug("Listening for connections on %s:%s\n", ipstr, portstr);
}
bool EthernetServer::hasClient()
{
// Check if any client has disconnected
for (size_t i = 0; i < clients.size(); ++i) {
EthernetClient client(clients[i]);
if (!client.connected()) {
// Checks if this disconnected client is also on the new clients list
for (std::list<int>::iterator it = new_clients.begin(); it != new_clients.end(); ++it) {
if (*it == clients[i]) {
new_clients.erase(it);
break;
}
}
client.stop();
clients[i] = clients.back();
clients.pop_back();
logDebug("Ethernet client disconnected.\n");
}
}
_accept();
return !new_clients.empty();
}
EthernetClient EthernetServer::available()
{
if (new_clients.empty()) {
return EthernetClient();
} else {
int sock = new_clients.front();
new_clients.pop_front();
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;
for (size_t i = 0; i < clients.size(); ++i) {
EthernetClient client(clients[i]);
if (client.status() == ETHERNETCLIENT_W5100_ESTABLISHED) {
n += client.write(buffer, size);
}
}
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 EthernetServer::_accept()
{
int new_fd;
socklen_t sin_size;
struct sockaddr_storage client_addr;
char ipstr[INET_ADDRSTRLEN];
sin_size = sizeof client_addr;
new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);
if (new_fd == -1) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
logError("accept: %s\n", strerror(errno));
}
return;
}
if (clients.size() == max_clients) {
// no free slots, search for a dead client
close(new_fd);
logDebug("Max number of ethernet clients reached.\n");
return;
}
new_clients.push_back(new_fd);
clients.push_back(new_fd);
void *addr = &(((struct sockaddr_in*)&client_addr)->sin_addr);
inet_ntop(client_addr.ss_family, addr, ipstr, sizeof ipstr);
logDebug("New connection from %s\n", ipstr);
}

View File

@@ -1,121 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 "IPAddress.h"
#ifdef ETHERNETSERVER_MAX_CLIENTS
#define ETHERNETSERVER_BACKLOG ETHERNETSERVER_MAX_CLIENTS //!< Maximum length to which the queue of pending connections may grow.
#else
#define ETHERNETSERVER_MAX_CLIENTS 10 //!< Default value for max_clients.
#define ETHERNETSERVER_BACKLOG 10 //!< Maximum length to which the queue of pending connections may grow.
#endif
class EthernetClient;
/**
* @brief EthernetServer class
*/
class EthernetServer : public Server
{
public:
/**
* @brief EthernetServer constructor.
*
* @param port number for the socket addresses.
* @param max_clients The maximum number allowed for connected clients.
*/
EthernetServer(uint16_t port, uint16_t max_clients = ETHERNETSERVER_MAX_CLIENTS);
/**
* @brief Listen for inbound connection request.
*
*/
virtual void begin();
/**
* @brief Listen on the specified ip for inbound connection request.
*
* @param addr IP address to bind to.
*/
void begin(IPAddress addr);
/**
* @brief Verifies if a new client has connected.
*
* @return @c true if a new client has connected, else @c false.
*/
bool hasClient();
/**
* @brief Get the new connected client.
*
* @return a EthernetClient object; if no new client has connected, this object will evaluate to false.
*/
EthernetClient available();
/**
* @brief Write a byte to all clients.
*
* @param b byte to send.
* @return 0 if FAILURE or 1 if SUCCESS.
*/
virtual size_t write(uint8_t b);
/**
* @brief Write at most 'size' bytes to all clients.
*
* @param buffer to read from.
* @param size of the buffer.
* @return 0 if FAILURE else number of bytes sent.
*/
virtual size_t write(const uint8_t *buffer, size_t size);
/**
* @brief Write a null-terminated string to all clients.
*
* @param str String to write.
* @return 0 if FAILURE else number of characters sent.
*/
size_t write(const char *str);
/**
* @brief Write at most 'size' characters to all clients.
*
* @param buffer to read from.
* @param size of the buffer.
* @return 0 if FAILURE else the number of characters sent.
*/
size_t write(const char *buffer, size_t size);
private:
uint16_t port; //!< @brief Port number for the network socket.
std::list<int> new_clients; //!< Socket list of new connected clients.
std::vector<int> clients; //!< @brief Socket list of connected clients.
uint16_t max_clients; //!< @brief The maximum number of allowed clients.
int sockfd; //!< @brief Network socket used to accept connections.
/**
* @brief Accept new clients if the total of connected clients is below max_clients.
*
*/
void _accept();
};
#endif

View File

@@ -1,211 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 "GPIO.h"
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "log.h"
// Declare a single default instance
GPIOClass GPIO = GPIOClass();
GPIOClass::GPIOClass()
{
FILE *f;
DIR* dp;
char file[64];
dp = opendir("/sys/class/gpio");
if (dp == NULL) {
logError("Could not open /sys/class/gpio directory");
exit(1);
}
lastPinNum = 0;
while (true) {
dirent *de = readdir(dp);
if (de == NULL) {
break;
}
if (strncmp("gpiochip", de->d_name, 8) == 0) {
sprintf(file, "/sys/class/gpio/%s/base", de->d_name);
f = fopen(file, "r");
int base;
if (fscanf(f, "%d", &base) == EOF) {
logError("Failed to open %s\n", file);
base = 0;
}
fclose(f);
sprintf(file, "/sys/class/gpio/%s/ngpio", de->d_name);
f = fopen(file, "r");
int ngpio;
if (fscanf(f, "%d", &ngpio) == EOF) {
logError("Failed to open %s\n", file);
ngpio = 0;
}
fclose(f);
int max = ngpio + base - 1;
if (lastPinNum < max) {
lastPinNum = max;
}
}
}
closedir(dp);
exportedPins = new uint8_t[lastPinNum + 1];
for (int i = 0; i < lastPinNum + 1; ++i) {
exportedPins[i] = 0;
}
}
GPIOClass::GPIOClass(const GPIOClass& other)
{
lastPinNum = other.lastPinNum;
exportedPins = new uint8_t[lastPinNum + 1];
for (int i = 0; i < lastPinNum + 1; ++i) {
exportedPins[i] = other.exportedPins[i];
}
}
GPIOClass::~GPIOClass()
{
FILE *f;
for (int i = 0; i < lastPinNum + 1; ++i) {
if (exportedPins[i]) {
f = fopen("/sys/class/gpio/unexport", "w");
fprintf(f, "%d\n", i);
fclose(f);
}
}
delete [] exportedPins;
}
void GPIOClass::pinMode(uint8_t pin, uint8_t mode)
{
FILE *f;
if (pin > lastPinNum) {
return;
}
f = fopen("/sys/class/gpio/export", "w");
fprintf(f, "%d\n", pin);
fclose(f);
int counter = 0;
char file[128];
sprintf(file, "/sys/class/gpio/gpio%d/direction", pin);
while ((f = fopen(file,"w")) == NULL) {
// Wait 10 seconds for the file to be accessible if not open on first attempt
sleep(1);
counter++;
if (counter > 10) {
logError("Could not open /sys/class/gpio/gpio%u/direction", pin);
exit(1);
}
}
if (mode == INPUT) {
fprintf(f, "in\n");
} else {
fprintf(f, "out\n");
}
exportedPins[pin] = 1;
fclose(f);
}
void GPIOClass::digitalWrite(uint8_t pin, uint8_t value)
{
FILE *f;
char file[128];
if (pin > lastPinNum) {
return;
}
if (0 == exportedPins[pin]) {
pinMode(pin, OUTPUT);
}
sprintf(file, "/sys/class/gpio/gpio%d/value", pin);
f = fopen(file, "w");
if (value == 0) {
fprintf(f, "0\n");
} else {
fprintf(f, "1\n");
}
fclose(f);
}
uint8_t GPIOClass::digitalRead(uint8_t pin)
{
FILE *f;
char file[128];
if (pin > lastPinNum) {
return 0;
}
if (0 == exportedPins[pin]) {
pinMode(pin, INPUT);
}
sprintf(file, "/sys/class/gpio/gpio%d/value", pin);
f = fopen(file, "r");
int i;
if (fscanf(f, "%d", &i) == EOF) {
logError("digitalRead: failed to read pin %u\n", pin);
i = 0;
}
fclose(f);
return i;
}
uint8_t GPIOClass::digitalPinToInterrupt(uint8_t pin)
{
return pin;
}
GPIOClass& GPIOClass::operator=(const GPIOClass& other)
{
if (this != &other) {
lastPinNum = other.lastPinNum;
exportedPins = new uint8_t[lastPinNum + 1];
for (int i = 0; i < lastPinNum + 1; ++i) {
exportedPins[i] = other.exportedPins[i];
}
}
return *this;
}

View File

@@ -1,91 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 GPIO_h
#define GPIO_h
#include <stdint.h>
#define INPUT 0
#define OUTPUT 1
#define LOW 0
#define HIGH 1
/**
* @brief GPIO class
*/
class GPIOClass
{
public:
/**
* @brief GPIOClass constructor.
*/
GPIOClass();
/**
* @brief GPIOClass copy constructor.
*/
GPIOClass(const GPIOClass& other);
/**
* @brief GPIOClass destructor.
*/
~GPIOClass();
/**
* @brief Configures the specified pin to behave either as an input or an output.
*
* @param pin The number of the pin.
* @param mode INPUT or OUTPUT.
*/
void pinMode(uint8_t pin, uint8_t mode);
/**
* @brief Write a high or a low value for the given pin.
*
* @param pin number.
* @param value HIGH or LOW.
*/
void digitalWrite(uint8_t pin, uint8_t value);
/**
* @brief Reads the value from a specified pin.
*
* @param pin The number of the pin.
* @return HIGH or LOW.
*/
uint8_t digitalRead(uint8_t pin);
/**
* @brief Arduino compatibility function, returns the same given pin.
*
* @param pin The number of the pin.
* @return The same parameter pin number.
*/
uint8_t digitalPinToInterrupt(uint8_t pin);
/**
* @brief Overloaded assign operator.
*
*/
GPIOClass& operator=(const GPIOClass& other);
private:
int lastPinNum; //!< @brief Highest pin number supported.
uint8_t *exportedPins; //!< @brief Array with information of which pins were exported.
};
extern GPIOClass GPIO;
#endif

View File

@@ -1,110 +0,0 @@
/*
* 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 <cstdio>
#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);
}

View File

@@ -1,165 +0,0 @@
/*
* 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>
/**
* @brief A class to make it easier to handle and pass around IP addresses
*/
class IPAddress
{
private:
union {
uint8_t bytes[4]; //!< IPv4 address as an array
uint32_t dword; //!< IPv4 address in 32 bits format
} _address;
/**
* @brief 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.
*
* @return pointer to the internal structure.
*/
uint8_t* raw_address()
{
return _address.bytes;
}
public:
/**
* @brief IPAddress constructor.
*/
IPAddress();
/**
* @brief IPAddress constructor.
*
* @param first_octet first octet of the IPv4 address.
* @param second_octet second octet of the IPv4 address.
* @param third_octet third octet of the IPv4 address.
* @param fourth_octet fourth octet of the IPv4 address.
*/
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
/**
* @brief IPAddress constructor.
*
* @param address to be set from a 32 bits integer.
*/
explicit IPAddress(uint32_t address);
/**
* @brief IPAddress constructor.
*
* @param address to be set from a byte array.
*/
explicit IPAddress(const uint8_t *address);
/**
* @brief Set the IP from a array of characters.
*
* @param address to be set.
*/
bool fromString(const char *address);
/**
* @brief Set the IP from a string class type.
*
* @param address to be set.
*/
bool fromString(const std::string &address)
{
return fromString(address.c_str());
}
/**
* @brief Overloaded cast operator
*
* 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;
}
/**
* @brief Overloaded cast operator
*
*/
bool operator==(const IPAddress& addr) const
{
return _address.dword == addr._address.dword;
}
/**
* @brief Overloaded cast operator
*
*/
bool operator==(uint32_t addr) const
{
return _address.dword == addr;
}
/**
* @brief Overloaded cast operator
*
*/
bool operator==(const uint8_t* addr) const;
/**
* @brief Overloaded index operator.
*
* Allow getting and setting individual octets of the address.
*
*/
uint8_t operator[](int index) const
{
return _address.bytes[index];
}
/**
* @brief Overloaded index operator
*
*/
uint8_t& operator[](int index)
{
return _address.bytes[index];
}
/**
* @brief Overloaded copy operators.
*
* Allow initialisation of IPAddress objects from byte array.
*/
IPAddress& operator=(const uint8_t *address);
/**
* @brief Overloaded copy operator.
*
* Allow initialisation of IPAddress objects from a 32 bits integer.
*/
IPAddress& operator=(uint32_t address);
/**
* @brief Convert the IP address to a string.
*
* @return A stringified IP address
*/
std::string toString();
friend class Client;
};
#endif

View File

@@ -1,272 +0,0 @@
/*
Print.cpp - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. 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 23 November 2006 by David A. Mellis
Modified December 2014 by Ivan Grokhotkov
Modified May 2015 by Michael C. Miller - esp8266 progmem support
Modified August 2016 by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
*/
#include <cstdlib>
#include <cstdio>
#include <cstdarg>
#include <cmath>
#include "Print.h"
// Public Methods //////////////////////////////////////////////////////////////
size_t Print::write(const uint8_t *buffer, size_t size)
{
size_t n = 0;
while(size--) {
n += write(*buffer++);
}
return n;
}
size_t
#ifdef __GNUC__
__attribute__((format(printf, 2, 3)))
#endif
Print::printf(const char *format, ...)
{
va_list arg;
va_start(arg, format);
char temp[64];
char* buffer = temp;
size_t len = vsnprintf(temp, sizeof(temp), format, arg);
va_end(arg);
if (len > sizeof(temp) - 1) {
buffer = new char[len + 1];
if (!buffer) {
return 0;
}
va_start(arg, format);
vsnprintf(buffer, len + 1, format, arg);
va_end(arg);
}
len = write((const uint8_t*) buffer, len);
if (buffer != temp) {
delete[] buffer;
}
return len;
}
size_t Print::print(const std::string &s)
{
return write(s.c_str(), s.length());
}
size_t Print::print(const char str[])
{
return write(str);
}
size_t Print::print(char c)
{
return write(c);
}
size_t Print::print(unsigned char b, int base)
{
return print((unsigned long) b, base);
}
size_t Print::print(int n, int base)
{
return print((long) n, base);
}
size_t Print::print(unsigned int n, int base)
{
return print((unsigned long) n, base);
}
size_t Print::print(long n, int base)
{
if(base == 0) {
return write(n);
} else if(base == 10) {
if(n < 0) {
int t = print('-');
n = -n;
return printNumber(n, 10) + t;
}
return printNumber(n, 10);
} else {
return printNumber(n, base);
}
}
size_t Print::print(unsigned long n, int base)
{
if(base == 0) {
return write(n);
} else {
return printNumber(n, base);
}
}
size_t Print::print(double n, int digits)
{
return printFloat(n, digits);
}
size_t Print::println(void)
{
return print("\r\n");
}
size_t Print::println(const std::string &s)
{
size_t n = print(s);
n += println();
return n;
}
size_t Print::println(const char c[])
{
size_t n = print(c);
n += println();
return n;
}
size_t Print::println(char c)
{
size_t n = print(c);
n += println();
return n;
}
size_t Print::println(unsigned char b, int base)
{
size_t n = print(b, base);
n += println();
return n;
}
size_t Print::println(int num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(unsigned int num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(long num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(unsigned long num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(double num, int digits)
{
size_t n = print(num, digits);
n += println();
return n;
}
// Private Methods /////////////////////////////////////////////////////////////
size_t Print::printNumber(unsigned long n, uint8_t base)
{
char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
char *str = &buf[sizeof(buf) - 1];
*str = '\0';
// prevent crash if called with base == 1
if(base < 2) {
base = 10;
}
do {
char c = n % base;
n /= base;
*--str = c < 10 ? c + '0' : c + 'A' - 10;
} while(n);
return write(str);
}
size_t Print::printFloat(double number, uint8_t digits)
{
size_t n = 0;
if(std::isnan(number)) {
return print("nan");
}
if(std::isinf(number)) {
return print("inf");
}
if(number > 4294967040.0) {
return print("ovf"); // constant determined empirically
}
if(number < -4294967040.0) {
return print("ovf"); // constant determined empirically
}
// Handle negative numbers
if(number < 0.0) {
n += print('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
for(uint8_t i = 0; i < digits; ++i) {
rounding /= 10.0;
}
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long) number;
double remainder = number - (double) int_part;
n += print(int_part);
// Print the decimal point, but only if there are digits beyond
if(digits > 0) {
n += print(".");
}
// Extract digits from the remainder one at a time
while(digits-- > 0) {
remainder *= 10.0;
int toPrint = int(remainder);
n += print(toPrint);
remainder -= toPrint;
}
return n;
}

View File

@@ -1,98 +0,0 @@
/*
Print.h - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. 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 August 2016 by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
*/
#ifndef Print_h
#define Print_h
#include <stdint.h>
#include <string>
#include <string.h>
#if !DOXYGEN
#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2
class Print
{
private:
int write_error;
size_t printNumber(unsigned long n, uint8_t base);
size_t printFloat(double number, uint8_t digits);
protected:
void setWriteError(int err = 1)
{
write_error = err;
}
public:
Print() : write_error(0) {}
int getWriteError()
{
return write_error;
}
void clearWriteError()
{
setWriteError(0);
}
virtual size_t write(uint8_t) = 0;
size_t write(const char *str)
{
if (str == NULL) {
return 0;
}
return write((const uint8_t *) str, strlen(str));
}
virtual size_t write(const uint8_t *buffer, size_t size);
size_t write(const char *buffer, size_t size)
{
return write((const uint8_t *) buffer, size);
}
size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3)));
size_t print(const std::string &);
size_t print(const char[]);
size_t print(char);
size_t print(unsigned char, int = DEC);
size_t print(int, int = DEC);
size_t print(unsigned int, int = DEC);
size_t print(long, int = DEC);
size_t print(unsigned long, int = DEC);
size_t print(double, int = 2);
size_t println(const std::string &s);
size_t println(const char[]);
size_t println(char);
size_t println(unsigned char, int = DEC);
size_t println(int, int = DEC);
size_t println(unsigned int, int = DEC);
size_t println(long, int = DEC);
size_t println(unsigned long, int = DEC);
size_t println(double, int = 2);
size_t println(void);
};
#endif
#endif

View File

@@ -1,31 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 _SPI_H_
#define _SPI_H_
#ifdef LINUX_SPI_BCM
#include "SPIBCM.h"
#define SPI SPIBCM
#elif LINUX_SPI_SPIDEV
#include "SPIDEV.h"
#define SPI SPIDEV
#endif
#endif

View File

@@ -1,368 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard <tmrh20@gmail.com>
*/
#include "SPIDEV.h"
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "log.h"
static pthread_mutex_t spiMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutexattr_t attr;
// Declare a single default instance
SPIDEVClass SPIDEV = SPIDEVClass();
uint8_t SPIDEVClass::initialized = 0;
int SPIDEVClass::fd = -1;
std::string SPIDEVClass::device = SPI_SPIDEV_DEVICE;
uint8_t SPIDEVClass::mode = SPI_MODE0;
uint32_t SPIDEVClass::speed = SPI_CLOCK_BASE;
uint8_t SPIDEVClass::bit_order = MSBFIRST;
struct spi_ioc_transfer SPIDEVClass::tr = {0,0,0,0,0,8,0,0,0,0}; // 8 bits_per_word, 0 cs_change
SPIDEVClass::SPIDEVClass()
{
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&spiMutex, &attr);
}
void SPIDEVClass::begin(int busNo)
{
if (!initialized) {
/* set spidev accordingly to busNo like:
* busNo = 23 -> /dev/spidev2.3
*
* a bit messy but simple
* */
device[11] += (busNo / 10) % 10;
device[13] += busNo % 10;
init();
}
initialized++; // reference count
}
void SPIDEVClass::end()
{
if (initialized) {
initialized--;
}
if (!initialized) {
if (!(fd < 0)) {
close(fd);
fd = -1;
}
}
}
void SPIDEVClass::setBitOrder(uint8_t border)
{
pthread_mutex_lock(&spiMutex);
/*
* bit order
*/
bit_order = border;
int ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &bit_order);
if (ret == -1) {
logError("Can't set SPI bit order.\n");
abort();
}
ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &bit_order);
if (ret == -1) {
logError("Can't set SPI bit order.\n");
abort();
}
pthread_mutex_unlock(&spiMutex);
}
void SPIDEVClass::setDataMode(uint8_t data_mode)
{
pthread_mutex_lock(&spiMutex);
/*
* spi mode
*/
mode = data_mode;
int ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1) {
logError("Can't set SPI mode.\n");
abort();
}
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1) {
logError("Can't set SPI mode.\n");
abort();
}
pthread_mutex_unlock(&spiMutex);
}
void SPIDEVClass::setClockDivider(uint16_t divider)
{
if (divider == 0) {
return;
}
pthread_mutex_lock(&spiMutex);
/*
* max speed hz
*/
speed = SPI_CLOCK_BASE / divider;
int ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1) {
logError("Can't set SPI max speed hz.\n");
abort();
}
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1) {
logError("Can't set SPI max speed hz.\n");
abort();
}
pthread_mutex_unlock(&spiMutex);
}
void SPIDEVClass::chipSelect(int csn_chip)
{
if (csn_chip >= 0 && csn_chip <= 9) {
device[13] = '0' + (csn_chip % 10);
init();
}
}
uint8_t SPIDEVClass::transfer(uint8_t data)
{
int ret;
uint8_t tx[1] = {data};
uint8_t rx[1] = {0};
pthread_mutex_lock(&spiMutex);
tr.tx_buf = (unsigned long)&tx[0];
tr.rx_buf = (unsigned long)&rx[0];
tr.len = 1;
tr.speed_hz = speed;
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1) {
logError("Can't send spi message.\n");
abort();
}
pthread_mutex_unlock(&spiMutex);
return rx[0];
}
void SPIDEVClass::transfernb(char* tbuf, char* rbuf, uint32_t len)
{
int ret;
pthread_mutex_lock(&spiMutex);
tr.tx_buf = (unsigned long)tbuf;
tr.rx_buf = (unsigned long)rbuf;
tr.len = len;
tr.speed_hz = speed;
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1) {
logError("Can't send spi message.\n");
abort();
}
pthread_mutex_unlock(&spiMutex);
}
void SPIDEVClass::transfern(char* buf, uint32_t len)
{
transfernb(buf, buf, len);
}
void SPIDEVClass::beginTransaction(SPISettings settings)
{
int ret;
pthread_mutex_lock(&spiMutex);
/*
* spi mode
*/
if (settings.dmode != mode) {
mode = settings.dmode;
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1) {
logError("Can't set spi mode.\n");
abort();
}
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1) {
logError("Can't set spi mode.\n");
abort();
}
}
/*
* speed
*/
if (settings.clock != speed) {
speed = settings.clock;
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1) {
logError("Can't set SPI max speed hz.\n");
abort();
}
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1) {
logError("Can't set SPI max speed hz.\n");
abort();
}
}
/*
* bit order
*/
if (settings.border != bit_order) {
bit_order = settings.border;
ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &bit_order);
if (ret == -1) {
logError("Can't set SPI bit order.\n");
abort();
}
ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &bit_order);
if (ret == -1) {
logError("Can't set SPI bit order.\n");
abort();
}
}
}
void SPIDEVClass::endTransaction()
{
pthread_mutex_unlock(&spiMutex);
}
void SPIDEVClass::usingInterrupt(uint8_t interruptNumber)
{
(void)interruptNumber;
}
void SPIDEVClass::notUsingInterrupt(uint8_t interruptNumber)
{
(void)interruptNumber;
}
void SPIDEVClass::init()
{
pthread_mutex_lock(&spiMutex);
if (fd >= 0) {
close(fd);
}
fd = open(device.c_str(), O_RDWR);
if (fd < 0) {
logError("Can't open SPI device: %s\n", device.c_str());
abort();
}
/*
* spi mode
*/
int ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1) {
logError("Can't set SPI mode.\n");
abort();
}
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1) {
logError("Can't set SPI mode.\n");
abort();
}
/*
* bits per word
*/
uint8_t bits = 8; // 8 bits per word
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1) {
logError("Can't set SPI bits per word.\n");
abort();
}
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1) {
logError("Can't set SPI bits per word.\n");
abort();
}
/*
* max speed hz
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1) {
logError("Can't set SPI max speed hz.\n");
abort();
}
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1) {
logError("Can't set SPI max speed hz.\n");
abort();
}
/*
* bit order
*/
ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &bit_order);
if (ret == -1) {
logError("Can't set SPI bit order.\n");
abort();
}
ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &bit_order);
if (ret == -1) {
logError("Can't set SPI bit order.\n");
abort();
}
pthread_mutex_unlock(&spiMutex);
}

View File

@@ -1,212 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard <tmrh20@gmail.com>
*/
#ifndef SPIDEV_h
#define SPIDEV_h
#include <stdint.h>
#include <string>
#include <linux/spi/spidev.h>
#define SPI_HAS_TRANSACTION
#define MSBFIRST 0
#define LSBFIRST SPI_LSB_FIRST
#define SPI_CLOCK_BASE 16000000 // 16Mhz
#define SPI_CLOCK_DIV1 1
#define SPI_CLOCK_DIV2 2
#define SPI_CLOCK_DIV4 4
#define SPI_CLOCK_DIV8 8
#define SPI_CLOCK_DIV16 16
#define SPI_CLOCK_DIV32 32
#define SPI_CLOCK_DIV64 64
#define SPI_CLOCK_DIV128 128
#define SPI_CLOCK_DIV256 256
// SPI Data mode
#define SPI_MODE0 SPI_MODE_0
#define SPI_MODE1 SPI_MODE_1
#define SPI_MODE2 SPI_MODE_2
#define SPI_MODE3 SPI_MODE_3
#ifndef SPI_SPIDEV_DEVICE
#define SPI_SPIDEV_DEVICE "/dev/spidev0.0"
#endif
// Default to Raspberry Pi
const uint8_t SS = 24;
const uint8_t MOSI = 19;
const uint8_t MISO = 21;
const uint8_t SCK = 23;
/**
* SPISettings class
*/
class SPISettings
{
public:
/**
* @brief SPISettings constructor.
*/
SPISettings()
{
init(SPI_CLOCK_BASE, MSBFIRST, SPI_MODE0);
}
/**
* @brief SPISettings constructor.
*
* @param clock SPI clock speed in Hz.
* @param bitOrder SPI bit order.
* @param dataMode SPI data mode.
*/
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
{
init(clock, bitOrder, dataMode);
}
uint32_t clock; //!< @brief SPI clock.
uint8_t border; //!< @brief SPI bit order.
uint8_t dmode; //!< @brief SPI data mode.
private:
/**
* @brief Initialized class members.
*
* @param clk SPI clock.
* @param bitOrder SPI bit order.
* @param dataMode SPI data mode.
*/
void init(uint32_t clk, uint8_t bitOrder, uint8_t dataMode)
{
clock = clk;
border = bitOrder;
dmode = dataMode;
}
friend class SPIDEVClass;
};
/**
* SPIDEV class
*/
class SPIDEVClass
{
public:
/**
* @brief SPIDEVClass constructor.
*/
SPIDEVClass();
/**
* @brief Start SPI operations.
*/
static void begin(int busNo=0);
/**
* @brief End SPI operations.
*/
static void end();
/**
* @brief Sets the SPI bit order.
*
* @param bit_order The desired bit order.
*/
static void setBitOrder(uint8_t bit_order);
/**
* @brief Sets the SPI data mode.
*
* @param data_mode The desired data mode.
*/
static void setDataMode(uint8_t data_mode);
/**
* @brief Sets the SPI clock divider and therefore the SPI clock speed.
*
* @param divider The desired SPI clock divider.
*/
static void setClockDivider(uint16_t divider);
/**
* @brief Sets the chip select pin.
*
* @param csn_chip Specifies the CS chip.
*/
static void chipSelect(int csn_chip);
/**
* @brief Transfer a single byte
*
* @param data Byte to send
* @return Data returned via spi
*/
static uint8_t transfer(uint8_t data);
/**
* @brief Transfer a buffer of data
*
* @param tbuf Transmit buffer
* @param rbuf Receive buffer
* @param len Length of the data
*/
static void transfernb(char* tbuf, char* rbuf, uint32_t len);
/**
* @brief Transfer a buffer of data without an rx buffer
*
* @param buf Pointer to a buffer of data
* @param len Length of the data
*/
static void transfern(char* buf, uint32_t len);
/**
* @brief Start SPI transaction.
*
* @param settings for SPI.
*/
static void beginTransaction(SPISettings settings);
/**
* @brief End SPI transaction.
*/
static void endTransaction();
/**
* @brief Not implemented.
*
* @param interruptNumber ignored parameter.
*/
static void usingInterrupt(uint8_t interruptNumber);
/**
* @brief Not implemented.
*
* @param interruptNumber ignored parameter.
*/
static void notUsingInterrupt(uint8_t interruptNumber);
private:
static uint8_t initialized; //!< @brief SPI initialized flag.
static int fd; //!< @brief SPI device file descriptor.
static std::string device; //!< @brief Default SPI device.
static uint8_t mode; //!< @brief SPI mode.
static uint32_t speed; //!< @brief SPI speed.
static uint8_t bit_order; //!< @brief SPI bit order.
static struct spi_ioc_transfer tr; //!< @brief Auxiliar struct for data transfer.
static void init();
};
extern SPIDEVClass SPIDEV;
#endif

View File

@@ -1,285 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <limits.h>
#include <unistd.h>
#include <termios.h>
#include <grp.h>
#include <errno.h>
#include <sys/stat.h>
#include "log.h"
#include "SerialPort.h"
SerialPort::SerialPort(const char *port, bool isPty) : serialPort(std::string(port)), isPty(isPty)
{
sd = -1;
}
void SerialPort::begin(int bauds)
{
if (!open(bauds)) {
logError("Failed to open serial port.\n");
exit(1);
}
logDebug("Serial port %s (%d baud) created\n", serialPort.c_str(), bauds);
}
bool SerialPort::open(int bauds)
{
speed_t speed;
struct termios options;
if (isPty) {
sd = posix_openpt(O_RDWR | O_NOCTTY | O_NDELAY);
if (sd < 0) {
logError("Couldn't open a PTY: %s\n", strerror(errno));
return false;
}
if (grantpt(sd) != 0) {
logError("Couldn't grant permission to the PTY: %s\n", strerror(errno));
return false;
}
if (unlockpt(sd) != 0) {
logError("Couldn't unlock the PTY: %s\n", strerror(errno));
return false;
}
/* create a symlink with predictable name to the PTY device */
unlink(serialPort.c_str()); // remove the symlink if it already exists
if (symlink(ptsname(sd), serialPort.c_str()) != 0) {
logError("Couldn't create a symlink '%s' to PTY! (%d) %s\n", serialPort.c_str(), errno,
strerror(errno));
return false;
}
} else {
if ((sd = ::open(serialPort.c_str(), O_RDWR | O_NOCTTY | O_NDELAY)) == -1) {
logError("Unable to open the serial port %s\n", serialPort.c_str());
return false;
}
// nonblocking mode
fcntl(sd, F_SETFL, FNDELAY);
}
switch (bauds) {
case 50:
speed = B50 ;
break ;
case 75:
speed = B75 ;
break ;
case 110:
speed = B110 ;
break ;
case 134:
speed = B134 ;
break ;
case 150:
speed = B150 ;
break ;
case 200:
speed = B200 ;
break ;
case 300:
speed = B300 ;
break ;
case 600:
speed = B600 ;
break ;
case 1200:
speed = B1200 ;
break ;
case 1800:
speed = B1800 ;
break ;
case 2400:
speed = B2400 ;
break ;
case 9600:
speed = B9600 ;
break ;
case 19200:
speed = B19200 ;
break ;
case 38400:
speed = B38400 ;
break ;
case 57600:
speed = B57600 ;
break ;
case 115200:
speed = B115200 ;
break ;
default:
speed = B115200 ;
break ;
}
// Get the current options of the port
if (tcgetattr(sd, &options) < 0) {
logError("Couldn't get term attributes: %s\n", strerror(errno));
return false;
}
// Clear all the options
bzero(&options, sizeof(options));
// Set the baud rate
cfsetispeed(&options, speed);
cfsetospeed(&options, speed);
// Configure the device : 8 bits, no parity, no control
options.c_cflag |= ( CLOCAL | CREAD | CS8);
// Ignore framing errors, parity errors and BREAK condition on input.
options.c_iflag |= ( IGNPAR | IGNBRK );
// Timer unused
options.c_cc[VTIME]=0;
// At least on character before satisfy reading
options.c_cc[VMIN]=0;
// Set parameters
if (tcsetattr(sd, TCSANOW, &options) < 0) {
logError("Couldn't set term attributes: %s\n", strerror(errno));
return false;
}
// flush
if (tcflush(sd, TCIOFLUSH) < 0) {
logError("Couldn't flush serial: %s\n", strerror(errno));
return false;
}
usleep(10000);
return true;
}
bool SerialPort::setGroupPerm(const char *groupName)
{
const mode_t ttyPermissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
if (sd != -1 && groupName != NULL) {
struct group *devGrp = getgrnam(groupName);
if (devGrp == NULL) {
logError("getgrnam: %s failed. (%d) %s\n", groupName, errno, strerror(errno));
return false;
}
const char *dev;
if (isPty) {
dev = ptsname(sd);
} else {
dev = serialPort.c_str();
}
int ret = chown(dev, -1, devGrp->gr_gid);
if (ret == -1) {
logError("Could not change PTY owner! (%d) %s\n", errno, strerror(errno));
return false;
}
ret = chmod(dev, ttyPermissions);
if (ret != 0) {
logError("Could not change PTY permissions! (%d) %s\n", errno, strerror(errno));
return false;
}
return true;
}
return false;
}
int SerialPort::available()
{
int nbytes = 0;
if (ioctl(sd, FIONREAD, &nbytes) < 0) {
logError("Failed to get byte count on serial.\n");
exit(-1);
}
return nbytes;
}
int SerialPort::read()
{
unsigned char c;
int ret = ::read(sd, &c, 1);
if (ret < 0) {
logError("Serial - read failed: %s\n", strerror(errno));
} else if (ret == 1) {
return c;
}
return -1;
}
size_t SerialPort::write(uint8_t b)
{
int ret = ::write(sd, &b, 1);
if (ret < 0) {
logError("Serial - write failed: %s\n", strerror(errno));
}
return ret;
}
size_t SerialPort::write(const uint8_t *buffer, size_t size)
{
int ret = ::write(sd, buffer, size);
if (ret < 0) {
logError("Serial - write failed: %s\n", strerror(errno));
}
return ret;
}
int SerialPort::peek()
{
FILE * f = fdopen(sd, "r+");
int c = getc(f);
if (c == EOF) {
return -1;
}
ungetc(c, f);
return c;
}
void SerialPort::flush()
{
// Waits until all output written to sd has been transmitted
if (tcdrain(sd) < 0) {
logError("Couldn't flush serial: %s\n", strerror(errno));
}
}
void SerialPort::end()
{
close(sd);
if (isPty) {
unlink(serialPort.c_str()); // remove the symlink
}
}

View File

@@ -1,114 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 SerialPort_h
#define SerialPort_h
#include <string>
#include <stdbool.h>
#include "Stream.h"
/**
* SerialPort Class
* Class that provides the functionality of arduino Serial library
*/
class SerialPort : public Stream
{
private:
int sd; //!< @brief file descriptor number.
std::string serialPort; //!< @brief tty name.
bool isPty; //!< @brief true if serial is pseudo terminal.
public:
/**
* @brief SerialPort constructor.
*/
SerialPort(const char *port, bool isPty = false);
/**
* @brief Open the serial port and set the data rate in bits per second (baud).
*
* This function will terminate the program on an error.
*
* @param bauds bits per second.
*/
void begin(int bauds);
/**
* @brief Open the serial port and set the data rate in bits per second (baud).
*
* @param bauds bits per second.
* @return @c true if no errors, else @c false.
*/
bool open(int bauds = 115200);
/**
* @brief Grant access to the specified system group for the serial device.
*
* @param groupName system group name.
*/
bool setGroupPerm(const char *groupName);
/**
* @brief Get the number of bytes available.
*
* Get the numberof bytes (characters) available for reading from
* the serial port.
*
* @return number of bytes avalable to read.
*/
int available();
/**
* @brief Reads 1 byte of incoming serial data.
*
* @return first byte of incoming serial data available.
*/
int read();
/**
* @brief Writes a single byte to the serial port.
*
* @param b byte to write.
* @return number of bytes written.
*/
size_t write(uint8_t b);
/**
* @brief Writes binary data to the serial port.
*
* @param buffer to write.
* @param size of the buffer.
* @return number of bytes written.
*/
size_t write(const uint8_t *buffer, size_t size);
/**
* @brief
*
* Returns the next byte (character) of incoming serial data without removing it from
* the internal serial buffer.
*
* @return -1 if no data else character in the buffer.
*/
int peek();
/**
* @brief Remove any data remaining on the serial buffer.
*/
void flush();
/**
* @brief Disables serial communication.
*/
void end();
};
#endif

View File

@@ -1,33 +0,0 @@
/*
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
#include "Print.h"
#if !DOXYGEN
class Server : public Print
{
public:
virtual void begin() =0;
};
#endif
#endif

View File

@@ -1,179 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 <stdlib.h>
#include <iostream>
#include <fstream>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include "log.h"
#include "SoftEeprom.h"
SoftEeprom::SoftEeprom() : _length(0), _fileName(NULL), _values(NULL)
{
}
SoftEeprom::SoftEeprom(const SoftEeprom& other)
{
_fileName = strdup(other._fileName);
_length = other._length;
_values = new uint8_t[_length];
for (size_t i = 0; i < _length; ++i) {
_values[i] = other._values[i];
}
}
SoftEeprom::~SoftEeprom()
{
destroy();
}
int SoftEeprom::init(const char *fileName, size_t length)
{
struct stat fileInfo;
destroy();
_fileName = strdup(fileName);
if (_fileName == NULL) {
logError("Error: %s\n", strerror(errno));
return -1;
}
_length = length;
_values = new uint8_t[_length];
if (stat(_fileName, &fileInfo) != 0) {
//File does not exist. Create it.
logInfo("EEPROM file %s does not exist, creating new file.\n", _fileName);
std::ofstream myFile(_fileName, std::ios::out | std::ios::binary);
if (!myFile) {
logError("Unable to create config file %s.\n", _fileName);
return -1;
}
// Fill the eeprom with 1s
for (size_t i = 0; i < _length; ++i) {
_values[i] = 0xFF;
}
myFile.write((const char*)_values, _length);
myFile.close();
} else if (fileInfo.st_size < 0 || (size_t)fileInfo.st_size != _length) {
logError("EEPROM file %s is not the correct size of %zu. Please remove the file and a new one will be created.\n",
_fileName, _length);
destroy();
return -1;
} else {
//Read config into local memory.
std::ifstream myFile(_fileName, std::ios::in | std::ios::binary);
if (!myFile) {
logError("Unable to open EEPROM file %s for reading.\n", _fileName);
return -1;
}
myFile.read((char*)_values, _length);
myFile.close();
}
return 0;
}
void SoftEeprom::destroy()
{
if (_values) {
delete[] _values;
}
if (_fileName) {
free(_fileName);
}
_length = 0;
}
void SoftEeprom::readBlock(void* buf, void* addr, size_t length)
{
unsigned long int offs = reinterpret_cast<unsigned long int>(addr);
if (!length) {
logError("EEPROM being read without being initialized!\n");
return;
}
if (offs + length <= _length) {
memcpy(buf, _values+offs, length);
}
}
void SoftEeprom::writeBlock(void* buf, void* addr, size_t length)
{
unsigned long int offs = reinterpret_cast<unsigned long int>(addr);
if (!length) {
logError("EEPROM being written without being initialized!\n");
return;
}
if (offs + length <= _length) {
if (memcmp(_values+offs, buf, length) == 0) {
return;
}
memcpy(_values+offs, buf, length);
std::ofstream myFile(_fileName, std::ios::out | std::ios::in | std::ios::binary);
if (!myFile) {
logError("Unable to write config to file %s.\n", _fileName);
return;
}
myFile.seekp(offs);
myFile.write((const char*)buf, length);
myFile.close();
}
}
uint8_t SoftEeprom::readByte(int addr)
{
uint8_t value = 0xFF;
readBlock(&value, reinterpret_cast<void*>(addr), 1);
return value;
}
void SoftEeprom::writeByte(int addr, uint8_t value)
{
uint8_t curr = readByte(addr);
if (curr != value) {
writeBlock(&value, reinterpret_cast<void*>(addr), 1);
}
}
SoftEeprom& SoftEeprom::operator=(const SoftEeprom& other)
{
if (this != &other) {
delete[] _values;
free(_fileName);
_fileName = strdup(other._fileName);
_length = other._length;
_values = new uint8_t[_length];
for (size_t i = 0; i < _length; ++i) {
_values[i] = other._values[i];
}
}
return *this;
}

View File

@@ -1,104 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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.
*/
/**
* This a software emulation of EEPROM that uses a file for data storage.
* A copy of the eeprom values are also held in memory for faster reading.
*/
#ifndef SoftEeprom_h
#define SoftEeprom_h
#include <stdint.h>
/**
* SoftEeprom class
*/
class SoftEeprom
{
public:
/**
* @brief SoftEeprom constructor.
*/
SoftEeprom();
/**
* @brief SoftEeprom copy constructor.
*/
SoftEeprom(const SoftEeprom& other);
/**
* @brief SoftEeprom destructor.
*/
~SoftEeprom();
/**
* @brief Initializes the eeprom class.
*
* @param fileName filepath where the data is saved.
* @param length eeprom size in bytes.
* @return 0 if SUCCESS or -1 if FAILURE.
*/
int init(const char *fileName, size_t length);
/**
* @brief Clear all allocated memory variables.
*
*/
void destroy();
/**
* @brief Read a block of bytes from eeprom.
*
* @param buf buffer to copy to.
* @param addr eeprom address to read from.
* @param length number of bytes to read.
*/
void readBlock(void* buf, void* addr, size_t length);
/**
* @brief Write a block of bytes to eeprom.
*
* @param buf buffer to read from.
* @param addr eeprom address to write to.
* @param length number of bytes to write.
*/
void writeBlock(void* buf, void* addr, size_t length);
/**
* @brief Read a byte from eeprom.
*
* @param addr eeprom address to read from.
* @return the read byte.
*/
uint8_t readByte(int addr);
/**
* @brief Write a byte to eeprom.
*
* @param addr eeprom address to write to.
* @param value to write.
*/
void writeByte(int addr, uint8_t value);
/**
* @brief Overloaded assign operator.
*
*/
SoftEeprom& operator=(const SoftEeprom& other);
private:
size_t _length; //!< @brief Eeprom max size.
char *_fileName; //!< @brief file where the eeprom values are stored.
uint8_t *_values; //!< @brief copy of the eeprom values held in memory for a faster reading.
};
#endif

View File

@@ -1,56 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 <stdio.h>
#include "StdInOutStream.h"
void StdInOutStream::begin(int baud)
{
(void)baud;
}
int StdInOutStream::available()
{
return 1;
}
int StdInOutStream::read()
{
return getchar();
}
size_t StdInOutStream::write(uint8_t b)
{
return (size_t)::printf("%c", b);
}
int StdInOutStream::peek()
{
return -1;
}
void StdInOutStream::flush()
{
fflush(stdout);
}
void StdInOutStream::end()
{
flush();
}

View File

@@ -1,76 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 StdInOutStream_h
#define StdInOutStream_h
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "Stream.h"
/**
* @brief A class that prints to stdout and reads from stdin
*/
class StdInOutStream : public Stream
{
public:
/**
* @brief This function does nothing.
*
* @param baud Ignored parameter.
*/
void begin(int baud);
/**
* @brief This function does nothing.
*
* @return always returns 1.
*/
int available();
/**
* @brief Reads 1 key pressed from the keyboard.
*
* @return key character pressed cast to an int.
*/
int read();
/**
* @brief Writes a single byte to stdout.
*
* @param b byte to write.
* @return -1 if error else, number of bytes written.
*/
size_t write(uint8_t b);
/**
* @brief Not supported.
*
* @return always returns -1.
*/
int peek();
/**
* @brief Flush stdout.
*/
void flush();
/**
* @brief Nothing to do, flush stdout.
*/
void end();
};
#endif

View File

@@ -1,292 +0,0 @@
/*
Stream.cpp - adds parsing methods to Stream class
Copyright (c) 2008 David A. Mellis. 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
Created July 2011
parsing functions based on TextFinder library by Michael Margolis
Modified August 2016 by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
*/
#include <Arduino.h>
#include <Stream.h>
#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
// private method to read stream with timeout
int Stream::timedRead()
{
_startMillis = millis();
do {
int c;
c = read();
if(c >= 0) {
return c;
}
yield();
} while(millis() - _startMillis < _timeout);
return -1; // -1 indicates timeout
}
// private method to peek stream with timeout
int Stream::timedPeek()
{
_startMillis = millis();
do {
int c;
c = peek();
if(c >= 0) {
return c;
}
yield();
} while(millis() - _startMillis < _timeout);
return -1; // -1 indicates timeout
}
// returns peek of the next digit in the stream or -1 if timeout
// discards non-numeric characters
int Stream::peekNextDigit()
{
while(1) {
int c;
c = timedPeek();
if(c < 0) {
return c; // timeout
}
if(c == '-') {
return c;
}
if(c >= '0' && c <= '9') {
return c;
}
read(); // discard non-numeric
}
}
// Public Methods
//////////////////////////////////////////////////////////////
void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait
{
_timeout = timeout;
}
// find returns true if the target string is found
bool Stream::find(const char *target)
{
return findUntil(target, (char*) "");
}
// reads data from the stream until the target string of given length is found
// returns true if target string is found, false if timed out
bool Stream::find(const char *target, size_t length)
{
return findUntil(target, length, NULL, 0);
}
// as find but search ends if the terminator string is found
bool Stream::findUntil(const char *target, const char *terminator)
{
return findUntil(target, strlen(target), terminator, strlen(terminator));
}
// reads data from the stream until the target string of the given length is found
// search terminated if the terminator string is found
// returns true if target string is found, false if terminated or timed out
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator,
size_t termLen)
{
size_t index = 0; // maximum target string length is 64k bytes!
size_t termIndex = 0;
int c;
if(*target == 0) {
return true; // return true if target is a null string
}
while((c = timedRead()) > 0) {
if(c != target[index]) {
index = 0; // reset index if any char does not match
}
if(c == target[index]) {
//////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
if(++index >= targetLen) { // return true if all chars in the target match
return true;
}
}
if(termLen > 0 && c == terminator[termIndex]) {
if(++termIndex >= termLen) {
return false; // return false if terminate string found before target string
}
} else {
termIndex = 0;
}
}
return false;
}
// returns the first valid (long) integer value from the current position.
// initial characters that are not digits (or the minus sign) are skipped
// function is terminated by the first character that is not a digit.
long Stream::parseInt()
{
return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
}
// as above but a given skipChar is ignored
// this allows format characters (typically commas) in values to be ignored
long Stream::parseInt(char skipChar)
{
bool isNegative = false;
long value = 0;
int c;
c = peekNextDigit();
// ignore non numeric leading characters
if(c < 0) {
return 0; // zero returned if timeout
}
do {
if(c == skipChar) {
// ignore this charactor
} else if(c == '-') {
isNegative = true;
} else if(c >= '0' && c <= '9') { // is c a digit?
value = value * 10 + c - '0';
}
read(); // consume the character we got with peek
c = timedPeek();
} while((c >= '0' && c <= '9') || c == skipChar);
if(isNegative) {
value = -value;
}
return value;
}
// as parseInt but returns a floating point value
float Stream::parseFloat()
{
return parseFloat(NO_SKIP_CHAR);
}
// as above but the given skipChar is ignored
// this allows format characters (typically commas) in values to be ignored
float Stream::parseFloat(char skipChar)
{
bool isNegative = false;
bool isFraction = false;
long value = 0;
int c;
float fraction = 1.0;
c = peekNextDigit();
// ignore non numeric leading characters
if(c < 0) {
return 0; // zero returned if timeout
}
do {
if(c == skipChar) {
// ignore
} else if(c == '-') {
isNegative = true;
} else if(c == '.') {
isFraction = true;
} else if(c >= '0' && c <= '9') { // is c a digit?
value = value * 10 + c - '0';
if(isFraction) {
fraction *= 0.1;
}
}
read(); // consume the character we got with peek
c = timedPeek();
} while((c >= '0' && c <= '9') || c == '.' || c == skipChar);
if(isNegative) {
value = -value;
}
if(isFraction) {
return value * fraction;
} else {
return value;
}
}
// read characters from stream into buffer
// terminates if length characters have been read, or timeout (see setTimeout)
// returns the number of characters placed in the buffer
// the buffer is NOT null terminated.
//
size_t Stream::readBytes(char *buffer, size_t length)
{
size_t count = 0;
while(count < length) {
int c = timedRead();
if(c < 0) {
break;
}
*buffer++ = (char) c;
count++;
}
return count;
}
// as readBytes with terminator character
// terminates if length characters have been read, timeout, or if the terminator character detected
// returns the number of characters placed in the buffer (0 means no valid data found)
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
{
if(length < 1) {
return 0;
}
size_t index = 0;
while(index < length) {
int c = timedRead();
if(c < 0 || c == terminator) {
break;
}
*buffer++ = (char) c;
index++;
}
return index; // return number of characters, not including null terminator
}
std::string Stream::readString()
{
std::string ret;
int c = timedRead();
while(c >= 0) {
ret += (char) c;
c = timedRead();
}
return ret;
}
std::string Stream::readStringUntil(char terminator)
{
std::string ret;
int c = timedRead();
while(c >= 0 && c != terminator) {
ret += (char) c;
c = timedRead();
}
return ret;
}

View File

@@ -1,138 +0,0 @@
/*
Stream.h - base class for character-based streams.
Copyright (c) 2010 David A. Mellis. 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
parsing functions based on TextFinder library by Michael Margolis
Modified August 2016 by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
*/
#ifndef Stream_h
#define Stream_h
#include <inttypes.h>
#include <string>
#include "Print.h"
// compatability macros for testing
/*
#define getInt() parseInt()
#define getInt(skipChar) parseInt(skipchar)
#define getFloat() parseFloat()
#define getFloat(skipChar) parseFloat(skipChar)
#define getString( pre_string, post_string, buffer, length)
readBytesBetween( pre_string, terminator, buffer, length)
*/
#if !DOXYGEN
class Stream: public Print
{
protected:
unsigned long
_timeout; // number of milliseconds to wait for the next char before aborting timed read
unsigned long _startMillis; // used for timeout measurement
int timedRead(); // private method to read stream with timeout
int timedPeek(); // private method to peek stream with timeout
int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout
public:
virtual int available() = 0;
virtual int read() = 0;
virtual int peek() = 0;
virtual void flush() = 0;
Stream()
{
_timeout = 1000;
_startMillis = 0;
}
// parsing methods
void setTimeout(unsigned long
timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
bool find(const char *target); // reads data from the stream until the target string is found
bool find(uint8_t *target)
{
return find((char *) target);
}
// returns true if target string is found, false if timed out (see setTimeout)
bool find(const char *target, size_t
length); // reads data from the stream until the target string of given length is found
bool find(const uint8_t *target, size_t length)
{
return find((char *) target, length);
}
// returns true if target string is found, false if timed out
bool find(char target)
{
return find (&target, 1);
}
bool findUntil(const char *target,
const char *terminator); // as find but search ends if the terminator string is found
bool findUntil(const uint8_t *target, const char *terminator)
{
return findUntil((char *) target, terminator);
}
bool findUntil(const char *target, size_t targetLen, const char *terminate,
size_t termLen); // as above but search ends if the terminate string is found
bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen)
{
return findUntil((char *) target, targetLen, terminate, termLen);
}
long parseInt(); // returns the first valid (long) integer value from the current position.
// initial characters that are not digits (or the minus sign) are skipped
// integer is terminated by the first character that is not a digit.
float parseFloat(); // float version of parseInt
virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer
virtual size_t readBytes(uint8_t *buffer, size_t length)
{
return readBytes((char *) buffer, length);
}
// terminates if length characters have been read or timeout (see setTimeout)
// returns the number of characters placed in the buffer (0 means no valid data found)
size_t readBytesUntil(char terminator, char *buffer,
size_t length); // as readBytes with terminator character
size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length)
{
return readBytesUntil(terminator, (char *) buffer, length);
}
// terminates if length characters have been read, timeout, or if the terminator character detected
// returns the number of characters placed in the buffer (0 means no valid data found)
// Arduino String functions to be added here
std::string readString();
std::string readStringUntil(char terminator);
protected:
long parseInt(char skipChar); // as above but the given skipChar is ignored
// as above but the given skipChar is ignored
// this allows format characters (typically commas) in values to be ignored
float parseFloat(char skipChar); // as above but the given skipChar is ignored
};
#endif
#endif

View File

@@ -1,96 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include "Arduino.h"
// For millis()
static unsigned long millis_at_start = 0;
void yield(void) {}
unsigned long millis(void)
{
timeval curTime;
if (millis_at_start == 0) {
gettimeofday(&curTime, NULL);
millis_at_start = curTime.tv_sec;
}
gettimeofday(&curTime, NULL);
return ((curTime.tv_sec - millis_at_start) * 1000) + (curTime.tv_usec / 1000);
}
unsigned long micros()
{
timeval curTime;
if (millis_at_start == 0) {
gettimeofday(&curTime, NULL);
millis_at_start = curTime.tv_sec;
}
gettimeofday(&curTime, NULL);
return ((curTime.tv_sec - millis_at_start) * 1000000) + (curTime.tv_usec);
}
void _delay_milliseconds(unsigned int millis)
{
struct timespec sleeper;
sleeper.tv_sec = (time_t)(millis / 1000);
sleeper.tv_nsec = (long)(millis % 1000) * 1000000;
nanosleep(&sleeper, NULL);
}
void _delay_microseconds(unsigned int micro)
{
struct timespec sleeper;
sleeper.tv_sec = (time_t)(micro / 1000000);
sleeper.tv_nsec = (long)(micro % 1000000) * 1000;
nanosleep(&sleeper, NULL);
}
void randomSeed(unsigned long seed)
{
if (seed != 0) {
srand(seed);
}
}
long randMax(long howbig)
{
if (howbig == 0) {
return 0;
}
return rand() % howbig;
}
long randMinMax(long howsmall, long howbig)
{
if (howsmall >= howbig) {
return howsmall;
}
long diff = howbig - howsmall;
return randMax(diff) + howsmall;
}

View File

@@ -1,304 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 mosquitto project, Copyright (c) 2012 Roger Light <roger@atchoo.org>
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include "log.h"
static int _config_create(const char *config_file);
static int _config_parse_int(char *token, const char *name, int *value);
static int _config_parse_string(char *token, const char *name, char **value);
int config_parse(const char *config_file)
{
FILE *fptr;
char buf[1024];
struct stat fileInfo;
if (stat(config_file, &fileInfo) != 0) {
//File does not exist. Create it.
logInfo("Config file %s does not exist, creating new file.\n", config_file);
_config_create(config_file);
}
fptr = fopen(config_file, "rt");
if (!fptr) {
logError("Error opening config file \"%s\".\n", config_file);
return -1;
}
conf.verbose = 7;
conf.log_pipe = 0;
conf.log_pipe_file = NULL;
conf.syslog = 0;
conf.eeprom_file = NULL;
conf.eeprom_size = 0;
conf.soft_hmac_key = NULL;
conf.soft_serial_key = NULL;
conf.aes_key = NULL;
while (fgets(buf, 1024, fptr)) {
if (buf[0] != '#' && buf[0] != 10 && buf[0] != 13) {
while (buf[strlen(buf)-1] == 10 || buf[strlen(buf)-1] == 13) {
buf[strlen(buf)-1] = 0;
}
if (!strncmp(buf, "verbose=", 8)) {
char *verbose = NULL;
if (_config_parse_string(&(buf[8]), "verbose", &verbose)) {
fclose(fptr);
return -1;
} else {
if (!strncmp(verbose, "err", 3)) {
conf.verbose = 3;
} else if (!strncmp(verbose, "warn", 4)) {
conf.verbose = 4;
} else if (!strncmp(verbose, "notice", 6)) {
conf.verbose = 5;
} else if (!strncmp(verbose, "info", 4)) {
conf.verbose = 6;
} else if (!strncmp(verbose, "debug", 5)) {
conf.verbose = 7;
} else {
logError("Invalid value for verbose in configuration.\n");
fclose(fptr);
free(verbose);
return -1;
}
free(verbose);
}
} else if (!strncmp(buf, "log_file=", 9)) {
if (_config_parse_int(&(buf[9]), "log_file", &conf.log_file)) {
fclose(fptr);
return -1;
} else {
if (conf.log_file != 0 && conf.log_file != 1) {
logError("log_file must be 1 or 0 in configuration.\n");
fclose(fptr);
return -1;
}
}
} else if (!strncmp(buf, "log_filepath=", 13)) {
if (_config_parse_string(&(buf[13]), "log_filepath", &conf.log_filepath)) {
fclose(fptr);
return -1;
}
} else if (!strncmp(buf, "log_pipe=", 9)) {
if (_config_parse_int(&(buf[9]), "log_pipe", &conf.log_pipe)) {
fclose(fptr);
return -1;
} else {
if (conf.log_pipe != 0 && conf.log_pipe != 1) {
logError("log_pipe must be 1 or 0 in configuration.\n");
fclose(fptr);
return -1;
}
}
} else if (!strncmp(buf, "log_pipe_file=", 14)) {
if (_config_parse_string(&(buf[14]), "log_pipe_file", &conf.log_pipe_file)) {
fclose(fptr);
return -1;
}
} else if (!strncmp(buf, "syslog=", 7)) {
if (_config_parse_int(&(buf[7]), "syslog", &conf.syslog)) {
fclose(fptr);
return -1;
} else {
if (conf.syslog != 0 && conf.syslog != 1) {
logError("syslog must be 1 or 0 in configuration.\n");
fclose(fptr);
return -1;
}
}
} else if (!strncmp(buf, "eeprom_file=", 12)) {
if (_config_parse_string(&(buf[12]), "eeprom_file", &conf.eeprom_file)) {
fclose(fptr);
return -1;
}
} else if (!strncmp(buf, "eeprom_size=", 12)) {
if (_config_parse_int(&(buf[12]), "eeprom_size", &conf.eeprom_size)) {
fclose(fptr);
return -1;
} else {
if (conf.eeprom_size <= 0) {
logError("eeprom_size value must be greater than 0 in configuration.\n");
fclose(fptr);
return -1;
}
}
} else if (!strncmp(buf, "soft_hmac_key=", 14)) {
if (_config_parse_string(&(buf[14]), "soft_hmac_key", &conf.soft_hmac_key)) {
fclose(fptr);
return -1;
}
} else if (!strncmp(buf, "soft_serial_key=", 16)) {
if (_config_parse_string(&(buf[16]), "soft_serial_key", &conf.soft_serial_key)) {
fclose(fptr);
return -1;
}
} else if (!strncmp(buf, "aes_key=", 8)) {
if (_config_parse_string(&(buf[8]), "aes_key", &conf.aes_key)) {
fclose(fptr);
return -1;
}
} else {
logWarning("Unknown config option \"%s\".\n", buf);
}
}
}
fclose(fptr);
if (!conf.eeprom_file) {
logError("No eeprom_file found in configuration.\n");
return -1;
}
if (conf.log_file && !conf.log_filepath) {
logError("log_filepath must be set if you enable log_file in configuration.\n");
return -1;
}
if (conf.log_pipe && !conf.log_pipe_file) {
logError("log_pipe_file must be set if you enable log_pipe in configuration.\n");
return -1;
}
return 0;
}
void config_cleanup(void)
{
if (conf.log_filepath) {
free(conf.log_filepath);
}
if (conf.log_pipe_file) {
free(conf.log_pipe_file);
}
if (conf.eeprom_file) {
free(conf.eeprom_file);
}
if (conf.soft_hmac_key) {
free(conf.soft_hmac_key);
}
if (conf.soft_serial_key) {
free(conf.soft_serial_key);
}
if (conf.aes_key) {
free(conf.aes_key);
}
}
int _config_create(const char *config_file)
{
FILE *myFile;
int ret;
const char default_conf[] = "# Logging\n" \
"# Verbosity: debug,info,notice,warn,err\n" \
"verbose=debug\n" \
"\n" \
"# Enable logging to a file.\n" \
"log_file=0\n" \
"# Log file path.\n" \
"log_filepath=/tmp/mysgw.log\n" \
"\n" \
"# Enable logging to a named pipe.\n" \
"# Use this option to view your gateway's log messages\n" \
"# from the log_pipe_file defined bellow.\n" \
"# To do so, run the following command on another terminal:\n" \
"# cat \"log_pipe_file\"\n" \
"log_pipe=0\n" \
"log_pipe_file=/tmp/mysgw.pipe\n" \
"\n" \
"# Enable logging to syslog.\n" \
"syslog=0\n" \
"\n" \
"# EEPROM settings\n" \
"eeprom_file=/etc/mysensors.eeprom\n" \
"eeprom_size=1024\n" \
"\n" \
"# Software signing settings\n" \
"# Note: The gateway must have been built with signing\n" \
"# support to use the options below.\n" \
"#\n" \
"# To generate a HMAC key run mysgw with: --gen-soft-hmac-key\n" \
"# copy the new key in the line below and uncomment it.\n" \
"#soft_hmac_key=\n" \
"# To generate a serial key run mysgw with: --gen-soft-serial-key\n" \
"# copy the new key in the line below and uncomment it.\n" \
"#soft_serial_key=\n" \
"\n" \
"# Encryption settings\n" \
"# Note: The gateway must have been built with encryption\n" \
"# support to use the options below.\n" \
"#\n" \
"# To generate a AES key run mysgw with: --gen-aes-key\n" \
"# copy the new key in the line below and uncomment it.\n" \
"#aes_key=\n";
myFile = fopen(config_file, "w");
if (!myFile) {
logError("Unable to create config file %s.\n", config_file);
return -1;
}
ret = fputs(default_conf, myFile);
fclose(myFile);
return (ret > 0);
}
int _config_parse_int(char *token, const char *name, int *value)
{
if (token) {
*value = atoi(token);
} else {
logError("Empty %s value in configuration.\n", name);
return 1;
}
return 0;
}
int _config_parse_string(char *token, const char *name, char **value)
{
if (token) {
if (*value) {
logError("Duplicate %s value in configuration.\n", name);
return 1;
}
while (token[0] == ' ' || token[0] == '\t') {
token++;
}
*value = strdup(token);
if (!*value) {
logError("Out of memory.\n");
return 1;
}
} else {
logError("Empty %s value in configuration.\n", name);
return 1;
}
return 0;
}

View File

@@ -1,48 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 CONFIG_H
#define CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
struct config {
int verbose;
int log_file;
char *log_filepath;
int log_pipe;
char *log_pipe_file;
int syslog;
char *eeprom_file;
int eeprom_size;
char *soft_hmac_key;
char *soft_serial_key;
char *aes_key;
} conf;
int config_parse(const char *config_file);
void config_cleanup(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,252 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 wiringPi Copyright (c) 2012 Gordon Henderson.
*/
#include "interrupt.h"
#include <pthread.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <unistd.h>
#include <poll.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stropts.h>
#include <errno.h>
#include <sched.h>
#include "log.h"
struct ThreadArgs {
void (*func)();
int gpioPin;
};
volatile bool interruptsEnabled = true;
static pthread_mutex_t intMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_t *threadIds[64] = {NULL};
// sysFds:
// Map a file descriptor from the /sys/class/gpio/gpioX/value
static int sysFds[64] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
/*
* Part of wiringPi: Simple way to get your program running at high priority
* with realtime schedulling.
*/
int piHiPri(const int pri)
{
struct sched_param sched ;
memset (&sched, 0, sizeof(sched)) ;
if (pri > sched_get_priority_max (SCHED_RR)) {
sched.sched_priority = sched_get_priority_max (SCHED_RR) ;
} else {
sched.sched_priority = pri ;
}
return sched_setscheduler (0, SCHED_RR, &sched) ;
}
void *interruptHandler(void *args)
{
int fd;
struct pollfd polls;
char c;
struct ThreadArgs *arguments = (struct ThreadArgs *)args;
int gpioPin = arguments->gpioPin;
void (*func)() = arguments->func;
delete arguments;
(void)piHiPri(55); // Only effective if we run as root
if ((fd = sysFds[gpioPin]) == -1) {
logError("Failed to attach interrupt for pin %d\n", gpioPin);
return NULL;
}
// Setup poll structure
polls.fd = fd;
polls.events = POLLPRI | POLLERR;
while (1) {
// Wait for it ...
int ret = poll(&polls, 1, -1);
if (ret < 0) {
logError("Error waiting for interrupt: %s\n", strerror(errno));
break;
}
// Do a dummy read to clear the interrupt
// A one character read appars to be enough.
if (lseek (fd, 0, SEEK_SET) < 0) {
logError("Interrupt handler error: %s\n", strerror(errno));
break;
}
if (read (fd, &c, 1) < 0) {
logError("Interrupt handler error: %s\n", strerror(errno));
break;
}
// Call user function.
pthread_mutex_lock(&intMutex);
if (interruptsEnabled) {
pthread_mutex_unlock(&intMutex);
func();
} else {
pthread_mutex_unlock(&intMutex);
}
}
close(fd);
return NULL;
}
void attachInterrupt(uint8_t gpioPin, void (*func)(), uint8_t mode)
{
FILE *fd;
char fName[40];
char c;
int count, i;
if (threadIds[gpioPin] == NULL) {
threadIds[gpioPin] = new pthread_t;
} else {
// Cancel the existing thread for that pin
pthread_cancel(*threadIds[gpioPin]);
// Wait a bit
usleep(1000);
}
// Export pin for interrupt
if ((fd = fopen("/sys/class/gpio/export", "w")) == NULL) {
logError("attachInterrupt: Unable to export pin %d for interrupt: %s\n", gpioPin, strerror(errno));
exit(1);
}
fprintf(fd, "%d\n", gpioPin);
fclose(fd);
// Wait a bit the system to create /sys/class/gpio/gpio<GPIO number>
usleep(1000);
snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/direction", gpioPin) ;
if ((fd = fopen (fName, "w")) == NULL) {
logError("attachInterrupt: Unable to open GPIO direction interface for pin %d: %s\n",
gpioPin, strerror(errno));
exit(1) ;
}
fprintf(fd, "in\n") ;
fclose(fd) ;
snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/edge", gpioPin) ;
if ((fd = fopen(fName, "w")) == NULL) {
logError("attachInterrupt: Unable to open GPIO edge interface for pin %d: %s\n", gpioPin,
strerror(errno));
exit(1) ;
}
switch (mode) {
case CHANGE:
fprintf(fd, "both\n");
break;
case FALLING:
fprintf(fd, "falling\n");
break;
case RISING:
fprintf(fd, "rising\n");
break;
case NONE:
fprintf(fd, "none\n");
break;
default:
logError("attachInterrupt: Invalid mode\n");
fclose(fd);
return;
}
fclose(fd);
if (sysFds[gpioPin] == -1) {
snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/value", gpioPin);
if ((sysFds[gpioPin] = open(fName, O_RDWR)) < 0) {
logError("Error reading pin %d: %s\n", gpioPin, strerror(errno));
exit(1);
}
}
// Clear any initial pending interrupt
ioctl(sysFds[gpioPin], FIONREAD, &count);
for (i = 0; i < count; ++i) {
if (read(sysFds[gpioPin], &c, 1) == -1) {
logError("attachInterrupt: failed to read pin status: %s\n", strerror(errno));
}
}
struct ThreadArgs *threadArgs = new struct ThreadArgs;
threadArgs->func = func;
threadArgs->gpioPin = gpioPin;
// Create a thread passing the pin and function
pthread_create(threadIds[gpioPin], NULL, interruptHandler, (void *)threadArgs);
}
void detachInterrupt(uint8_t gpioPin)
{
// Cancel the thread
if (threadIds[gpioPin] != NULL) {
pthread_cancel(*threadIds[gpioPin]);
delete threadIds[gpioPin];
threadIds[gpioPin] = NULL;
}
// Close filehandle
if (sysFds[gpioPin] != -1) {
close(sysFds[gpioPin]);
sysFds[gpioPin] = -1;
}
FILE *fp = fopen("/sys/class/gpio/unexport", "w");
if (fp == NULL) {
logError("Unable to unexport pin %d for interrupt\n", gpioPin);
exit(1);
}
fprintf(fp, "%d", gpioPin);
fclose(fp);
}
void interrupts()
{
pthread_mutex_lock(&intMutex);
interruptsEnabled = true;
pthread_mutex_unlock(&intMutex);
}
void noInterrupts()
{
pthread_mutex_lock(&intMutex);
interruptsEnabled = false;
pthread_mutex_unlock(&intMutex);
}

View File

@@ -1,45 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 wiringPi Copyright (c) 2012 Gordon Henderson.
*/
#ifndef interrupt_h
#define interrupt_h
#include <stdint.h>
#define CHANGE 1
#define FALLING 2
#define RISING 3
#define NONE 4
#ifdef __cplusplus
extern "C" {
#endif
void attachInterrupt(uint8_t gpioPin, void(*func)(), uint8_t mode);
void detachInterrupt(uint8_t gpioPin);
void interrupts();
void noInterrupts();
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,277 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 "log.h"
#include <stdio.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
static const char *_log_level_colors[] = {
"\x1b[1;5;91m", "\x1b[1;91m", "\x1b[91m", "\x1b[31m", "\x1b[33m", "\x1b[34m", "\x1b[32m", "\x1b[36m"
};
static const char *_log_level_names[] = {
"EMERGENCY", "ALERT", "CRITICAL", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG"
};
static uint8_t _log_quiet = 0;
static uint8_t _log_level = LOG_DEBUG;
static uint8_t _log_syslog = 0;
static uint8_t _log_pipe = 0;
static char *_log_pipe_file = NULL;
static int _log_pipe_fd = -1;
static FILE *_log_file_fp = NULL;
void logSetQuiet(uint8_t enable)
{
_log_quiet = enable ? 1 : 0;
}
void logSetLevel(int level)
{
if (level < LOG_EMERG || level > LOG_DEBUG) {
return;
}
_log_level = level;
}
void logSetSyslog(int options, int facility)
{
openlog(NULL, options, facility);
_log_syslog = 1;
}
int logSetPipe(char *pipe_file)
{
if (pipe_file == NULL) {
return -1;
}
_log_pipe_file = strdup(pipe_file);
if (_log_pipe_file == NULL) {
return -1;
}
int ret = mkfifo(_log_pipe_file, 0666);
if (ret == 0) {
_log_pipe = 1;
}
return ret;
}
int logSetFile(char *file)
{
if (file == NULL) {
return -1;
}
_log_file_fp = fopen(file, "a");
if (_log_file_fp == NULL) {
return errno;
}
return 0;
}
void logClose(void)
{
if (_log_syslog) {
closelog();
_log_syslog = 0;
}
if (_log_pipe) {
if (_log_pipe_fd > 0) {
close(_log_pipe_fd);
}
/* remove the FIFO */
unlink(_log_pipe_file);
_log_pipe = 0;
}
if (_log_pipe_file != NULL) {
free(_log_pipe_file);
_log_pipe_file = NULL;
}
if (_log_file_fp != NULL) {
fclose(_log_file_fp);
_log_file_fp = NULL;
}
}
void vlog(int level, const char *fmt, va_list args)
{
if (_log_level < level) {
return;
}
if (!_log_quiet || _log_file_fp != NULL) {
/* Get current time */
time_t t = time(NULL);
struct tm *lt = localtime(&t);
char date[16];
date[strftime(date, sizeof(date), "%b %d %H:%M:%S", lt)] = '\0';
if (_log_file_fp != NULL) {
fprintf(_log_file_fp, "%s %-5s ", date, _log_level_names[level]);
vfprintf(_log_file_fp, fmt, args);
}
if (!_log_quiet) {
#ifdef LOG_DISABLE_COLOR
(void)_log_level_colors;
fprintf(stderr, "%s %-5s ", date, _log_level_names[level]);
vfprintf(stderr, fmt, args);
#else
fprintf(stderr, "%s %s%-5s\x1b[0m ", date, _log_level_colors[level], _log_level_names[level]);
vfprintf(stderr, fmt, args);
#endif
}
}
if (_log_syslog) {
vsyslog(level, fmt, args);
}
if (_log_pipe) {
if (_log_pipe_fd < 0) {
_log_pipe_fd = open(_log_pipe_file, O_WRONLY | O_NONBLOCK);
}
if (_log_pipe_fd > 0) {
if (vdprintf(_log_pipe_fd, fmt, args) < 0) {
close(_log_pipe_fd);
_log_pipe_fd = -1;
}
}
}
}
void
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
logEmergency(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlog(LOG_EMERG, fmt, args);
va_end(args);
}
void
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
logAlert(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlog(LOG_ALERT, fmt, args);
va_end(args);
}
void
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
logCritical(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlog(LOG_CRIT, fmt, args);
va_end(args);
}
void
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
logError(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlog(LOG_ERR, fmt, args);
va_end(args);
}
void
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
logWarning(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlog(LOG_WARNING, fmt, args);
va_end(args);
}
void
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
logNotice(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlog(LOG_NOTICE, fmt, args);
va_end(args);
}
void
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
logInfo(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlog(LOG_INFO, fmt, args);
va_end(args);
}
void
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
logDebug(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlog(LOG_DEBUG, fmt, args);
va_end(args);
}

View File

@@ -1,59 +0,0 @@
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2018 Sensnology AB
* 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 LOG_H
#define LOG_H
#include <stdarg.h>
#include <stdio.h>
#include <syslog.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define vlogError(...) vlog(LOG_ERR, __VA_ARGS__)
#define vlogWarning(...) vlog(LOG_WARNING, __VA_ARGS__)
#define vlogNotice(...) vlog(LOG_NOTICE, __VA_ARGS__)
#define vlogInfo(...) vlog(LOG_INFO, __VA_ARGS__)
#define vlogDebug(...) vlog(LOG_DEBUG, __VA_ARGS__)
void logSetQuiet(uint8_t enable);
void logSetLevel(int level);
void logSetSyslog(int options, int facility);
int logSetPipe(char *pipe_file);
int logSetFile(char *file);
void logClose(void);
void vlog(int level, const char *fmt, va_list args);
void logEmergency(const char *fmt, ...) __attribute__((format(printf,1,2)));
void logAlert(const char *fmt, ...) __attribute__((format(printf,1,2)));
void logCritical(const char *fmt, ...) __attribute__((format(printf,1,2)));
void logError(const char *fmt, ...) __attribute__((format(printf,1,2)));
void logWarning(const char *fmt, ...) __attribute__((format(printf,1,2)));
void logNotice(const char *fmt, ...) __attribute__((format(printf,1,2)));
void logInfo(const char *fmt, ...) __attribute__((format(printf,1,2)));
void logDebug(const char *fmt, ...) __attribute__((format(printf,1,2)));
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,158 +0,0 @@
/*
noniso.cpp - replacements for non-ISO functions used by Arduino core
Copyright © 2016 Ivan Grokhotkov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
Modified August 2016 by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <math.h>
#include "stdlib_noniso.h"
char* utoa(unsigned value, char* result, int base)
{
if(base < 2 || base > 16) {
*result = 0;
return result;
}
char* out = result;
unsigned quotient = value;
do {
const unsigned tmp = quotient / base;
*out = "0123456789abcdef"[quotient - (tmp * base)];
++out;
quotient = tmp;
} while(quotient);
reverse(result, out);
*out = 0;
return result;
}
char* itoa(int value, char* result, int base)
{
if(base < 2 || base > 16) {
*result = 0;
return result;
}
char* out = result;
int quotient = abs(value);
do {
const int tmp = quotient / base;
*out = "0123456789abcdef"[quotient - (tmp * base)];
++out;
quotient = tmp;
} while(quotient);
// Apply negative sign
if(value < 0) {
*out++ = '-';
}
reverse(result, out);
*out = 0;
return result;
}
int atoi(const char* s)
{
return (int) atol(s);
}
long atol(const char* s)
{
char * tmp;
return strtol(s, &tmp, 10);
}
double atof(const char* s)
{
char * tmp;
return strtod(s, &tmp);
}
void reverse(char* begin, char* end)
{
char *is = begin;
char *ie = end - 1;
while(is < ie) {
char tmp = *ie;
*ie = *is;
*is = tmp;
++is;
--ie;
}
}
char* ltoa(long value, char* result, int base)
{
if(base < 2 || base > 16) {
*result = 0;
return result;
}
char* out = result;
long quotient = abs(value);
do {
const long tmp = quotient / base;
*out = "0123456789abcdef"[quotient - (tmp * base)];
++out;
quotient = tmp;
} while(quotient);
// Apply negative sign
if(value < 0) {
*out++ = '-';
}
reverse(result, out);
*out = 0;
return result;
}
char* ultoa(unsigned long value, char* result, int base)
{
if(base < 2 || base > 16) {
*result = 0;
return result;
}
char* out = result;
unsigned long quotient = value;
do {
const unsigned long tmp = quotient / base;
*out = "0123456789abcdef"[quotient - (tmp * base)];
++out;
quotient = tmp;
} while(quotient);
reverse(result, out);
*out = 0;
return result;
}
char* dtostrf (double val, signed char width, unsigned char prec, char *s)
{
sprintf(s,"%*.*f", width, prec, val);
return s;
}

View File

@@ -1,52 +0,0 @@
/*
stdlib_noniso.h - nonstandard (but usefull) conversion functions
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
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 STDLIB_NONISO_H
#define STDLIB_NONISO_H
#ifdef __cplusplus
extern "C" {
#endif
int atoi(const char *s);
long atol(const char* s);
double atof(const char* s);
char* itoa (int val, char *s, int radix);
char* ltoa (long val, char *s, int radix);
char* utoa (unsigned int val, char *s, int radix);
char* ultoa (unsigned long val, char *s, int radix);
char* dtostrf (double val, signed char width, unsigned char prec, char *s);
void reverse(char* begin, char* end);
#ifdef __cplusplus
} // extern "C"
#endif
#endif