265 lines
6.3 KiB
C++
265 lines
6.3 KiB
C++
// RasPi.cpp
|
|
//(9/22/2019) Contributed by Brody M. This file is based off RHutil\RasPi.cpp
|
|
// but modified for the pigpio library instead of BCM2835. Original
|
|
// code maintained where possible. Unused code commented out and
|
|
// left in place.
|
|
|
|
// Routines for implementing RadioHead on Raspberry Pi
|
|
// using BCM2835 library for GPIO
|
|
//
|
|
// Contributed by Mike Poublon and used with permission
|
|
|
|
|
|
#include <RadioHead.h>
|
|
|
|
#if (RH_PLATFORM == RH_PLATFORM_RASPI)
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
#include "RasPi.h"
|
|
#include <stdio.h>
|
|
|
|
int spiHandle;
|
|
|
|
//Initialize the values for sanity
|
|
timeval RHStartTime;
|
|
|
|
void SPIClass::begin()
|
|
{
|
|
//Set SPI Defaults
|
|
//Retaining BCM2835 macros for compatibility with RadioHead
|
|
uint16_t divider = BCM2835_SPI_CLOCK_DIVIDER_256;
|
|
uint8_t bitorder = BCM2835_SPI_BIT_ORDER_MSBFIRST;
|
|
uint8_t datamode = BCM2835_SPI_MODE0;
|
|
begin(divider, bitorder, datamode);
|
|
}
|
|
|
|
//void SPIClass::begin(uint32_t spiChannel, uint32_t spiBaud, uint32_t spiFlags)
|
|
void SPIClass::begin(uint16_t divider, uint8_t bitOrder, uint8_t dataMode)
|
|
{
|
|
|
|
//Set CS pins polarity to low
|
|
//bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, 0);
|
|
|
|
//pigpio SPI Defailts
|
|
//SPI Speed
|
|
//BCM2835 divider of 256 is approx 1MHz SCLK, depending on model
|
|
//uint32_t spiBaud = 1000000;
|
|
//Spi Flag Settings
|
|
//21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
|
//b b b b b b R T n n n n W A u2 u1 u0 p2 p1 p0 m m
|
|
//m m bits = mode
|
|
//Mode 0 = 0 0
|
|
|
|
uint32_t spiBaud = convertClockDivider(divider);
|
|
//datamode is 0 to 3 on BCM2835
|
|
uint32_t spiFlags = 0; //Zero is a good default start.
|
|
//on pigpio, the least sig 2 bits set datamode, which will probably be zero.
|
|
spiFlags = 0x00000000 | (uint32_t) dataMode;
|
|
//According to documentation, bitOrder for SPI MAIN in pigpio is always MSBFIRST. So bitOrder ignored.
|
|
printf("\nSPI Settings:\nBaud rate=%d\nFlags=%d\n\n", spiBaud, spiFlags);
|
|
spiHandle = spiOpen(0, spiBaud, spiFlags); //spiChannel assumed to be zero.
|
|
|
|
//Initialize a timestamp for millis calculation
|
|
gettimeofday(&RHStartTime, NULL);
|
|
}
|
|
|
|
void SPIClass::end()
|
|
{
|
|
//End the SPI
|
|
//bcm2835_spi_end();
|
|
spiClose(spiHandle);
|
|
}
|
|
|
|
uint32_t SPIClass::convertClockDivider(uint16_t rate)
|
|
{
|
|
//Simple divide default RPi SPI clock by divider amount.
|
|
//Nominal clock at 250MHz for Zero.
|
|
return 250000000/rate;
|
|
}
|
|
/*
|
|
//Thes functions aren't necessary
|
|
void SPIClass::setBitOrder(uint8_t bitOrder)
|
|
{
|
|
//Set the SPI bit Order
|
|
bcm2835_spi_setBitOrder(bitOrder);
|
|
}
|
|
|
|
void SPIClass::setDataMode(uint8_t mode)
|
|
{
|
|
//Set SPI data mode
|
|
bcm2835_spi_setDataMode(mode);
|
|
}
|
|
|
|
void SPIClass::setClockDivider(uint16_t rate)
|
|
{
|
|
//Set SPI clock divider
|
|
bcm2835_spi_setClockDivider(rate);
|
|
}
|
|
*/
|
|
|
|
byte SPIClass::transfer(byte _data)
|
|
{
|
|
char txByte[1] = {(char)_data};
|
|
char rxByte[1];
|
|
//For RF Compatibility, just transfer 1 byte
|
|
spiXfer(spiHandle, txByte, rxByte, 1);
|
|
return (byte)rxByte[0];
|
|
}
|
|
|
|
|
|
//void pinMode(unsigned char pin, unsigned char mode)
|
|
void pinMode(uint8_t pin, WiringPinMode mode)
|
|
{
|
|
if (mode == OUTPUT)
|
|
{
|
|
gpioSetMode(pin, PI_OUTPUT);
|
|
//bcm2835_gpio_fsel(pin,BCM2835_GPIO_FSEL_OUTP);
|
|
}
|
|
else if (mode == INPUT)
|
|
{
|
|
gpioSetMode(pin, PI_INPUT);
|
|
//bcm2835_gpio_fsel(pin,BCM2835_GPIO_FSEL_INPT);
|
|
}
|
|
else if (mode == INPUT_PULLUP)
|
|
{
|
|
gpioSetMode(pin, PI_INPUT);
|
|
gpioSetPullUpDown(pin, PI_PUD_UP);
|
|
}
|
|
else if (mode == INPUT_PULLDOWN)
|
|
{
|
|
gpioSetMode(pin, PI_INPUT);
|
|
gpioSetPullUpDown(pin, PI_PUD_DOWN);
|
|
}
|
|
else
|
|
{
|
|
//For safety
|
|
gpioSetMode(pin, PI_INPUT);
|
|
}
|
|
}
|
|
|
|
void digitalWrite(unsigned char pin, unsigned char value)
|
|
{
|
|
//bcm2835_gpio_write(pin,value);
|
|
//Could have just written gpioWrite(pin, value)
|
|
if(value == HIGH)
|
|
{
|
|
gpioWrite(pin, PI_ON);
|
|
}
|
|
else
|
|
{
|
|
gpioWrite(pin, PI_OFF);
|
|
}
|
|
}
|
|
|
|
unsigned long millis()
|
|
{
|
|
//Declare a variable to store current time
|
|
struct timeval RHCurrentTime;
|
|
//Get current time
|
|
gettimeofday(&RHCurrentTime,NULL);
|
|
//Calculate the difference between our start time and the end time
|
|
unsigned long difference = ((RHCurrentTime.tv_sec - RHStartTime.tv_sec) * 1000);
|
|
difference += ((RHCurrentTime.tv_usec - RHStartTime.tv_usec)/1000);
|
|
//Return the calculated value
|
|
return difference;
|
|
}
|
|
|
|
void delay (unsigned long ms)
|
|
{
|
|
//Implement Delay function
|
|
struct timespec ts;
|
|
ts.tv_sec=0;
|
|
ts.tv_nsec=(ms * 1000);
|
|
nanosleep(&ts,&ts);
|
|
}
|
|
|
|
long random(long min, long max)
|
|
{
|
|
long diff = max - min;
|
|
long ret = diff * rand() + min;
|
|
return ret;
|
|
}
|
|
|
|
//******************************
|
|
//* Attach Interupt
|
|
//* Emulate Arduino Function
|
|
//******************************
|
|
|
|
void attachInterrupt(unsigned char pin, void (*handler)(void), int mode)
|
|
{
|
|
switch(mode)
|
|
{
|
|
case CHANGE:
|
|
gpioSetISRFunc(pin, EITHER_EDGE, 0, (void (*)(int,int,unsigned int))handler);
|
|
break;
|
|
case RISING:
|
|
gpioSetISRFunc(pin, RISING_EDGE, 0, (void (*)(int,int,unsigned int))handler);
|
|
break;
|
|
case FALLING:
|
|
gpioSetISRFunc(pin, FALLING_EDGE, 0, (void (*)(int,int,unsigned int))handler);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SerialSimulator::begin(int baud)
|
|
{
|
|
//No implementation neccesary - Serial emulation on Linux = standard console
|
|
//
|
|
//Initialize a timestamp for millis calculation - we do this here as well in case SPI
|
|
//isn't used for some reason
|
|
gettimeofday(&RHStartTime, NULL);
|
|
}
|
|
|
|
size_t SerialSimulator::println(const char* s)
|
|
{
|
|
size_t charsPrinted = 0;
|
|
charsPrinted = print(s);
|
|
printf("\n");
|
|
return charsPrinted + 1;
|
|
}
|
|
|
|
size_t SerialSimulator::print(const char* s)
|
|
{
|
|
return (size_t)printf(s);
|
|
}
|
|
|
|
size_t SerialSimulator::print(unsigned int n, int base)
|
|
{
|
|
if (base == DEC)
|
|
return (size_t)printf("%d", n);
|
|
else if (base == HEX)
|
|
return (size_t)printf("%02x", n);
|
|
else if (base == OCT)
|
|
return (size_t)printf("%o", n);
|
|
// TODO: BIN
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
size_t SerialSimulator::print(char ch)
|
|
{
|
|
return (size_t)printf("%c", ch);
|
|
}
|
|
|
|
size_t SerialSimulator::println(char ch)
|
|
{
|
|
return (size_t)printf("%c\n", ch);
|
|
}
|
|
|
|
size_t SerialSimulator::print(unsigned char ch, int base)
|
|
{
|
|
return print((unsigned int)ch, base);
|
|
}
|
|
|
|
size_t SerialSimulator::println(unsigned char ch, int base)
|
|
{
|
|
size_t charsPrinted = 0;
|
|
charsPrinted = print((unsigned int)ch, base);
|
|
printf("\n");
|
|
return charsPrinted + 1;
|
|
}
|
|
|
|
#endif
|