/* Copyright (C) 2021 Michel Stempin This file is part of the FunKey S GPIO keyboard daemon. This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ /** * @file main.c * This file contains the main function for the FunKey S GPIO daemon */ #include #include #include #include #include #include #include #include "daemon.h" #include "uinput.h" #include "gpio_mapping.h" #define VERSION "0.0.1" #define PID_FILE "/var/run/fkgpiod.pid" /* Background daemon flag */ static bool daemon = false; /* GPIO configuration file name */ static const char *config_file = "fkgpiod.conf"; /* Print usage information */ static void print_usage(void) { printf("Usage: fkgpiod [options] [config_file]\n" "Options:\n" " -d, -D, --daemonize Launch as a background daemon\n" " -h, -H, --help Print option help\n" " -k, -K, --kill Kill background daemon\n" " -v, --version Print version information\n" "\n" "You can send script commands to the fkgpiod daemon by writting to the /tmp/fkgpiod.fifo file:\n" "\n" "$ echo \"LOAD /etc/fkgpiod.conf\" > /tmp/fkgpiod.fifo\n" "\n" "Available script commands (commands are not case sensitive):\n" "-----------------------------------------------------------\n" "CLEAR Clear the button mapping\n" "DUMP Dump the button mapping\n" "KEYDOWN Send a key down event with the given keycode\n" "KEYPRESS Send key press event with the given keycode\n" "KEYUP Send a key up event with the given keycode\n" "LOAD Load a configuration file\n" "MAP TO KEY Map a button combination to a keycode\n" "MAP TO COMMAND Map a button combination to a Shell command\n" "SLEEP Sleep for the given delay in ms\n" "TYPE Type in a string\n" "UNMAP Unmap a button combination\n" "\n" "where:\n" " - is a list of UP, DOWN, LEFT, RIGHT, A, B, L, R, X, Y, MENU, START or FN\n" " separated by \"+\" signs\n" " - is any valid Shell command with its arguments\n" " - is the full path to a configurtion file\n" " - is a delay in ms\n" " - is a character string\n" " - is taken from the Linux key and button codes\n" " (https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h),\n" " which in turn is modeled after USB HUT 1.12 (see http://www.usb.org/developers/hidpage):\n" " - KEY_0 to KEY_9, KEY_A to KEY_Z\n" " - KEY_F1 to KEY_F24, KEY_KP0 to KEY_KP9, KEY_PROG1 to KEY_PROG4\n" " - BTN_0 to BTN_9, BTN_A to BTN_C, BTN_X to BTN_Z, BTN_BASE2 to BTN_BASE6\n" " - BTN_BACK, BTN_BASE, BTN_DEAD, BTN_EXTRA, BTN_FORWARD, BTN_GAMEPAD, BTN_JOYSTICK, BTN_LEFT,\n" " BTN_MIDDLE, BTN_MISC, BTN_MODE, BTN_MOUSE, BTN_PINKIE, BTN_RIGHT, BTN_SELECT, BTN_SIDE,\n" " BTN_START, BTN_TASK, BTN_THUMB, BTN_THUMB2, BTN_THUMBL, BTN_THUMBR, BTN_TL, BTN_TL2, \n" " BTN_TOP, BTN_TOP2, BTN_TR, BTN_TR2, BTN_TRIGGER,\n" " - KEY_102ND, KEY_AGAIN, KEY_ALTERASE, KEY_APOSTROPHE, KEY_BACK, KEY_BACKSLASH, KEY_BACKSPACE,\n" " KEY_BASSBOOST, KEY_BATTERY, KEY_BLUETOOTH, KEY_BOOKMARKS, KEY_BRIGHTNESSDOWN,\n" " KEY_BRIGHTNESSUP, KEY_BRIGHTNESS_CYCLE, KEY_BRIGHTNESS_ZERO, KEY_CALC, KEY_CAMERA,\n" " KEY_CANCEL, KEY_CAPSLOCK, KEY_CHAT, KEY_CLOSE, KEY_CLOSECD, KEY_COFFEE, KEY_COMMA,\n" " KEY_COMPOSE, KEY_COMPUTER, KEY_CONFIG, KEY_CONNECT, KEY_COPY, KEY_CUT, KEY_CYCLEWINDOWS,\n" " KEY_DASHBOARD, KEY_DELETE, KEY_DELETEFILE, KEY_DIRECTION, KEY_DISPLAY_OFF, KEY_DOCUMENTS,\n" " KEY_DOT, KEY_DOWN, KEY_EDIT, KEY_EJECTCD, KEY_EJECTCLOSECD, KEY_EMAIL, KEY_END, KEY_ENTER,\n" " KEY_EQUAL, KEY_ESC, KEY_EXIT, KEY_FASTFORWARD, KEY_FILE, KEY_FINANCE, KEY_FIND,\n" " KEY_FORWARD, KEY_FORWARDMAIL, KEY_FRONT, KEY_GRAVE, KEY_HANGEUL, KEY_HANGUEL, KEY_HANJA,\n" " KEY_HELP, KEY_HENKAN, KEY_HIRAGANA, KEY_HOME, KEY_HOMEPAGE, KEY_HP, KEY_INSERT, KEY_ISO,\n" " KEY_KATAKANA, KEY_KATAKANAHIRAGANA, KEY_KBDILLUMDOWN, KEY_KBDILLUMTOGGLE, KEY_KBDILLUMUP,\n" " KEY_KPASTERISK,KEY_KPCOMMA, KEY_KPDOT, KEY_KPENTER, KEY_KPEQUAL, KEY_KPJPCOMMA,\n" " KEY_KPLEFTPAREN, KEY_KPMINUS, KEY_KPPLUS, KEY_KPPLUSMINUS, KEY_KPRIGHTPAREN, KEY_KPSLASH,\n" " KEY_LEFT, KEY_LEFTALT, KEY_LEFTBRACE, KEY_LEFTCTRL, KEY_LEFTMETA, KEY_LEFTSHIFT,\n" " KEY_LINEFEED, KEY_MACRO, KEY_MAIL, KEY_MEDIA, KEY_MENU, KEY_MICMUTE, KEY_MINUS, KEY_MOVE,\n" " KEY_MSDOS, KEY_MUHENKAN, KEY_MUTE, KEY_NEW, KEY_NEXTSONG, KEY_NUMLOCK, KEY_OPEN,\n" " KEY_PAGEDOWN, KEY_PAGEUP, KEY_PASTE, KEY_PAUSE, KEY_PAUSECD, KEY_PHONE, KEY_PLAY,\n" " KEY_PLAYCD, KEY_PLAYPAUSE, KEY_POWER, EY_PREVIOUSSONG, KEY_PRINT, KEY_PROPS, KEY_QUESTION,\n" " KEY_RECORD, KEY_REDO, KEY_REFRESH, KEY_REPLY, KEY_REWIND, KEY_RFKILL, KEY_RIGHT,\n" " KEY_RIGHTALT, KEY_RIGHTBRACE, KEY_RIGHTCTRL, KEY_RIGHTMETA, KEY_RIGHTSHIFT, KEY_RO,\n" " KEY_SAVE, KEY_SCALE, KEY_SCREENLOCK, KEY_SCROLLDOWN, KEY_SCROLLLOCK, KEY_SCROLLUP,\n" " KEY_SEARCH, KEY_SEMICOLON, KEY_SEND, KEY_SENDFILE, KEY_SETUP, KEY_SHOP, KEY_SLASH,\n" " KEY_SLEEP, KEY_SOUND, KEY_SPACE, KEY_SPORT, KEY_STOP, KEY_STOPCD, KEY_SUSPEND,\n" " KEY_SWITCHVIDEOMODE, KEY_SYSRQ, KEY_TAB, KEY_UNDO, KEY_UNKNOWN, KEY_UP, KEY_UWB,\n" " KEY_VIDEO_NEXT, KEY_VIDEO_PREV, KEY_VOLUMEDOWN, KEY_VOLUMEUP, KEY_WAKEUP, KEY_WIMAX,\n" " KEY_WLAN, KEY_WWW, KEY_XFER, KEY_YEN, KEY_ZENKAKUHANKAKU\n"); } /* Print version information */ static void print_version(void) { printf("fkgpiod version "VERSION"\n"); printf("FunKey S GPIO daemon\n\n"); printf("Copyright (C) 2020-2021, Vincent Buso ,\n"); printf("Copyright (C) 2021, Michel Stempin ,\n"); printf("All rights reserved.\n"); printf("Released under the GNU Lesser General Public License version 2.1 or later\n"); } /* Parse command line options */ static void parse_options(int argc, char *argv[]) { struct option long_options[] = { {"daemonize", 0, NULL, 0}, {"help", 0, NULL, 0}, {"kill", 0, NULL, 0}, {"version", 0, NULL, 0}, {0, 0, NULL, 0} }; int c, opt; while (true) { c = getopt_long(argc, argv, "dDhHkKvV", long_options, &opt); if (c == -1) { /* End of options */ break; } if (c == 0) { /* Match long option names and convert them to short options */ if (!strcmp(long_options[opt].name, "daemonize")) { c = 'd'; } else if (!strcmp(long_options[opt].name, "help")) { c = 'h'; } else if (!strcmp(long_options[opt].name, "kill")) { c = 'k'; } else if (!strcmp(long_options[opt].name, "version")) { c = 'v'; } } switch (c) { case 'd': case 'D': /* Daemonize */ daemon = true; break; case 'h': case 'H': /* Help */ print_usage(); exit(EXIT_SUCCESS); case 'k': case 'K': /* Kill running daemon */ kill_daemon(PID_FILE); exit(EXIT_SUCCESS); case 'v': case 'V': /* Version */ print_version(); exit(EXIT_SUCCESS); default: print_usage(); exit(EXIT_FAILURE); } } if (optind > argc) { print_usage(); exit(EXIT_FAILURE); } else if (optind < argc) { /* Last argument is the GPIO confguration file name */ config_file = strdup(argv[optind]); } } /* Entry point */ int main(int argc, char *argv[]) { mapping_list_t mapping_list; /* Parse command line options */ parse_options(argc, argv); if (daemon) { /* Run as a background daemon, redirect all output to syslog */ // to_log(&stdout); // to_log(&stderr); daemonize("fkgpiod", "/", PID_FILE); } else { openlog("fkgpiod", LOG_PERROR | LOG_PID | LOG_NDELAY, LOG_DAEMON); } /* Initialize the uinput device */ init_uinput(); /* Initialize the GPIO mapping */ if (init_gpio_mapping(config_file, &mapping_list) == false) { /* Close the uinput device */ close_uinput(); if (daemon) { /* Close the syslog */ closelog(); } exit(EXIT_FAILURE); } while (true) { /* Main loop to handle the GPIOs */ handle_gpio_mapping(&mapping_list); } /* Deinitialize the GPIO mapping */ deinit_gpio_mapping(); /* Close the uinput device */ close_uinput(); if (daemon) { /* Close the syslog */ closelog(); } return EXIT_SUCCESS; }