// 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 #if (RH_PLATFORM == RH_PLATFORM_RASPI) #include #include #include "RasPi.h" #include 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