C++程序  |  1152行  |  29.6 KB

/*
 *Copyright (C) 2015 The Android Open Source Project
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
 *
 * This file was copied from https://github.com/devttys0/libmpsse.git (sha1
 * f1a6744b), and modified to suite the Chromium OS project.
 *
 * Main libmpsse source file.
 *
 * Craig Heffner
 * 27 December 2011
 */

#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>

#include "trunks/ftdi/support.h"

/* List of known FT2232-based devices */
struct vid_pid supported_devices[] = {
    {0x0403, 0x6010, "FT2232 Future Technology Devices International, Ltd"},
    {0x0403, 0x6011, "FT4232 Future Technology Devices International, Ltd"},
    {0x0403, 0x6014, "FT232H Future Technology Devices International, Ltd"},

    /* These devices are based on FT2232 chips, but have not been tested. */
    {0x0403, 0x8878, "Bus Blaster v2 (channel A)"},
    {0x0403, 0x8879, "Bus Blaster v2 (channel B)"},
    {0x0403, 0xBDC8, "Turtelizer JTAG/RS232 Adapter A"},
    {0x0403, 0xCFF8, "Amontec JTAGkey"},
    {0x0403, 0x8A98, "TIAO Multi Protocol Adapter"},
    {0x15BA, 0x0003, "Olimex Ltd. OpenOCD JTAG"},
    {0x15BA, 0x0004, "Olimex Ltd. OpenOCD JTAG TINY"},

    {0, 0, NULL}};

/*
 * Opens and initializes the first FTDI device found.
 *
 * @mode      - Mode to open the device in. One of enum modes.
 * @freq      - Clock frequency to use for the specified mode.
 * @endianess - Specifies how data is clocked in/out (MSB, LSB).
 *
 * Returns a pointer to an MPSSE context structure if succeeded, NULL otherwise.
 */
struct mpsse_context* MPSSE(enum modes mode, int freq, int endianess) {
  int i = 0;
  struct mpsse_context* mpsse = NULL;

  for (i = 0; supported_devices[i].vid != 0; i++) {
    mpsse = Open(supported_devices[i].vid, supported_devices[i].pid, mode,
                 freq, endianess, IFACE_A, NULL, NULL);
    if (mpsse) {
      mpsse->description = supported_devices[i].description;
      return mpsse;
    }
  }

  return NULL;
}

/*
 * Open device by VID/PID
 *
 * @vid         - Device vendor ID.
 * @pid         - Device product ID.
 * @mode        - MPSSE mode, one of enum modes.
 * @freq        - Clock frequency to use for the specified mode.
 * @endianess   - Specifies how data is clocked in/out (MSB, LSB).
 * @interface   - FTDI interface to use (IFACE_A - IFACE_D).
 * @description - Device product description (set to NULL if not needed).
 * @serial      - Device serial number (set to NULL if not needed).
 *
 * Returns a pointer to an MPSSE context structure on success.
 */
struct mpsse_context* Open(int vid,
                           int pid,
                           enum modes mode,
                           int freq,
                           int endianess,
                           int interface,
                           const char* description,
                           const char* serial) {
  return OpenIndex(vid, pid, mode, freq, endianess, interface, description,
                   serial, 0);
}

/*
 * Open device by VID/PID/index
 *
 * @vid         - Device vendor ID.
 * @pid         - Device product ID.
 * @mode        - MPSSE mode, one of enum modes.
 * @freq        - Clock frequency to use for the specified mode.
 * @endianess   - Specifies how data is clocked in/out (MSB, LSB).
 * @interface   - FTDI interface to use (IFACE_A - IFACE_D).
 * @description - Device product description (set to NULL if not needed).
 * @serial      - Device serial number (set to NULL if not needed).
 * @index       - Device index (set to 0 if not needed).
 *
 * Returns a pointer to an MPSSE context structure.
 * On success, mpsse->open will be set to 1.
 * On failure, mpsse->open will be set to 0.
 */
