/* * cleopatre/application/managerd/src/gpio_event.c * * (C) Copyright 2010 SPiDCOM Technologies * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include "nvram.h" #include "../../linux/gpio.h" #include "managerd.h" #include "gpio_event.h" /* Global variable for "/dev/gpio" file descriptor * needed during SIGALRM signal handling */ int gpio_fd = -1; /** * Simple Connect detection event. * * \param ctx managerd context * \return error code */ int simple_connect_event (struct managerd_ctx *ctx) { if (!ctx->is_sc_available) return 0; /* Write SC button GPIO status */ libspid_config_write_item (LIBSPID_HPAV_INFO_PATH, LIBSPID_HPAV_INFO_LABEL_SC_BUTTON, "yes"); /* plc daemon needs to be informed */ if (LIBSPID_SUCCESS != libspid_system_file_update_warn (getpid(), LIBSPID_HPAV_INFO_PATH)) { syslog (LOG_WARNING, "libspid system file update warn failed"); return -1; } return 0; } /** * Open and set GPIO direction. * * \param ctx managerd context * \return error code */ int simple_connect_init (struct managerd_ctx *ctx) { /* Check arguments */ assert (ctx != NULL); /* Set GPIO info for SC button */ ctx->sc_gpio.gpiodir.num = SC_BUT_GPIO_NUM; ctx->sc_gpio.gpiodir.dir = SPC300_GPIO_DIRECTION_INPUT; /* Set GPIO info for SC button interruption */ ctx->sc_it.gpioit.enable = 1; ctx->sc_it.gpioit.mask = (1 << SC_BUT_GPIO_NUM); /* Open GPIO device */ if (0 > (ctx->gpio_fd = open (GPIO_DEVICE_NAME, O_RDWR))) { syslog (LOG_WARNING, "cannot open gpio device (%s)", strerror (errno)); return -1; } /* Set gpio direction for Simple Connect */ if (0 > ioctl (ctx->gpio_fd, GPIOIOC_SETDIRECTION, (unsigned long *) &ctx->sc_gpio)) { syslog (LOG_WARNING, "cannot call ioctl for SC gpio (%s)", strerror (errno)); } else { ctx->is_sc_available = 1; } /* Set GPIO interrupt for SC button */ if (0 > ioctl (ctx->gpio_fd, GPIOIOC_SETIT, (unsigned long *) &ctx->sc_it)) { syslog (LOG_WARNING, "cannot call ioctl for SC interruption (%s)", strerror (errno)); } return 0; } unsigned int simple_connect_button_status_get (struct managerd_ctx *ctx) { if (0 > ioctl (ctx->gpio_fd, GPIOIOC_GETVALUE, (unsigned long *) &ctx->sc_gpio)) { syslog (LOG_WARNING, "cannot call ioctl for SC gpio (%s)", strerror (errno)); return -1; } else { return ctx->sc_gpio.gpioval.val; } } /** * Close gpio device. * * \param ctx managerd context */ void simple_connect_uninit (struct managerd_ctx *ctx) { /* Check arguments */ assert (ctx != NULL); /* Reet GPIO info for SC button interruption */ ctx->sc_it.gpioit.enable = 0; ctx->sc_it.gpioit.mask = 0; /* Reset GPIO interrupt for SC button */ if (0 > ioctl (ctx->gpio_fd, GPIOIOC_SETIT, (unsigned long *) &ctx->sc_it)) { syslog (LOG_WARNING, "cannot call ioctl for SC interruption (%s)", strerror (errno)); } /* Close GPIO device */ close (ctx->gpio_fd); } /** * Handle SIGALRM reception. * * \param signal_nb signal identifier */ void led_signal_handler (int signal_nb) { /* check that we received a SIGALRM signal (other signals must be ignored) */ if (SIGALRM == signal_nb) { led_flashing (); } } /** * When timer expires, this function is called to invert current value of LED, * in order to make it blink. */ void led_flashing (void) { union gpio_info led_gpio; /* Set GPIO number */ led_gpio.gpioval.num = LED_ATTACHMENT_GPIO_NUM; /* Get GPIO value */ if (0 > (ioctl (gpio_fd, GPIOIOC_GETVALUE, (unsigned long *) &led_gpio))) { syslog (LOG_WARNING, "cannot call ioctl GETVALUE for LED GPIO (%s)", strerror (errno)); } /* Invert GPIO value */ if (led_gpio.gpioval.val) led_gpio.gpioval.val = 0; else led_gpio.gpioval.val = 1; /* Set GPIO value */ if (0 > (ioctl (gpio_fd, GPIOIOC_SETVALUE, (unsigned long *) &led_gpio))) { syslog (LOG_WARNING, "cannot call ioctl SETVALUE for LED GPIO (%s)", strerror (errno)); } } /** * LED attachment event. * * \param ctx managerd context * \return error code */ int led_attachment_event (struct managerd_ctx *ctx, const char *status, libspid_boolean_t is_sc) { struct itimerval itv; /* Set default timer interval */ itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; /* Set default current value */ itv.it_value.tv_sec = 0; itv.it_value.tv_usec = 0; /* Check arguments */ assert (NULL != ctx); assert (NULL != status); /* Set GPIO number */ ctx->led_gpio.gpioval.num = LED_ATTACHMENT_GPIO_NUM; if ((LIBSPID_TRUE == ctx->hpav_info.is_sc) && (LIBSPID_FALSE == is_sc) && strcmp (LIBSPID_HPAV_INFO_VALUE_STATUS_AUTHENTICATED, status)) { /* SC has failed: modem is not authenticated after a SC procedure * Fast flashing of the LED: one flash every 100ms * Start timer */ itv.it_interval.tv_usec = LED_FAST_TIMER_US; itv.it_value.tv_usec = LED_FAST_TIMER_US; if (0 > setitimer (ITIMER_REAL, &itv, &itv)) { syslog (LOG_WARNING, "setitimer failed (%s)", strerror (errno)); } } else if (((LIBSPID_FALSE == is_sc) && !strcmp(LIBSPID_HPAV_INFO_VALUE_STATUS_ASSOCIATED, status)) || (LIBSPID_TRUE == is_sc)) { /* Associated (or associating): standard attachment procedure, * or SC is on-going * Low flashing of the LED: one flash every 500ms * Start timer */ itv.it_interval.tv_usec = LED_LOW_TIMER_US; itv.it_value.tv_usec = LED_LOW_TIMER_US; if (0 > setitimer (ITIMER_REAL, &itv, &itv)) { syslog (LOG_WARNING, "setitimer failed (%s)", strerror (errno)); } } else if (!strcmp (LIBSPID_HPAV_INFO_VALUE_STATUS_AUTHENTICATED, status)) { /* Authenticated: modem is attached to an AVLN * Stop timer and set GPIO value */ if (0 > setitimer (ITIMER_REAL, &itv, &itv)) { syslog (LOG_WARNING, "setitimer failed (%s)", strerror (errno)); } ctx->led_gpio.gpioval.val = 1; if (0 > (ioctl (ctx->gpio_fd, GPIOIOC_SETVALUE, (unsigned long *) &ctx->led_gpio))) { syslog (LOG_WARNING, "cannot call ioctl SETVALUE for LED GPIO (%s)", strerror (errno)); } } else if ((LIBSPID_FALSE == is_sc) && !strcmp (LIBSPID_HPAV_INFO_VALUE_STATUS_UNASSOCIATED, status)) { /* Unassociated: modem is on, * but standard attachment procedure has not started (or has failed) * Stop timer and reset GPIO value */ if (0 > setitimer (ITIMER_REAL, &itv, &itv)) { syslog (LOG_WARNING, "setitimer failed (%s)", strerror (errno)); } ctx->led_gpio.gpioval.val = 0; if (0 > (ioctl (ctx->gpio_fd, GPIOIOC_SETVALUE, (unsigned long *) &ctx->led_gpio))) { syslog (LOG_WARNING, "cannot call ioctl SETVALUE for LED GPIO (%s)", strerror (errno)); } } else { syslog (LOG_WARNING, "led_attachment_event: unknown state"); } return 0; } /** * LED1 event. * * \param ctx managerd context * \param cco current CCo value from hpav.info * \return error code */ int led1_event (struct managerd_ctx *ctx, const char *cco) { /* Check arguments */ assert (NULL != ctx); assert (NULL != cco); #if defined (CONFIG_EXTRA_LEDS) /* Set GPIO number */ ctx->led_gpio.gpioval.num = CONFIG_LED1_GPIO_NUM; if (!strcmp (LIBSPID_HPAV_INFO_VALUE_CCO_STATION, cco) || !strcmp (LIBSPID_HPAV_INFO_VALUE_CCO_PROXY, cco)) { /* Simple station or proxy CCo * Reset GPIO value */ ctx->led_gpio.gpioval.val = 0; if (0 > (ioctl (ctx->gpio_fd, GPIOIOC_SETVALUE, (unsigned long *) &ctx->led_gpio))) { syslog (LOG_WARNING, "cannot call ioctl SETVALUE for LED1 GPIO (%s)", strerror (errno)); } } else if (!strcmp (LIBSPID_HPAV_INFO_VALUE_CCO_MAIN, cco)) { /* Main CCo: modem took control of the AVLN * Set GPIO value */ ctx->led_gpio.gpioval.val = 1; if (0 > (ioctl (ctx->gpio_fd, GPIOIOC_SETVALUE, (unsigned long *) &ctx->led_gpio))) { syslog (LOG_WARNING, "cannot call ioctl SETVALUE for LED1 GPIO (%s)", strerror (errno)); } } else { syslog (LOG_WARNING, "led1_event: unknown state"); } #else syslog (LOG_DEBUG, "led1_event: no led1"); #endif return 0; } /** * LED2 event. * * \param ctx managerd context * \param is_backup_cco current backup CCo value from hpav.info * \return error code */ int led2_event (struct managerd_ctx *ctx, libspid_boolean_t is_backup_cco) { /* Check arguments */ assert (NULL != ctx); #if defined (CONFIG_EXTRA_LEDS) /* Set GPIO number */ ctx->led_gpio.gpioval.num = CONFIG_LED2_GPIO_NUM; if (LIBSPID_FALSE == is_backup_cco) { /* Not a backup CCo * Reset GPIO value */ ctx->led_gpio.gpioval.val = 0; if (0 > (ioctl (ctx->gpio_fd, GPIOIOC_SETVALUE, (unsigned long *) &ctx->led_gpio))) { syslog (LOG_WARNING, "cannot call ioctl SETVALUE for LED2 GPIO (%s)", strerror (errno)); } } else if (LIBSPID_TRUE == is_backup_cco) { /* Backup CCo * Set GPIO value */ ctx->led_gpio.gpioval.val = 1; if (0 > (ioctl (ctx->gpio_fd, GPIOIOC_SETVALUE, (unsigned long *) &ctx->led_gpio))) { syslog (LOG_WARNING, "cannot call ioctl SETVALUE for LED2 GPIO (%s)", strerror (errno)); } } else { syslog (LOG_WARNING, "led2_event: unknown state"); } #else syslog (LOG_DEBUG, "led2_event: no led2"); #endif return 0; } /** * Set GPIO direction. * * \param ctx managerd context * \return error code */ int led_init (struct managerd_ctx *ctx) { /* Check arguments */ assert (NULL != ctx); assert (0 <= ctx->gpio_fd); /* Set GPIO direction */ ctx->led_gpio.gpiodir.num = LED_ATTACHMENT_GPIO_NUM; ctx->led_gpio.gpiodir.dir = SPC300_GPIO_DIRECTION_OUTPUT; ctx->led_gpio.gpiodir.val = 0; if (0 > (ioctl (ctx->gpio_fd, GPIOIOC_SETDIRECTION, (unsigned long *) &ctx->led_gpio))) { syslog (LOG_WARNING, "cannot call ioctl SETDIRECTION for LED GPIO (%s)", strerror (errno)); } #if defined (CONFIG_EXTRA_LEDS) /* Set GPIO direction of LED1&2 */ ctx->led_gpio.gpiodir.num = CONFIG_LED1_GPIO_NUM; if (0 > (ioctl (ctx->gpio_fd, GPIOIOC_SETDIRECTION, (unsigned long *) &ctx->led_gpio))) { syslog (LOG_WARNING, "cannot call ioctl SETDIRECTION for LED1 GPIO (%s)", strerror (errno)); } ctx->led_gpio.gpiodir.num = CONFIG_LED2_GPIO_NUM; if (0 > (ioctl (ctx->gpio_fd, GPIOIOC_SETDIRECTION, (unsigned long *) &ctx->led_gpio))) { syslog (LOG_WARNING, "cannot call ioctl SETDIRECTION for LED2 GPIO (%s)", strerror (errno)); } #endif /* Register the SIGALRM signal handler for LED flashing */ if (SIG_ERR == signal (SIGALRM, led_signal_handler)) { syslog (LOG_WARNING, "cannot register led signal handler"); return -1; } /* Set global variable */ gpio_fd = ctx->gpio_fd; return 0; } /** * Reset GPIO value. * * \param ctx managerd context */ void led_uninit (struct managerd_ctx *ctx) { /* Check argument */ assert (ctx != NULL); /* Reset GPIO value */ ctx->led_gpio.gpioval.num = LED_ATTACHMENT_GPIO_NUM; ctx->led_gpio.gpioval.val = 0; if (0 > (ioctl (ctx->gpio_fd, GPIOIOC_SETVALUE, (unsigned long *) &ctx->led_gpio))) { syslog (LOG_WARNING, "cannot call ioctl SETVALUE for LED GPIO (%s)", strerror (errno)); } #if defined (CONFIG_EXTRA_LEDS) /* Reset GPIO value of LED1&2 */ ctx->led_gpio.gpioval.num = CONFIG_LED1_GPIO_NUM; if (0 > (ioctl (ctx->gpio_fd, GPIOIOC_SETVALUE, (unsigned long *) &ctx->led_gpio))) { syslog (LOG_WARNING, "cannot call ioctl SETVALUE for LED1 GPIO (%s)", strerror (errno)); } ctx->led_gpio.gpioval.num = CONFIG_LED2_GPIO_NUM; if (0 > (ioctl (ctx->gpio_fd, GPIOIOC_SETVALUE, (unsigned long *) &ctx->led_gpio))) { syslog (LOG_WARNING, "cannot call ioctl SETVALUE for LED2 GPIO (%s)", strerror (errno)); } #endif }