Use mysensors built-in nrf24 library for RPi
This commit is contained in:
@@ -13,14 +13,22 @@ include $(CONFIG_FILE)
|
||||
|
||||
GATEWAY_BIN=mysGateway
|
||||
GATEWAY=examples_linux/$(GATEWAY_BIN)
|
||||
GATEWAY_SOURCES=$(wildcard drivers/Linux/*.cpp) examples_linux/mysGateway.cpp
|
||||
GATEWAY_OBJECTS=$(patsubst %.cpp,%.o,$(GATEWAY_SOURCES))
|
||||
DEPS+=$(patsubst %.cpp,%.d,$(GATEWAY_SOURCES))
|
||||
GATEWAY_C_SOURCES=$(wildcard drivers/Linux/*.c)
|
||||
GATEWAY_CPP_SOURCES=$(wildcard drivers/Linux/*.cpp) examples_linux/mysGateway.cpp
|
||||
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
|
||||
|
||||
ifneq ($(RF24H_LIB_DIR),)
|
||||
CINCLUDE+=-I$(RF24H_LIB_DIR)
|
||||
ifeq ($(SOC),$(filter $(SOC),BCM2835 BCM2836))
|
||||
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
|
||||
|
||||
.PHONY: all gateway cleanconfig clean install uninstall force
|
||||
@@ -28,15 +36,18 @@ endif
|
||||
all: $(GATEWAY)
|
||||
|
||||
# Gateway Build
|
||||
$(GATEWAY): $(GATEWAY_OBJECTS)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(GATEWAY_OBJECTS)
|
||||
$(GATEWAY): $(OBJECTS)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(OBJECTS)
|
||||
|
||||
# Include all .d files
|
||||
-include $(DEPS)
|
||||
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) $(CINCLUDE) -MMD -c -o $@ $<
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(CINCLUDE) -MMD -c -o $@ $<
|
||||
|
||||
# clear configuration files
|
||||
cleanconfig:
|
||||
@echo "[Cleaning configuration]"
|
||||
@@ -45,7 +56,7 @@ cleanconfig:
|
||||
# clear build files
|
||||
clean:
|
||||
@echo "[Cleaning]"
|
||||
rm -rf build $(GATEWAY_OBJECTS) $(GATEWAY) $(DEPS)
|
||||
rm -rf build $(OBJECTS) $(GATEWAY) $(DEPS)
|
||||
|
||||
$(CONFIG_FILE):
|
||||
@echo "[Running configure]"
|
||||
|
||||
+2
-2
@@ -410,7 +410,7 @@
|
||||
#define MY_RF24_CE_PIN 4
|
||||
#elif defined(ARDUINO_ARCH_SAMD)
|
||||
#define MY_RF24_CE_PIN 27
|
||||
#elif defined(__linux__)
|
||||
#elif defined(LINUX_ARCH_RASPBERRYPI)
|
||||
#define MY_RF24_CE_PIN 22
|
||||
#else
|
||||
#define MY_RF24_CE_PIN 9
|
||||
@@ -426,7 +426,7 @@
|
||||
#define MY_RF24_CS_PIN 15
|
||||
#elif defined(ARDUINO_ARCH_SAMD)
|
||||
#define MY_RF24_CS_PIN 3
|
||||
#elif defined(__linux__)
|
||||
#elif defined(LINUX_ARCH_RASPBERRYPI)
|
||||
#define MY_RF24_CS_PIN 24
|
||||
#else
|
||||
#define MY_RF24_CS_PIN 10
|
||||
|
||||
+5
-5
@@ -276,6 +276,10 @@
|
||||
#include "drivers/AVR/DigitalIO/DigitalIO.h"
|
||||
#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"
|
||||
#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
|
||||
@@ -284,11 +288,7 @@
|
||||
#if defined(MY_RF24_ENABLE_ENCRYPTION)
|
||||
#include "drivers/AES/AES.cpp"
|
||||
#endif
|
||||
#if defined(__linux__)
|
||||
#include "drivers/RF24/RF24_Linux.cpp"
|
||||
#else
|
||||
#include "drivers/RF24/RF24.cpp"
|
||||
#endif
|
||||
#include "drivers/RF24/RF24.cpp"
|
||||
#include "core/MyTransportNRF24.cpp"
|
||||
#elif defined(MY_RS485)
|
||||
#include "drivers/AltSoftSerial/AltSoftSerial.cpp"
|
||||
|
||||
@@ -54,7 +54,6 @@ MySensors options:
|
||||
--my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW]
|
||||
RF24 PA level. [RF24_PA_MAX]
|
||||
--my-rf24-irq-pin=<PIN> Pin number connected to nRF24L01 IRQ pin.
|
||||
For RaspberryPi use BCM numbering.
|
||||
--my-rx-message-buffer-size=<SIZE>
|
||||
Buffer size for incoming messages when using rf24 interrupts. [20]
|
||||
|
||||
@@ -197,7 +196,7 @@ debug=enable
|
||||
gateway_type=ethernet
|
||||
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
|
||||
if [ "$opt" = "-h" ] || [ "$opt" = "--help" ]; then
|
||||
@@ -312,6 +311,7 @@ if [ -z "${CPUFLAGS}" ]; then
|
||||
fi
|
||||
|
||||
CXXFLAGS="$CPUFLAGS -Ofast -g -Wall -Wextra $CXXFLAGS"
|
||||
CFLAGS="-Ofast -g -Wall -Wextra $CFLAGS"
|
||||
|
||||
if [[ $TYPE == "RPi2" || $TYPE == "RPi3" || $REV == "0010" ]]; then
|
||||
CXXFLAGS+="-D__RPI_BPLUS"
|
||||
@@ -331,8 +331,6 @@ fi
|
||||
|
||||
if [[ ${radio_type} == "nrf24" ]]; then
|
||||
CXXFLAGS="-DMY_RADIO_NRF24 $CXXFLAGS"
|
||||
LDFLAGS="-lrf24-bcm $LDFLAGS"
|
||||
RF24H_LIB_DIR=${PREFIX}/include/RF24
|
||||
fi
|
||||
|
||||
LDFLAGS="-pthread $LDFLAGS"
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include "log.h"
|
||||
|
||||
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!
|
||||
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);
|
||||
uint8_t hwReadConfig(int adr);
|
||||
void hwWriteConfig(int adr, uint8_t value);
|
||||
void hwRandomNumberInit();
|
||||
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
+14
-5
@@ -72,6 +72,15 @@ static int daemonize(void)
|
||||
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 opt, log_opts, debug = 0, foreground = 1;
|
||||
@@ -83,11 +92,7 @@ int main(int argc, char *argv[])
|
||||
while ((opt = getopt(argc, argv, "hdb")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
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");
|
||||
print_usage();
|
||||
exit(0);
|
||||
case 'd':
|
||||
debug = 1;
|
||||
@@ -95,11 +100,15 @@ int main(int argc, char *argv[])
|
||||
case 'b':
|
||||
foreground = 0;
|
||||
break;
|
||||
default:
|
||||
print_usage();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
log_opts = LOG_CONS;
|
||||
if (foreground && isatty(STDIN_FILENO)) {
|
||||
// Also print syslog to stderror
|
||||
log_opts |= LOG_PERROR;
|
||||
}
|
||||
if (!debug) {
|
||||
|
||||
@@ -20,11 +20,7 @@
|
||||
#include "MyConfig.h"
|
||||
#include "MyTransport.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include "drivers/RF24/RF24_Linux.h"
|
||||
#else
|
||||
#include "drivers/RF24/RF24.h"
|
||||
#endif
|
||||
#include "drivers/RF24/RF24.h"
|
||||
|
||||
#include "drivers/CircularBuffer/CircularBuffer.h"
|
||||
|
||||
|
||||
+10
-1
@@ -13,6 +13,11 @@
|
||||
#include <algorithm>
|
||||
#include "stdlib_noniso.h"
|
||||
|
||||
#ifdef LINUX_ARCH_RASPBERRYPI
|
||||
#include "rpi_util.h"
|
||||
using namespace rpi_util;
|
||||
#endif
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define HALF_PI 1.5707963267948966192313216916398
|
||||
#define TWO_PI 6.283185307179586476925286766559
|
||||
@@ -39,6 +44,10 @@
|
||||
#define GET_MACRO(_0, _1, _2, NAME, ...) NAME
|
||||
#define random(...) GET_MACRO(_0, ##__VA_ARGS__, randMinMax, randMax, rand)(__VA_ARGS__)
|
||||
|
||||
#ifndef delay
|
||||
#define delay _delay_ms
|
||||
#endif
|
||||
|
||||
using std::string;
|
||||
using std::min;
|
||||
using std::max;
|
||||
@@ -50,7 +59,7 @@ typedef string String;
|
||||
|
||||
void yield(void);
|
||||
unsigned long millis(void);
|
||||
void delay(unsigned int millis);
|
||||
void _delay_ms(unsigned int millis);
|
||||
void randomSeed(unsigned long seed);
|
||||
long randMax(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);
|
||||
}
|
||||
|
||||
void delay(unsigned int millis)
|
||||
void _delay_ms(unsigned int millis)
|
||||
{
|
||||
struct timespec sleeper;
|
||||
|
||||
|
||||
@@ -4,7 +4,15 @@
|
||||
#include <stdarg.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(int level, const char *fmt, ...) __attribute__((format(printf,2,3)));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+43
-10
@@ -29,8 +29,13 @@ LOCAL uint8_t MY_RF24_NODE_ADDRESS = AUTO;
|
||||
LOCAL RF24_receiveCallbackType RF24_receiveCallback = NULL;
|
||||
#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) {
|
||||
digitalWrite(MY_RF24_CS_PIN, level);
|
||||
digitalWrite(MY_RF24_CS_PIN, level);
|
||||
}
|
||||
|
||||
LOCAL void RF24_ce(bool 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) {
|
||||
uint8_t status;
|
||||
uint8_t* current = buf;
|
||||
#if !defined(MY_SOFTSPI)
|
||||
_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);
|
||||
// timing
|
||||
delayMicroseconds(10);
|
||||
uint8_t status = _SPI.transfer( cmd );
|
||||
while ( len-- ) {
|
||||
if (aReadMode) {
|
||||
status = _SPI.transfer( NOP );
|
||||
if(buf != NULL) *current++ = status;
|
||||
} else status = _SPI.transfer(*current++);
|
||||
}
|
||||
#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-- ) {
|
||||
if (aReadMode) {
|
||||
status = _SPI.transfer( NOP );
|
||||
if (buf != NULL) *current++ = status;
|
||||
} else status = _SPI.transfer(*current++);
|
||||
}
|
||||
#endif
|
||||
RF24_csn(HIGH);
|
||||
#if !defined(MY_SOFTSPI)
|
||||
_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.
|
||||
// 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.
|
||||
#ifdef MY_GATEWAY_SERIAL
|
||||
#if defined(MY_GATEWAY_SERIAL) && !defined(__linux__)
|
||||
detachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN));
|
||||
interrupts();
|
||||
#endif
|
||||
@@ -283,7 +316,7 @@ LOCAL void RF24_irqHandler( void )
|
||||
RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ !
|
||||
}
|
||||
// Restore our interrupt handler.
|
||||
#ifdef MY_GATEWAY_SERIAL
|
||||
#if defined(MY_GATEWAY_SERIAL) && !defined(__linux__)
|
||||
noInterrupts();
|
||||
attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING);
|
||||
#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