struct mpsse_context* OpenIndex(int vid,
                                int pid,
                                enum modes mode,
                                int freq,
                                int endianess,
                                int interface,
                                const char* description,
                                const char* serial,
                                int index) {
  int status = 0;
  struct mpsse_context* mpsse = NULL;

  mpsse = malloc(sizeof(struct mpsse_context));
  if (!mpsse)
    return NULL;

  memset(mpsse, 0, sizeof(struct mpsse_context));

  /* Legacy; flushing is no longer needed, so disable it by default. */
  FlushAfterRead(mpsse, 0);

  /* ftdilib initialization */
  if (ftdi_init(&mpsse->ftdi)) {
    free(mpsse);
    return NULL;
  }

  /* Set the FTDI interface  */
  ftdi_set_interface(&mpsse->ftdi, interface);

  /* Open the specified device */
  if (!ftdi_usb_open_desc_index(&mpsse->ftdi, vid, pid, description, serial,
                                index)) {
    mpsse->mode = mode;
    mpsse->vid = vid;
    mpsse->pid = pid;
    mpsse->status = STOPPED;
    mpsse->endianess = endianess;

    /* Set the appropriate transfer size for the requested protocol */
    if (mpsse->mode == I2C)
      mpsse->xsize = I2C_TRANSFER_SIZE;
    else
      mpsse->xsize = SPI_RW_SIZE;

    status |= ftdi_usb_reset(&mpsse->ftdi);
    status |= ftdi_set_latency_timer(&mpsse->ftdi, LATENCY_MS);
    status |= ftdi_write_data_set_chunksize(&mpsse->ftdi, CHUNK_SIZE);
    status |= ftdi_read_data_set_chunksize(&mpsse->ftdi, CHUNK_SIZE);
    status |= ftdi_set_bitmode(&mpsse->ftdi, 0, BITMODE_RESET);

    if (status == 0) {
      /* Set the read and write timeout periods */
      set_timeouts(mpsse, USB_TIMEOUT);

      if (mpsse->mode != BITBANG) {
        ftdi_set_bitmode(&mpsse->ftdi, 0, BITMODE_MPSSE);

        if (SetClock(mpsse, freq) == MPSSE_OK) {
          if (SetMode(mpsse, endianess) == MPSSE_OK) {
            mpsse->opened = 1;

            /* Give the chip a few mS to initialize */
            usleep(SETUP_DELAY);

            /*
             * Not all FTDI chips support all the commands that SetMode may
             * have sent.
             * This clears out any errors from unsupported commands that
             * might have been sent during set up.
             */
            ftdi_usb_purge_buffers(&mpsse->ftdi);
          }
        }
      } else {
        /* Skip the setup functions if we're just operating in BITBANG mode
         */
        if (!ftdi_set_bitmode(&mpsse->ftdi, 0xFF, BITMODE_BITBANG))
          mpsse->opened = 1;
      }
    }
  }

  if (mpsse && !mpsse->opened) {
    Close(mpsse);
    mpsse = NULL;
  }

  return mpsse;
}

/*
 * Closes the device, deinitializes libftdi, and frees the MPSSE context
 *pointer.
 *
 * @mpsse - MPSSE context pointer.
 *
 * Returns void.
 */
void Close(struct mpsse_context* mpsse) {
  if (!mpsse)
    return;

  if (mpsse->opened) {
    /* Shut these down only if initialization succeeded before. */
    ftdi_set_bitmode(&mpsse->ftdi, 0, BITMODE_RESET);
    ftdi_usb_close(&mpsse->ftdi);
  }
  ftdi_deinit(&mpsse->ftdi);
  free(mpsse);
}

/* Enables bit-wise data transfers.
 * Must be called after MPSSE() / Open() / OpenIndex().
 *
 * Returns void.
 */
void EnableBitmode(struct mpsse_context* mpsse, int tf) {
  if (is_valid_context(mpsse)) {
    if (tf) {
      mpsse->tx |= MPSSE_BITMODE;
      mpsse->rx |= MPSSE_BITMODE;
      mpsse->txrx |= MPSSE_BITMODE;
    } else {
      mpsse->tx &= ~MPSSE_BITMODE;
      mpsse->rx &= ~MPSSE_BITMODE;
      mpsse->txrx &= ~MPSSE_BITMODE;
    }
  }
}

/*
 * Sets the appropriate transmit and receive commands based on the requested
 *mode and byte order.
 *
 * @mpsse     - MPSSE context pointer.
 * @endianess - MPSSE_MSB or MPSSE_LSB.
 *
 * Returns MPSSE_OK on success.
 * Returns MPSSE_FAIL on failure.
 */
