// Copyright (c) 2008  Future Technology Devices International Ltd.
//
// Module Name
//
//     FT2232HSPIC++NETTestApp.cpp
//
// Abstract:
//
//    C++ console program, to test the FTCSPI.DLL. The FTCSPI.DLL is used to control the FT2232H dual hi-speed device
//    and the FT4232H quad hi-speed device to simulate the Serial Peripheral Interface(SPI) synchronous serial protocol
//    to communicate with SPI devices connected to FT2232H dual hi-speed devices and FT4232H quad hi-speed devices.
//
// Revision History:
//
//   26/08/08    Kirke Ashton    Created.
//   21/08/09    Modifications to Write Statement by Forbes
//
// FT2232HSPIC++NETTestApp.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <windows.h>

#include "FTCSPI.h"

#define MAX_SPI_93LC56B_CHIP_SIZE_IN_WORDS 128

// To communicate with the 93LC56(2048 word) EEPROM, the maximum frequency the clock can be set is 1MHz 
#define MAX_FREQ_93LC56B_CLOCK_DIVISOR 29 // defualt is 29 equivalent to 1MHz

const BYTE SPI_EWEN_CMD = '\x9F'; // set up write enable command
const BYTE SPI_EWDS_CMD = '\x87'; // set up write disable command
const BYTE SPI_ERAL_CMD = '\x97'; // set up erase all command

#define NUM_93LC56B_CMD_CONTOL_BITS 11
#define NUM_93LC56B_CMD_CONTOL_BYTES 2

#define NUM_93LC56B_CMD_DATA_BITS 16
#define NUM_93LC56B_CMD_DATA_BYTES 2

#define MAX_READ_DATA_WORDS_BUFFER_SIZE 256  // 65536 64k bytes

typedef WORD ReadDataWordBuffer[MAX_READ_DATA_WORDS_BUFFER_SIZE];
typedef ReadDataWordBuffer *PReadDataWordBuffer;

