MySensors 2.1.1 release (#752)
* Bump version to 2.2.0-beta (#713) * OTA: Add incoming FW block check (#718) * Linux: Add support for SPIDEV (#734) RPi and Linux refactor. Add GPIO Sysfs for GPIO operations. Update configure script. Fix some cppcheck warnings. Add serial emulation that prints to stdout. Fix some file headers. * Fix getControllerConfig() (#737) * Rename MyHwATmega328 to MyHwAVR (#738) * AVR: Restrict fast pin function use (#739) * Fix signing presentation bug (#740) * Consolidate open PRs for bugfix release (#741) * Revert "Bump version to 2.2.0-beta" (#744) * Merge Master into Dev (#745) * Fix spi flash error when compiling in Arduino IDE 1.6.6 * Bump minor version * Fixed "invalid suffix on literal" warning * Fix addressing bug in _doSign bitfield * Make sure nodes not supporting signing informs GW A node that does not support signing, still needs to inform the gateway about this to make sure the gateway carries a valid signing requirement table when a node Id that was requiering signing stops doing this. This fixes #286. * Prevent SecureActuator from accepting ACKs as commands As ACKs are not currently signed, allowing ACKs as commands is a considerable security hole for this sketch. This is now resolved. * Backport of bugfix (#259) in repeaters when forwarding signed messages * Bumped version to 1.5.2 * Corrected doSign variable name (was _doSign) * Bumped version to 1.5.3 * Add NULL termination to payloads Messages addressed to "this" node, will have a null char appended to the payload after message verification is done, because some "getters" assume the message being a string. * MySensors 2.1.1 release
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "RPi.h"
|
||||
#include <stdlib.h>
|
||||
#include "log.h"
|
||||
|
||||
const static int pin_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 pin_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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
const static int pin_to_gpio_rev3[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
|
||||
RPi rpi = RPi();
|
||||
|
||||
const int* RPi::pin_to_gpio = NULL;
|
||||
rpi_info RPi::rpiinfo;
|
||||
|
||||
RPi::RPi()
|
||||
{
|
||||
if (!bcm2835_init()) {
|
||||
logError("Failed to initialized bcm2835.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
RPi::~RPi()
|
||||
{
|
||||
bcm2835_close();
|
||||
}
|
||||
|
||||
void RPi::pinMode(uint8_t physPin, uint8_t mode)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (physToGPIO(physPin, &gpioPin)) {
|
||||
logError("pinMode: invalid pin: %d\n", physPin);
|
||||
return;
|
||||
}
|
||||
|
||||
bcm2835_gpio_fsel(gpioPin, mode);
|
||||
}
|
||||
|
||||
void RPi::digitalWrite(uint8_t physPin, uint8_t value)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (physToGPIO(physPin, &gpioPin)) {
|
||||
logError("digitalWrite: invalid pin: %d\n", physPin);
|
||||
return;
|
||||
}
|
||||
|
||||
bcm2835_gpio_write(gpioPin, value);
|
||||
// Delay to allow any change in state to be reflected in the LEVn, register bit.
|
||||
delayMicroseconds(1);
|
||||
}
|
||||
|
||||
uint8_t RPi::digitalRead(uint8_t physPin)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (physToGPIO(physPin, &gpioPin)) {
|
||||
logError("digitalRead: invalid pin: %d\n", physPin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bcm2835_gpio_lev(gpioPin);
|
||||
}
|
||||
|
||||
uint8_t RPi::digitalPinToInterrupt(uint8_t physPin)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (physToGPIO(physPin, &gpioPin)) {
|
||||
logError("digitalPinToInterrupt: invalid pin: %d\n", physPin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return gpioPin;
|
||||
}
|
||||
|
||||
int RPi::physToGPIO(uint8_t physPin, uint8_t *gpio)
|
||||
{
|
||||
if (pin_to_gpio == NULL) {
|
||||
// detect board revision and set up accordingly
|
||||
if (get_rpi_info(&rpiinfo)) {
|
||||
logError("This module can only be run on a Raspberry Pi!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (rpiinfo.p1_revision == 1) {
|
||||
pin_to_gpio = &pin_to_gpio_rev1[0];
|
||||
} else if (rpiinfo.p1_revision == 2) {
|
||||
pin_to_gpio = &pin_to_gpio_rev2[0];
|
||||
} else { // assume model B+ or A+ or 2B
|
||||
pin_to_gpio = &pin_to_gpio_rev3[0];
|
||||
}
|
||||
}
|
||||
|
||||
if ((rpiinfo.p1_revision != 3 && physPin > 26)
|
||||
|| (rpiinfo.p1_revision == 3 && physPin > 40)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*(pin_to_gpio+physPin) == -1) {
|
||||
return -1;
|
||||
} else {
|
||||
*gpio = *(pin_to_gpio+physPin);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef RPi_h
|
||||
#define RPi_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bcm2835.h"
|
||||
#include "cpuinfo.h"
|
||||
|
||||
#define INPUT BCM2835_GPIO_FSEL_INPT
|
||||
#define OUTPUT BCM2835_GPIO_FSEL_OUTP
|
||||
|
||||
/**
|
||||
* @brief RPi class
|
||||
*/
|
||||
class RPi
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief RPi constructor.
|
||||
*/
|
||||
RPi();
|
||||
/**
|
||||
* @brief RPi destructor.
|
||||
*/
|
||||
~RPi();
|
||||
/**
|
||||
* @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 *pin_to_gpio; //!< @brief Pointer to array of GPIO pins numbers.
|
||||
static rpi_info rpiinfo; //!< @brief Board information.
|
||||
};
|
||||
|
||||
extern RPi rpi;
|
||||
|
||||
#endif
|
||||
@@ -1,112 +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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* Based on TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard <tmrh20@gmail.com>
|
||||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "log.h"
|
||||
|
||||
static pthread_mutex_t spiMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// Declare a single default instance
|
||||
SPIClass SPI = SPIClass();
|
||||
|
||||
uint8_t SPIClass::initialized = 0;
|
||||
|
||||
uint8_t SPIClass::is_initialized()
|
||||
{
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void SPIClass::begin()
|
||||
{
|
||||
if (!initialized) {
|
||||
if (!bcm2835_spi_begin()) {
|
||||
logError("You need root privilege to use SPI.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
initialized++; // reference count
|
||||
}
|
||||
|
||||
void SPIClass::end()
|
||||
{
|
||||
if (initialized) {
|
||||
initialized--;
|
||||
}
|
||||
|
||||
if (!initialized) {
|
||||
// End the SPI
|
||||
bcm2835_spi_end();
|
||||
}
|
||||
}
|
||||
|
||||
void SPIClass::setBitOrder(uint8_t bit_order)
|
||||
{
|
||||
bcm2835_spi_setBitOrder(bit_order);
|
||||
}
|
||||
|
||||
void SPIClass::setDataMode(uint8_t data_mode)
|
||||
{
|
||||
bcm2835_spi_setDataMode(data_mode);
|
||||
}
|
||||
|
||||
void SPIClass::setClockDivider(uint16_t divider)
|
||||
{
|
||||
bcm2835_spi_setClockDivider(divider);
|
||||
}
|
||||
|
||||
void SPIClass::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 SPIClass::beginTransaction(SPISettings settings)
|
||||
{
|
||||
pthread_mutex_lock(&spiMutex);
|
||||
setBitOrder(settings.border);
|
||||
setDataMode(settings.dmode);
|
||||
setClockDivider(settings.cdiv);
|
||||
}
|
||||
|
||||
void SPIClass::endTransaction()
|
||||
{
|
||||
pthread_mutex_unlock(&spiMutex);
|
||||
}
|
||||
|
||||
void SPIClass::usingInterrupt(uint8_t interruptNumber)
|
||||
{
|
||||
(void)interruptNumber;
|
||||
}
|
||||
|
||||
void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
|
||||
{
|
||||
(void)interruptNumber;
|
||||
}
|
||||
@@ -1,232 +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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* Based on TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard <tmrh20@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _SPI_H_
|
||||
#define _SPI_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include "bcm2835.h"
|
||||
|
||||
#define SPI_HAS_TRANSACTION
|
||||
|
||||
// SPI Clock divider
|
||||
#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
|
||||
|
||||
// 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
|
||||
|
||||
/**
|
||||
* SPISettings class
|
||||
*/
|
||||
class SPISettings
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief SPISettings constructor.
|
||||
*
|
||||
* Default clock speed is 8Mhz.
|
||||
*/
|
||||
SPISettings()
|
||||
{
|
||||
init(BCM2835_SPI_CLOCK_DIVIDER_32, BCM2835_SPI_BIT_ORDER_MSBFIRST, BCM2835_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;
|
||||
|
||||
switch (clock) {
|
||||
case 500000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_512;
|
||||
break;
|
||||
case 1000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_256;
|
||||
break;
|
||||
case 2000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_128;
|
||||
break;
|
||||
case 4000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_64;
|
||||
break;
|
||||
case 8000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_32;
|
||||
break;
|
||||
case 16000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_16;
|
||||
break;
|
||||
default:
|
||||
// 8Mhz
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_32;
|
||||
}
|
||||
|
||||
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 SPIClass;
|
||||
};
|
||||
|
||||
/**
|
||||
* SPIClass class
|
||||
*/
|
||||
class SPIClass
|
||||
{
|
||||
|
||||
private:
|
||||
static uint8_t initialized; //!< @brief SPI initialized flag.
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Checks if SPI was initialized.
|
||||
*
|
||||
* @return 0 if wasn't initialized, else 1 or more.
|
||||
*/
|
||||
static uint8_t is_initialized();
|
||||
/**
|
||||
* @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);
|
||||
};
|
||||
|
||||
uint8_t SPIClass::transfer(uint8_t data)
|
||||
{
|
||||
return bcm2835_spi_transfer(data);
|
||||
}
|
||||
|
||||
void SPIClass::transfernb(char* tbuf, char* rbuf, uint32_t len)
|
||||
{
|
||||
bcm2835_spi_transfernb( tbuf, rbuf, len);
|
||||
}
|
||||
|
||||
void SPIClass::transfern(char* buf, uint32_t len)
|
||||
{
|
||||
transfernb(buf, buf, len);
|
||||
}
|
||||
|
||||
extern SPIClass SPI;
|
||||
|
||||
#endif
|
||||
@@ -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();
|
||||
@@ -1,93 +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"
|
||||
|
||||
#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
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* piHiPri:
|
||||
* Simple way to get your program running at high priority
|
||||
* with realtime schedulling.
|
||||
*
|
||||
* Copyright (c) 2012 Gordon Henderson
|
||||
***********************************************************************
|
||||
* This file is part of wiringPi:
|
||||
* https://projects.drogon.net/raspberry-pi/wiringpi/
|
||||
*
|
||||
* wiringPi 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* wiringPi 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 wiringPi.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
#include <sched.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* piHiPri:
|
||||
* Attempt to set a high priority schedulling for the running program
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
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) ;
|
||||
}
|
||||
@@ -1,341 +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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* Based on wiringPi Copyright (c) 2012 Gordon Henderson.
|
||||
*/
|
||||
|
||||
#include "rpi_util.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 "SPI.h"
|
||||
#include "log.h"
|
||||
#include "cpuinfo.h"
|
||||
|
||||
extern "C" {
|
||||
int piHiPri(const int pri);
|
||||
}
|
||||
|
||||
struct ThreadArgs {
|
||||
void (*func)();
|
||||
int gpioPin;
|
||||
};
|
||||
|
||||
static const int *pin_to_gpio = 0;
|
||||
static rpi_info rpiinfo;
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
int get_gpio_number(uint8_t physPin, uint8_t *gpio)
|
||||
{
|
||||
if (pin_to_gpio == 0) {
|
||||
// detect board revision and set up accordingly
|
||||
if (get_rpi_info(&rpiinfo)) {
|
||||
logError("This module can only be run on a Raspberry Pi!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (rpiinfo.p1_revision == 1) {
|
||||
pin_to_gpio = &pin_to_gpio_rev1[0];
|
||||
} else if (rpiinfo.p1_revision == 2) {
|
||||
pin_to_gpio = &pin_to_gpio_rev2[0];
|
||||
} else { // assume model B+ or A+ or 2B
|
||||
pin_to_gpio = &pin_to_gpio_rev3[0];
|
||||
}
|
||||
}
|
||||
|
||||
if ((rpiinfo.p1_revision != 3 && physPin > 26)
|
||||
|| (rpiinfo.p1_revision == 3 && physPin > 40)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*(pin_to_gpio+physPin) == -1) {
|
||||
return -1;
|
||||
} else {
|
||||
*gpio = *(pin_to_gpio+physPin);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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.
|
||||
// Followed by a seek to reset it.
|
||||
(void)read (fd, &c, 1) ;
|
||||
lseek (fd, 0, SEEK_SET) ;
|
||||
// Call user function.
|
||||
pthread_mutex_lock(&intMutex);
|
||||
if (interruptsEnabled) {
|
||||
pthread_mutex_unlock(&intMutex);
|
||||
func();
|
||||
} else {
|
||||
pthread_mutex_unlock(&intMutex);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void rpi_util::pinMode(uint8_t physPin, uint8_t mode)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (get_gpio_number(physPin, &gpioPin)) {
|
||||
logError("pinMode: invalid pin: %d\n", physPin);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if SPI is in use and target pin is related to SPI
|
||||
if (SPIClass::is_initialized() && gpioPin >= RPI_GPIO_P1_26 && gpioPin <= RPI_GPIO_P1_23) {
|
||||
return;
|
||||
} else {
|
||||
bcm2835_gpio_fsel(gpioPin, mode);
|
||||
}
|
||||
}
|
||||
|
||||
void rpi_util::digitalWrite(uint8_t physPin, uint8_t value)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (get_gpio_number(physPin, &gpioPin)) {
|
||||
logError("digitalWrite: invalid pin: %d\n", physPin);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if SPI is in use and target pin is related to SPI
|
||||
if (SPIClass::is_initialized() && gpioPin >= RPI_GPIO_P1_26 && gpioPin <= RPI_GPIO_P1_23) {
|
||||
if (value == LOW && (gpioPin == RPI_GPIO_P1_24 || gpioPin == RPI_GPIO_P1_26)) {
|
||||
SPI.chipSelect(gpioPin);
|
||||
}
|
||||
} else {
|
||||
bcm2835_gpio_write(gpioPin, value);
|
||||
// Delay to allow any change in state to be reflected in the LEVn, register bit.
|
||||
delayMicroseconds(1);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t rpi_util::digitalRead(uint8_t physPin)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (get_gpio_number(physPin, &gpioPin)) {
|
||||
logError("digitalRead: invalid pin: %d\n", physPin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if SPI is in use and target pin is related to SPI
|
||||
if (SPIClass::is_initialized() && gpioPin >= RPI_GPIO_P1_26 && gpioPin <= RPI_GPIO_P1_23) {
|
||||
return 0;
|
||||
} else {
|
||||
return bcm2835_gpio_lev(gpioPin);
|
||||
}
|
||||
}
|
||||
|
||||
void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode)
|
||||
{
|
||||
FILE *fd;
|
||||
char fName[40];
|
||||
char c;
|
||||
int count, i;
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (get_gpio_number(physPin, &gpioPin)) {
|
||||
logError("attachInterrupt: invalid pin: %d\n", physPin);
|
||||
return;
|
||||
}
|
||||
|
||||
if (threadIds[gpioPin] == NULL) {
|
||||
threadIds[gpioPin] = new pthread_t;
|
||||
} else {
|
||||
// Cancel the existing thread for that pin
|
||||
pthread_cancel(*threadIds[gpioPin]);
|
||||
// Wait a bit
|
||||
delay(1L);
|
||||
}
|
||||
|
||||
// Export pin for interrupt
|
||||
if ((fd = fopen("/sys/class/gpio/export", "w")) == NULL) {
|
||||
logError("attachInterrupt: Unable to export pin %d for interrupt: %s\n", physPin, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
fprintf(fd, "%d\n", gpioPin);
|
||||
fclose(fd);
|
||||
|
||||
// Wait a bit the system to create /sys/class/gpio/gpio<GPIO number>
|
||||
delay(1L);
|
||||
|
||||
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",
|
||||
physPin, 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", physPin,
|
||||
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", physPin, 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 rpi_util::detachInterrupt(uint8_t physPin)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (get_gpio_number(physPin, &gpioPin)) {
|
||||
logError("detachInterrupt: invalid pin: %d\n", physPin);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
uint8_t rpi_util::digitalPinToInterrupt(uint8_t physPin)
|
||||
{
|
||||
// No need to convert the pin to gpio, we do it in attachInterrupt().
|
||||
return physPin;
|
||||
}
|
||||
|
||||
void rpi_util::interrupts()
|
||||
{
|
||||
pthread_mutex_lock(&intMutex);
|
||||
interruptsEnabled = true;
|
||||
pthread_mutex_unlock(&intMutex);
|
||||
}
|
||||
|
||||
void rpi_util::noInterrupts()
|
||||
{
|
||||
pthread_mutex_lock(&intMutex);
|
||||
interruptsEnabled = false;
|
||||
pthread_mutex_unlock(&intMutex);
|
||||
}
|
||||
@@ -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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* Based on wiringPi Copyright (c) 2012 Gordon Henderson.
|
||||
*/
|
||||
|
||||
#ifndef rpi_util_h
|
||||
#define rpi_util_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bcm2835.h"
|
||||
|
||||
const int pin_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 int pin_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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
const int pin_to_gpio_rev3[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 };
|
||||
|
||||
namespace rpi_util
|
||||
{
|
||||
|
||||
typedef enum {
|
||||
LSBFIRST = BCM2835_SPI_BIT_ORDER_LSBFIRST,
|
||||
MSBFIRST = BCM2835_SPI_BIT_ORDER_MSBFIRST
|
||||
} rpi_bitorder;
|
||||
|
||||
typedef enum {
|
||||
INPUT = BCM2835_GPIO_FSEL_INPT,
|
||||
OUTPUT = BCM2835_GPIO_FSEL_OUTP
|
||||
} rpi_pinmode;
|
||||
|
||||
typedef enum {
|
||||
CHANGE = 1,
|
||||
FALLING = 2,
|
||||
RISING = 3,
|
||||
NONE = 4
|
||||
} rpi_pinedge;
|
||||
|
||||
typedef enum {
|
||||
PIN_SPI_SS = 24,
|
||||
PIN_SPI_MOSI = 19,
|
||||
PIN_SPI_MISO = 21,
|
||||
PIN_SPI_SCK = 23
|
||||
} rpi_spipins;
|
||||
|
||||
const uint8_t SS = PIN_SPI_SS;
|
||||
const uint8_t MOSI = PIN_SPI_MOSI;
|
||||
const uint8_t MISO = PIN_SPI_MISO;
|
||||
const uint8_t SCK = PIN_SPI_SCK;
|
||||
|
||||
/* Some useful arduino functions */
|
||||
void pinMode(uint8_t physPin, uint8_t mode);
|
||||
void digitalWrite(uint8_t physPin, uint8_t value);
|
||||
uint8_t digitalRead(uint8_t physPin);
|
||||
void attachInterrupt(uint8_t physPin,void (*func)(), uint8_t mode);
|
||||
void detachInterrupt(uint8_t physPin);
|
||||
uint8_t digitalPinToInterrupt(uint8_t physPin);
|
||||
void interrupts();
|
||||
void noInterrupts();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user