int SetMode(struct mpsse_context* mpsse, int endianess) {
  int retval = MPSSE_OK, i = 0, setup_commands_size = 0;
  uint8_t buf[CMD_SIZE] = {0};
  uint8_t setup_commands[CMD_SIZE * MAX_SETUP_COMMANDS] = {0};

  /* Do not call is_valid_context() here, as the FTDI chip may not be completely
   * configured when SetMode is called */
  if (mpsse) {
    /* Read and write commands need to include endianess */
    mpsse->tx = MPSSE_DO_WRITE | endianess;
    mpsse->rx = MPSSE_DO_READ | endianess;
    mpsse->txrx = MPSSE_DO_WRITE | MPSSE_DO_READ | endianess;

    /* Clock, data out, chip select pins are outputs; all others are inputs. */
    mpsse->tris = DEFAULT_TRIS;

    /* Clock and chip select pins idle high; all others are low */
    mpsse->pidle = mpsse->pstart = mpsse->pstop = DEFAULT_PORT;

    /* During reads and writes the chip select pin is brought low */
    mpsse->pstart &= ~CS;

    /* Disable FTDI internal loopback */
    SetLoopback(mpsse, 0);

    /* Send ACKs by default */
    SetAck(mpsse, ACK);

    /* Ensure adaptive clock is disabled */
    setup_commands[setup_commands_size++] = DISABLE_ADAPTIVE_CLOCK;

    switch (mpsse->mode) {
      case SPI0:
        /* SPI mode 0 clock idles low */
        mpsse->pidle &= ~SK;
        mpsse->pstart &= ~SK;
        mpsse->pstop &= ~SK;
        /* SPI mode 0 propogates data on the falling edge and read data on the
         * rising edge of the clock */
        mpsse->tx |= MPSSE_WRITE_NEG;
        mpsse->rx &= ~MPSSE_READ_NEG;
        mpsse->txrx |= MPSSE_WRITE_NEG;
        mpsse->txrx &= ~MPSSE_READ_NEG;
        break;
      case SPI3:
        /* SPI mode 3 clock idles high */
        mpsse->pidle |= SK;
        mpsse->pstart |= SK;
        /* Keep the clock low while the CS pin is brought high to ensure we
         * don't accidentally clock out an extra bit */
        mpsse->pstop &= ~SK;
        /* SPI mode 3 propogates data on the falling edge and read data on the
         * rising edge of the clock */
        mpsse->tx |= MPSSE_WRITE_NEG;
        mpsse->rx &= ~MPSSE_READ_NEG;
        mpsse->txrx |= MPSSE_WRITE_NEG;
        mpsse->txrx &= ~MPSSE_READ_NEG;
        break;
      case SPI1:
        /* SPI mode 1 clock idles low */
        mpsse->pidle &= ~SK;
        /* Since this mode idles low, the start condition should ensure that the
         * clock is low */
        mpsse->pstart &= ~SK;
        /* Even though we idle low in this mode, we need to keep the clock line
         * high when we set the CS pin high to prevent
         * an unintended clock cycle from being sent by the FT2232. This way,
         * the clock goes high, but does not go low until
         * after the CS pin goes high.
         */
        mpsse->pstop |= SK;
        /* Data read on falling clock edge */
        mpsse->rx |= MPSSE_READ_NEG;
        mpsse->tx &= ~MPSSE_WRITE_NEG;
        mpsse->txrx |= MPSSE_READ_NEG;
        mpsse->txrx &= ~MPSSE_WRITE_NEG;
        break;
      case SPI2:
        /* SPI 2 clock idles high */
        mpsse->pidle |= SK;
        mpsse->pstart |= SK;
        mpsse->pstop |= SK;
        /* Data read on falling clock edge */
        mpsse->rx |= MPSSE_READ_NEG;
        mpsse->tx &= ~MPSSE_WRITE_NEG;
        mpsse->txrx |= MPSSE_READ_NEG;
        mpsse->txrx &= ~MPSSE_WRITE_NEG;
        break;
      case I2C:
        /* I2C propogates data on the falling clock edge and reads data on the
         * falling (or rising) clock edge */
        mpsse->tx |= MPSSE_WRITE_NEG;
        mpsse->rx &= ~MPSSE_READ_NEG;
        /* In I2C, both the clock and the data lines idle high */
        mpsse->pidle |= DO | DI;
        /* I2C start bit == data line goes from high to low while clock line is
         * high */
        mpsse->pstart &= ~DO & ~DI;
        /* I2C stop bit == data line goes from low to high while clock line is
         * high - set data line low here, so the transition to the idle state
         * triggers the stop condition. */
        mpsse->pstop &= ~DO & ~DI;
        /* Enable three phase clock to ensure that I2C data is available on both
         * the rising and falling clock edges */
        setup_commands[setup_commands_size++] = ENABLE_3_PHASE_CLOCK;
        break;
      case GPIO:
        break;
      default:
        retval = MPSSE_FAIL;
    }

    /* Send any setup commands to the chip */
    if (retval == MPSSE_OK && setup_commands_size > 0) {
      retval = raw_write(mpsse, setup_commands, setup_commands_size);
    }

    if (retval == MPSSE_OK) {
      /* Set the idle pin states */
      set_bits_low(mpsse, mpsse->pidle);

      /* All GPIO pins are outputs, set low */
      mpsse->trish = 0xFF;
      mpsse->gpioh = 0x00;

      buf[i++] = SET_BITS_HIGH;
      buf[i++] = mpsse->gpioh;
      buf[i++] = mpsse->trish;

      retval = raw_write(mpsse, buf, i);
    }
  } else {
    retval = MPSSE_FAIL;
  }

  return retval;
}

