初始化提交

This commit is contained in:
王立帮
2024-07-20 22:09:06 +08:00
commit c247dd07a6
6876 changed files with 2743096 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
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 __ARCH_CONFIG_H__
#define __ARCH_CONFIG_H__
#define RF24_LINUX
#include <stddef.h>
#include "spi.h"
#include "gpio.h"
#include "compatibility.h"
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <sys/time.h>
//#define RF24_SPI_SPEED RF24_SPIDEV_SPEED
#define _BV(x) (1<<(x))
#define _SPI spi
//#undef SERIAL_DEBUG
#ifdef SERIAL_DEBUG
#define IF_SERIAL_DEBUG(x) ({x;})
#else
#define IF_SERIAL_DEBUG(x)
#endif
// Avoid spurious warnings
#if 1
#if !defined( NATIVE ) && defined( ARDUINO )
#undef PROGMEM
#define PROGMEM __attribute__(( section(".progmem.data") ))
#undef PSTR
#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];}))
#endif
#endif
typedef uint16_t prog_uint16_t;
#define PSTR(x) (x)
#define printf_P printf
#define strlen_P strlen
#define PROGMEM
#define pgm_read_word(p) (*(p))
#define PRIPSTR "%s"
#define pgm_read_byte(p) (*(p))
#define pgm_read_ptr(p) (*(p))
// Function, constant map as a result of migrating from Arduino
#define LOW GPIO::OUTPUT_LOW
#define HIGH GPIO::OUTPUT_HIGH
#define INPUT GPIO::DIRECTION_IN
#define OUTPUT GPIO::DIRECTION_OUT
#define digitalWrite(pin, value) GPIO::write(pin, value)
#define pinMode(pin, direction) GPIO::open(pin, direction)
#define delay(milisec) __msleep(milisec)
#define delayMicroseconds(usec) __usleep(usec)
#define millis() __millis()
#endif // __ARCH_CONFIG_H__
// vim:ai:cin:sts=2 sw=2 ft=cpp

View File

@@ -0,0 +1,50 @@
#include "compatibility.h"
static uint32_t mtime, seconds, useconds;
//static struct timeval start, end;
struct timespec start, end;
/**********************************************************************/
/**
* This function is added in order to simulate arduino delay() function
* @param milisec
*/
void __msleep(int milisec)
{
struct timespec req;// = {0};
req.tv_sec = (time_t) milisec / 1000;
req.tv_nsec = (milisec % 1000) * 1000000L;
//nanosleep(&req, (struct timespec *)NULL);
clock_nanosleep(CLOCK_REALTIME, 0, &req, NULL);
}
void __usleep(int microsec)
{
struct timespec req;// = {0};
req.tv_sec = (time_t) microsec / 1000000;
req.tv_nsec = (microsec / 1000000) * 1000;
//nanosleep(&req, (struct timespec *)NULL);
clock_nanosleep(CLOCK_REALTIME, 0, &req, NULL);
}
/**
* This function is added in order to simulate arduino millis() function
*/
void __start_timer()
{
//gettimeofday(&start, NULL);
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
}
uint32_t __millis()
{
//gettimeofday(&end, NULL);
clock_gettime(CLOCK_MONOTONIC_RAW, &end);
seconds = end.tv_sec - start.tv_sec;
useconds = (end.tv_nsec - start.tv_nsec) / 1000;
mtime = ((seconds) * 1000 + useconds / 1000.0) + 0.5;
return mtime;
}

View File

@@ -0,0 +1,34 @@
/*
* File: compatiblity.h
* Author: purinda
*
* Created on 24 June 2012, 3:08 PM
* patch for safer monotonic clock & millis() correction for 64bit LDV 2018
*/
#ifndef COMPATIBLITY_H
#define COMPATIBLITY_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h> // for uintXX_t types
#include <stddef.h>
#include <time.h>
#include <sys/time.h>
void __msleep(int milisec);
void __usleep(int milisec);
void __start_timer();
uint32_t __millis();
#ifdef __cplusplus
}
#endif
#endif /* COMPATIBLITY_H */

