Use mysensors built-in nrf24 library for RPi

This commit is contained in:
Marcelo Aquino
2016-09-14 23:26:12 -03:00
parent 4175a5f423
commit fab2112f9b
22 changed files with 4051 additions and 544 deletions
+20 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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"
Vendored
+2 -4
View File
@@ -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"
+6
View File
@@ -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)
{
+1
View File
@@ -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
View File
@@ -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) {
+1 -5
View File
@@ -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
View File
@@ -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);
+1 -1
View File
@@ -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;
+8
View File
@@ -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
View File
@@ -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
-200
View File
@@ -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;
}
-302
View File
@@ -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
+106
View File
@@ -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;
}
+231
View File
@@ -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
+48
View File
@@ -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) ;
}
+330
View File
@@ -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);
}
+71
View File
@@ -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