#include #include #include #include #include static int ftdi_open(const struct gpio *gpio) { int res; if((gpio->ftdi_dev->ftdi = ftdi_new()) == 0) { syslog(LOG_ERR, "ftdi_new failed\n"); return EXIT_FAILURE; } res = ftdi_usb_open(gpio->ftdi_dev->ftdi, gpio->ftdi_dev->vendor_id, gpio->ftdi_dev->product_id); if (res < 0 && res != -5) { syslog(LOG_ERR, "unable to open ftdi device: %d (%s)\n", res, ftdi_get_error_string(gpio->ftdi_dev->ftdi)); ftdi_free(gpio->ftdi_dev->ftdi); return EXIT_FAILURE; } res = ftdi_read_data(gpio->ftdi_dev->ftdi, &(gpio->ftdi_dev->status_mask), 1); if(res < 0) { syslog(LOG_ERR, "unable to readfrom ftdi device: %d (%s)\n", res, ftdi_get_error_string(gpio->ftdi_dev->ftdi)); return EXIT_FAILURE; } return EXIT_SUCCESS; } int gpio_open(const struct gpio *gpio) { int res; unsigned int init_value = 0; if(NULL == gpio) { syslog(LOG_ERR, "No valid gpio object given.\n"); return EXIT_FAILURE; } if(!gpio->ftdi_dev->is_open) { res = ftdi_open(gpio); if(res != EXIT_SUCCESS) { return EXIT_FAILURE; } } gpio->ftdi_dev->bit_mask |= (unsigned char)gpio->pin; syslog(LOG_DEBUG, "bitmask: 0x%02x\n", gpio->ftdi_dev->bit_mask); res = ftdi_set_bitmode(gpio->ftdi_dev->ftdi, gpio->ftdi_dev->bit_mask, BITMODE_BITBANG); if(res < 0) { syslog(LOG_ERR, "unable to set bit bang mode: %d (%s)\n", res, ftdi_get_error_string(gpio->ftdi_dev->ftdi)); ftdi_usb_close(gpio->ftdi_dev->ftdi); ftdi_free(gpio->ftdi_dev->ftdi); return EXIT_FAILURE; } res = gpio_write(gpio, init_value); if(res < 0) { syslog(LOG_ERR, "unable to write to gpio %u (%s)\n", gpio->pin, ftdi_get_error_string(gpio->ftdi_dev->ftdi)); ftdi_usb_close(gpio->ftdi_dev->ftdi); ftdi_free(gpio->ftdi_dev->ftdi); return EXIT_FAILURE; } gpio->ftdi_dev->is_open = true; return EXIT_SUCCESS; } int gpio_close(const struct gpio *gpio) { if(NULL == gpio) { return EXIT_FAILURE; } gpio_write(gpio, 0); gpio->ftdi_dev->bit_mask &= ~(unsigned char)(gpio->pin); if(gpio->ftdi_dev->bit_mask == 0) { ftdi_usb_close(gpio->ftdi_dev->ftdi); ftdi_free(gpio->ftdi_dev->ftdi); } return EXIT_SUCCESS; } int gpio_read(const struct gpio *gpio, unsigned int *value) { if(NULL == gpio || NULL == value) { return EXIT_FAILURE; } if(gpio->ftdi_dev->status_mask & (unsigned char)(gpio->pin)) { *value = 1; } else { *value = 0; } return EXIT_SUCCESS; } int gpio_write(const struct gpio *gpio, unsigned int value) { int res; unsigned char mask = gpio->ftdi_dev->status_mask; if(NULL == gpio) { return EXIT_FAILURE; } if(value == 0) { mask &= ~(unsigned char)(gpio->pin); } else { mask |= (unsigned char)(gpio->pin); } res = ftdi_write_data(gpio->ftdi_dev->ftdi, &mask, 1); if(res < 0) { syslog(LOG_ERR, "write failed for 0x%x, error %d (%s)\n", value, res, ftdi_get_error_string(gpio->ftdi_dev->ftdi)); return EXIT_FAILURE; } gpio->ftdi_dev->status_mask = mask; return EXIT_SUCCESS; } int gpio_toggle(const struct gpio *gpio) { int res; unsigned char mask = gpio->ftdi_dev->status_mask; if(NULL == gpio) { return EXIT_FAILURE; } mask ^= (unsigned char)(gpio->pin); res = ftdi_write_data(gpio->ftdi_dev->ftdi, &mask, 1); if(res < 0) { syslog(LOG_ERR, "toggle failed, error %d (%s)\n", res, ftdi_get_error_string(gpio->ftdi_dev->ftdi)); return EXIT_FAILURE; } gpio->ftdi_dev->status_mask = mask; return EXIT_SUCCESS; }