View File

@@ -0,0 +1,167 @@
/*
* https://github.com/mrshu/GPIOlib
* Copyright (c) 2011, Copyright (c) 2011 mr.Shu
* All rights reserved.
*
* Modified on 24 June 2012, 11:06 AM
* File: gpio.cpp
* Author: purinda (purinda@gmail.com)
*
* Patched for filedescriptor catching and error control by L Diaz 2018
*/
#include "gpio.h"
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
std::map<int, GPIOfdCache_t> GPIO::cache;
GPIO::GPIO()
{
}
GPIO::~GPIO()
{
}
void GPIO::open(int port, int DDR)
{
FILE* f;
f = fopen("/sys/class/gpio/export", "w");
if (f == NULL) {
throw GPIOException("can't export GPIO pin .check access rights");
}
fprintf(f, "%d\n", port);
fclose(f);
int counter = 0;
char file[128];
sprintf(file, "/sys/class/gpio/gpio%d/direction", port);
while ((f = fopen(file, "w")) == NULL) { //Wait 10 seconds for the file to be accessible if not open on first attempt
sleep(1);
counter++;
if (counter > 10) {
throw GPIOException("can't access /sys/class/gpio/gpio%d/direction GPIO pin. check access rights");
/*perror("Could not open /sys/class/gpio/gpio%d/direction");
exit(0); */
}
}
int l = (DDR == 0) ? fprintf(f, "in\n") : fprintf(f, "out\n");
if (!(l == 3 || l == 4)) {
fclose(f);
throw GPIOException("can't set direction on GPIO pin. check access rights");
}
/*
if (DDR == 0)
fprintf(f, "in\n");
else printf(f, "out\n");
*/
fclose(f);
// Caches the GPIO descriptor;
sprintf(file, "/sys/class/gpio/gpio%d/value", port);
int flags = (DDR == 0) ? O_RDONLY : O_WRONLY;
int fd = ::open(file, flags);
if (fd < 0) {
throw GPIOException("Can't open the GPIO");
} else {
cache[port] = fd; // cache the fd;
lseek(fd, SEEK_SET, 0);
}
}
void GPIO::close(int port)
{
std::map<int, GPIOfdCache_t>::iterator i;
i = cache.find(port);
if (i != cache.end()) {
close(i->second); // close the cached fd
cache.erase(i); // Delete cache entry
}
// Do unexport
FILE* f;
f = fopen("/sys/class/gpio/unexport", "w");
if (f != NULL) {
fprintf(f, "%d\n", port);
fclose(f);
}
}
int GPIO::read(int port)
{
std::map<int, GPIOfdCache_t>::iterator i;
int fd;
i = cache.find(port);
if (i == cache.end()) { // Fallback to open the gpio
GPIO::open(port, GPIO::DIRECTION_IN);
i = cache.find(port);
if (i == cache.end()) {
throw GPIOException("can't access to GPIO");
} else {
fd = i->second;
}
} else {
fd = i->second;
}
char c;
if (lseek(fd, 0, SEEK_SET) == 0 && ::read(fd, &c, 1) == 1) {
return (c == '0') ? 0 : 1;
} else {
throw GPIOException("can't access to GPIO");
}
/*FILE *f;
char file[128];
sprintf(file, "/sys/class/gpio/gpio%d/value", port);
f = fopen(file, "r");
int i;
fscanf(f, "%d", &i);
fclose(f);
return i;
*/
}
void GPIO::write(int port, int value)
{
std::map<int, GPIOfdCache_t>::iterator i;
int fd;
i = cache.find(port);
if (i == cache.end()) { // Fallback to open the gpio
GPIO::open(port, GPIO::DIRECTION_OUT);
i = cache.find(port);
if (i == cache.end()) {
throw GPIOException("can't access to GPIO");
} else {
fd = i->second;
}
} else {
fd = i->second;
}
if (lseek(fd, 0, SEEK_SET) != 0) {
throw GPIOException("can't access to GPIO");
}
int l = (value == 0) ? ::write(fd, "0\n", 2) : ::write(fd, "1\n", 2);
if (l != 2) {
throw GPIOException("can't access to GPIO");
}
/*FILE *f;
char file[128];
sprintf(file, "/sys/class/gpio/gpio%d/value", port);
f = fopen(file, "w");
if (value == 0) fprintf(f, "0\n");
else fprintf(f, "1\n");
fclose(f);*/
}

