pigpiod.c
Go to the documentation of this file.
00001 /*
00002 This is free and unencumbered software released into the public domain.
00003 
00004 Anyone is free to copy, modify, publish, use, compile, sell, or
00005 distribute this software, either in source code form or as a compiled
00006 binary, for any purpose, commercial or non-commercial, and by any
00007 means.
00008 
00009 In jurisdictions that recognize copyright laws, the author or authors
00010 of this software dedicate any and all copyright interest in the
00011 software to the public domain. We make this dedication for the benefit
00012 of the public at large and to the detriment of our heirs and
00013 successors. We intend this dedication to be an overt act of
00014 relinquishment in perpetuity of all present and future rights to this
00015 software under copyright law.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00018 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00019 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00020 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
00021 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00022 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00023 OTHER DEALINGS IN THE SOFTWARE.
00024 
00025 For more information, please refer to <http://unlicense.org/>
00026 */
00027 
00028 /*
00029 This version is for pigpio version 65+
00030 */
00031 
00032 #include <sys/types.h>
00033 #include <sys/stat.h>
00034 #include <pwd.h>
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <stdarg.h>
00038 #include <fcntl.h>
00039 #include <errno.h>
00040 #include <unistd.h>
00041 #include <syslog.h>
00042 #include <string.h>
00043 #include <signal.h>
00044 #include <ctype.h>
00045 #include <sys/socket.h>
00046 #include <netdb.h>
00047 
00048 #include "pigpio.h"
00049 
00050 /*
00051 This program starts the pigpio library as a daemon.
00052 */
00053 
00054 static unsigned bufferSizeMilliseconds = PI_DEFAULT_BUFFER_MILLIS;
00055 static unsigned clockMicros            = PI_DEFAULT_CLK_MICROS;
00056 static unsigned clockPeripheral        = PI_DEFAULT_CLK_PERIPHERAL;
00057 static unsigned ifFlags                = PI_DEFAULT_IF_FLAGS;
00058 static int      foreground             = PI_DEFAULT_FOREGROUND;
00059 static unsigned DMAprimaryChannel      = PI_DEFAULT_DMA_PRIMARY_CHANNEL;
00060 static unsigned DMAsecondaryChannel    = PI_DEFAULT_DMA_SECONDARY_CHANNEL;
00061 static unsigned socketPort             = PI_DEFAULT_SOCKET_PORT;
00062 static unsigned memAllocMode           = PI_DEFAULT_MEM_ALLOC_MODE;
00063 static uint64_t updateMask             = -1;
00064 
00065 static uint32_t cfgInternals           = PI_DEFAULT_CFG_INTERNALS;
00066 
00067 static int updateMaskSet = 0;
00068 
00069 static FILE * errFifo;
00070 
00071 static uint32_t sockNetAddr[MAX_CONNECT_ADDRESSES];
00072 
00073 static int numSockNetAddr = 0;
00074 
00075 void fatal(char *fmt, ...)
00076 {
00077    char buf[128];
00078    va_list ap;
00079 
00080    va_start(ap, fmt);
00081    vsnprintf(buf, sizeof(buf), fmt, ap);
00082    va_end(ap);
00083 
00084    fprintf(stderr, "%s\n", buf);
00085 
00086    fflush(stderr);
00087 
00088    exit(EXIT_FAILURE);
00089 }
00090 
00091 void usage()
00092 {
00093    fprintf(stderr, "\n" \
00094       "pigpio V%d\n" \
00095       "Usage: sudo pigpiod [OPTION] ...\n" \
00096       "   -a value,   DMA mode, 0=AUTO, 1=PMAP, 2=MBOX,  default AUTO\n" \
00097       "   -b value,   sample buffer size in ms,          default 120\n" \
00098       "   -c value,   library internal settings,         default 0\n" \
00099       "   -d value,   primary DMA channel, 0-14,         default 14\n" \
00100       "   -e value,   secondary DMA channel, 0-14,       default 6\n" \
00101       "   -f,         disable fifo interface,            default enabled\n" \
00102       "   -g,         run in foreground (do not fork),   default disabled\n" \
00103       "   -k,         disable socket interface,          default enabled\n" \
00104       "   -l,         localhost socket only              default local+remote\n" \
00105       "   -m,         disable alerts                     default enabled\n" \
00106       "   -n IP addr, allow address, name or dotted,     default allow all\n" \
00107       "   -p value,   socket port, 1024-32000,           default 8888\n" \
00108       "   -s value,   sample rate, 1, 2, 4, 5, 8, or 10, default 5\n" \
00109       "   -t value,   clock peripheral, 0=PWM 1=PCM,     default PCM\n" \
00110       "   -v, -V,     display pigpio version and exit\n" \
00111       "   -x mask,    GPIO which may be updated,         default board GPIO\n" \
00112       "EXAMPLE\n" \
00113       "sudo pigpiod -s 2 -b 200 -f\n" \
00114       "  Set a sample rate of 2 microseconds with a 200 millisecond\n" \
00115       "  buffer.  Disable the fifo interface.\n" \
00116    "\n", PIGPIO_VERSION);
00117 }
00118 
00119 static uint64_t getNum(char *str, int *err)
00120 {
00121    uint64_t val;
00122    char *endptr;
00123 
00124    *err = 0;
00125    val = strtoll(str, &endptr, 0);
00126    if (*endptr) {*err = 1; val = -1;}
00127    return val;
00128 }
00129 
00130 static uint32_t checkAddr(char *addrStr)
00131 {
00132    int err;
00133    struct addrinfo hints, *res;
00134    struct sockaddr_in *sin;
00135    const char *portStr;
00136    uint32_t addr;
00137 
00138    portStr = getenv(PI_ENVPORT);
00139 
00140    if (!portStr) portStr = PI_DEFAULT_SOCKET_PORT_STR;
00141 
00142    memset (&hints, 0, sizeof (hints));
00143 
00144    hints.ai_family   = AF_INET;
00145    hints.ai_socktype = SOCK_STREAM;
00146    hints.ai_flags   |= AI_CANONNAME;
00147 
00148    err = getaddrinfo(addrStr, portStr, &hints, &res);
00149 
00150    if (err) return 0;
00151 
00152    sin = (struct sockaddr_in *)res->ai_addr;
00153    addr = sin->sin_addr.s_addr;
00154 
00155    freeaddrinfo(res);
00156 
00157    return addr;
00158 }
00159 
00160 static void initOpts(int argc, char *argv[])
00161 {
00162    int opt, err, i;
00163    uint32_t addr;
00164    int64_t mask;
00165 
00166    while ((opt = getopt(argc, argv, "a:b:c:d:e:fgkln:mp:s:t:x:vV")) != -1)
00167    {
00168       switch (opt)
00169       {
00170          case 'a':
00171             i = getNum(optarg, &err);
00172             if ((i >= PI_MEM_ALLOC_AUTO) && (i <= PI_MEM_ALLOC_MAILBOX))
00173                memAllocMode = i;
00174             else fatal("invalid -a option (%d)", i);
00175             break;
00176 
00177          case 'b':
00178             i = getNum(optarg, &err);
00179             if ((i >= PI_BUF_MILLIS_MIN) && (i <= PI_BUF_MILLIS_MAX))
00180                bufferSizeMilliseconds = i;
00181             else fatal("invalid -b option (%d)", i);
00182             break;
00183 
00184          case 'c':
00185             i = getNum(optarg, &err);
00186             if ((i >= 0) && (i < PI_CFG_ILLEGAL_VAL))
00187                cfgInternals = i;
00188             else fatal("invalid -c option (%x)", i);
00189             break;
00190 
00191          case 'd':
00192             i = getNum(optarg, &err);
00193             if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_DMA_CHANNEL))
00194                DMAprimaryChannel = i;
00195             else fatal("invalid -d option (%d)", i);
00196             break;
00197 
00198          case 'e':
00199             i = getNum(optarg, &err);
00200             if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_DMA_CHANNEL))
00201                DMAsecondaryChannel = i;
00202             else fatal("invalid -e option (%d)", i);
00203             break;
00204 
00205          case 'f':
00206             ifFlags |= PI_DISABLE_FIFO_IF;
00207             break; 
00208 
00209          case 'g':
00210             foreground = 1;
00211             break;
00212 
00213          case 'k':
00214             ifFlags |= PI_DISABLE_SOCK_IF;
00215             break; 
00216 
00217          case 'l':
00218             ifFlags |= PI_LOCALHOST_SOCK_IF;
00219             break; 
00220 
00221          case 'm':
00222             ifFlags |= PI_DISABLE_ALERT;
00223             break; 
00224 
00225          case 'n':
00226             addr = checkAddr(optarg);
00227             if (addr && (numSockNetAddr<MAX_CONNECT_ADDRESSES))
00228                sockNetAddr[numSockNetAddr++] = addr;
00229             else fatal("invalid -n option (%s)", optarg);
00230             break; 
00231 
00232          case 'p':
00233             i = getNum(optarg, &err);
00234             if ((i >= PI_MIN_SOCKET_PORT) && (i <= PI_MAX_SOCKET_PORT))
00235                socketPort = i;
00236             else fatal("invalid -p option (%d)", i);
00237             break;
00238 
00239          case 's':
00240             i = getNum(optarg, &err);
00241 
00242             switch(i)
00243             {
00244                case 1:
00245                case 2:
00246                case 4:
00247                case 5:
00248                case 8:
00249                case 10:
00250                   clockMicros = i;
00251                   break;
00252 
00253                default:
00254                   fatal("invalid -s option (%d)", i);
00255                   break;
00256             }
00257             break;
00258 
00259          case 't':
00260             i = getNum(optarg, &err);
00261             if ((i >= PI_CLOCK_PWM) && (i <= PI_CLOCK_PCM))
00262                clockPeripheral = i;
00263             else fatal("invalid -t option (%d)", i);
00264             break;
00265 
00266          case 'v':
00267          case 'V':
00268             printf("%d\n", PIGPIO_VERSION);
00269             exit(EXIT_SUCCESS);
00270             break;
00271 
00272          case 'x':
00273             mask = getNum(optarg, &err);
00274             if (!err)
00275             {
00276                updateMask = mask;
00277                updateMaskSet = 1;
00278             }
00279             else fatal("invalid -x option (%s)", optarg);
00280             break;
00281 
00282         default: /* '?' */
00283            usage();
00284            exit(EXIT_FAILURE);
00285         }
00286     }
00287 }
00288 
00289 void terminate(int signum)
00290 {
00291    /* only registered for SIGHUP/SIGTERM */
00292 
00293    gpioTerminate();
00294 
00295    fprintf(errFifo, "SIGHUP/SIGTERM received\n");
00296 
00297    fflush(NULL);
00298 
00299    fclose(errFifo);
00300 
00301    unlink(PI_ERRFIFO);
00302 
00303    exit(0);
00304 }
00305 
00306 
00307 int main(int argc, char **argv)
00308 {
00309    pid_t pid;
00310    int flags;
00311 
00312    /* check command line parameters */
00313 
00314    initOpts(argc, argv);
00315 
00316    if (!foreground) {
00317       /* Fork off the parent process */
00318 
00319       pid = fork();
00320 
00321       if (pid < 0) { exit(EXIT_FAILURE); }
00322 
00323       /* If we got a good PID, then we can exit the parent process. */
00324 
00325       if (pid > 0) { exit(EXIT_SUCCESS); }
00326 
00327       /* Change the file mode mask */
00328 
00329       umask(0);
00330 
00331       /* Open any logs here */
00332 
00333       /* NONE */
00334 
00335       /* Create a new SID for the child process */
00336 
00337       if (setsid() < 0) fatal("setsid failed (%m)");
00338 
00339       /* Change the current working directory */
00340 
00341       if ((chdir("/")) < 0) fatal("chdir failed (%m)");
00342 
00343       /* Close out the standard file descriptors */
00344 
00345       fclose(stdin);
00346       fclose(stdout);
00347    }
00348 
00349    /* configure library */
00350 
00351    gpioCfgBufferSize(bufferSizeMilliseconds);
00352 
00353    gpioCfgClock(clockMicros, clockPeripheral, 0);
00354 
00355    gpioCfgInterfaces(ifFlags);
00356 
00357    gpioCfgDMAchannels(DMAprimaryChannel, DMAsecondaryChannel);
00358 
00359    gpioCfgSocketPort(socketPort);
00360 
00361    gpioCfgMemAlloc(memAllocMode);
00362 
00363    if (updateMaskSet) gpioCfgPermissions(updateMask);
00364 
00365    gpioCfgNetAddr(numSockNetAddr, sockNetAddr);
00366 
00367    gpioCfgSetInternals(cfgInternals);
00368 
00369    /* start library */
00370 
00371    if (gpioInitialise()< 0) fatal("Can't initialise pigpio library");
00372 
00373    /* create pipe for error reporting */
00374 
00375    unlink(PI_ERRFIFO);
00376 
00377    mkfifo(PI_ERRFIFO, 0664);
00378 
00379    if (chmod(PI_ERRFIFO, 0664) < 0)
00380       fatal("chmod %s failed (%m)", PI_ERRFIFO);
00381 
00382    errFifo = freopen(PI_ERRFIFO, "w+", stderr);
00383 
00384    if (errFifo)
00385    {
00386       /* set stderr non-blocking */
00387 
00388       flags = fcntl(fileno(errFifo), F_GETFL, 0);
00389       fcntl(fileno(errFifo), F_SETFL, flags | O_NONBLOCK);
00390 
00391       /* request SIGHUP/SIGTERM from libarary for termination */
00392 
00393       gpioSetSignalFunc(SIGHUP, terminate);
00394       gpioSetSignalFunc(SIGTERM, terminate);
00395 
00396       /* sleep forever */
00397 
00398       while (1)
00399       {
00400          /* cat /dev/pigerr to view daemon errors */
00401 
00402          sleep(5);
00403 
00404          fflush(errFifo);
00405       }
00406    }
00407    else
00408    {
00409       fprintf(stderr, "freopen failed (%m)");
00410 
00411       gpioTerminate();
00412    }
00413 
00414    return 0;
00415 }
00416 
00417 


cob_hand_bridge
Author(s): Mathias Lüdtke
autogenerated on Thu Jun 6 2019 20:43:57