#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <stdint.h>
#include "ftd2xx.h"

#define BUFFER_SIZE (64*1024) // reading buffer 64kB

HANDLE hFile;
FT_HANDLE ftHandle;
FT_STATUS ftStatus;
char buffer[BUFFER_SIZE]; // recieved data
char txbuf[2]; // transmitt buffer (only for dummy data to signalize PC app ready to recieve)
DWORD bytesRead, bytesWritten;
unsigned long int totalBytes=0; // total number of recieved bytes (just to check the integrity of the transfer)

LARGE_INTEGER freq; // for time masurment
LARGE_INTEGER t_start;
LARGE_INTEGER t_end;
char mereni_casu=0;

int main(void){
 // I will open the file where I will write the received data
 hFile = CreateFileA("output.bin",GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
 if (hFile == INVALID_HANDLE_VALUE) {printf("Nelze otevrit vystupni soubor\n"); return 1;}
 // prepare time measurment
 QueryPerformanceFrequency(&freq);

 // open FTDI (as written, there must be only one FTDI in the PC, otherwise it is necessary to use a more suitable method of opening that identifies the specific chip)
 ftStatus = FT_Open(0, &ftHandle);
 if (ftStatus != FT_OK){printf("Err\n");return 1;}else{printf("OK.\n");}
 // set USB timeouts
 ftStatus = FT_SetTimeouts(ftHandle,20,20);
 if(ftStatus != FT_OK){printf("timeout A status not ok %lu\n", ftStatus);}
 // set USB buffers and latency timer
 FT_SetUSBParameters(ftHandle, 65536, 65536);
 FT_SetLatencyTimer(ftHandle, 1);

 // clear FTDI buffers
 ftStatus = FT_Purge(ftHandle, FT_PURGE_RX | FT_PURGE_TX);
 printf("FT_Purge %u\n",ftStatus);
 if(ftStatus != FT_OK){printf("Error FT_PURGE");return 1;}

 // Send dummy data to FTDI, which then sets RXF=0 and the MCU learns that the program is running and can send a test data packet.
 if(FT_Write(ftHandle, txbuf, 1, &bytesWritten) != FT_OK){printf("error FT_Write\n");return 1;}
 else{printf("Written %lu\n",bytesWritten);}

 while(1){
  // Try to read data from FTDI
  ftStatus = FT_Read(ftHandle, buffer, BUFFER_SIZE, &bytesRead);
  if (ftStatus != FT_OK){printf("FT_Read Error\n");break;}
  // if I've read something, it's time to start the stopwatch (we measure the transfer time)
  if(!mereni_casu && bytesRead>0){mereni_casu=1;QueryPerformanceCounter(&t_start);}
  // If I have read 0 bytes and the stopwatch was running, the transfer is complete and I will stop the stopwatch.
  if(mereni_casu==1 && bytesRead==0){QueryPerformanceCounter(&t_end);mereni_casu=2;}
  // count recieved bytes
  totalBytes += bytesRead;
  // write recieved data to file
  if (bytesRead > 0) {
   if (!WriteFile(hFile, buffer, bytesRead, &bytesWritten, NULL)) {printf("Chyba pri zapisu do souboru\n");break;}
  }
  // check keypress to stop program
  if (_kbhit()) {_getch();break;}
 }

 // close FTDI and file
 FT_Close(ftHandle);
 CloseHandle(hFile);
 // Print report
 printf("Total: %lu\n",totalBytes);
 double elapsed_s =(double)(t_end.QuadPart - t_start.QuadPart) / freq.QuadPart;
 double speed = ((double)totalBytes/(1024*1024))/elapsed_s;
 printf("Elapsed ms: %6.2fms\n",elapsed_s*1000.0);
 printf("Speed: %3.3fMB/s\n",speed);


 // ------------------------- recievede data check -----------------------------------
 // Open the file with the received data and check if the first byte is 0 and each subsequent byte is 1 greater.
 FILE *file = fopen("output.bin", "rb");
 if (file == NULL)
 {
  perror("Error file opening\n");
  return 1;
 }

 unsigned char prev_byte;
 unsigned char curr_byte;
 long long total_bytes = 0;
 int mismatch_count = 0;

 if (fread(&prev_byte, 1, 1, file) != 1)
 {
  printf("File is empty\n");
  fclose(file);
  return 1;
 }


 if (prev_byte != 0)
 {
  printf("error at address 0 (value %u)\n", prev_byte);
  mismatch_count++;
 }

 total_bytes = 1;
 long long address = 1;

 while (fread(&curr_byte, 1, 1, file) == 1)
 {
  unsigned char expected = (unsigned char)(prev_byte + 1);

  if (curr_byte != expected)
  {
   printf("Nesrovnalost na adrese %lld: ocekavano %u, nalezeno %u\n",
       address, expected, curr_byte);
   mismatch_count++;
  }

  prev_byte = curr_byte;
  total_bytes++;
  address++;
 }

 fclose(file);
 // output report
 printf("\n===== REPORT =====\n");
 printf("Number of bytes: %lld\n", total_bytes);
 printf("number of mismatch: %d\n", mismatch_count);

 if (mismatch_count == 0)
 {
  printf("Check succesful.\n");
 }
 else
 {
  printf("Check unsuccesful.\n");
 }
 return 0;
}