/*
 * Sets the appropriate divisor for the desired clock frequency.
 *
 * @mpsse - MPSSE context pointer.
 * @freq  - Desired clock frequency in hertz.
 *
 * Returns MPSSE_OK on success.
 * Returns MPSSE_FAIL on failure.
 */
int SetClock(struct mpsse_context* mpsse, uint32_t freq) {
  int retval = MPSSE_FAIL;
  uint32_t system_clock = 0;
  uint16_t divisor = 0;
  uint8_t buf[CMD_SIZE] = {0};

  /* Do not call is_valid_context() here, as the FTDI chip may not be completely
   * configured when SetClock is called */
  if (mpsse) {
    if (freq > SIX_MHZ) {
      buf[0] = TCK_X5;
      system_clock = SIXTY_MHZ;
    } else {
      buf[0] = TCK_D5;
      system_clock = TWELVE_MHZ;
    }

    if (raw_write(mpsse, buf, 1) == MPSSE_OK) {
      if (freq <= 0) {
        divisor = 0xFFFF;
      } else {
        divisor = freq2div(system_clock, freq);
      }

      buf[0] = TCK_DIVISOR;
      buf[1] = (divisor & 0xFF);
      buf[2] = ((divisor >> 8) & 0xFF);

      if (raw_write(mpsse, buf, 3) == MPSSE_OK) {
        mpsse->clock = div2freq(system_clock, divisor);
        retval = MPSSE_OK;
      }
    }
  }

  return retval;
}

/*
 * Retrieves the last error string from libftdi.
 *
 * @mpsse - MPSSE context pointer.
 *
 * Returns a pointer to the last error string.
 */
const char* ErrorString(struct mpsse_context* mpsse) {
  if (mpsse != NULL) {
    return ftdi_get_error_string(&mpsse->ftdi);
  }

  return NULL_CONTEXT_ERROR_MSG;
}

/*
 * Gets the currently configured clock rate.
 *
 * @mpsse - MPSSE context pointer.
 *
 * Returns the existing clock rate in hertz.
 */
int GetClock(struct mpsse_context* mpsse) {
  int clock = 0;

  if (is_valid_context(mpsse)) {
    clock = mpsse->clock;
  }

  return clock;
}

/*
 * Returns the vendor ID of the FTDI chip.
 *
 * @mpsse - MPSSE context pointer.
 *
 * Returns the integer value of the vendor ID.
 */
int GetVid(struct mpsse_context* mpsse) {
  int vid = 0;

  if (is_valid_context(mpsse)) {
    vid = mpsse->vid;
  }

  return vid;
}

/*
 * Returns the product ID of the FTDI chip.
 *
 * @mpsse - MPSSE context pointer.
 *
 * Returns the integer value of the product ID.
 */
int GetPid(struct mpsse_context* mpsse) {
  int pid = 0;

  if (is_valid_context(mpsse)) {
    pid = mpsse->pid;
  }

  return pid;
}

/*
 * Returns the description of the FTDI chip, if any.
 *
 * @mpsse - MPSSE context pointer.
 *
 * Returns the description of the FTDI chip.
 */
const char* GetDescription(struct mpsse_context* mpsse) {
  char* description = NULL;

  if (is_valid_context(mpsse)) {
    description = mpsse->description;
  }

  return description;
}

