156 lines
3.9 KiB
C
156 lines
3.9 KiB
C
#include <stdlib.h>
|
|
#include <syslog.h>
|
|
#include <stdbool.h>
|
|
#include <ftdi_dev.h>
|
|
|
|
#include <gpio.h>
|
|
|
|
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;
|
|
}
|