mirror of https://github.com/arendst/Tasmota.git
226 lines
5.3 KiB
C
226 lines
5.3 KiB
C
|
/*
|
||
|
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) ;
|
||
|
}
|