/*
 * Enable / disable internal loopback.
 *
 * @mpsse  - MPSSE context pointer.
 * @enable - Zero to disable loopback, 1 to enable loopback.
 *
 * Returns MPSSE_OK on success.
 * Returns MPSSE_FAIL on failure.
 */
int SetLoopback(struct mpsse_context* mpsse, int enable) {
  uint8_t buf[1] = {0};
  int retval = MPSSE_FAIL;

  if (is_valid_context(mpsse)) {
    if (enable) {
      buf[0] = LOOPBACK_START;
    } else {
      buf[0] = LOOPBACK_END;
    }

    retval = raw_write(mpsse, buf, 1);
  }

  return retval;
}

/*
 * Sets the idle state of the chip select pin. CS idles high by default.
 *
 * @mpsse - MPSSE context pointer.
 * @idle  - Set to 1 to idle high, 0 to idle low.
 *
 * Returns void.
 */
void SetCSIdle(struct mpsse_context* mpsse, int idle) {
  if (is_valid_context(mpsse)) {
    if (idle > 0) {
      /* Chip select idles high, active low */
      mpsse->pidle |= CS;
      mpsse->pstop |= CS;
      mpsse->pstart &= ~CS;
    } else {
      /* Chip select idles low, active high */
      mpsse->pidle &= ~CS;
      mpsse->pstop &= ~CS;
      mpsse->pstart |= CS;
    }
  }

  return;
}

/*
 * Enables or disables flushing of the FTDI chip's RX buffers after each read
 *operation.
 * Flushing is disable by default.
 *
 * @mpsse - MPSSE context pointer.
 * @tf    - Set to 1 to enable flushing, or 0 to disable flushing.
 *
 * Returns void.
 */
void FlushAfterRead(struct mpsse_context* mpsse, int tf) {
  mpsse->flush_after_read = tf;
  return;
}

/*
 * Send data start condition.
 *
 * @mpsse - MPSSE context pointer.
 *
 * Returns MPSSE_OK on success.
 * Returns MPSSE_FAIL on failure.
 */
int Start(struct mpsse_context* mpsse) {
  int status = MPSSE_OK;

  if (is_valid_context(mpsse)) {
    if (mpsse->mode == I2C && mpsse->status == STARTED) {
      /* Set the default pin states while the clock is low since this is an I2C
       * repeated start condition */
      status |= set_bits_low(mpsse, (mpsse->pidle & ~SK));

      /* Make sure the pins are in their default idle state */
      status |= set_bits_low(mpsse, mpsse->pidle);
    }

    /* Set the start condition */
    status |= set_bits_low(mpsse, mpsse->pstart);

    /*
     * Hackish work around to properly support SPI mode 3.
     * SPI3 clock idles high, but needs to be set low before sending out
     * data to prevent unintenteded clock glitches from the FT2232.
     */
    if (mpsse->mode == SPI3) {
      status |= set_bits_low(mpsse, (mpsse->pstart & ~SK));
    }
    /*
     * Hackish work around to properly support SPI mode 1.
     * SPI1 clock idles low, but needs to be set high before sending out
     * data to preven unintended clock glitches from the FT2232.
     */
    else if (mpsse->mode == SPI1) {
      status |= set_bits_low(mpsse, (mpsse->pstart | SK));
    }

    mpsse->status = STARTED;
  } else {
    status = MPSSE_FAIL;
    mpsse->status = STOPPED;
  }

  return status;
}

/*
 * Performs a bit-wise write of up to 8 bits at a time.
 *
 * @mpsse - MPSSE context pointer.
 * @bits  - A byte containing the desired bits to write.
 * @size  - The number of bits from the 'bits' byte to write.
 *
 * Returns MPSSE_OK on success, MPSSE_FAIL on failure.
 */
int WriteBits(struct mpsse_context* mpsse, char bits, size_t size) {
  uint8_t data[8] = {0};
  size_t i = 0;
  int retval = MPSSE_OK;

  if (size > sizeof(data)) {
    size = sizeof(data);
  }

  /* Convert each bit in bits to an array of bytes */
  for (i = 0; i < size; i++) {
    if (bits & (1 << i)) {
      /* Be sure to honor endianess */
      if (mpsse->endianess == LSB) {
        data[i] = '\xFF';
      } else {
        data[size - i - 1] = '\xFF';
      }
    }
  }

  /* Enable bit mode before writing, then disable it afterwards. */
  EnableBitmode(mpsse, 1);
  retval = Write(mpsse, data, size);
  EnableBitmode(mpsse, 0);

  return retval;
}