int _tmain(int argc, _TCHAR* argv[])
{
  FTC_STATUS Status = FTC_SUCCESS;
  DWORD dwNumHiSpeedDevices = 0;
  char szDeviceName[100];
  char szChannel[5];
  DWORD dwLocationID = 0;
  DWORD dwHiSpeedDeviceType = 0;
  DWORD dwHiSpeedDeviceIndex = 0;
  FTC_HANDLE ftHandle = 0;
  char szDeviceDetails[150];
  BYTE timerValue = 0;
  DWORD dwClockFrequencyHz = 0;
  BOOL bPerformCommandSequence = false;
  FTC_CHIP_SELECT_PINS ChipSelectsDisableStates;
  FTH_INPUT_OUTPUT_PINS HighInputOutputPins;
  FTH_LOW_HIGH_PINS HighPinsInputData;
  FTC_INIT_CONDITION WriteStartCondition;
  WriteControlByteBuffer WriteControlBuffer;
  WriteDataByteBuffer WriteDataBuffer;
  DWORD dwNumDataBytesToWrite = 0;
  FTC_WAIT_DATA_WRITE WaitDataWriteComplete;
  FTH_HIGHER_OUTPUT_PINS HighPinsWriteActiveStates;
  FTC_CLOSE_FINAL_STATE_PINS CloseFinalStatePinsData;
  DWORD dwDataWordInitValue = 0;
  DWORD dwDataWordValue = 0;
  DWORD dwWriteDataWordAddress = 0;
  DWORD dwControlLocAddress1 = 0;
  DWORD dwControlLocAddress2 = 0;
  FTC_INIT_CONDITION ReadStartCondition;
  DWORD dwReadDataWordAddress = 0;
  DWORD dwReadWordValue = 0;
  ReadDataWordBuffer ReadWordData;
  DWORD dwNumDataBytesReturned = 0;
  DWORD dwDataWordWritten = 0;
  DWORD dwCharCntr = 0;
  ReadDataByteBuffer ReadDataBuffer;
  DWORD dwReadDataIndex = 0;
  ReadCmdSequenceDataByteBuffer ReadCmdSequenceDataBuffer;
  int MsgBoxKeyPressed = 0;
  DWORD dwLoopCntr = 0;

  char szDllVersion[10];
  char szTitleErrorMessage[100];
  char szStatusErrorMessage[100];
  char szErrorMessage[200];
  char szMismatchMessage[100];

  for (dwCharCntr = 0; (dwCharCntr < 100); dwCharCntr++)
    szMismatchMessage[dwCharCntr] = '\0';

  Status = SPI_GetDllVersion(szDllVersion, 10);
  MessageBox(NULL, szDllVersion, "FTCSPI DLL Version", MB_OK);

  Status = SPI_GetNumHiSpeedDevices(&dwNumHiSpeedDevices);

  if ((Status == FTC_SUCCESS) && (dwNumHiSpeedDevices > 0))
  {
    do
    {
      Status = SPI_GetHiSpeedDeviceNameLocIDChannel(dwHiSpeedDeviceIndex, szDeviceName, 100, &dwLocationID, szChannel, 5, &dwHiSpeedDeviceType);

      dwHiSpeedDeviceIndex = dwHiSpeedDeviceIndex + 1;
    }
    while ((Status == FTC_SUCCESS) && (dwHiSpeedDeviceIndex < dwNumHiSpeedDevices) && (strcmp(szChannel, "A") != 0));

    if (Status == FTC_SUCCESS)
    {
      if (strcmp(szChannel, "A") != 0)
        Status = FTC_DEVICE_IN_USE;
    }

    if (Status == FTC_SUCCESS) {
      Status = SPI_OpenHiSpeedDevice(szDeviceName, dwLocationID, szChannel, &ftHandle);

      if (Status == FTC_SUCCESS) {
        Status = SPI_GetHiSpeedDeviceType(ftHandle, &dwHiSpeedDeviceType);

        if (Status == FTC_SUCCESS) {
          strcpy_s(szDeviceDetails, "Type = ");

          if (dwHiSpeedDeviceType == FT4232H_DEVICE_TYPE)
            strcat_s(szDeviceDetails, "FT4232H");
          else if (dwHiSpeedDeviceType == FT2232H_DEVICE_TYPE)
            strcat_s(szDeviceDetails, "FT2232H");

          strcat_s(szDeviceDetails, ", Name = ");
          strcat_s(szDeviceDetails, szDeviceName);

          MessageBox(NULL, szDeviceDetails, "Hi Speed Device", MB_OK);
        }
      }
    }
  }

  if ((Status == FTC_SUCCESS) && (ftHandle != 0))
  {
    Status = SPI_InitDevice(ftHandle, MAX_FREQ_93LC56B_CLOCK_DIVISOR); //65536

    if (Status == FTC_SUCCESS) {
      if ((Status = SPI_GetDeviceLatencyTimer(ftHandle, &timerValue)) == FTC_SUCCESS) {
        if ((Status = SPI_SetDeviceLatencyTimer(ftHandle, 50)) == FTC_SUCCESS) {
          Status = SPI_GetDeviceLatencyTimer(ftHandle, &timerValue);

          Status = SPI_SetDeviceLatencyTimer(ftHandle, 16);

          Status = SPI_GetDeviceLatencyTimer(ftHandle, &timerValue);
        }
      }
    }

    if (Status == FTC_SUCCESS)
    {
      if ((Status = SPI_GetHiSpeedDeviceClock(0, &dwClockFrequencyHz)) == FTC_SUCCESS)
      {
        if ((Status = SPI_TurnOnDivideByFiveClockingHiSpeedDevice(ftHandle)) == FTC_SUCCESS)
        {
          Status = SPI_GetHiSpeedDeviceClock(0, &dwClockFrequencyHz);

          if ((Status = SPI_SetClock(ftHandle, MAX_FREQ_93LC56B_CLOCK_DIVISOR, &dwClockFrequencyHz)) == FTC_SUCCESS)
          {
            if ((Status = SPI_TurnOffDivideByFiveClockingHiSpeedDevice(ftHandle)) == FTC_SUCCESS)
              Status = SPI_SetClock(ftHandle, MAX_FREQ_93LC56B_CLOCK_DIVISOR, &dwClockFrequencyHz);
          }
        }
      }
    }

    if (Status == FTC_SUCCESS)
    {
      Status = SPI_SetLoopback(ftHandle, false);

      if (Status == FTC_SUCCESS)
      {
        bPerformCommandSequence = false;

        if (bPerformCommandSequence == true)
        {
            if (Status == FTC_SUCCESS)
              Status = SPI_ClearDeviceCmdSequence(ftHandle);
        }

        if (Status == FTC_SUCCESS)
        {
          // Must set the chip select disable states for all the SPI devices connected to a FT2232H hi-speed dual
          // device or FT4332H hi-speed quad device
          ChipSelectsDisableStates.bADBUS3ChipSelectPinState = false;
          ChipSelectsDisableStates.bADBUS4GPIOL1PinState = false;
          ChipSelectsDisableStates.bADBUS5GPIOL2PinState = false;
          ChipSelectsDisableStates.bADBUS6GPIOL3PinState = false;
          ChipSelectsDisableStates.bADBUS7GPIOL4PinState = false;

          HighInputOutputPins.bPin1InputOutputState = true;
          HighInputOutputPins.bPin1LowHighState = false;
          HighInputOutputPins.bPin2InputOutputState = true;
          HighInputOutputPins.bPin2LowHighState = false;
          HighInputOutputPins.bPin3InputOutputState = true;
          HighInputOutputPins.bPin3LowHighState = false;
          HighInputOutputPins.bPin4InputOutputState = true;
          HighInputOutputPins.bPin4LowHighState = false;

          HighInputOutputPins.bPin5InputOutputState = true;
          HighInputOutputPins.bPin5LowHighState = false;
          HighInputOutputPins.bPin6InputOutputState = true;
          HighInputOutputPins.bPin6LowHighState = false;
          HighInputOutputPins.bPin7InputOutputState = true;
          HighInputOutputPins.bPin7LowHighState = false;
          HighInputOutputPins.bPin8InputOutputState = true;
          HighInputOutputPins.bPin8LowHighState = false;

          Status = SPI_SetHiSpeedDeviceGPIOs(ftHandle, &ChipSelectsDisableStates, &HighInputOutputPins); //NULL

          if (Status == FTC_SUCCESS)
          {
            Sleep(200);

            Status = SPI_GetHiSpeedDeviceGPIOs(ftHandle, &HighPinsInputData); //NULL);

            Sleep(200);
          }
        }

        do
        {
          if (Status == FTC_SUCCESS)
          {
            WriteStartCondition.bClockPinState = false;
            WriteStartCondition.bDataOutPinState = false;
            WriteStartCondition.bChipSelectPinState = false;
            WriteStartCondition.dwChipSelectPin = ADBUS3ChipSelect;

            WaitDataWriteComplete.bWaitDataWriteComplete = false;

            // Set the 8 general purpose higher input/output pins
            HighPinsWriteActiveStates.bPin1ActiveState = false;
            HighPinsWriteActiveStates.bPin1State = false;
            HighPinsWriteActiveStates.bPin2ActiveState = false;
            HighPinsWriteActiveStates.bPin2State = false;
            HighPinsWriteActiveStates.bPin3ActiveState = false;
            HighPinsWriteActiveStates.bPin3State = false;
            HighPinsWriteActiveStates.bPin4ActiveState = false;
            HighPinsWriteActiveStates.bPin4State = false;
            HighPinsWriteActiveStates.bPin5ActiveState = false;
            HighPinsWriteActiveStates.bPin5State = false;
            HighPinsWriteActiveStates.bPin6ActiveState = false;
            HighPinsWriteActiveStates.bPin6State = false;
            HighPinsWriteActiveStates.bPin7ActiveState = false;
            HighPinsWriteActiveStates.bPin7State = false;
            HighPinsWriteActiveStates.bPin8ActiveState = false;
            HighPinsWriteActiveStates.bPin8State = false;   
           
          }

		      // Setup Erase Opcode
              WriteControlBuffer[0] = SPI_ERAL_CMD;  // This is the opcode to "Erase All" for the 93C56
		      WriteControlBuffer[1] = '\FF';  // The second byte of FF toggles the CS signal at the end of the Erase All command

              // Erase the entire 93C56 EEPROM
              Status = SPI_WriteHiSpeedDevice(ftHandle, &WriteStartCondition, true, false,
                                              NUM_93LC56B_CMD_CONTOL_BITS, &WriteControlBuffer, NUM_93LC56B_CMD_CONTOL_BYTES,
                                              false, 0, &WriteDataBuffer, 0, &WaitDataWriteComplete, &HighPinsWriteActiveStates);

          Sleep(700);

          
          {
            WaitDataWriteComplete.bWaitDataWriteComplete = true;
            WaitDataWriteComplete.dwWaitDataWritePin = ADBUS2DataIn;
            WaitDataWriteComplete.bDataWriteCompleteState = true;
            WaitDataWriteComplete.dwDataWriteTimeoutmSecs = 5000;  //def is 5000

            dwWriteDataWordAddress = 0;

            do
            {
			  // Set up Write Enable Opcodes
			 // WriteControlBuffer[0] = SPI_EWEN_CMD;
             // WriteControlBuffer[1] = '\xFF';

			  // enable writing
             //  Status = SPI_WriteHiSpeedDevice(ftHandle, &WriteStartCondition, true, false,
             //                              NUM_93LC56B_CMD_CONTOL_BITS, &WriteControlBuffer, NUM_93LC56B_CMD_CONTOL_BYTES,
             //                              false, 0, &WriteDataBuffer, 0, &WaitDataWriteComplete, &HighPinsWriteActiveStates);

              // set up write command opcode and address
              dwControlLocAddress1 = 160; //'\xA0';
              dwControlLocAddress1 = (dwControlLocAddress1 | ((dwWriteDataWordAddress / 8) & '\x0F'));

              // shift left 5 bits ie make bottom 3 bits the 3 MSB's
              dwControlLocAddress2 = ((dwWriteDataWordAddress & '\x07') * 32);

              WriteControlBuffer[0] = (dwControlLocAddress1 & '\xFF');
              WriteControlBuffer[1] = (dwControlLocAddress2 & '\xFF');

              if (dwDataWordInitValue == 0)
                dwDataWordValue = dwWriteDataWordAddress;
              else
                dwDataWordValue = dwDataWordInitValue;

              // write data
              WriteDataBuffer[0] = (dwDataWordValue & '\xFF');
              WriteDataBuffer[1] = ((dwDataWordValue / 256) & '\xFF');

              Status = SPI_WriteHiSpeedDevice(ftHandle, &WriteStartCondition, true, false,
                                              NUM_93LC56B_CMD_CONTOL_BITS, &WriteControlBuffer, NUM_93LC56B_CMD_CONTOL_BYTES,
                                              true, NUM_93LC56B_CMD_DATA_BITS, &WriteDataBuffer, NUM_93LC56B_CMD_DATA_BYTES,
                                              &WaitDataWriteComplete, &HighPinsWriteActiveStates);

			  // Disable Writing until next cycle

				//WriteControlBuffer[0] = SPI_EWDS_CMD;

                // disable writing
                //Status = SPI_WriteHiSpeedDevice(ftHandle, &WriteStartCondition, true, false,
                //                                NUM_93LC56B_CMD_CONTOL_BITS, &WriteControlBuffer, NUM_93LC56B_CMD_CONTOL_BYTES,
                //                                false, 0, &WriteDataBuffer, 0, &WaitDataWriteComplete, &HighPinsWriteActiveStates);

				dwWriteDataWordAddress++;
            }
            while ((dwWriteDataWordAddress < MAX_SPI_93LC56B_CHIP_SIZE_IN_WORDS) && (Status == FTC_SUCCESS));

            Sleep(200);

            if (Status == FTC_SUCCESS)
            {
              ReadStartCondition.bClockPinState = false;
              ReadStartCondition.bDataOutPinState = false;
              ReadStartCondition.bChipSelectPinState = false;
              ReadStartCondition.dwChipSelectPin = ADBUS3ChipSelect;

              dwReadDataWordAddress = 0;

              do
              {
                // set up read command and address
                dwControlLocAddress1 = 192; //'\xC0';
                dwControlLocAddress1 = (dwControlLocAddress1 | ((dwReadDataWordAddress / 8) & '\x0F'));

                // shift left 5 bits ie make bottom 3 bits the 3 MSB's
                dwControlLocAddress2 = ((dwReadDataWordAddress & '\x07') * 32);

                WriteControlBuffer[0] = (dwControlLocAddress1 & '\xFF');
                WriteControlBuffer[1] = (dwControlLocAddress2 & '\xFF');

                if (bPerformCommandSequence == false)
                {
                  Status = SPI_ReadHiSpeedDevice(ftHandle, &ReadStartCondition, true, false, NUM_93LC56B_CMD_CONTOL_BITS,
                                                 &WriteControlBuffer, NUM_93LC56B_CMD_CONTOL_BYTES, true, false, NUM_93LC56B_CMD_DATA_BITS,
                                                 &ReadDataBuffer, &dwNumDataBytesReturned, &HighPinsWriteActiveStates);

                  if (Status == FTC_SUCCESS)
                  {
                    dwReadWordValue = ((ReadDataBuffer[1] * 256) | ReadDataBuffer[0]);

                    ReadWordData[dwReadDataWordAddress] = dwReadWordValue;
                    printf("For Address = %d , Data Read = %d\n ", dwReadDataWordAddress, dwReadWordValue);
                  }
                }
                else
                  Status = SPI_AddHiSpeedDeviceReadCmd(ftHandle, &ReadStartCondition, true, false, NUM_93LC56B_CMD_CONTOL_BITS,
                                                       &WriteControlBuffer, NUM_93LC56B_CMD_CONTOL_BYTES, true, false, NUM_93LC56B_CMD_DATA_BITS,
                                                       &HighPinsWriteActiveStates);

                dwReadDataWordAddress++;
              }
              while ((dwReadDataWordAddress < MAX_SPI_93LC56B_CHIP_SIZE_IN_WORDS) && (Status == FTC_SUCCESS));

              MsgBoxKeyPressed = IDOK;

              if (Status == FTC_SUCCESS)
              {
                if (bPerformCommandSequence == true)
                {
                  Status = SPI_ExecuteDeviceCmdSequence(ftHandle, &ReadCmdSequenceDataBuffer, &dwNumDataBytesReturned);

                  if (Status == FTC_SUCCESS)
                  {
                    if (dwNumDataBytesReturned > 0)
                    {
                      dwReadDataWordAddress = 0;

                      dwReadDataIndex = 0;

                      do
                      {
                        dwReadWordValue = ((ReadCmdSequenceDataBuffer[(dwReadDataIndex + 1)] * 256) | ReadCmdSequenceDataBuffer[dwReadDataIndex]);

                        ReadWordData[dwReadDataWordAddress] = dwReadWordValue;

                        dwReadDataIndex = (dwReadDataIndex + 2);

                        dwReadDataWordAddress++;
                      }
                      while (dwReadDataIndex < dwNumDataBytesReturned);
                    }
                    else
                      MsgBoxKeyPressed = MessageBox(NULL, "No data returned.", "SPI Execute Command Sequence", MB_OK | MB_OKCANCEL);
                  }
                }

                if ((Status == FTC_SUCCESS) && (MsgBoxKeyPressed == IDOK))
                {
                  for (dwReadDataIndex = 0; ((dwReadDataIndex < MAX_SPI_93LC56B_CHIP_SIZE_IN_WORDS) && (MsgBoxKeyPressed == IDOK)); dwReadDataIndex++)
                  {
                    if (dwDataWordInitValue != 0)
                      dwDataWordWritten = dwDataWordInitValue;
                    else
                      dwDataWordWritten = (dwReadDataIndex & '\xFF');

                    if (((ReadWordData[dwReadDataIndex] != dwDataWordWritten) && (dwDataWordValue != 0)) ||
                        ((ReadWordData[dwReadDataIndex] != dwDataWordWritten) && (dwDataWordValue == 0)))
                    {
                      for (dwCharCntr = 0; (dwCharCntr < 100); dwCharCntr++)
                        szMismatchMessage[dwCharCntr] = '\0';

                      sprintf(szMismatchMessage, "SPI 93LC56B Read/Write mismatch, Loop = %i, Address = %i, Write Value = %X, Read Value = %X", dwLoopCntr, dwReadDataIndex, dwDataWordWritten, ReadWordData[dwReadDataIndex]);
                      MsgBoxKeyPressed = MessageBox(NULL, szMismatchMessage, "SPI Read Error Message", MB_OK | MB_OKCANCEL);
                    }
                  }
                }
              }
            }
          }

          dwLoopCntr++;
        }
        while ((dwLoopCntr < 10) && (Status == FTC_SUCCESS) && (MsgBoxKeyPressed == IDOK));
      }
    }
  }

  if (ftHandle != 0)
  {
    //CloseFinalStatePinsData.bTCKPinState = true;
    //CloseFinalStatePinsData.bTCKPinActiveState = true;
    //CloseFinalStatePinsData.bTDIPinState = true;
    //CloseFinalStatePinsData.bTDIPinActiveState = false;
    //CloseFinalStatePinsData.bTMSPinState = true;
    //CloseFinalStatePinsData.bTMSPinActiveState = false;

    //Status = SPI_CloseDevice(ftHandle, &CloseFinalStatePinsData);

    SPI_Close(ftHandle);
    ftHandle = 0;
  }

  if ((Status != FTC_SUCCESS) || (dwNumHiSpeedDevices == 0) || (strlen(szMismatchMessage) > 0))
  {
    if (Status != FTC_SUCCESS)
    {
      sprintf_s(szErrorMessage, "Status Code(%u) - ", Status);

      Status = SPI_GetErrorCodeString("EN", Status, szStatusErrorMessage, 100);

      strcat_s(szErrorMessage, szStatusErrorMessage);

      MessageBox(NULL, szErrorMessage, "FTCSPI DLL Error Status Message", MB_OK);
    } else {
      if (dwNumHiSpeedDevices == 0)
        strcpy_s(szErrorMessage, "There are no devices connected.");
      else
        strcpy_s(szErrorMessage, szMismatchMessage);

      MessageBox(NULL, szErrorMessage, "FTCSPI DLL Error Message", MB_OK);
    }
  }
  else
  {
    Status = SPI_GetDllVersion(szDllVersion, 10);

    
    strcpy_s(szErrorMessage, "You have passed the EEPROM test");

    MessageBox(NULL, szErrorMessage, "FTCSPI DLL Message", MB_OK);
  }

	return 0;
}