View File

@@ -0,0 +1,95 @@
/*
* https://github.com/mrshu/GPIOlib
* Copyright (c) 2011, Copyright (c) 2011 mr.Shu
* All rights reserved.
*
* Modified on 24 June 2012, 11:06 AM
* File: gpio.h
* Author: purinda (purinda@gmail.com)
*
*/
#ifndef H
#define H
#include <cstdio>
#include <map>
#include <stdexcept>
/** Specific excpetion for SPI errors */
class GPIOException : public std::runtime_error {
public:
explicit GPIOException(const std::string& msg)
:std::runtime_error(msg)
{
}
};
/**
* @file gpio.h
* \cond HIDDEN_SYMBOLS
* Class declaration for GPIO helper files
*/
/**
* Example GPIO.h file
*
* @defgroup GPIO GPIO Example
*
* See RF24_arch_config.h for additional information
* @{
*/
typedef int GPIOfdCache_t;
class GPIO {
public:
/* Constants */
static const int DIRECTION_OUT = 1;
static const int DIRECTION_IN = 0;
static const int OUTPUT_HIGH = 1;
static const int OUTPUT_LOW = 0;
GPIO();
/**
* Similar to Arduino pinMode(pin,mode);
* @param port
* @param DDR
*/
static void open(int port, int DDR);
/**
*
* @param port
*/
static void close(int port);
/**
* Similar to Arduino digitalRead(pin);
* @param port
* @param value
*/
static int read(int port);
/**
* Similar to Arduino digitalWrite(pin,state);
* @param port
* @param value
*/
static void write(int port, int value);
virtual ~GPIO();
private:
/* fd cache */
static std::map<int, GPIOfdCache_t> cache;
};
/**
* \endcond
*/
/*@}*/
#endif /* H */

View File

@@ -0,0 +1,9 @@
#ifndef __RF24_INCLUDES_H__
#define __RF24_INCLUDES_H__
#define RF24_SPIDEV
#include "SPIDEV/RF24_arch_config.h"
#include "SPIDEV/interrupt.h"
#endif

View File

