/*******************************************************************************
* rp-measure-fan-speed.c    Example program that measures fan speed in RPM.    *
*                                                                              *
* JST Lawrence, 2019 Novel Devices                                             *
* Source code at http://www.noveldevices.co.uk/rpdl/rp-measure-fan-speed.c     *
*                                                                              *
* V1.0    18-Mar-2019 Written.                                                 *
*                                                                              *
*                                                                              *
*******************************************************************************/

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>

#define READINGS 30

char *UpLines="\033[%dA"; // Put this as printf format specifier

int fd;

// Return microseconds
long getMicroSeconds (void)
{
    struct timeval currentTime;
    gettimeofday(&currentTime,NULL);
    return currentTime.tv_usec;
}

void main(int argc, char *argv[])
{
    int           ReturnCode;
    struct pollfd pfd;
    char          CharIn;
    long          Start,Stop;
    double        HzNow;
    int           i;
	char         *GPIO={"21"};
    
// Enable GPIO pin
    fd = open("/sys/class/gpio/export", O_WRONLY);
    write(fd,GPIO,2);
    close(fd);

// Set GPIO as input
    fd = open("/sys/class/gpio/gpio21/direction", O_WRONLY);
    write(fd, "in", 2);
    close(fd);

// Set detection type: edge, falling
    fd = open("/sys/class/gpio/gpio21/edge", O_WRONLY);
    write(fd, "falling", 6);
    close(fd);

// Open value file and poll for a change
    fd = open("/sys/class/gpio/gpio21/value", O_RDONLY);
    pfd.fd = fd;
    pfd.events = POLLPRI | POLLERR;

// Main loop
    for(;;)
    {
// Start each set of readings at zero microseconds (avoids checking for negative differences and keeps the processor focused on this process)
        while(getMicroSeconds()>0);
        
// Take 30 readings but keep only 3rd [2] and 28th [27]
        for(i=0;i<READINGS;i++)
        {   lseek(fd, 0, SEEK_SET);
            ReturnCode=poll(&pfd,1,3000);
            if(0==ReturnCode)break; // Leave if no signal
            read(fd, &CharIn, 1);
            if(2==i)Start=getMicroSeconds();
            if(27==i)Stop=getMicroSeconds();
        }
        if(0==ReturnCode)break;

// Take the difference between the readings at 3rd and 28th and calculate frequency (divide by 2 because of 2 pulses per second and 60 for rpm)
        HzNow=25000000.00/(double)(Stop-Start)/2.0/60.0;
        printf("Speed is %2.2fRPM\n",HzNow);
        printf(UpLines,1);

    } // END OF FOR

// Will never reach here...

}
