160 lines
3.5 KiB
C
160 lines
3.5 KiB
C
#include <stdlib.h>
|
|
#include <syslog.h>
|
|
#include <stdbool.h>
|
|
#include <ftdi.h>
|
|
|
|
#include <gpio.h>
|
|
|
|
struct ftdi_obj {
|
|
struct ftdi_context *ftdi;
|
|
bool is_open;
|
|
unsigned int vendor_id;
|
|
unsigned int product_id;
|
|
unsigned char bit_mask;
|
|
};
|
|
|
|
static struct ftdi_obj ftdi_obj = {
|
|
.ftdi = NULL,
|
|
.is_open = false,
|
|
.vendor_id = 0x0403,
|
|
.product_id = 0x6001,
|
|
.bit_mask = 0,
|
|
};
|
|
|
|
static int ftdi_open(void)
|
|
{
|
|
int res;
|
|
|
|
if((ftdi_obj.ftdi = ftdi_new()) == 0) {
|
|
syslog(LOG_ERR, "ftdi_new failed\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
res = ftdi_usb_open(ftdi_obj.ftdi, ftdi_obj.vendor_id, ftdi_obj.product_id);
|
|
if (res < 0 && res != -5) {
|
|
syslog(LOG_ERR, "unable to open ftdi device: %d (%s)\n", res,
|
|
ftdi_get_error_string(ftdi_obj.ftdi));
|
|
ftdi_free(ftdi_obj.ftdi);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int gpio_open(const struct gpio *gpio)
|
|
{
|
|
int res;
|
|
unsigned char init_value = 0;
|
|
bool init_write = false;
|
|
|
|
|
|
if(NULL == gpio) {
|
|
syslog(LOG_ERR, "No valid gpio object given.\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if(!ftdi_obj.is_open) {
|
|
res = ftdi_open();
|
|
if(res != EXIT_SUCCESS) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
init_write = true;
|
|
}
|
|
|
|
ftdi_obj.bit_mask |= (unsigned char)gpio->pin;
|
|
res = ftdi_set_bitmode(ftdi_obj.ftdi, ftdi_obj.bit_mask, BITMODE_BITBANG);
|
|
if(res < 0) {
|
|
syslog(LOG_ERR, "unable to set bit bang mode: %d (%s)\n", res,
|
|
ftdi_get_error_string(ftdi_obj.ftdi));
|
|
ftdi_free(ftdi_obj.ftdi);
|
|
return EXIT_FAILURE;
|
|
}
|
|
ftdi_obj.is_open = true;
|
|
|
|
if(init_write) {
|
|
ftdi_write_data(ftdi_obj.ftdi, &init_value, 1);
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int gpio_close(const struct gpio *gpio)
|
|
{
|
|
if(NULL == gpio) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
unsigned char pin = (unsigned char)gpio->pin;
|
|
ftdi_obj.bit_mask &= ~pin;
|
|
if(ftdi_obj.bit_mask == 0) {
|
|
ftdi_usb_close(ftdi_obj.ftdi);
|
|
ftdi_free(ftdi_obj.ftdi);
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int gpio_read(const struct gpio *gpio, unsigned int *value)
|
|
{
|
|
int res;
|
|
unsigned char buf;
|
|
|
|
if(NULL == gpio || NULL == value) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
res = ftdi_read_data(ftdi_obj.ftdi, &buf, 1);
|
|
if(res < 0) {
|
|
syslog(LOG_ERR, "unable to readfrom ftdi device: %d (%s)\n", res,
|
|
ftdi_get_error_string(ftdi_obj.ftdi));
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if(buf & (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 int current_state;
|
|
unsigned char buf;
|
|
|
|
if(NULL == gpio) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
res = gpio_read(gpio, ¤t_state);
|
|
if(res != EXIT_SUCCESS) {
|
|
syslog(LOG_ERR, "write failed for 0x%x, error %d (%s)\n", value, res,
|
|
ftdi_get_error_string(ftdi_obj.ftdi));
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
buf = (unsigned char)current_state;
|
|
if(value == 0) {
|
|
buf &= ~(unsigned char)(gpio->pin);
|
|
}
|
|
else {
|
|
buf |= (unsigned char)(gpio->pin);
|
|
}
|
|
|
|
res = ftdi_write_data(ftdi_obj.ftdi, &buf, 1);
|
|
if(res < 0) {
|
|
syslog(LOG_ERR, "write failed for 0x%x, error %d (%s)\n", value, res,
|
|
ftdi_get_error_string(ftdi_obj.ftdi));
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
void gpio_toggle(const struct gpio *gpio)
|
|
{
|
|
}
|