/*
 * Send data out via the selected serial protocol.
 *
 * @mpsse - MPSSE context pointer.
 * @data  - Buffer of data to send.
 * @size  - Size of data.
 *
 * Returns MPSSE_OK on success.
 * Returns MPSSE_FAIL on failure.
 */
int Write(struct mpsse_context* mpsse, const void* vdata, int size) {
  const uint8_t* data = vdata;
  uint8_t* buf = NULL;
  int retval = MPSSE_FAIL, buf_size = 0, txsize = 0, n = 0;

  if (is_valid_context(mpsse)) {
    if (mpsse->mode) {
      while (n < size) {
        txsize = size - n;
        if (txsize > mpsse->xsize) {
          txsize = mpsse->xsize;
        }

        /*
         * For I2C we need to send each byte individually so that we can
         * read back each individual ACK bit, so set the transmit size to 1.
         */
        if (mpsse->mode == I2C) {
          txsize = 1;
        }

        buf = build_block_buffer(mpsse, mpsse->tx, data + n, txsize, &buf_size);
        if (buf) {
          retval = raw_write(mpsse, buf, buf_size);
          n += txsize;
          free(buf);

          if (retval == MPSSE_FAIL) {
            break;
          }

          /* Read in the ACK bit and store it in mpsse->rack */
          if (mpsse->mode == I2C) {
            raw_read(mpsse, (uint8_t*)&mpsse->rack, 1);
          }
        } else {
          break;
        }
      }
    }

    if (retval == MPSSE_OK && n == size) {
      retval = MPSSE_OK;
    }
  }

  return retval;
}

/* Performs a read. For internal use only; see Read() and ReadBits(). */
static uint8_t* InternalRead(struct mpsse_context* mpsse, int size) {
  uint8_t *data = NULL, *buf = NULL;
  uint8_t sbuf[SPI_RW_SIZE] = {0};
  int n = 0, rxsize = 0, data_size = 0, retval = 0;

  if (is_valid_context(mpsse)) {
    if (mpsse->mode) {
      buf = malloc(size);
      if (buf) {
        memset(buf, 0, size);

        while (n < size) {
          rxsize = size - n;
          if (rxsize > mpsse->xsize) {
            rxsize = mpsse->xsize;
          }

          data = build_block_buffer(mpsse, mpsse->rx, sbuf, rxsize, &data_size);
          if (data) {
            retval = raw_write(mpsse, data, data_size);
            free(data);

            if (retval == MPSSE_OK) {
              n += raw_read(mpsse, buf + n, rxsize);
            } else {
              break;
            }
          } else {
            break;
          }
        }
      }
    }
  }

  return buf;
}

/*
 * Reads data over the selected serial protocol.
 *
 * @mpsse - MPSSE context pointer.
 * @size  - Number of bytes to read.
 *
 * Returns a pointer to the read data on success.
 * Returns NULL on failure.
 */
#ifdef SWIGPYTHON
swig_string_data Read(struct mpsse_context* mpsse, int size)
#else
uint8_t* Read(struct mpsse_context* mpsse, int size)
#endif
{
  uint8_t* buf = NULL;

  buf = InternalRead(mpsse, size);

#ifdef SWIGPYTHON
  swig_string_data sdata = {0};
  sdata.size = size;
  sdata.data = buf;
  return sdata;
#else
  return buf;
#endif
}

/*
 * Performs a bit-wise read of up to 8 bits.
 *
 * @mpsse - MPSSE context pointer.
 * @size  - Number of bits to read.
 *
 * Returns an 8-bit byte containing the read bits.
 */
char ReadBits(struct mpsse_context* mpsse, int size) {
  char bits = 0;
  uint8_t* rdata = NULL;

  if (size > 8) {
    size = 8;
  }

  EnableBitmode(mpsse, 1);
  rdata = InternalRead(mpsse, size);
  EnableBitmode(mpsse, 0);

  if (rdata) {
    /* The last byte in rdata will have all the read bits set or unset as
     * needed. */
    bits = rdata[size - 1];

    if (mpsse->endianess == MSB) {
      /*
       * In MSB mode, bits are sifted in from the left. If less than 8 bits were
       * read, we need to shift them left accordingly.
       */
      bits = bits << (8 - size);
    } else if (mpsse->endianess == LSB) {
      /*
       * In LSB mode, bits are shifted in from the right. If less than 8 bits
       * were
       * read, we need to shift them right accordingly.
       */
      bits = bits >> (8 - size);
    }

    free(rdata);
  }

  return bits;
}

