From 20b1459a95e9a287e7e552ba0211095a92d1a59a Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Mon, 13 Oct 2008 15:47:52 +0000 Subject: [PATCH] libftdi: (tomj) initial submission of C++ wrapper --- Makefile.am | 2 +- configure.in | 2 +- ftdipp/Makefile.am | 12 ++ ftdipp/ftdi.cpp | 423 ++++++++++++++++++++++++++++++++++++++++++++++++++++ ftdipp/ftdi.hpp | 160 ++++++++++++++++++++ libftdipp.pc.in | 11 ++ 6 files changed, 608 insertions(+), 2 deletions(-) create mode 100644 ftdipp/Makefile.am create mode 100644 ftdipp/ftdi.cpp create mode 100644 ftdipp/ftdi.hpp create mode 100644 libftdipp.pc.in diff --git a/Makefile.am b/Makefile.am index 801ccf5..9c6cb10 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ # have all needed files, that a GNU package needs AUTOMAKE_OPTIONS = foreign 1.4 -SUBDIRS = src examples doc +SUBDIRS = src ftdipp examples doc EXTRA_DIST = libftdi.spec libftdi.spec.in COPYING.LIB README AUTHORS ChangeLog libftdi-config.in diff --git a/configure.in b/configure.in index ac62645..4ea7482 100644 --- a/configure.in +++ b/configure.in @@ -52,4 +52,4 @@ AC_PATH_PROG(DOXYGEN, doxygen) AM_CONDITIONAL(HAVE_DOXYGEN, test -n $DOXYGEN) AC_OUTPUT([libftdi-config],[chmod a+x libftdi-config]) -AC_OUTPUT(Makefile src/Makefile examples/Makefile doc/Doxyfile doc/Makefile libftdi.pc libftdi.spec) +AC_OUTPUT(Makefile src/Makefile ftdipp/Makefile examples/Makefile doc/Doxyfile doc/Makefile libftdi.pc libftdipp.pc libftdi.spec) diff --git a/ftdipp/Makefile.am b/ftdipp/Makefile.am new file mode 100644 index 0000000..a06822c --- /dev/null +++ b/ftdipp/Makefile.am @@ -0,0 +1,12 @@ +# set the include path found by configure +INCLUDES= -I$(top_srcdir)/src $(all_includes) + +# the library search path. +lib_LTLIBRARIES = libftdipp.la +include_HEADERS = ftdi.hpp +libftdipp_la_SOURCES = $(top_builddir)/src/libftdi.la ftdi.cpp + +# Note: If you specify a:b:c as the version in the next line, +# the library that is made has version (a-c).c.b. In this +# example, the version is 2.1.2. (3:2:1) +libftdipp_la_LDFLAGS = -version-info 15:0:14 $(all_libraries) diff --git a/ftdipp/ftdi.cpp b/ftdipp/ftdi.cpp new file mode 100644 index 0000000..0515f56 --- /dev/null +++ b/ftdipp/ftdi.cpp @@ -0,0 +1,423 @@ +#include "ftdi.hpp" +#include "ftdi.h" + +namespace Ftdi +{ + +class Context::Private +{ + public: + Private() + : ftdi(0), dev(0), open(false) + {} + + bool open; + + struct ftdi_context* ftdi; + struct usb_device* dev; + + std::string vendor; + std::string description; + std::string serial; +}; + +/*! \brief Constructor. + */ +Context::Context() + : d( new Private() ) +{ + d->ftdi = ftdi_new(); +} + +/*! \brief Destructor. + */ +Context::~Context() +{ + if(d->open) + close(); + + ftdi_free(d->ftdi); + delete d; +} + +bool Context::is_open() +{ + return d->open; +} + +int Context::open(int vendor, int product, const std::string& description, const std::string& serial) +{ + int ret = 0; + if(description.empty() && serial.empty()) + ret = ftdi_usb_open(d->ftdi, vendor, product); + else + ret = ftdi_usb_open_desc(d->ftdi, vendor, product, description.c_str(), serial.c_str()); + + d->dev = usb_device(d->ftdi->usb_dev); + + if((ret = ftdi_usb_open_dev(d->ftdi, d->dev)) >= 0) + { + d->open = true; + get_strings(); + } + + return ret; +} + +int Context::open(struct usb_device *dev) +{ + int ret = 0; + + if(dev != 0) + d->dev = dev; + + if(d->dev == 0) + return -1; + + if((ret = ftdi_usb_open_dev(d->ftdi, d->dev)) >= 0) + { + d->open = true; + get_strings(); + } + + return ret; +} + +int Context::close() +{ + d->open = false; + return ftdi_usb_close(d->ftdi); +} + +int Context::reset() +{ + return ftdi_usb_reset(d->ftdi); +} + +int Context::flush(int mask) +{ + int ret = 1; + if(mask & Input) + ret &= ftdi_usb_purge_rx_buffer(d->ftdi); + if(mask & Output) + ret &= ftdi_usb_purge_tx_buffer(d->ftdi); + + return ret; +} + +int Context::set_interface(enum ftdi_interface interface) +{ + return ftdi_set_interface(d->ftdi, interface); +} + +void Context::set_usb_device(struct usb_dev_handle *dev) +{ + ftdi_set_usbdev(d->ftdi, dev); + d->dev = usb_device(dev); +} + +int Context::set_baud_rate(int baudrate) +{ + return ftdi_set_baudrate(d->ftdi, baudrate); +} + +int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity) +{ + return ftdi_set_line_property(d->ftdi, bits, sbit, parity); +} + +int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity, enum ftdi_break_type break_type) +{ + return ftdi_set_line_property2(d->ftdi, bits, sbit, parity, break_type); +} + +int Context::read(unsigned char *buf, int size) +{ + return ftdi_read_data(d->ftdi, buf, size); +} + +int Context::set_read_chunk_size(unsigned int chunksize) +{ + return ftdi_read_data_set_chunksize(d->ftdi, chunksize); +} + +int Context::read_chunk_size() +{ + unsigned chunk = -1; + if(ftdi_read_data_get_chunksize(d->ftdi, &chunk) < 0) + return -1; + + return chunk; +} + + +int Context::write(unsigned char *buf, int size) +{ + return ftdi_write_data(d->ftdi, buf, size); +} + +int Context::set_write_chunk_size(unsigned int chunksize) +{ + return ftdi_write_data_set_chunksize(d->ftdi, chunksize); +} + +int Context::write_chunk_size() +{ + unsigned chunk = -1; + if(ftdi_write_data_get_chunksize(d->ftdi, &chunk) < 0) + return -1; + + return chunk; +} + +int Context::set_flow_control(int flowctrl) +{ + return ftdi_setflowctrl(d->ftdi, flowctrl); +} + +int Context::set_modem_control(int mask) +{ + int dtr = 0, rts = 0; + + if(mask & Dtr) + dtr = 1; + if(mask & Rts) + rts = 1; + + return ftdi_setdtr_rts(d->ftdi, dtr, rts); +} + +int Context::set_dtr(bool state) +{ + return ftdi_setdtr(d->ftdi, state); +} + +int Context::set_rts(bool state) +{ + return ftdi_setrts(d->ftdi, state); +} + +int Context::set_latency(unsigned char latency) +{ + return ftdi_set_latency_timer(d->ftdi, latency); +} + +unsigned Context::latency() +{ + unsigned char latency = 0; + ftdi_get_latency_timer(d->ftdi, &latency); + return latency; +} + +unsigned short Context::poll_modem_status() +{ + unsigned short status = 0; + ftdi_poll_modem_status(d->ftdi, &status); + return status; +} + + +int Context::set_event_char(unsigned char eventch, unsigned char enable) +{ + return ftdi_set_event_char(d->ftdi, eventch, enable); +} + +int Context::set_error_char(unsigned char errorch, unsigned char enable) +{ + return ftdi_set_error_char(d->ftdi, errorch, enable); +} + +int Context::bitbang_enable(unsigned char bitmask) +{ + return ftdi_enable_bitbang(d->ftdi, bitmask); +} + +int Context::bitbang_disable() +{ + return ftdi_disable_bitbang(d->ftdi); +} + +int Context::set_bitmode(unsigned char bitmask, unsigned char mode) +{ + return ftdi_set_bitmode(d->ftdi, bitmask, mode); +} + +int Context::read_pins(unsigned char *pins) +{ + return ftdi_read_pins(d->ftdi, pins); +} + +char* Context::error_string() +{ + return ftdi_get_error_string(d->ftdi); +} + +int Context::get_strings() +{ + // Prepare buffers + char vendor[512], desc[512], serial[512]; + + int ret = ftdi_usb_get_strings(d->ftdi, d->dev, vendor, 512, desc, 512, serial, 512); + + if(ret < 0) + return -1; + + d->vendor = vendor; + d->description = desc; + d->serial = serial; + + return 1; +} + +/*! \fn vendor + * \fn description + * \fn serial + * \brief Device strings properties. + */ +const std::string& Context::vendor() +{ + return d->vendor; +} + +const std::string& Context::description() +{ + return d->description; +} + +const std::string& Context::serial() +{ + return d->serial; +} + +void Context::set_context(struct ftdi_context* context) +{ + ftdi_free(d->ftdi); + d->ftdi = context; +} + +void Context::set_usb_device(struct usb_device *dev) +{ + d->dev = dev; +} + +struct ftdi_context* Context::context() +{ + return d->ftdi; +} + +class Eeprom::Private +{ + public: + Private() + : context(0) + {} + + struct ftdi_eeprom eeprom; + struct ftdi_context* context; +}; + +Eeprom::Eeprom(Context* parent) + : d ( new Private() ) +{ + d->context = parent->context(); +} + +Eeprom::~Eeprom() +{ + delete d; +} + +void Eeprom::init_defaults() +{ + return ftdi_eeprom_initdefaults(&d->eeprom); +} + +void Eeprom::set_size(int size) +{ + return ftdi_eeprom_setsize(d->context, &d->eeprom, size); +} + +int Eeprom::size(unsigned char *eeprom, int maxsize) +{ + return ftdi_read_eeprom_getsize(d->context, eeprom, maxsize); +} + +int Eeprom::chip_id(unsigned int *chipid) +{ + return ftdi_read_chipid(d->context, chipid); +} + +int Eeprom::build(unsigned char *output) +{ + return ftdi_eeprom_build(&d->eeprom, output); +} + +int Eeprom::read(unsigned char *eeprom) +{ + return ftdi_read_eeprom(d->context, eeprom); +} + +int Eeprom::write(unsigned char *eeprom) +{ + return ftdi_write_eeprom(d->context, eeprom); +} + +int Eeprom::erase() +{ + return ftdi_erase_eeprom(d->context); +} + +class List::Private +{ + public: + Private() + : list(0) + {} + + struct ftdi_device_list* list; +}; + +List::List(struct ftdi_device_list* devlist) + : ListBase(), d( new Private() ) +{ + if(devlist != 0) + { + // Iterate list + Context* c = 0; + for(d->list = devlist; d->list != 0; d->list = d->list->next) + { + c = new Context(); + c->set_usb_device(d->list->dev); + push_back(c); + } + + // Store pointer + d->list = devlist; + } +} + +List::~List() +{ + // Deallocate instances + for(iterator it = begin(); it != end(); it++) + delete *it; + + // Clear list + clear(); + ftdi_list_free(&d->list); + + // Delete d-ptr + delete d; +} + +List* List::find_all(int vendor, int product) +{ + struct ftdi_device_list* dlist = 0; + struct ftdi_context ftdi; + ftdi_init(&ftdi); + ftdi_usb_find_all(&ftdi, &dlist, vendor, product); + ftdi_deinit(&ftdi); + return new List(dlist); +} + +} diff --git a/ftdipp/ftdi.hpp b/ftdipp/ftdi.hpp new file mode 100644 index 0000000..7b6a9a0 --- /dev/null +++ b/ftdipp/ftdi.hpp @@ -0,0 +1,160 @@ +#ifndef FTDICPP_H +#define FTDICPP_H + +#include +#include +#include "ftdi.h" + +namespace Ftdi +{ + +/* Forward declarations*/ +class List; +class Eeprom; + +/*! \brief FTDI device context. + * Represents single FTDI device context. + */ +class Context +{ + /* Friends */ + friend class Eeprom; + friend class List; + + public: + + /*! \brief Direction flags for flush(). + */ + enum Direction + { + Input, + Output + }; + + /*! \brief Modem control flags. + */ + enum ModemCtl + { + Dtr, + Rts + }; + + /* Constructor, Destructor */ + Context(); + ~Context(); + + /* Properties */ + Eeprom* eeprom(); + const std::string& vendor(); + const std::string& description(); + const std::string& serial(); + + /* Device manipulators */ + bool is_open(); + int open(struct usb_device *dev = 0); + int open(int vendor, int product, const std::string& description = std::string(), const std::string& serial = std::string()); + int close(); + int reset(); + int flush(int mask = Input|Output); + int set_interface(enum ftdi_interface interface); + void set_usb_device(struct usb_dev_handle *dev); + + /* Line manipulators */ + int set_baud_rate(int baudrate); + int set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity); + int set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity, enum ftdi_break_type break_type); + + /* I/O */ + int read(unsigned char *buf, int size); + int write(unsigned char *buf, int size); + int set_read_chunk_size(unsigned int chunksize); + int set_write_chunk_size(unsigned int chunksize); + int read_chunk_size(); + int write_chunk_size(); + + /* Async IO + TODO: should wrap? + int writeAsync(unsigned char *buf, int size); + void asyncComplete(int wait_for_more); + */ + + /* Flow control */ + int set_event_char(unsigned char eventch, unsigned char enable); + int set_error_char(unsigned char errorch, unsigned char enable); + int set_flow_control(int flowctrl); + int set_modem_control(int mask = Dtr|Rts); + int set_latency(unsigned char latency); + int set_dtr(bool state); + int set_rts(bool state); + + unsigned short poll_modem_status(); + unsigned latency(); + + /* BitBang mode */ + int set_bitmode(unsigned char bitmask, unsigned char mode); + int bitbang_enable(unsigned char bitmask); + int bitbang_disable(); + int read_pins(unsigned char *pins); + + /* Misc */ + char* error_string(); + + protected: + int get_strings(); + + /* Properties */ + struct ftdi_context* context(); + void set_context(struct ftdi_context* context); + void set_usb_device(struct usb_device *dev); + + private: + class Private; + Private *d; + + /* Disable copy constructor */ + Context(const Context &) {} + Context& operator=(const Context &) {} +}; + +/*! \brief Device EEPROM. + */ +class Eeprom +{ + public: + Eeprom(Context* parent); + ~Eeprom(); + + void init_defaults(); + void set_size(int size); + int size(unsigned char *eeprom, int maxsize); + int chip_id(unsigned int *chipid); + int build(unsigned char *output); + int read(unsigned char *eeprom); + int write(unsigned char *eeprom); + int erase(); + + private: + class Private; + Private *d; +}; + +typedef std::list ListBase; + +/*! \brief Device list. + */ +class List : public ListBase +{ + public: + List(struct ftdi_device_list* devlist = 0); + ~List(); + + static List* find_all(int vendor, int product); + + private: + class Private; + Private *d; +}; + +} + +#endif diff --git a/libftdipp.pc.in b/libftdipp.pc.in new file mode 100644 index 0000000..ee81fef --- /dev/null +++ b/libftdipp.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libftdipp +Description: C++ wrapper for libftdi +Requires: libftdi +Version: @VERSION@ +Libs: -L${libdir} -lftdipp +Cflags: -I${includedir} -- 1.7.1