#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <stdint.h>
#include "ftd2xx.h"

#define BUFFER_SIZE (64*1024)

HANDLE hFile;
FT_HANDLE ftHandle;
FT_STATUS ftStatus;
char buffer[BUFFER_SIZE]; // recieved data buffer
char txbuf[2]; // for transmit dummy data
DWORD bytesRead, bytesWritten;
unsigned long int totalBytes=0; // number of total recieved bytes

LARGE_INTEGER freq; // for time measurment
LARGE_INTEGER t_start;
LARGE_INTEGER t_end;
char mereni_casu=0;

int main(void){
    // open file to save recieved 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;}
    // set time measurment
    QueryPerformanceFrequency(&freq);

    // open FTDI (only one FTDI connected now !)
    ftStatus = FT_Open(0, &ftHandle);
    if (ftStatus != FT_OK){printf("Err\n");return 1;}else{printf("OK.\n");}
    // Set timeouts for FT_Read/FT_Write
    ftStatus = FT_SetTimeouts(ftHandle,20,20);
    if(ftStatus != FT_OK){printf("timeout A status not ok %lu\n", ftStatus);}
    // Setu USB buffers and latency timer
    FT_SetUSBParameters(ftHandle, 65536, 65536);
    FT_SetLatencyTimer(ftHandle, 1);

    // Clear all buffers (MCU should not transmit now)
    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;}

    // Transmit dummy byte to MCU to indicate that PC program runs
    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 readed something, then start time measurment
        if(!mereni_casu && bytesRead>0){mereni_casu=1;QueryPerformanceCounter(&t_start);}
        // if readed 0 bytes, and measuring time, then acquire "stop time"
        if(mereni_casu==1 && bytesRead==0){QueryPerformanceCounter(&t_end);mereni_casu=2;}
        // count number of 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;}
        }
        // stop if keypres
        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);


    // ------------------------- data check -----------------------------------

    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;

    // get first byte
    if (fread(&prev_byte, 1, 1, file) != 1)
    {
        printf("File is empty\n");
        fclose(file);
        return 1;
    }

    // first byte should be 0
    if (prev_byte != 0)
    {
        printf("error at address 0 (value %u)\n", prev_byte);
        mismatch_count++;
    }

    total_bytes = 1;
    long long address = 1;

    // read all following bytes from file and chek if it count 0->256...
    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);

    // 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;

}