/*
 * Reads and writes data over the selected serial protocol (SPI only).
 *
 * @mpsse - MPSSE context pointer.
 * @data  - Buffer containing bytes to write.
 * @size  - Number of bytes to transfer.
 *
 * Returns a pointer to the read data on success.
 * Returns NULL on failure.
 */
#ifdef SWIGPYTHON
swig_string_data Transfer(struct mpsse_context* mpsse, char* data, int size)
#else
uint8_t* Transfer(struct mpsse_context* mpsse, uint8_t* data, int size)
#endif
{
  uint8_t *txdata = NULL, *buf = NULL;
  int n = 0, data_size = 0, rxsize = 0, retval = 0;

  if (is_valid_context(mpsse)) {
    /* Make sure we're configured for one of the SPI modes */
    if (mpsse->mode >= SPI0 && mpsse->mode <= SPI3) {
      buf = malloc(size);
      if (buf) {
        memset(buf, 0, size);

        while (n < size) {
          /* When sending and recieving, FTDI chips don't seem to like large
           * data blocks. Limit the size of each block to SPI_TRANSFER_SIZE */
          rxsize = size - n;
          if (rxsize > SPI_TRANSFER_SIZE) {
            rxsize = SPI_TRANSFER_SIZE;
          }

          txdata =
              build_block_buffer(mpsse, mpsse->txrx, data + n,
                                 rxsize, &data_size);
          if (txdata) {
            retval = raw_write(mpsse, txdata, data_size);
            free(txdata);

            if (retval == MPSSE_OK) {
              n += raw_read(mpsse, (buf + n), rxsize);
            } else {
              break;
            }
          } else {
            break;
          }
        }
      }
    }
  }

#ifdef SWIGPYTHON
  swig_string_data sdata = {0};
  sdata.size = n;
  sdata.data = (char*)buf;
  return sdata;
#else
  return buf;
#endif
}

/*
 * Returns the last received ACK bit.
 *
 * @mpsse - MPSSE context pointer.
 *
 * Returns either an ACK (0) or a NACK (1).
 */
int GetAck(struct mpsse_context* mpsse) {
  int ack = 0;

  if (is_valid_context(mpsse)) {
    ack = (mpsse->rack & 0x01);
  }

  return ack;
}

/*
 * Sets the transmitted ACK bit.
 *
 * @mpsse - MPSSE context pointer.
 * @ack   - 0 to send ACKs, 1 to send NACKs.
 *
 * Returns void.
 */
void SetAck(struct mpsse_context* mpsse, int ack) {
  if (is_valid_context(mpsse)) {
    if (ack == NACK) {
      mpsse->tack = 0xFF;
    } else {
      mpsse->tack = 0x00;
    }
  }

  return;
}

/*
 * Causes libmpsse to send ACKs after each read byte in I2C mode.
 *
 * @mpsse - MPSSE context pointer.
 *
 * Returns void.
 */
void SendAcks(struct mpsse_context* mpsse) {
  return SetAck(mpsse, ACK);
}

/*
 * Causes libmpsse to send NACKs after each read byte in I2C mode.
 *
 * @mpsse - MPSSE context pointer.
 *
 * Returns void.
 */
void SendNacks(struct mpsse_context* mpsse) {
  return SetAck(mpsse, NACK);
}

/*
 * Send data stop condition.
 *
 * @mpsse - MPSSE context pointer.
 *
 * Returns MPSSE_OK on success.
 * Returns MPSSE_FAIL on failure.
 */
int Stop(struct mpsse_context* mpsse) {
  int retval = MPSSE_OK;

  if (is_valid_context(mpsse)) {
    /* In I2C mode, we need to ensure that the data line goes low while the
     * clock line is low to avoid sending an inadvertent start condition */
    if (mpsse->mode == I2C) {
      retval |= set_bits_low(mpsse, (mpsse->pidle & ~DO & ~SK));
    }

    /* Send the stop condition */
    retval |= set_bits_low(mpsse, mpsse->pstop);

    if (retval == MPSSE_OK) {
      /* Restore the pins to their idle states */
      retval |= set_bits_low(mpsse, mpsse->pidle);
    }

    mpsse->status = STOPPED;
  } else {
    retval = MPSSE_FAIL;
    mpsse->status = STOPPED;
  }

  return retval;
}

