

#include <stdio.h>
#include <stdlib.h>
#include <mpsse.h>
#include <../libftdi1/src/ftdi.h>

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 }
};

struct mpsse_context *i2c_dev = NULL;
char i2c_adress;
int i;

struct ftdi_context *ftdi;
int f;//,i;

int i2c_open (int clockrate, int index, int port)
//  PORT A - 1, PORT B - 2, ANY PORT - 0
//  CLOCKRATE IN HERZ
//  INDEX IS FOR SITUATION WHEN NO ONE FTDI MPSSE DEVICE IS CONNECTED TO PC (IF ONE DEVICE IS CONNECTED PLEASE SET INDEX TO ZERO, IF MULTIPLE DEVICES - INDEX MAY BE NOT ZERO)
{
    i2c_dev = OpenIndex(0x0403, 0x6010, I2C, clockrate, MSB, port, NULL, NULL, index);
    if (i2c_dev->open)
        return 0;       //  ALL OK, RETURN ZERO
    //  NOT OK, CLOSING AND RETURNING NON-ZERO
    Close(i2c_dev);
    i2c_dev = NULL;
    return 1;
}

void i2c_close ()
{
    Close(i2c_dev);
    i2c_dev = NULL;
}

int i2c_tx (char adress, char* data, int len, int stt, int stp)
{
    if ((i2c_dev == NULL) || (i2c_dev->open == 0))
        return 1;   //  NO OPENED DEVICE
    if (stt)
        Start (i2c_dev);
    i2c_adress = (adress << 1) & (~0x01) ;
    Write (i2c_dev, &i2c_adress, 1);
    if (GetAck (i2c_dev) != ACK)    {
        if (stp)
            Stop (i2c_dev);
        return 10;  //  NO ACK ADRESS
    }
    Write (i2c_dev, data, len);
    i = GetAck(i2c_dev);
    if (stp)
        Stop (i2c_dev);
    if (i != ACK)
        return 11;  //  NO ACK DATA
    return 0;
}

int i2c_rx (char adress, char* data, int len, int stt, int stp)
{
    char* temp_data;
    if ((i2c_dev == NULL) || (i2c_dev->open == 0))
        return 1;
    if (stt)
        Start (i2c_dev);
    i2c_adress = (adress << 1) | (0x01) ;
    Write (i2c_dev, &i2c_adress, 1);
    if (GetAck (i2c_dev) != ACK)    {
        if (stp)
            Stop (i2c_dev);
        return 10;  //  NO ACK ADRESS
    }
    SendAcks (i2c_dev); //  SEND ACKS WHEN DATA PROCESSING
    temp_data = Read (i2c_dev, len);

    /* Tell libmpsse to send NACKs after reading data */
    SendNacks(i2c_dev);
    /* Read in one dummy byte, with a NACK */
    Read(i2c_dev, 1);

    if (stp)
        Stop (i2c_dev);
    if (data)   {
        for (int i = 0; i < len; i++)
            data[i] = temp_data[i];
        free(temp_data);
        return 0;   //  ALL GOOD
    }
    return 12;  //  UNKNOWN ERROR, NO DATA
}

int bitbang_open (int index, int port, int mask)
{
    if ((ftdi = ftdi_new()) == 0)
    {
        fprintf(stderr, "ftdi_new failed\n");
        return EXIT_FAILURE;
    }
    f = ftdi_usb_open_desc_index (ftdi, 0x0403, 0x6010, NULL, NULL, index);
    if (f < 0 && f != -5)
    {
        fprintf(stderr, "unable to open ftdi device: %d (%s)\n", f, ftdi_get_error_string(ftdi));
        ftdi_free(ftdi);
        return 2;
    }
    f = ftdi_set_interface(ftdi, port);
    if (f < 0 && f != -5)
    {
        fprintf(stderr, "unable to open ftdi device: %d (%s)\n", f, ftdi_get_error_string(ftdi));
        ftdi_free(ftdi);
        return 3;
    }
    ftdi_set_bitmode(ftdi, mask, BITMODE_BITBANG);
    char buf[1] = {0xFF};
    ftdi_write_data(ftdi, buf, 1);
    buf[0] = 0x00;
    ftdi_write_data(ftdi, buf, 1);
    return 0;
}

void bitbang_close ()
{
    ftdi_disable_bitbang(ftdi);

    ftdi_usb_close(ftdi);

    ftdi_free(ftdi);
}

int bitbang_read (char* pins)
{
    return ftdi_read_pins(ftdi, pins);
}