@@ -0,0 +1,221 @@
/*
Interrupts functions extruded from wiringPi library by Oitzu.
wiringPi Copyright (c) 2012 Gordon Henderson
https://projects.drogon.net/raspberry-pi/wiringpi
wiringPi is free software: GNU Lesser General Public License
see <http://www.gnu.org/licenses/>
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <sys/stat.h>
#include "interrupt.h"
#include <pthread.h>
//#define delay(x) bcm2835_delay(x)
static pthread_mutex_t pinMutex = PTHREAD_MUTEX_INITIALIZER;
static volatile int pinPass = -1;
pthread_t threadId[64];
// 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,};
// ISR Data
static void (* isrFunctions[64])(void);
int waitForInterrupt(int pin, int mS)
{
int fd, x;
uint8_t c;
struct pollfd polls;
if ((fd = sysFds[pin]) == -1) {
return -2;
}
// Setup poll structure
polls.fd = fd;
polls.events = POLLPRI; // Urgent data!
// Wait for it ...
x = poll(&polls, 1, mS);
// 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);
return x;
}
int piHiPri(const int pri)
{
struct sched_param sched;
memset(&sched, 0, sizeof(sched));
if (pri > sched_get_priority_max(SCHED_RR)) {
sched.sched_priority = sched_get_priority_max(SCHED_RR);
} else {
sched.sched_priority = pri;
}
return sched_setscheduler(0, SCHED_RR, &sched);
}
void* interruptHandler(void* arg)
{
int myPin;
(void) piHiPri(55); // Only effective if we run as root
myPin = pinPass;
pinPass = -1;
for (;;) {
if (waitForInterrupt(myPin, -1) > 0) {
pthread_mutex_lock(&pinMutex);
isrFunctions[myPin]();
pthread_mutex_unlock(&pinMutex);
pthread_testcancel(); //Cancel at this point if we have an cancellation request.
}
}
return NULL;
}
int attachInterrupt(int pin, int mode, void (* function)(void))
{
const char* modeS;
char fName[64];
char pinS[8];
pid_t pid;
int count, i;
char c;
int bcmGpioPin;
bcmGpioPin = pin;
if (mode != INT_EDGE_SETUP) {
/**/ if (mode == INT_EDGE_FALLING) {
modeS = "falling";
} else if (mode == INT_EDGE_RISING) {
modeS = "rising";
} else {
modeS = "both";
}
sprintf(pinS, "%d", bcmGpioPin);
if ((pid = fork()) < 0) { // Fail
return printf("wiringPiISR: fork failed: %s\n", strerror(errno));
}
if (pid == 0) // Child, exec
{
/**/ if (access("/usr/local/bin/gpio", X_OK) == 0) {
execl("/usr/local/bin/gpio", "gpio", "edge", pinS, modeS, (char*) NULL);
return printf("wiringPiISR: execl failed: %s\n", strerror(errno));
} else if (access("/usr/bin/gpio", X_OK) == 0) {
execl("/usr/bin/gpio", "gpio", "edge", pinS, modeS, (char*) NULL);
return printf("wiringPiISR: execl failed: %s\n", strerror(errno));
} else {
return printf("wiringPiISR: Can't find gpio program\n");
}
} else { // Parent, wait
wait(NULL);
}
}
if (sysFds[bcmGpioPin] == -1) {
sprintf(fName, "/sys/class/gpio/gpio%d/value", bcmGpioPin);
if ((sysFds[bcmGpioPin] = open(fName, O_RDWR)) < 0) {
return printf("wiringPiISR: unable to open %s: %s\n", fName, strerror(errno));
}
}
ioctl(sysFds[bcmGpioPin], FIONREAD, &count);
for (i = 0; i < count; ++i) {
read(sysFds[bcmGpioPin], &c, 1);
}
isrFunctions[pin] = function;
pthread_mutex_lock(&pinMutex);
pinPass = pin;
pthread_create(&threadId[bcmGpioPin], NULL, interruptHandler, NULL);
while (pinPass != -1)
delay (1);
pthread_mutex_unlock(&pinMutex);
return 0;
}
int detachInterrupt(int pin)
{
char pinS[8];
const char* modeS = "none";
pid_t pid;
if (!pthread_cancel(threadId[pin])) //Cancel the thread
{
return 0;
}
if (!close(sysFds[pin])) //Close filehandle
{
return 0;
}
/* Set wiringPi to 'none' interrupt mode */
sprintf(pinS, "%d", pin);
if ((pid = fork()) < 0) { // Fail
return printf("wiringPiISR: fork failed: %s\n", strerror(errno));
}
if (pid == 0) // Child, exec
{
/**/ if (access("/usr/local/bin/gpio", X_OK) == 0) {
execl("/usr/local/bin/gpio", "gpio", "edge", pinS, modeS, (char*) NULL);
return printf("wiringPiISR: execl failed: %s\n", strerror(errno));
} else if (access("/usr/bin/gpio", X_OK) == 0) {
execl("/usr/bin/gpio", "gpio", "edge", pinS, modeS, (char*) NULL);
return printf("wiringPiISR: execl failed: %s\n", strerror(errno));
} else {
return printf("wiringPiISR: Can't find gpio program\n");
}
} else { // Parent, wait
wait(NULL);
}
return 1;
}
void rfNoInterrupts()
{
pthread_mutex_lock(&pinMutex);
}
void rfInterrupts()
{
pthread_mutex_unlock(&pinMutex);
}

