mirror of https://github.com/joan2937/pigpio
689 lines
14 KiB
C
689 lines
14 KiB
C
|
/*
|
||
|
This is free and unencumbered software released into the public domain.
|
||
|
|
||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||
|
distribute this software, either in source code form or as a compiled
|
||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||
|
means.
|
||
|
|
||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||
|
of this software dedicate any and all copyright interest in the
|
||
|
software to the public domain. We make this dedication for the benefit
|
||
|
of the public at large and to the detriment of our heirs and
|
||
|
successors. We intend this dedication to be an overt act of
|
||
|
relinquishment in perpetuity of all present and future rights to this
|
||
|
software under copyright law.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||
|
|
||
|
For more information, please refer to <http://unlicense.org/>
|
||
|
*/
|
||
|
|
||
|
/* PIGPIOD_IF_VERSION 1 */
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stdint.h>
|
||
|
#include <string.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <unistd.h>
|
||
|
#include <errno.h>
|
||
|
#include <time.h>
|
||
|
#include <netdb.h>
|
||
|
#include <pthread.h>
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/time.h>
|
||
|
#include <sys/socket.h>
|
||
|
#include <sys/select.h>
|
||
|
|
||
|
#include <arpa/inet.h>
|
||
|
|
||
|
#include "pigpio.h"
|
||
|
#include "command.h"
|
||
|
|
||
|
#include "pigpiod_if.h"
|
||
|
|
||
|
#define PISCOPE_MAX_REPORTS_PER_READ 4096
|
||
|
|
||
|
#define STACK_SIZE (256*1024)
|
||
|
|
||
|
typedef void (*CBF_t) ();
|
||
|
|
||
|
struct callback_s
|
||
|
{
|
||
|
int id;
|
||
|
int gpio;
|
||
|
int edge;
|
||
|
CBF_t f;
|
||
|
void * user;
|
||
|
int ex;
|
||
|
callback_t *prev;
|
||
|
callback_t *next;
|
||
|
};
|
||
|
|
||
|
/* GLOBALS ---------------------------------------------------------------- */
|
||
|
|
||
|
static gpioReport_t gReport[PISCOPE_MAX_REPORTS_PER_READ];
|
||
|
|
||
|
static int gPigCommand = -1;
|
||
|
static int gPigHandle = -1;
|
||
|
static int gPigNotify = -1;
|
||
|
|
||
|
static uint32_t gNotifyBits;
|
||
|
|
||
|
callback_t *gCallBackFirst = 0;
|
||
|
callback_t *gCallBackLast = 0;
|
||
|
|
||
|
static int gPigStarted = 0;
|
||
|
|
||
|
static pthread_t *pthNotify;
|
||
|
|
||
|
/* PRIVATE ---------------------------------------------------------------- */
|
||
|
|
||
|
static int pigpio_command(int fd, int command, int p1, int p2)
|
||
|
{
|
||
|
cmdCmd_t cmd;
|
||
|
|
||
|
cmd.cmd = command;
|
||
|
cmd.p1 = p1;
|
||
|
cmd.p2 = p2;
|
||
|
cmd.res = 0;
|
||
|
|
||
|
if (send(fd, &cmd, sizeof(cmdCmd_t), 0) != sizeof(cmdCmd_t))
|
||
|
return pigif_bad_send;
|
||
|
|
||
|
if (recv(fd, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) != sizeof(cmdCmd_t))
|
||
|
return pigif_bad_recv;
|
||
|
|
||
|
return cmd.res;
|
||
|
}
|
||
|
|
||
|
static int pigpioOpenSocket(char *addr, char *port)
|
||
|
{
|
||
|
int sock, err;
|
||
|
struct addrinfo hints, *res, *rp;
|
||
|
const char *addrStr, *portStr;
|
||
|
|
||
|
if (!addr)
|
||
|
{
|
||
|
addrStr = getenv(PI_ENVADDR);
|
||
|
|
||
|
if ((!addrStr) || (!strlen(addrStr)))
|
||
|
{
|
||
|
addrStr = PI_DEFAULT_SOCKET_ADDR_STR;
|
||
|
}
|
||
|
}
|
||
|
else addrStr = addr;
|
||
|
|
||
|
if (!port)
|
||
|
{
|
||
|
portStr = getenv(PI_ENVPORT);
|
||
|
|
||
|
if ((!portStr) || (!strlen(portStr)))
|
||
|
{
|
||
|
portStr = PI_DEFAULT_SOCKET_PORT_STR;
|
||
|
}
|
||
|
}
|
||
|
else portStr = port;
|
||
|
|
||
|
memset (&hints, 0, sizeof (hints));
|
||
|
|
||
|
hints.ai_family = PF_UNSPEC;
|
||
|
hints.ai_socktype = SOCK_STREAM;
|
||
|
hints.ai_flags |= AI_CANONNAME;
|
||
|
|
||
|
err = getaddrinfo (addrStr, portStr, &hints, &res);
|
||
|
|
||
|
if (err) return pigif_bad_getaddrinfo;
|
||
|
|
||
|
for (rp=res; rp!=NULL; rp=rp->ai_next)
|
||
|
{
|
||
|
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||
|
|
||
|
if (sock == -1) continue;
|
||
|
|
||
|
if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) break;
|
||
|
}
|
||
|
|
||
|
freeaddrinfo(res);
|
||
|
|
||
|
if (rp == NULL) return pigif_bad_connect;
|
||
|
|
||
|
return sock;
|
||
|
}
|
||
|
|
||
|
static void dispatch_notification(gpioReport_t *r)
|
||
|
{
|
||
|
static uint32_t lastLevel = 0;
|
||
|
|
||
|
callback_t *p;
|
||
|
uint32_t changed;
|
||
|
int l, g;
|
||
|
|
||
|
/*
|
||
|
printf("s=%d f=%d l=%8X, t=%10u\n",
|
||
|
r->seqno, r->flags, r->level, r->tick);
|
||
|
*/
|
||
|
|
||
|
if (r->flags == 0)
|
||
|
{
|
||
|
changed = (r->level ^ lastLevel) & gNotifyBits;
|
||
|
|
||
|
lastLevel = r->level;
|
||
|
|
||
|
p = gCallBackFirst;
|
||
|
|
||
|
while (p)
|
||
|
{
|
||
|
if (changed & (1<<(p->gpio)))
|
||
|
{
|
||
|
if ((r->level) & (1<<(p->gpio))) l = 1; else l = 0;
|
||
|
if ((p->edge) ^ l)
|
||
|
{
|
||
|
if (p->ex) (p->f)(p->gpio, l, r->tick, p->user);
|
||
|
else (p->f)(p->gpio, l, r->tick);
|
||
|
}
|
||
|
}
|
||
|
p = p->next;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g = (r->flags) & 31;
|
||
|
|
||
|
p = gCallBackFirst;
|
||
|
|
||
|
while (p)
|
||
|
{
|
||
|
if ((p->gpio) == g)
|
||
|
{
|
||
|
if (p->ex) (p->f)(g, PI_TIMEOUT, r->tick, p->user);
|
||
|
else (p->f)(g, PI_TIMEOUT, r->tick);
|
||
|
}
|
||
|
p = p->next;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void *pthNotifyThread(void *x)
|
||
|
{
|
||
|
static int got = 0;
|
||
|
|
||
|
int bytes, r;
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
bytes = read(gPigNotify, (char*)&gReport+got, sizeof(gReport)-got);
|
||
|
|
||
|
if (bytes > 0) got += bytes;
|
||
|
else break;
|
||
|
|
||
|
r = 0;
|
||
|
|
||
|
while (got >= sizeof(gpioReport_t))
|
||
|
{
|
||
|
dispatch_notification(&gReport[r]);
|
||
|
|
||
|
r++;
|
||
|
|
||
|
got -= sizeof(gpioReport_t);
|
||
|
}
|
||
|
|
||
|
/* copy any partial report to start of array */
|
||
|
|
||
|
if (got && r) gReport[0] = gReport[r];
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void findNotifyBits(void)
|
||
|
{
|
||
|
callback_t *p;
|
||
|
uint32_t bits = 0;
|
||
|
|
||
|
p = gCallBackFirst;
|
||
|
|
||
|
while (p)
|
||
|
{
|
||
|
bits |= (1<<(p->gpio));
|
||
|
p = p->next;
|
||
|
}
|
||
|
|
||
|
if (bits != gNotifyBits)
|
||
|
{
|
||
|
gNotifyBits = bits;
|
||
|
pigpio_command(gPigCommand, PI_CMD_NB, gPigHandle, gNotifyBits);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void _wfe(int gpio, int level, uint32_t tick, void *user)
|
||
|
{
|
||
|
*(int *)user = 1;
|
||
|
}
|
||
|
|
||
|
static int intCallback(int gpio, int edge, void *f, void *user, int ex)
|
||
|
{
|
||
|
static int id = 0;
|
||
|
callback_t *p;
|
||
|
|
||
|
if ((gpio >=0) && (gpio < 32) && (edge >=0) && (edge <= 2) && f)
|
||
|
{
|
||
|
/* prevent duplicates */
|
||
|
|
||
|
p = gCallBackFirst;
|
||
|
|
||
|
while (p)
|
||
|
{
|
||
|
if ((p->gpio == gpio) && (p->edge == edge) && (p->f == f))
|
||
|
{
|
||
|
return pigif_duplicate_callback;
|
||
|
}
|
||
|
p = p->next;
|
||
|
}
|
||
|
|
||
|
p = malloc(sizeof(callback_t));
|
||
|
|
||
|
if (p)
|
||
|
{
|
||
|
if (!gCallBackFirst) gCallBackFirst = p;
|
||
|
|
||
|
p->id = id++;
|
||
|
p->gpio = gpio;
|
||
|
p->edge = edge;
|
||
|
p->f = f;
|
||
|
p->user = user;
|
||
|
p->ex = ex;
|
||
|
p->next = 0;
|
||
|
p->prev = gCallBackLast;
|
||
|
|
||
|
if (p->prev) (p->prev)->next = p;
|
||
|
gCallBackLast = p;
|
||
|
|
||
|
findNotifyBits();
|
||
|
|
||
|
return p->id;
|
||
|
}
|
||
|
|
||
|
return pigif_bad_malloc;
|
||
|
}
|
||
|
|
||
|
return pigif_bad_callback;
|
||
|
}
|
||
|
|
||
|
/* PUBLIC ----------------------------------------------------------------- */
|
||
|
|
||
|
double time_time(void)
|
||
|
{
|
||
|
struct timeval tv;
|
||
|
double t;
|
||
|
|
||
|
gettimeofday(&tv, 0);
|
||
|
|
||
|
t = (double)tv.tv_sec + ((double)tv.tv_usec / 1E6);
|
||
|
|
||
|
return t;
|
||
|
}
|
||
|
|
||
|
void time_sleep(double seconds)
|
||
|
{
|
||
|
struct timespec ts, rem;
|
||
|
|
||
|
if (seconds > 0.0)
|
||
|
{
|
||
|
ts.tv_sec = seconds;
|
||
|
ts.tv_nsec = (seconds-(double)ts.tv_sec) * 1E9;
|
||
|
|
||
|
while (clock_nanosleep(CLOCK_REALTIME, 0, &ts, &rem))
|
||
|
{
|
||
|
/* copy remaining time to ts */
|
||
|
ts.tv_sec = rem.tv_sec;
|
||
|
ts.tv_nsec = rem.tv_nsec;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const char *pigpio_error(int error)
|
||
|
{
|
||
|
if (error > -1000) return cmdErrStr(error);
|
||
|
else
|
||
|
{
|
||
|
switch(error)
|
||
|
{
|
||
|
case pigif_bad_send:
|
||
|
return "failed to send to pigpiod";
|
||
|
case pigif_bad_recv:
|
||
|
return "failed to receive from pigpiod";
|
||
|
case pigif_bad_getaddrinfo:
|
||
|
return "failed to find address of pigpiod";
|
||
|
case pigif_bad_connect:
|
||
|
return "failed to connect to pigpiod";
|
||
|
case pigif_bad_socket:
|
||
|
return "failed to create socket";
|
||
|
case pigif_bad_noib:
|
||
|
return "failed to open noib";
|
||
|
case pigif_duplicate_callback:
|
||
|
return "identical callback exists";
|
||
|
case pigif_bad_malloc:
|
||
|
return "failed to malloc";
|
||
|
case pigif_bad_callback:
|
||
|
return "bad callback parameter";
|
||
|
case pigif_notify_failed:
|
||
|
return "failed to create notification thread";
|
||
|
case pigif_callback_not_found:
|
||
|
return "callback not found";
|
||
|
default:
|
||
|
return "unknown error";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
unsigned pigpiod_if_version(void)
|
||
|
{
|
||
|
return PIGPIOD_IF_VERSION;
|
||
|
}
|
||
|
|
||
|
pthread_t *start_thread(ThreadFunc_t func, void *arg)
|
||
|
{
|
||
|
pthread_t *pth;
|
||
|
pthread_attr_t pthAttr;
|
||
|
|
||
|
pth = malloc(sizeof(pthread_t));
|
||
|
|
||
|
if (pth)
|
||
|
{
|
||
|
if (pthread_attr_init(&pthAttr))
|
||
|
{
|
||
|
perror("pthread_attr_init failed");
|
||
|
free(pth);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (pthread_attr_setstacksize(&pthAttr, STACK_SIZE))
|
||
|
{
|
||
|
perror("pthread_attr_setstacksize failed");
|
||
|
free(pth);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (pthread_create(pth, &pthAttr, func, arg))
|
||
|
{
|
||
|
perror("pthread_create socket failed");
|
||
|
free(pth);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
return pth;
|
||
|
}
|
||
|
|
||
|
void stop_thread(pthread_t *pth)
|
||
|
{
|
||
|
if (pth)
|
||
|
{
|
||
|
pthread_cancel(*pth);
|
||
|
pthread_join(*pth, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int pigpio_start(char *addrStr, char *portStr)
|
||
|
{
|
||
|
if (!gPigStarted)
|
||
|
{
|
||
|
gPigCommand = pigpioOpenSocket(addrStr, portStr);
|
||
|
|
||
|
if (gPigCommand >= 0)
|
||
|
{
|
||
|
gPigNotify = pigpioOpenSocket(addrStr, portStr);
|
||
|
|
||
|
if (gPigNotify >= 0)
|
||
|
{
|
||
|
gPigHandle = pigpio_command(gPigNotify, PI_CMD_NOIB, 0, 0);
|
||
|
|
||
|
if (gPigHandle < 0) return pigif_bad_noib;
|
||
|
else
|
||
|
{
|
||
|
pthNotify = start_thread(pthNotifyThread, 0);
|
||
|
if (pthNotify)
|
||
|
{
|
||
|
gPigStarted = 1;
|
||
|
return 0;
|
||
|
}
|
||
|
else return pigif_notify_failed;
|
||
|
}
|
||
|
}
|
||
|
else return gPigNotify;
|
||
|
}
|
||
|
else return gPigCommand;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void pigpio_stop(void)
|
||
|
{
|
||
|
gPigStarted = 0;
|
||
|
|
||
|
if (pthNotify)
|
||
|
{
|
||
|
stop_thread(pthNotify);
|
||
|
pthNotify = 0;
|
||
|
}
|
||
|
|
||
|
if (gPigNotify >= 0)
|
||
|
{
|
||
|
if (gPigHandle >= 0)
|
||
|
{
|
||
|
pigpio_command(gPigNotify, PI_CMD_NC, gPigHandle, 0);
|
||
|
gPigHandle = -1;
|
||
|
}
|
||
|
|
||
|
close(gPigNotify);
|
||
|
gPigNotify = -1;
|
||
|
}
|
||
|
|
||
|
if (gPigCommand >= 0)
|
||
|
{
|
||
|
if (gPigHandle >= 0)
|
||
|
{
|
||
|
pigpio_command(gPigCommand, PI_CMD_NC, gPigHandle, 0);
|
||
|
gPigHandle = -1;
|
||
|
}
|
||
|
|
||
|
close(gPigCommand);
|
||
|
gPigCommand = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int set_mode(int gpio, int mode)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_MODES, gpio, mode);
|
||
|
}
|
||
|
|
||
|
int get_mode(int gpio)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_MODEG, gpio, 0);
|
||
|
}
|
||
|
|
||
|
int set_pull_up_down(int gpio, int pud)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_PUD, gpio, pud);
|
||
|
}
|
||
|
|
||
|
int read_gpio(int gpio)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_READ, gpio, 0);
|
||
|
}
|
||
|
|
||
|
int write_gpio(int gpio, int level)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_WRITE, gpio, level);
|
||
|
}
|
||
|
|
||
|
int set_PWM_dutycycle(int user_gpio, int dutycycle)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_PWM, user_gpio, dutycycle);
|
||
|
}
|
||
|
|
||
|
int set_PWM_range(int user_gpio, int range_)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_PRS, user_gpio, range_);
|
||
|
}
|
||
|
|
||
|
int get_PWM_range(int user_gpio)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_PRG, user_gpio, 0);
|
||
|
}
|
||
|
|
||
|
int get_PWM_real_range(int user_gpio)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_PRRG, user_gpio, 0);
|
||
|
}
|
||
|
|
||
|
int set_PWM_frequency(int user_gpio, int frequency)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_PFS, user_gpio, frequency);
|
||
|
}
|
||
|
|
||
|
int get_PWM_frequency(int user_gpio)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_PFG, user_gpio, 0);
|
||
|
}
|
||
|
|
||
|
int set_servo_pulsewidth(int user_gpio, int pulsewidth)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_SERVO, user_gpio, pulsewidth);
|
||
|
}
|
||
|
|
||
|
int notify_open(void)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_NO, 0, 0);
|
||
|
}
|
||
|
|
||
|
int notify_begin(int handle, uint32_t bits)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_NB, handle, bits);
|
||
|
}
|
||
|
|
||
|
int notify_pause(int handle)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_NB, handle, 0);
|
||
|
}
|
||
|
|
||
|
int notify_close(int handle)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_NC, handle, 0);
|
||
|
}
|
||
|
|
||
|
int set_watchdog(int user_gpio, int timeout)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_WDOG, user_gpio, timeout);
|
||
|
}
|
||
|
|
||
|
uint32_t read_bank_1(void)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_BR1, 0, 0);
|
||
|
}
|
||
|
|
||
|
uint32_t read_bank_2(void)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_BR2, 0, 0);
|
||
|
}
|
||
|
|
||
|
int clear_bank_1(uint32_t levels)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_BC1, levels, 0);
|
||
|
}
|
||
|
|
||
|
int clear_bank_2(uint32_t levels)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_BC2, levels, 0);
|
||
|
}
|
||
|
|
||
|
int set_bank_1(uint32_t levels)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_BS1, levels, 0);
|
||
|
}
|
||
|
|
||
|
int set_bank_2(uint32_t levels)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_BS2, levels, 0);
|
||
|
}
|
||
|
|
||
|
uint32_t get_current_tick(void)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_TICK, 0, 0);
|
||
|
}
|
||
|
|
||
|
uint32_t get_hardware_revision(void)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_HWVER, 0, 0);
|
||
|
}
|
||
|
|
||
|
unsigned get_pigpio_version(void)
|
||
|
{
|
||
|
return pigpio_command(gPigCommand, PI_CMD_PIGPV, 0, 0);
|
||
|
}
|
||
|
|
||
|
int callback(int gpio, int edge, CBFunc_t f)
|
||
|
{
|
||
|
return intCallback(gpio, edge, f, 0, 0);
|
||
|
}
|
||
|
|
||
|
int callback_ex(int gpio, int edge, CBFuncEx_t f, void *user)
|
||
|
{
|
||
|
return intCallback(gpio, edge, f, user, 1);
|
||
|
}
|
||
|
|
||
|
int callback_cancel(int id)
|
||
|
{
|
||
|
callback_t *p;
|
||
|
|
||
|
p = gCallBackFirst;
|
||
|
|
||
|
while (p)
|
||
|
{
|
||
|
if (p->id == id)
|
||
|
{
|
||
|
if (p->prev) p->prev->next = p->next;
|
||
|
else gCallBackFirst = p->next;
|
||
|
|
||
|
if (p->next) p->next->prev = p->prev;
|
||
|
else gCallBackLast = p->prev;
|
||
|
|
||
|
free(p);
|
||
|
|
||
|
findNotifyBits();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
p = p->next;
|
||
|
}
|
||
|
return pigif_callback_not_found;
|
||
|
}
|
||
|
|
||
|
int wait_for_edge(int gpio, int edge, double timeout)
|
||
|
{
|
||
|
int triggered = 0;
|
||
|
int id;
|
||
|
double due;
|
||
|
|
||
|
if (timeout <= 0.0) return 0;
|
||
|
|
||
|
due = time_time() + timeout;
|
||
|
|
||
|
id = callback_ex(gpio, edge, _wfe, &triggered);
|
||
|
|
||
|
while (!triggered && (time_time() < due)) time_sleep(0.1);
|
||
|
|
||
|
callback_cancel(id);
|
||
|
|
||
|
return triggered;
|
||
|
}
|
||
|
|