/*
 * Sets the specified pin high.
 *
 * @mpsse - MPSSE context pointer.
 * @pin   - Pin number to set high.
 *
 * Returns MPSSE_OK on success.
 * Returns MPSSE_FAIL on failure.
 */
int PinHigh(struct mpsse_context* mpsse, int pin) {
  int retval = MPSSE_FAIL;

  if (is_valid_context(mpsse)) {
    retval = gpio_write(mpsse, pin, HIGH);
  }

  return retval;
}

/*
 * Sets the specified pin low.
 *
 * @mpsse - MPSSE context pointer.
 * @pin   - Pin number to set low.
 *
 * Returns MPSSE_OK on success.
 * Returns MPSSE_FAIL on failure.
 */
int PinLow(struct mpsse_context* mpsse, int pin) {
  int retval = MPSSE_FAIL;

  if (is_valid_context(mpsse)) {
    retval = gpio_write(mpsse, pin, LOW);
  }

  return retval;
}

/*
 * Sets the input/output direction of all pins. For use in BITBANG mode only.
 *
 * @mpsse     - MPSSE context pointer.
 * @direction - Byte indicating input/output direction of each bit.  1 is out.
 *
 * Returns MPSSE_OK if direction could be set, MPSSE_FAIL otherwise.
 */
int SetDirection(struct mpsse_context* mpsse, uint8_t direction) {
  int retval = MPSSE_FAIL;

  if (is_valid_context(mpsse)) {
    if (mpsse->mode == BITBANG) {
      if (ftdi_set_bitmode(&mpsse->ftdi, direction, BITMODE_BITBANG) == 0) {
        retval = MPSSE_OK;
      }
    }
  }

  return retval;
}

/*
 * Sets the input/output value of all pins. For use in BITBANG mode only.
 *
 * @mpsse - MPSSE context pointer.
 * @data  - Byte indicating bit hi/low value of each bit.
 *
 * Returns MPSSE_OK if direction could be set, MPSSE_FAIL otherwise.
 */
int WritePins(struct mpsse_context* mpsse, uint8_t data) {
  int retval = MPSSE_FAIL;

  if (is_valid_context(mpsse)) {
    if (mpsse->mode == BITBANG) {
      if (ftdi_write_data(&mpsse->ftdi, &data, 1) == 0) {
        retval = MPSSE_OK;
      }
    }
  }

  return retval;
}

/*
 * Reads the state of the chip's pins. For use in BITBANG mode only.
 *
 * @mpsse - MPSSE context pointer.
 *
 * Returns a byte with the corresponding pin's bits set to 1 or 0.
 */
int ReadPins(struct mpsse_context* mpsse) {
  uint8_t val = 0;

  if (is_valid_context(mpsse)) {
    ftdi_read_pins((struct ftdi_context*)&mpsse->ftdi, (uint8_t*)&val);
  }

  return (int)val;
}

/*
 * Checks if a specific pin is high or low. For use in BITBANG mode only.
 *
 * @mpsse - MPSSE context pointer.
 * @pin   - The pin number.
 * @state - The state of the pins, as returned by ReadPins.
 *          If set to -1, ReadPins will automatically be called.
 *
 * Returns a 1 if the pin is high, 0 if the pin is low.
 */
int PinState(struct mpsse_context* mpsse, int pin, int state) {
  if (state == -1) {
    state = ReadPins(mpsse);
  }

  /* If not in bitbang mode, the specified pin should be one of GPIOLx. Convert
   * these defines into an absolute pin number. */
  if (mpsse->mode != BITBANG) {
    pin += NUM_GPIOL_PINS;
  }

  return ((state & (1 << pin)) >> pin);
}

/*
 * Places all I/O pins into a tristate mode.
 *
 * @mpsse - MPSSE context pointer.
 *
 * Returns MPSSE_OK on success, MPSSE_FAIL on failure.
 */
int Tristate(struct mpsse_context* mpsse) {
  uint8_t cmd[CMD_SIZE] = {0};

  /* Tristate the all I/O pins (FT232H only) */
  cmd[0] = TRISTATE_IO;
  cmd[1] = 0xFF;
  cmd[2] = 0xFF;

  return raw_write(mpsse, cmd, sizeof(cmd));
}