View File

@@ -0,0 +1,72 @@
/*
Interrupts functions extruded from wiringPi library by Oitzu.
wiringPi Copyright (c) 2012 Gordon Henderson
https://projects.drogon.net/raspberry-pi/wiringpi
wiringPi is free software: GNU Lesser General Public License
see <http://www.gnu.org/licenses/>
*/
#include "RF24_arch_config.h"
#define INT_EDGE_SETUP 0
#define INT_EDGE_FALLING 1
#define INT_EDGE_RISING 2
#define INT_EDGE_BOTH 3
/*
* interruptHandler:
* This is a thread and gets started to wait for the interrupt we're
* hoping to catch. It will call the user-function when the interrupt
* fires.
*********************************************************************************
*/
void* interruptHandler(void* arg);
#ifdef __cplusplus
extern "C" {
#endif
/*
* waitForInterrupt:
* Pi Specific.
* Wait for Interrupt on a GPIO pin.
* This is actually done via the /sys/class/gpio interface regardless of
* the wiringPi access mode in-use. Maybe sometime it might get a better
* way for a bit more efficiency.
*********************************************************************************
*/
extern int waitForInterrupt(int pin, int mS);
/*
* piHiPri:
* Attempt to set a high priority schedulling for the running program
*********************************************************************************
*/
extern int piHiPri(const int pri);
/*
* attachInterrupt (Original: wiringPiISR):
* Pi Specific.
* Take the details and create an interrupt handler that will do a call-
* back to the user supplied function.
*********************************************************************************
*/
extern int attachInterrupt(int pin, int mode, void (* function)(void));
/*
* detachInterrupt:
* Pi Specific detachInterrupt.
* Will cancel the interrupt thread, close the filehandle and
* setting wiringPi back to 'none' mode.
*********************************************************************************
*/
extern int detachInterrupt(int pin);
extern void rfNoInterrupts();
extern void rfInterrupts();
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,191 @@
/*
* File: spi.cpp
* Author: Purinda Gunasekara <purinda@gmail.com>
*
* Created on 24 June 2012, 11:00 AM
*
* Patched for exception handling and selectable SPI SPEED by ldiaz 2018.
*
* Inspired from spidev test in linux kernel documentation
* www.kernel.org/doc/Documentation/spi/spidev_test.c
*/
#include "spi.h"
#include <fcntl.h>
#include <linux/spi/spidev.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
#define RF24_SPIDEV_BITS 8
SPI::SPI()
:fd(-1), _spi_speed(RF24_SPI_SPEED)
{
}
void SPI::begin(int busNo, uint32_t spi_speed)
{
if (this->spiIsInitialized) {
return;
}
/* set spidev accordingly to busNo like:
* busNo = 23 -> /dev/spidev2.3
*
* a bit messy but simple
* */
char device[] = "/dev/spidev0.0";
device[11] += (busNo / 10) % 10;
device[13] += busNo % 10;
if (this->fd >= 0) // check whether spi is already open
{
close(this->fd);
this->fd = -1;
}
this->fd = open(device, O_RDWR);
if (this->fd < 0) {
throw SPIException("can't open device");
}
/*
{
perror("can't open device");
abort();
}*/
this->spiIsInitialized = true;
init(spi_speed);
}
void SPI::init(uint32_t speed)
{
uint8_t bits = RF24_SPIDEV_BITS;
uint8_t mode = 0;
int ret;
/*
* spi mode
*/
ret = ioctl(this->fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1) {
throw SPIException("cant set WR spi mode");
}
/*{
perror("can't set spi mode");
abort();
}*/
ret = ioctl(this->fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1) {
throw SPIException("can't set RD spi mode");
}
/*{
perror("can't set spi mode");
abort();
}*/
/*
* bits per word
*/
ret = ioctl(this->fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1) {
throw SPIException("can't set WR bits per word");
}
/*{
perror("can't set bits per word");
abort();
}*/
ret = ioctl(this->fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1) {
throw SPIException("can't set RD bits per word");
}
/*{
perror("can't set bits per word");
abort();
}*/
/*
* max speed hz
*/
ret = ioctl(this->fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1) {
throw SPIException("can't WR set max speed hz");
}
/*{
perror("can't set max speed hz");
abort();
}*/
ret = ioctl(this->fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1) {
throw SPIException("can't RD set max speed hz");
}
/*{
perror("can't set max speed hz");
abort();
}*/
_spi_speed = speed;
}
uint8_t SPI::transfer(uint8_t tx)
{
struct spi_ioc_transfer tr;
memset(&tr, 0, sizeof(tr));
tr.tx_buf = (unsigned long) &tx;
uint8_t rx;
tr.rx_buf = (unsigned long) &rx;
tr.len = sizeof(tx);
tr.speed_hz = _spi_speed; //RF24_SPI_SPEED;
tr.delay_usecs = 0;
tr.bits_per_word = RF24_SPIDEV_BITS;
tr.cs_change = 0;
int ret;
ret = ioctl(this->fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1) {
throw SPIException("can't send spi message");
}
/*{
perror("can't send spi message");
abort();
}*/
return rx;
}
void SPI::transfernb(char* tbuf, char* rbuf, uint32_t len)
{
struct spi_ioc_transfer tr;
memset(&tr, 0, sizeof(tr));
tr.tx_buf = (unsigned long) tbuf;
tr.rx_buf = (unsigned long) rbuf;
tr.len = len;
tr.speed_hz = _spi_speed; //RF24_SPI_SPEED;
tr.delay_usecs = 0;
tr.bits_per_word = RF24_SPIDEV_BITS;
tr.cs_change = 0;
int ret;
ret = ioctl(this->fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1) {
throw SPIException("can't send spi message");
}
/*{
perror("can't send spi message");
abort();
}*/
}
SPI::~SPI()
{
if (this->fd >= 0) {
close(this->fd);
}
}

View File

@@ -0,0 +1,93 @@
/*
* File: spi.h
* Author: Purinda Gunasekara <purinda@gmail.com>
*
* Created on 24 June 2012, 11:00 AM
*/
#ifndef SPI_H
#define SPI_H
/**
* @file spi.h
* \cond HIDDEN_SYMBOLS
* Class declaration for SPI helper files
*/
/**
* Example GPIO.h file
*
* @defgroup SPI SPI Example
*
* See RF24_arch_config.h for additional information
* @{
*/
#include <inttypes.h>
#include <stdexcept>
#include "../../RF24_config.h"
/** Specific excpetion for SPI errors */
class SPIException : public std::runtime_error {
public:
explicit SPIException(const std::string& msg)
:std::runtime_error(msg)
{
}
};
class SPI {
public:
/**
* SPI constructor
*/
SPI();
/**
* Start SPI
*/
void begin(int busNo, uint32_t spi_speed = RF24_SPI_SPEED);
/**
* Transfer a single byte
* @param tx Byte to send
* @return Data returned via spi
*/
uint8_t transfer(uint8_t tx);
/**
* Transfer a buffer of data
* @param tbuf Transmit buffer
* @param rbuf Receive buffer
* @param len Length of the data
*/
void transfernb(char* tbuf, char* rbuf, uint32_t len);
/**
* Transfer a buffer of data without an rx buffer
* @param buf Pointer to a buffer of data
* @param len Length of the data
*/
void transfern(char* buf, uint32_t len)
{
transfernb(buf, buf, len);
}
~SPI();
private:
int fd;
uint32_t _spi_speed;
bool spiIsInitialized = false;
void init(uint32_t spi_speed = RF24_SPI_SPEED);
};
/**
* \endcond
*/
/*@}*/
#endif /* SPI_H */