Use mysensors built-in nrf24 library for RPi
This commit is contained in:
@@ -13,14 +13,22 @@ include $(CONFIG_FILE)
|
|||||||
|
|
||||||
GATEWAY_BIN=mysGateway
|
GATEWAY_BIN=mysGateway
|
||||||
GATEWAY=examples_linux/$(GATEWAY_BIN)
|
GATEWAY=examples_linux/$(GATEWAY_BIN)
|
||||||
GATEWAY_SOURCES=$(wildcard drivers/Linux/*.cpp) examples_linux/mysGateway.cpp
|
GATEWAY_C_SOURCES=$(wildcard drivers/Linux/*.c)
|
||||||
GATEWAY_OBJECTS=$(patsubst %.cpp,%.o,$(GATEWAY_SOURCES))
|
GATEWAY_CPP_SOURCES=$(wildcard drivers/Linux/*.cpp) examples_linux/mysGateway.cpp
|
||||||
DEPS+=$(patsubst %.cpp,%.d,$(GATEWAY_SOURCES))
|
OBJECTS=$(patsubst %.c,%.o,$(GATEWAY_C_SOURCES)) $(patsubst %.cpp,%.o,$(GATEWAY_CPP_SOURCES))
|
||||||
|
|
||||||
|
DEPS+=$(patsubst %.c,%.d,$(GATEWAY_C_SOURCES)) $(patsubst %.cpp,%.d,$(GATEWAY_CPP_SOURCES))
|
||||||
|
|
||||||
CINCLUDE=-I. -I./core -I./drivers/Linux
|
CINCLUDE=-I. -I./core -I./drivers/Linux
|
||||||
|
|
||||||
ifneq ($(RF24H_LIB_DIR),)
|
ifeq ($(SOC),$(filter $(SOC),BCM2835 BCM2836))
|
||||||
CINCLUDE+=-I$(RF24H_LIB_DIR)
|
RPI_C_SOURCES=$(wildcard drivers/RPi/*.c)
|
||||||
|
RPI_CPP_SOURCES=$(wildcard drivers/RPi/*.cpp)
|
||||||
|
OBJECTS+=$(patsubst %.c,%.o,$(RPI_C_SOURCES)) $(patsubst %.cpp,%.o,$(RPI_CPP_SOURCES))
|
||||||
|
|
||||||
|
DEPS+=$(patsubst %.c,%.d,$(RPI_C_SOURCES)) $(patsubst %.cpp,%.d,$(RPI_CPP_SOURCES))
|
||||||
|
|
||||||
|
CINCLUDE+=-I./drivers/RPi
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: all gateway cleanconfig clean install uninstall force
|
.PHONY: all gateway cleanconfig clean install uninstall force
|
||||||
@@ -28,8 +36,8 @@ endif
|
|||||||
all: $(GATEWAY)
|
all: $(GATEWAY)
|
||||||
|
|
||||||
# Gateway Build
|
# Gateway Build
|
||||||
$(GATEWAY): $(GATEWAY_OBJECTS)
|
$(GATEWAY): $(OBJECTS)
|
||||||
$(CXX) $(LDFLAGS) -o $@ $(GATEWAY_OBJECTS)
|
$(CXX) $(LDFLAGS) -o $@ $(OBJECTS)
|
||||||
|
|
||||||
# Include all .d files
|
# Include all .d files
|
||||||
-include $(DEPS)
|
-include $(DEPS)
|
||||||
@@ -37,6 +45,9 @@ $(GATEWAY): $(GATEWAY_OBJECTS)
|
|||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
$(CXX) $(CXXFLAGS) $(CINCLUDE) -MMD -c -o $@ $<
|
$(CXX) $(CXXFLAGS) $(CINCLUDE) -MMD -c -o $@ $<
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) $(CINCLUDE) -MMD -c -o $@ $<
|
||||||
|
|
||||||
# clear configuration files
|
# clear configuration files
|
||||||
cleanconfig:
|
cleanconfig:
|
||||||
@echo "[Cleaning configuration]"
|
@echo "[Cleaning configuration]"
|
||||||
@@ -45,7 +56,7 @@ cleanconfig:
|
|||||||
# clear build files
|
# clear build files
|
||||||
clean:
|
clean:
|
||||||
@echo "[Cleaning]"
|
@echo "[Cleaning]"
|
||||||
rm -rf build $(GATEWAY_OBJECTS) $(GATEWAY) $(DEPS)
|
rm -rf build $(OBJECTS) $(GATEWAY) $(DEPS)
|
||||||
|
|
||||||
$(CONFIG_FILE):
|
$(CONFIG_FILE):
|
||||||
@echo "[Running configure]"
|
@echo "[Running configure]"
|
||||||
|
|||||||
+2
-2
@@ -410,7 +410,7 @@
|
|||||||
#define MY_RF24_CE_PIN 4
|
#define MY_RF24_CE_PIN 4
|
||||||
#elif defined(ARDUINO_ARCH_SAMD)
|
#elif defined(ARDUINO_ARCH_SAMD)
|
||||||
#define MY_RF24_CE_PIN 27
|
#define MY_RF24_CE_PIN 27
|
||||||
#elif defined(__linux__)
|
#elif defined(LINUX_ARCH_RASPBERRYPI)
|
||||||
#define MY_RF24_CE_PIN 22
|
#define MY_RF24_CE_PIN 22
|
||||||
#else
|
#else
|
||||||
#define MY_RF24_CE_PIN 9
|
#define MY_RF24_CE_PIN 9
|
||||||
@@ -426,7 +426,7 @@
|
|||||||
#define MY_RF24_CS_PIN 15
|
#define MY_RF24_CS_PIN 15
|
||||||
#elif defined(ARDUINO_ARCH_SAMD)
|
#elif defined(ARDUINO_ARCH_SAMD)
|
||||||
#define MY_RF24_CS_PIN 3
|
#define MY_RF24_CS_PIN 3
|
||||||
#elif defined(__linux__)
|
#elif defined(LINUX_ARCH_RASPBERRYPI)
|
||||||
#define MY_RF24_CS_PIN 24
|
#define MY_RF24_CS_PIN 24
|
||||||
#else
|
#else
|
||||||
#define MY_RF24_CS_PIN 10
|
#define MY_RF24_CS_PIN 10
|
||||||
|
|||||||
+4
-4
@@ -276,6 +276,10 @@
|
|||||||
#include "drivers/AVR/DigitalIO/DigitalIO.h"
|
#include "drivers/AVR/DigitalIO/DigitalIO.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(MY_RADIO_NRF24) && defined(__linux__) && !defined(LINUX_ARCH_RASPBERRYPI)
|
||||||
|
#error No support for nRF24 radio on this platform
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "core/MyTransport.cpp"
|
#include "core/MyTransport.cpp"
|
||||||
#if (defined(MY_RADIO_NRF24) && defined(MY_RADIO_RFM69)) || (defined(MY_RADIO_NRF24) && defined(MY_RS485)) || (defined(MY_RADIO_RFM69) && defined(MY_RS485))
|
#if (defined(MY_RADIO_NRF24) && defined(MY_RADIO_RFM69)) || (defined(MY_RADIO_NRF24) && defined(MY_RS485)) || (defined(MY_RADIO_RFM69) && defined(MY_RS485))
|
||||||
#error Only one forward link driver can be activated
|
#error Only one forward link driver can be activated
|
||||||
@@ -284,11 +288,7 @@
|
|||||||
#if defined(MY_RF24_ENABLE_ENCRYPTION)
|
#if defined(MY_RF24_ENABLE_ENCRYPTION)
|
||||||
#include "drivers/AES/AES.cpp"
|
#include "drivers/AES/AES.cpp"
|
||||||
#endif
|
#endif
|
||||||
#if defined(__linux__)
|
|
||||||
#include "drivers/RF24/RF24_Linux.cpp"
|
|
||||||
#else
|
|
||||||
#include "drivers/RF24/RF24.cpp"
|
#include "drivers/RF24/RF24.cpp"
|
||||||
#endif
|
|
||||||
#include "core/MyTransportNRF24.cpp"
|
#include "core/MyTransportNRF24.cpp"
|
||||||
#elif defined(MY_RS485)
|
#elif defined(MY_RS485)
|
||||||
#include "drivers/AltSoftSerial/AltSoftSerial.cpp"
|
#include "drivers/AltSoftSerial/AltSoftSerial.cpp"
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ MySensors options:
|
|||||||
--my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW]
|
--my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW]
|
||||||
RF24 PA level. [RF24_PA_MAX]
|
RF24 PA level. [RF24_PA_MAX]
|
||||||
--my-rf24-irq-pin=<PIN> Pin number connected to nRF24L01 IRQ pin.
|
--my-rf24-irq-pin=<PIN> Pin number connected to nRF24L01 IRQ pin.
|
||||||
For RaspberryPi use BCM numbering.
|
|
||||||
--my-rx-message-buffer-size=<SIZE>
|
--my-rx-message-buffer-size=<SIZE>
|
||||||
Buffer size for incoming messages when using rf24 interrupts. [20]
|
Buffer size for incoming messages when using rf24 interrupts. [20]
|
||||||
|
|
||||||
@@ -197,7 +196,7 @@ debug=enable
|
|||||||
gateway_type=ethernet
|
gateway_type=ethernet
|
||||||
radio_type=nrf24
|
radio_type=nrf24
|
||||||
|
|
||||||
params="SOC CXXFLAGS LDFLAGS PREFIX CXX RF24H_LIB_DIR GATEWAY_DIR INIT_SYSTEM"
|
params="SOC CXXFLAGS LDFLAGS PREFIX CXX GATEWAY_DIR INIT_SYSTEM"
|
||||||
|
|
||||||
for opt do
|
for opt do
|
||||||
if [ "$opt" = "-h" ] || [ "$opt" = "--help" ]; then
|
if [ "$opt" = "-h" ] || [ "$opt" = "--help" ]; then
|
||||||
@@ -312,6 +311,7 @@ if [ -z "${CPUFLAGS}" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
CXXFLAGS="$CPUFLAGS -Ofast -g -Wall -Wextra $CXXFLAGS"
|
CXXFLAGS="$CPUFLAGS -Ofast -g -Wall -Wextra $CXXFLAGS"
|
||||||
|
CFLAGS="-Ofast -g -Wall -Wextra $CFLAGS"
|
||||||
|
|
||||||
if [[ $TYPE == "RPi2" || $TYPE == "RPi3" || $REV == "0010" ]]; then
|
if [[ $TYPE == "RPi2" || $TYPE == "RPi3" || $REV == "0010" ]]; then
|
||||||
CXXFLAGS+="-D__RPI_BPLUS"
|
CXXFLAGS+="-D__RPI_BPLUS"
|
||||||
@@ -331,8 +331,6 @@ fi
|
|||||||
|
|
||||||
if [[ ${radio_type} == "nrf24" ]]; then
|
if [[ ${radio_type} == "nrf24" ]]; then
|
||||||
CXXFLAGS="-DMY_RADIO_NRF24 $CXXFLAGS"
|
CXXFLAGS="-DMY_RADIO_NRF24 $CXXFLAGS"
|
||||||
LDFLAGS="-lrf24-bcm $LDFLAGS"
|
|
||||||
RF24H_LIB_DIR=${PREFIX}/include/RF24
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
LDFLAGS="-pthread $LDFLAGS"
|
LDFLAGS="-pthread $LDFLAGS"
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <time.h>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
static const char* CONFIG_FILE = MY_LINUX_CONFIG_FILE;
|
static const char* CONFIG_FILE = MY_LINUX_CONFIG_FILE;
|
||||||
@@ -124,6 +125,11 @@ void hwWriteConfig(int adr, uint8_t value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hwRandomNumberInit()
|
||||||
|
{
|
||||||
|
randomSeed(time(NULL));
|
||||||
|
}
|
||||||
|
|
||||||
// Not supported!
|
// Not supported!
|
||||||
int8_t hwSleep(unsigned long ms)
|
int8_t hwSleep(unsigned long ms)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ void hwReadConfigBlock(void* buf, void* adr, size_t length);
|
|||||||
void hwWriteConfigBlock(void* buf, void* adr, size_t length);
|
void hwWriteConfigBlock(void* buf, void* adr, size_t length);
|
||||||
uint8_t hwReadConfig(int adr);
|
uint8_t hwReadConfig(int adr);
|
||||||
void hwWriteConfig(int adr, uint8_t value);
|
void hwWriteConfig(int adr, uint8_t value);
|
||||||
|
void hwRandomNumberInit();
|
||||||
|
|
||||||
#ifdef MY_RF24_IRQ_PIN
|
#ifdef MY_RF24_IRQ_PIN
|
||||||
static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|||||||
+14
-5
@@ -72,6 +72,15 @@ static int daemonize(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_usage()
|
||||||
|
{
|
||||||
|
printf("Usage: mysGateway [options]\n\n" \
|
||||||
|
"Options:\n" \
|
||||||
|
" -h Display a short summary of all program options.\n" \
|
||||||
|
" -d Enable debug.\n" \
|
||||||
|
" -b Become a daemon.\n");
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int opt, log_opts, debug = 0, foreground = 1;
|
int opt, log_opts, debug = 0, foreground = 1;
|
||||||
@@ -83,11 +92,7 @@ int main(int argc, char *argv[])
|
|||||||
while ((opt = getopt(argc, argv, "hdb")) != -1) {
|
while ((opt = getopt(argc, argv, "hdb")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
printf("Usage: mysGateway [options]\n\n" \
|
print_usage();
|
||||||
"Options:\n" \
|
|
||||||
"-h Display a short summary of all program options.\n" \
|
|
||||||
"-d Enable debug.\n" \
|
|
||||||
"-b Become a daemon.\n");
|
|
||||||
exit(0);
|
exit(0);
|
||||||
case 'd':
|
case 'd':
|
||||||
debug = 1;
|
debug = 1;
|
||||||
@@ -95,11 +100,15 @@ int main(int argc, char *argv[])
|
|||||||
case 'b':
|
case 'b':
|
||||||
foreground = 0;
|
foreground = 0;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
print_usage();
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log_opts = LOG_CONS;
|
log_opts = LOG_CONS;
|
||||||
if (foreground && isatty(STDIN_FILENO)) {
|
if (foreground && isatty(STDIN_FILENO)) {
|
||||||
|
// Also print syslog to stderror
|
||||||
log_opts |= LOG_PERROR;
|
log_opts |= LOG_PERROR;
|
||||||
}
|
}
|
||||||
if (!debug) {
|
if (!debug) {
|
||||||
|
|||||||
@@ -20,11 +20,7 @@
|
|||||||
#include "MyConfig.h"
|
#include "MyConfig.h"
|
||||||
#include "MyTransport.h"
|
#include "MyTransport.h"
|
||||||
|
|
||||||
#ifdef __linux__
|
#include "drivers/RF24/RF24.h"
|
||||||
#include "drivers/RF24/RF24_Linux.h"
|
|
||||||
#else
|
|
||||||
#include "drivers/RF24/RF24.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "drivers/CircularBuffer/CircularBuffer.h"
|
#include "drivers/CircularBuffer/CircularBuffer.h"
|
||||||
|
|
||||||
|
|||||||
+10
-1
@@ -13,6 +13,11 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "stdlib_noniso.h"
|
#include "stdlib_noniso.h"
|
||||||
|
|
||||||
|
#ifdef LINUX_ARCH_RASPBERRYPI
|
||||||
|
#include "rpi_util.h"
|
||||||
|
using namespace rpi_util;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define PI 3.1415926535897932384626433832795
|
#define PI 3.1415926535897932384626433832795
|
||||||
#define HALF_PI 1.5707963267948966192313216916398
|
#define HALF_PI 1.5707963267948966192313216916398
|
||||||
#define TWO_PI 6.283185307179586476925286766559
|
#define TWO_PI 6.283185307179586476925286766559
|
||||||
@@ -39,6 +44,10 @@
|
|||||||
#define GET_MACRO(_0, _1, _2, NAME, ...) NAME
|
#define GET_MACRO(_0, _1, _2, NAME, ...) NAME
|
||||||
#define random(...) GET_MACRO(_0, ##__VA_ARGS__, randMinMax, randMax, rand)(__VA_ARGS__)
|
#define random(...) GET_MACRO(_0, ##__VA_ARGS__, randMinMax, randMax, rand)(__VA_ARGS__)
|
||||||
|
|
||||||
|
#ifndef delay
|
||||||
|
#define delay _delay_ms
|
||||||
|
#endif
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::min;
|
using std::min;
|
||||||
using std::max;
|
using std::max;
|
||||||
@@ -50,7 +59,7 @@ typedef string String;
|
|||||||
|
|
||||||
void yield(void);
|
void yield(void);
|
||||||
unsigned long millis(void);
|
unsigned long millis(void);
|
||||||
void delay(unsigned int millis);
|
void _delay_ms(unsigned int millis);
|
||||||
void randomSeed(unsigned long seed);
|
void randomSeed(unsigned long seed);
|
||||||
long randMax(long howbig);
|
long randMax(long howbig);
|
||||||
long randMinMax(long howsmall, long howbig);
|
long randMinMax(long howsmall, long howbig);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ unsigned long millis(void)
|
|||||||
return ((curTime.tv_sec - millis_at_start) * 1000) + (curTime.tv_usec / 1000);
|
return ((curTime.tv_sec - millis_at_start) * 1000) + (curTime.tv_usec / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void delay(unsigned int millis)
|
void _delay_ms(unsigned int millis)
|
||||||
{
|
{
|
||||||
struct timespec sleeper;
|
struct timespec sleeper;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,15 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
extern void mys_log_v(int level, const char *fmt, va_list args);
|
extern void mys_log_v(int level, const char *fmt, va_list args);
|
||||||
extern void mys_log(int level, const char *fmt, ...) __attribute__((format(printf,2,3)));
|
extern void mys_log(int level, const char *fmt, ...) __attribute__((format(printf,2,3)));
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+37
-4
@@ -29,6 +29,11 @@ LOCAL uint8_t MY_RF24_NODE_ADDRESS = AUTO;
|
|||||||
LOCAL RF24_receiveCallbackType RF24_receiveCallback = NULL;
|
LOCAL RF24_receiveCallbackType RF24_receiveCallback = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LINUX_ARCH_RASPBERRYPI
|
||||||
|
uint8_t spi_rxbuff[32+1] ; //SPI receive buffer (payload max 32 bytes)
|
||||||
|
uint8_t spi_txbuff[32+1] ; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command)
|
||||||
|
#endif
|
||||||
|
|
||||||
LOCAL void RF24_csn(bool level) {
|
LOCAL void RF24_csn(bool level) {
|
||||||
digitalWrite(MY_RF24_CS_PIN, level);
|
digitalWrite(MY_RF24_CS_PIN, level);
|
||||||
}
|
}
|
||||||
@@ -38,6 +43,7 @@ LOCAL void RF24_ce(bool level) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOCAL uint8_t RF24_spiMultiByteTransfer(uint8_t cmd, uint8_t* buf, uint8_t len, bool aReadMode) {
|
LOCAL uint8_t RF24_spiMultiByteTransfer(uint8_t cmd, uint8_t* buf, uint8_t len, bool aReadMode) {
|
||||||
|
uint8_t status;
|
||||||
uint8_t* current = buf;
|
uint8_t* current = buf;
|
||||||
#if !defined(MY_SOFTSPI)
|
#if !defined(MY_SOFTSPI)
|
||||||
_SPI.beginTransaction(SPISettings(MY_RF24_SPI_MAX_SPEED, MY_RF24_SPI_DATA_ORDER, MY_RF24_SPI_DATA_MODE));
|
_SPI.beginTransaction(SPISettings(MY_RF24_SPI_MAX_SPEED, MY_RF24_SPI_DATA_ORDER, MY_RF24_SPI_DATA_MODE));
|
||||||
@@ -45,13 +51,40 @@ LOCAL uint8_t RF24_spiMultiByteTransfer(uint8_t cmd, uint8_t* buf, uint8_t len,
|
|||||||
RF24_csn(LOW);
|
RF24_csn(LOW);
|
||||||
// timing
|
// timing
|
||||||
delayMicroseconds(10);
|
delayMicroseconds(10);
|
||||||
uint8_t status = _SPI.transfer( cmd );
|
#ifdef LINUX_ARCH_RASPBERRYPI
|
||||||
|
uint8_t * prx = spi_rxbuff;
|
||||||
|
uint8_t * ptx = spi_txbuff;
|
||||||
|
uint8_t size = len + 1; // Add register value to transmit buffer
|
||||||
|
|
||||||
|
*ptx++ = cmd;
|
||||||
|
while ( len-- ) {
|
||||||
|
if (aReadMode) {
|
||||||
|
*ptx++ = NOP ;
|
||||||
|
} else {
|
||||||
|
*ptx++ = *current++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, size);
|
||||||
|
if (aReadMode) {
|
||||||
|
if (size == 2) {
|
||||||
|
status = *++prx; // result is 2nd byte of receive buffer
|
||||||
|
} else {
|
||||||
|
status = *prx++; // status is 1st byte of receive buffer
|
||||||
|
// decrement before to skip status byte
|
||||||
|
while (--size) { *buf++ = *prx++; }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status = *prx; // status is 1st byte of receive buffer
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
status = _SPI.transfer( cmd );
|
||||||
while ( len-- ) {
|
while ( len-- ) {
|
||||||
if (aReadMode) {
|
if (aReadMode) {
|
||||||
status = _SPI.transfer( NOP );
|
status = _SPI.transfer( NOP );
|
||||||
if(buf != NULL) *current++ = status;
|
if (buf != NULL) *current++ = status;
|
||||||
} else status = _SPI.transfer(*current++);
|
} else status = _SPI.transfer(*current++);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
RF24_csn(HIGH);
|
RF24_csn(HIGH);
|
||||||
#if !defined(MY_SOFTSPI)
|
#if !defined(MY_SOFTSPI)
|
||||||
_SPI.endTransaction();
|
_SPI.endTransaction();
|
||||||
@@ -268,7 +301,7 @@ LOCAL void RF24_irqHandler( void )
|
|||||||
// rx coming in during our stay will not be handled and will cause characters to be lost.
|
// rx coming in during our stay will not be handled and will cause characters to be lost.
|
||||||
// As a workaround we re-enable interrupts to allow nested processing of other interrupts.
|
// As a workaround we re-enable interrupts to allow nested processing of other interrupts.
|
||||||
// Our own handler is disconnected to prevent recursive calling of this handler.
|
// Our own handler is disconnected to prevent recursive calling of this handler.
|
||||||
#ifdef MY_GATEWAY_SERIAL
|
#if defined(MY_GATEWAY_SERIAL) && !defined(__linux__)
|
||||||
detachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN));
|
detachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN));
|
||||||
interrupts();
|
interrupts();
|
||||||
#endif
|
#endif
|
||||||
@@ -283,7 +316,7 @@ LOCAL void RF24_irqHandler( void )
|
|||||||
RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ !
|
RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ !
|
||||||
}
|
}
|
||||||
// Restore our interrupt handler.
|
// Restore our interrupt handler.
|
||||||
#ifdef MY_GATEWAY_SERIAL
|
#if defined(MY_GATEWAY_SERIAL) && !defined(__linux__)
|
||||||
noInterrupts();
|
noInterrupts();
|
||||||
attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING);
|
attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,200 +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.
|
|
||||||
*
|
|
||||||
* This is a wrapper for maniacbug's RF24 library, copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <RF24.h>
|
|
||||||
#include "RF24_Linux.h"
|
|
||||||
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
typedef void (*RF24_receiveCallbackType)(void);
|
|
||||||
|
|
||||||
void (* RF24_receiveCallback)(void) = NULL;
|
|
||||||
|
|
||||||
static pthread_mutex_t rf24_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static uint8_t MY_RF24_BASE_ADDR[MY_RF24_ADDR_WIDTH] = { MY_RF24_BASE_RADIO_ID };
|
|
||||||
static uint8_t MY_RF24_NODE_ADDRESS = AUTO;
|
|
||||||
|
|
||||||
RF24 _rf24(RF24_CE_PIN, RF24_CS_PIN, MY_RF24_SPI_MAX_SPEED);
|
|
||||||
|
|
||||||
static void RF24_startListening(void) {
|
|
||||||
RF24_DEBUG(PSTR("start listening\n"));
|
|
||||||
|
|
||||||
_rf24.startListening();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RF24_powerDown(void) {
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
pthread_mutex_lock(&rf24_mutex);
|
|
||||||
#endif
|
|
||||||
_rf24.powerDown();
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
pthread_mutex_unlock(&rf24_mutex);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool RF24_sendMessage( uint8_t recipient, const void* buf, uint8_t len ) {
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
pthread_mutex_lock(&rf24_mutex);
|
|
||||||
#endif
|
|
||||||
// Make sure radio has powered up
|
|
||||||
_rf24.powerUp();
|
|
||||||
_rf24.stopListening();
|
|
||||||
|
|
||||||
RF24_DEBUG(PSTR("send message to %d, len=%d\n"), recipient,len);
|
|
||||||
|
|
||||||
MY_RF24_BASE_ADDR[0] = recipient;
|
|
||||||
_rf24.openWritingPipe(MY_RF24_BASE_ADDR);
|
|
||||||
bool ok = _rf24.write(buf, len, recipient == BROADCAST_ADDRESS);
|
|
||||||
_rf24.startListening();
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
pthread_mutex_unlock(&rf24_mutex);
|
|
||||||
#endif
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool RF24_isDataAvailable() {
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
pthread_mutex_lock(&rf24_mutex);
|
|
||||||
#endif
|
|
||||||
uint8_t pipe_num = 255;
|
|
||||||
_rf24.available(&pipe_num);
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
pthread_mutex_unlock(&rf24_mutex);
|
|
||||||
#endif
|
|
||||||
return (pipe_num <= 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t RF24_readMessage( void* buf) {
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
pthread_mutex_lock(&rf24_mutex);
|
|
||||||
#endif
|
|
||||||
uint8_t len = _rf24.getDynamicPayloadSize();
|
|
||||||
_rf24.read(buf, len);
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
pthread_mutex_unlock(&rf24_mutex);
|
|
||||||
#endif
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RF24_setNodeAddress(uint8_t address) {
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
pthread_mutex_lock(&rf24_mutex);
|
|
||||||
#endif
|
|
||||||
if (address != AUTO){
|
|
||||||
MY_RF24_NODE_ADDRESS = address;
|
|
||||||
// enable node pipe
|
|
||||||
MY_RF24_BASE_ADDR[0] = MY_RF24_NODE_ADDRESS;
|
|
||||||
_rf24.openReadingPipe(NODE_PIPE, MY_RF24_BASE_ADDR);
|
|
||||||
// enable autoACK on node pipe
|
|
||||||
_rf24.setAutoAck(NODE_PIPE, true);
|
|
||||||
}
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
pthread_mutex_unlock(&rf24_mutex);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t RF24_getNodeID(void) {
|
|
||||||
return MY_RF24_NODE_ADDRESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RF24_sanityCheck(void) {
|
|
||||||
bool ok = true;
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
pthread_mutex_lock(&rf24_mutex);
|
|
||||||
#endif
|
|
||||||
// detect HW defect ot interrupted SPI line, CE disconnect cannot be detected
|
|
||||||
if (_rf24.getPALevel() != MY_RF24_PA_LEVEL || _rf24.getDataRate() != MY_RF24_DATARATE ||
|
|
||||||
_rf24.getChannel() != MY_RF24_CHANNEL) {
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
pthread_mutex_unlock(&rf24_mutex);
|
|
||||||
#endif
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
void RF24_irqHandler(void) {
|
|
||||||
if (RF24_receiveCallback) {
|
|
||||||
while (RF24_isDataAvailable()) {
|
|
||||||
RF24_receiveCallback();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// clear RX interrupt
|
|
||||||
bool tx_ok,tx_fail,rx;
|
|
||||||
_rf24.whatHappened(tx_ok,tx_fail,rx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RF24_registerReceiveCallback(RF24_receiveCallbackType cb) {
|
|
||||||
RF24_receiveCallback = cb;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool RF24_initialize(void) {
|
|
||||||
// start up the radio library
|
|
||||||
_rf24.begin();
|
|
||||||
// determine whether the hardware is an nRF24L01+ or not
|
|
||||||
if (!_rf24.isPVariant()) {
|
|
||||||
RF24_DEBUG(PSTR("radio hardware not compatible"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// set CRC
|
|
||||||
_rf24.setCRCLength(RF24_CRC_16);
|
|
||||||
// set address width
|
|
||||||
_rf24.setAddressWidth(MY_RF24_ADDR_WIDTH);
|
|
||||||
// auto retransmit delay 1500us, auto retransmit count 15
|
|
||||||
_rf24.setRetries(5, 15);
|
|
||||||
// channel
|
|
||||||
_rf24.setChannel(MY_RF24_CHANNEL);
|
|
||||||
// PA level
|
|
||||||
_rf24.setPALevel(MY_RF24_PA_LEVEL);
|
|
||||||
// data rate
|
|
||||||
_rf24.setDataRate(MY_RF24_DATARATE);
|
|
||||||
// sanity check
|
|
||||||
#if defined(MY_RF24_SANITY_CHECK)
|
|
||||||
if (!RF24_sanityCheck()) {
|
|
||||||
RF24_DEBUG(PSTR("RF24:Sanity check failed: configuration mismatch! Check wiring, replace module or non-P version\n"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// enable Dynamic payload
|
|
||||||
_rf24.enableDynamicPayloads();
|
|
||||||
// enable ACK payload
|
|
||||||
_rf24.enableAckPayload();
|
|
||||||
// disable AA on all pipes, activate when node pipe set
|
|
||||||
_rf24.setAutoAck(false);
|
|
||||||
// all nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages)
|
|
||||||
MY_RF24_BASE_ADDR[0] = BROADCAST_ADDRESS;
|
|
||||||
_rf24.openReadingPipe(BROADCAST_PIPE, MY_RF24_BASE_ADDR);
|
|
||||||
|
|
||||||
//_rf24.printDetails();
|
|
||||||
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_FEATURE
|
|
||||||
// Mask all interrupts except the receive interrupt
|
|
||||||
_rf24.maskIRQ(1,1,0);
|
|
||||||
|
|
||||||
attachInterrupt(MY_RF24_IRQ_PIN, INT_EDGE_FALLING, RF24_irqHandler);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@@ -1,302 +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.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __RF24_LINUX_H__
|
|
||||||
#define __RF24_LINUX_H__
|
|
||||||
|
|
||||||
// SPI settings
|
|
||||||
#if !defined(MY_RF24_SPI_MAX_SPEED)
|
|
||||||
#define MY_RF24_SPI_MAX_SPEED BCM2835_SPI_SPEED_8MHZ
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// verify RF24 IRQ defs
|
|
||||||
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
|
|
||||||
#if !defined(MY_RF24_IRQ_PIN)
|
|
||||||
#error Message buffering feature requires MY_RF24_IRQ_PIN to be defined!
|
|
||||||
#endif
|
|
||||||
#ifndef SPI_HAS_TRANSACTION
|
|
||||||
#error RF24 IRQ usage requires transactional SPI support
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#ifdef MY_RX_MESSAGE_BUFFER_SIZE
|
|
||||||
#error Receive message buffering requires RF24 IRQ usage
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// pipes
|
|
||||||
#define BROADCAST_PIPE 1
|
|
||||||
#define NODE_PIPE 2
|
|
||||||
|
|
||||||
// debug
|
|
||||||
#if defined(MY_DEBUG_VERBOSE_RF24)
|
|
||||||
#define RF24_DEBUG(x,...) debug(x, ##__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define RF24_DEBUG(x,...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef LINUX_ARCH_RASPBERRYPI
|
|
||||||
// CE pin
|
|
||||||
#ifdef MY_RF24_CE_PIN
|
|
||||||
#ifdef __RPI_BPLUS
|
|
||||||
#if MY_RF24_CE_PIN == 3
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_03
|
|
||||||
#elif MY_RF24_CE_PIN == 5
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_05
|
|
||||||
#elif MY_RF24_CE_PIN == 7
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_07
|
|
||||||
#elif MY_RF24_CE_PIN == 8
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_08
|
|
||||||
#elif MY_RF24_CE_PIN == 10
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_10
|
|
||||||
#elif MY_RF24_CE_PIN == 11
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_11
|
|
||||||
#elif MY_RF24_CE_PIN == 12
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_12
|
|
||||||
#elif MY_RF24_CE_PIN == 13
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_13
|
|
||||||
#elif MY_RF24_CE_PIN == 15
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_15
|
|
||||||
#elif MY_RF24_CE_PIN == 16
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_16
|
|
||||||
#elif MY_RF24_CE_PIN == 18
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_18
|
|
||||||
#elif MY_RF24_CE_PIN == 19
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_19
|
|
||||||
#elif MY_RF24_CE_PIN == 21
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_21
|
|
||||||
#elif MY_RF24_CE_PIN == 22
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_22
|
|
||||||
#elif MY_RF24_CE_PIN == 23
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_23
|
|
||||||
#elif MY_RF24_CE_PIN == 24
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_24
|
|
||||||
#elif MY_RF24_CE_PIN == 26
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_26
|
|
||||||
#elif MY_RF24_CE_PIN == 29
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_29
|
|
||||||
#elif MY_RF24_CE_PIN == 31
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_31
|
|
||||||
#elif MY_RF24_CE_PIN == 32
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_32
|
|
||||||
#elif MY_RF24_CE_PIN == 33
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_33
|
|
||||||
#elif MY_RF24_CE_PIN == 35
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_35
|
|
||||||
#elif MY_RF24_CE_PIN == 36
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_36
|
|
||||||
#elif MY_RF24_CE_PIN == 37
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_37
|
|
||||||
#elif MY_RF24_CE_PIN == 38
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_38
|
|
||||||
#elif MY_RF24_CE_PIN == 40
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_40
|
|
||||||
#else
|
|
||||||
#error invalid value for MY_RF24_CE_PIN
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#if MY_RF24_CE_PIN == 3
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_03
|
|
||||||
#elif MY_RF24_CE_PIN == 5
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_05
|
|
||||||
#elif MY_RF24_CE_PIN == 7
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_07
|
|
||||||
#elif MY_RF24_CE_PIN == 8
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_08
|
|
||||||
#elif MY_RF24_CE_PIN == 10
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_10
|
|
||||||
#elif MY_RF24_CE_PIN == 11
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_11
|
|
||||||
#elif MY_RF24_CE_PIN == 12
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_12
|
|
||||||
#elif MY_RF24_CE_PIN == 13
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_13
|
|
||||||
#elif MY_RF24_CE_PIN == 15
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_15
|
|
||||||
#elif MY_RF24_CE_PIN == 16
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_16
|
|
||||||
#elif MY_RF24_CE_PIN == 18
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_18
|
|
||||||
#elif MY_RF24_CE_PIN == 19
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_19
|
|
||||||
#elif MY_RF24_CE_PIN == 21
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_21
|
|
||||||
#elif MY_RF24_CE_PIN == 22
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_22
|
|
||||||
#elif MY_RF24_CE_PIN == 23
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_23
|
|
||||||
#elif MY_RF24_CE_PIN == 24
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_24
|
|
||||||
#elif MY_RF24_CE_PIN == 26
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_26
|
|
||||||
#elif MY_RF24_CE_PIN == 29
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_29
|
|
||||||
#elif MY_RF24_CE_PIN == 31
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_31
|
|
||||||
#elif MY_RF24_CE_PIN == 32
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_32
|
|
||||||
#elif MY_RF24_CE_PIN == 33
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_33
|
|
||||||
#elif MY_RF24_CE_PIN == 35
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_35
|
|
||||||
#elif MY_RF24_CE_PIN == 36
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_36
|
|
||||||
#elif MY_RF24_CE_PIN == 37
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_37
|
|
||||||
#elif MY_RF24_CE_PIN == 38
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_38
|
|
||||||
#elif MY_RF24_CE_PIN == 40
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_40
|
|
||||||
#else
|
|
||||||
#error invalid value for MY_RF24_CE_PIN
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#ifdef __RPI_BPLUS
|
|
||||||
#define RF24_CE_PIN RPI_BPLUS_GPIO_J8_22
|
|
||||||
#else
|
|
||||||
#define RF24_CE_PIN RPI_V2_GPIO_P1_22
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// CS pin
|
|
||||||
#ifdef MY_RF24_CS_PIN
|
|
||||||
#ifdef __RPI_BPLUS
|
|
||||||
#if MY_RF24_CS_PIN == 3
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_03
|
|
||||||
#elif MY_RF24_CS_PIN == 5
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_05
|
|
||||||
#elif MY_RF24_CS_PIN == 7
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_07
|
|
||||||
#elif MY_RF24_CS_PIN == 8
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_08
|
|
||||||
#elif MY_RF24_CS_PIN == 10
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_10
|
|
||||||
#elif MY_RF24_CS_PIN == 11
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_11
|
|
||||||
#elif MY_RF24_CS_PIN == 12
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_12
|
|
||||||
#elif MY_RF24_CS_PIN == 13
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_13
|
|
||||||
#elif MY_RF24_CS_PIN == 15
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_15
|
|
||||||
#elif MY_RF24_CS_PIN == 16
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_16
|
|
||||||
#elif MY_RF24_CS_PIN == 18
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_18
|
|
||||||
#elif MY_RF24_CS_PIN == 19
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_19
|
|
||||||
#elif MY_RF24_CS_PIN == 21
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_21
|
|
||||||
#elif MY_RF24_CS_PIN == 22
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_22
|
|
||||||
#elif MY_RF24_CS_PIN == 23
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_23
|
|
||||||
#elif MY_RF24_CS_PIN == 24
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_24
|
|
||||||
#elif MY_RF24_CS_PIN == 26
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_26
|
|
||||||
#elif MY_RF24_CS_PIN == 29
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_29
|
|
||||||
#elif MY_RF24_CS_PIN == 31
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_31
|
|
||||||
#elif MY_RF24_CS_PIN == 32
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_32
|
|
||||||
#elif MY_RF24_CS_PIN == 33
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_33
|
|
||||||
#elif MY_RF24_CS_PIN == 35
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_35
|
|
||||||
#elif MY_RF24_CS_PIN == 36
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_36
|
|
||||||
#elif MY_RF24_CS_PIN == 37
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_37
|
|
||||||
#elif MY_RF24_CS_PIN == 38
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_38
|
|
||||||
#elif MY_RF24_CS_PIN == 40
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_40
|
|
||||||
#else
|
|
||||||
#error invalid value for MY_RF24_CS_PIN
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#if MY_RF24_CS_PIN == 3
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_03
|
|
||||||
#elif MY_RF24_CS_PIN == 5
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_05
|
|
||||||
#elif MY_RF24_CS_PIN == 7
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_07
|
|
||||||
#elif MY_RF24_CS_PIN == 8
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_08
|
|
||||||
#elif MY_RF24_CS_PIN == 10
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_10
|
|
||||||
#elif MY_RF24_CS_PIN == 11
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_11
|
|
||||||
#elif MY_RF24_CS_PIN == 12
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_12
|
|
||||||
#elif MY_RF24_CS_PIN == 13
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_13
|
|
||||||
#elif MY_RF24_CS_PIN == 15
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_15
|
|
||||||
#elif MY_RF24_CS_PIN == 16
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_16
|
|
||||||
#elif MY_RF24_CS_PIN == 18
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_18
|
|
||||||
#elif MY_RF24_CS_PIN == 19
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_19
|
|
||||||
#elif MY_RF24_CS_PIN == 21
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_21
|
|
||||||
#elif MY_RF24_CS_PIN == 22
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_22
|
|
||||||
#elif MY_RF24_CS_PIN == 23
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_23
|
|
||||||
#elif MY_RF24_CS_PIN == 24
|
|
||||||
#define RF24_CS_PIN BCM2835_SPI_CS0
|
|
||||||
#elif MY_RF24_CS_PIN == 26
|
|
||||||
#define RF24_CS_PIN BCM2835_SPI_CS1
|
|
||||||
#elif MY_RF24_CS_PIN == 29
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_29
|
|
||||||
#elif MY_RF24_CS_PIN == 31
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_31
|
|
||||||
#elif MY_RF24_CS_PIN == 32
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_32
|
|
||||||
#elif MY_RF24_CS_PIN == 33
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_33
|
|
||||||
#elif MY_RF24_CS_PIN == 35
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_35
|
|
||||||
#elif MY_RF24_CS_PIN == 36
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_36
|
|
||||||
#elif MY_RF24_CS_PIN == 37
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_37
|
|
||||||
#elif MY_RF24_CS_PIN == 38
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_38
|
|
||||||
#elif MY_RF24_CS_PIN == 40
|
|
||||||
#define RF24_CS_PIN RPI_V2_GPIO_P1_40
|
|
||||||
#else
|
|
||||||
#error invalid value for MY_RF24_CS_PIN
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#ifdef __RPI_BPLUS
|
|
||||||
#define RF24_CS_PIN RPI_BPLUS_GPIO_J8_24
|
|
||||||
#else
|
|
||||||
#define RF24_CS_PIN BCM2835_SPI_CS0
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
SPIClass::SPIClass() {
|
||||||
|
if (!bcm2835_init()) {
|
||||||
|
mys_log(LOG_ERR, "Failed to initialized bcm2835.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPIClass::~SPIClass() {}
|
||||||
|
|
||||||
|
uint8_t SPIClass::isInitialized() {
|
||||||
|
return initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPIClass::begin() {
|
||||||
|
if (!initialized) {
|
||||||
|
if (!bcm2835_spi_begin()) {
|
||||||
|
mys_log(LOG_ERR, "You need to be root 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
* 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 SPIClass constructor.
|
||||||
|
*/
|
||||||
|
SPIClass();
|
||||||
|
/**
|
||||||
|
* @brief SPIClass destructor.
|
||||||
|
*/
|
||||||
|
virtual ~SPIClass();
|
||||||
|
/**
|
||||||
|
* @brief Checks if SPI was initialized.
|
||||||
|
*
|
||||||
|
* @return 0 if wasn't initialized, else 1 or more.
|
||||||
|
*/
|
||||||
|
static uint8_t isInitialized();
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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) ;
|
||||||
|
}
|
||||||
@@ -0,0 +1,330 @@
|
|||||||
|
/*
|
||||||
|
* 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 <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 "rpi_util.h"
|
||||||
|
#include "SPI.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
int piHiPri(const int pri);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ThreadArgs {
|
||||||
|
void (*func)();
|
||||||
|
int gpioPin;
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __RPI_BPLUS
|
||||||
|
static uint8_t physToGpio[64] =
|
||||||
|
{
|
||||||
|
255, // 0
|
||||||
|
255, 255, // 1, 2
|
||||||
|
2, 255,
|
||||||
|
3, 255,
|
||||||
|
4, 14,
|
||||||
|
255, 15,
|
||||||
|
17, 18,
|
||||||
|
27, 255,
|
||||||
|
22, 23,
|
||||||
|
255, 24,
|
||||||
|
10, 255,
|
||||||
|
9, 25,
|
||||||
|
11, 8,
|
||||||
|
255, 7, // 25, 26
|
||||||
|
// B+
|
||||||
|
0, 1,
|
||||||
|
5, 255,
|
||||||
|
6, 12,
|
||||||
|
13, 255,
|
||||||
|
19, 16,
|
||||||
|
26, 20,
|
||||||
|
255, 21,
|
||||||
|
// the P5 connector on the Rev 2 boards:
|
||||||
|
255, 255,
|
||||||
|
255, 255,
|
||||||
|
255, 255,
|
||||||
|
255, 255,
|
||||||
|
255, 255,
|
||||||
|
28, 29,
|
||||||
|
30, 31,
|
||||||
|
255, 255,
|
||||||
|
255, 255,
|
||||||
|
255, 255,
|
||||||
|
255, 255,
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
static uint8_t physToGpio[64] =
|
||||||
|
{
|
||||||
|
255, // 0
|
||||||
|
255, 255, // 1, 2
|
||||||
|
0, 255,
|
||||||
|
1, 255,
|
||||||
|
4, 14,
|
||||||
|
255, 15,
|
||||||
|
17, 18,
|
||||||
|
21, 255,
|
||||||
|
22, 23,
|
||||||
|
255, 24,
|
||||||
|
10, 255,
|
||||||
|
9, 25,
|
||||||
|
11, 8,
|
||||||
|
255, 7, // 25, 26
|
||||||
|
255, 255, 255, 255, 255, // ... 31
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // ... 47
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // ... 63
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *interruptHandler(void *args) {
|
||||||
|
int fd, ret;
|
||||||
|
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) {
|
||||||
|
mys_log(LOG_ERR, "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 ...
|
||||||
|
ret = poll(&polls, 1, -1);
|
||||||
|
if (ret < 0) {
|
||||||
|
mys_log(LOG_ERR, "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.
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpi_util::pinMode(uint8_t physPin, uint8_t mode) {
|
||||||
|
uint8_t gpioPin = (physPin > 63)? 255 : physToGpio[physPin];
|
||||||
|
if (gpioPin == 255) {
|
||||||
|
mys_log(LOG_ERR, "pinMode: invalid pin: %d\n", physPin);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check if SPI is in use and target pin is related to SPI
|
||||||
|
if (SPIClass::isInitialized() && 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 = (physPin > 63)? 255 : physToGpio[physPin];
|
||||||
|
if (gpioPin == 255) {
|
||||||
|
mys_log(LOG_ERR, "digitalWrite: invalid pin: %d\n", physPin);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check if SPI is in use and target pin is related to SPI
|
||||||
|
if (SPIClass::isInitialized() && 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 = (physPin > 63)? 255 : physToGpio[physPin];
|
||||||
|
if (gpioPin == 255) {
|
||||||
|
mys_log(LOG_ERR, "digitalRead: invalid pin: %d\n", physPin);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Check if SPI is in use and target pin is related to SPI
|
||||||
|
if (SPIClass::isInitialized() && 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 = (physPin > 63)? 255 : physToGpio[physPin];
|
||||||
|
if (gpioPin == 255) {
|
||||||
|
mys_log(LOG_ERR, "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) {
|
||||||
|
mys_log(LOG_ERR, "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) {
|
||||||
|
fprintf (stderr, "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) {
|
||||||
|
fprintf (stderr, "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:
|
||||||
|
mys_log(LOG_ERR, "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) {
|
||||||
|
fprintf (stderr, "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) {
|
||||||
|
mys_log(LOG_ERR, "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 = (physPin > 63)? 255 : physToGpio[physPin];
|
||||||
|
if (gpioPin == 255) {
|
||||||
|
mys_log(LOG_ERR, "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) {
|
||||||
|
mys_log(LOG_ERR, "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_unlock(&intMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpi_util::noInterrupts() {
|
||||||
|
pthread_mutex_lock(&intMutex);
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* 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 pins_io_h
|
||||||
|
#define pins_io_h
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "bcm2835.h"
|
||||||
|
|
||||||
|
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 = RPI_GPIO_P1_24,
|
||||||
|
PIN_SPI_MOSI = RPI_GPIO_P1_19,
|
||||||
|
PIN_SPI_MISO = RPI_GPIO_P1_21,
|
||||||
|
PIN_SPI_SCK = RPI_GPIO_P1_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