#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <linux/types.h>
#include <string.h>
#include <iostream>
#include <unistd.h>
#include <sys/mman.h>
#include <stdint.h>
#include <cstdio>
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include <fstream>
#include <limits>

#include "rio_lib_api.h"

#include "dwl_fw.h"

#define WRITE_DELAY_US       100000
#define WAITFLASH_DELAY_US   100000

#define MAX_RETRY_READ 1000

int srio_id = -1;

#define MAX_BUFFER_SIZE (1024 * 1024)  // 1MB
#define MAX_NUMBERS (MAX_BUFFER_SIZE / 9) // circa 9 byte per numero: 8 hex + separatore

constexpr size_t DWL_CHUNK_SIZE = 256;
constexpr size_t DWL_WORDS = DWL_CHUNK_SIZE / sizeof(unsigned int);
unsigned int dwl_buffer[DWL_WORDS];

unsigned int flashport;

constexpr size_t ERASE_BLOCK_SIZE = 65536;

int initSrio(int *srio_id)
{
    const char*                 devFullPathName = "/dev/zynq_xmc_rio_0";
    int                         openFlags = O_RDWR + O_NONBLOCK; // O_NONBLOCK makes the read operation not blocking when no data are available
    //int                         deviceFile; 

    if (rio_ok != (rio_open(devFullPathName, srio_id)))
    {   int err = errno;
        char buf[256];
        snprintf (buf, sizeof(buf), "open(\"%s\", %d) returns FAIL (%s)\n", devFullPathName, openFlags, strerror(err));
        perror (buf);
        exit(-err);
        return 0;
    }
    else
    {
        //rio_to_eth_mirror_set(1);
        return 1;
    }
}

bool parse_args(int argc, char** argv, uint16_t* endpoint, uint32_t* address, uint32_t* value) {
    if (argc != 4) {
        fprintf(stderr, "Uso: %s <endpoint hex> <address hex> <value>\n", argv[0]);
        return false;
    }

    // Parsing dell'endpoint come uint16_t
    char* endptr = nullptr;
    unsigned long ep = strtoul(argv[1], &endptr, 0);
    if (*endptr != '\0' || ep > 0xFFFF) {
        fprintf(stderr, "Endpoint non valido: %s\n", argv[1]);
        return false;
    }
    *endpoint = static_cast<uint16_t>(ep);

    // Parsing dell'address come uint32_t
    unsigned long addr = strtoul(argv[2], &endptr, 0);
    if (*endptr != '\0' || addr > 0xFFFFFFFF) {
        fprintf(stderr, "Address non valido: %s\n", argv[2]);
        return false;
    }
    *address = static_cast<uint32_t>(addr);

    // Parsing del valore come uint32_t
    unsigned long val = strtoul(argv[3], &endptr, 0);
    if (*endptr != '\0' || val > 0xFFFFFFFF) {
        fprintf(stderr, "valore non valido: %s\n", argv[2]);
        return false;
    }
    *value = static_cast<uint32_t>(val);
    return true;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////// BASE FUNCTION //////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


int srio_write_reg(uint16_t endpoint, uint32_t address, uint32_t value, int max_retry = 500, int timeout_us = 1000)     //fatto
{
    /*printf("Endpoint: 0x%04x\n", endpoint);
    printf("Address:  0x%08x\n", address);
    printf("Value:        %d\n", value);*/
    rio_result res;

    uint32_t address_offset = address & 0x000000FF;
    if (address_offset % 4)
    {
        printf("\nAddress 0x%08X non è multiplo di 4",address);
        return INPUT_NOT_VALID;
    }

    uint32_t buffer_size = 256/sizeof(unsigned int);

    unsigned int* buffer = (unsigned int*)malloc(256);
    if (!buffer) {
        perror("Errore nell'allocazione del buffer");
        free(buffer); 
        return GENERIC_ERROR;
    }    

    uint32_t address_aligned = address & 0xFFFFFF00;
 
    res = rio_nread(srio_id, endpoint, address_aligned, buffer, buffer_size*4);
    if (res != rio_ok) {
        printf("\nErrore nella lettura da SRIO %d",res);
        free(buffer); 
        return SRIO_READ_ERROR;
    }  

    int i;
    for ( i = 0; i < max_retry; i++)
    {
        buffer[address_offset/4] = value;

        res =  rio_nwrite(	srio_id, 				    //rio_id rid
                        endpoint,			        //uint16_t remote_endpoint_id
                        address_aligned,        	        //void* remote_addr (the virtual machine is a 64bit operating system)
                        buffer,	    //void* sending_payload
                        buffer_size*4);                      //numCount*sizeof(uint32_t));		//size_t payload_size  
        if (res != rio_ok)
        {
            printf("\nError writing to srio res=%d",res);        
            free(buffer);
            return SRIO_WRITE_ERROR;
        }
        
        if(address == TX_FIFO_REG) break;

        res = rio_nread(srio_id, endpoint, address_aligned, buffer, buffer_size*4);
        if (res != rio_ok) {
            printf("\nErrore nella lettura da SRIO %d",res);
            free(buffer); 
            return SRIO_READ_ERROR;
        }
        
        if(buffer[address_offset/4] == value) break;
        
        usleep(timeout_us);
    }

    if(i == max_retry) printf("\nsrio_write_reg:: FAIL (max retry) address 0x%08X, value 0x%08X\n",address, value);
    // Cleanup
    free(buffer);

    return NO_ERROR;
}

int srio_wait_reg(  uint16_t endpoint,              //fatto
                    uint32_t address,
                    uint32_t pos,
                    uint32_t value, 
                    int max_retry       = 500,
                    int timeout_us      = 1000)
{
    /*printf("Endpoint: 0x%04x\n", endpoint);
    printf("Address:  0x%08x\n", address);
    printf("Value:        %d\n", value);*/


    uint32_t address_offset = address & 0x000000FF;
    if (address_offset % 4)
    {
        printf("\nAddress 0x%08X non è multiplo di 4",address);
        return INPUT_NOT_VALID;
    }

    uint32_t buffer_size = 256/sizeof(unsigned int);

    unsigned int* buffer = (unsigned int*)malloc(256);
    if (!buffer) {
        perror("Errore nell'allocazione del buffer");
        free(buffer); 
        return GENERIC_ERROR;
    }    

    uint32_t    address_aligned = address & 0xFFFFFF00;
    int         i;
    int         res = NO_ERROR;
    rio_result  res_srio;

    for ( i = 0; i < max_retry; i++)
    {
        res_srio = rio_nread(srio_id, endpoint, address_aligned, buffer, buffer_size*4);
        if (res_srio != rio_ok) {
            printf("\nErrore nella lettura da SRIO %d",res);
            free(buffer); 
            return SRIO_READ_ERROR;
        }

        if (( (buffer[address_offset/4]) >> pos & 0x00000001 ) == value)
        {
            //printf("\nreg: 0x%08X, pos: %d, value: %d. (wait finish)\n",address, pos, value);
            break;
        }
        else
        {
            //printf("\nWarning: SRIO WAIT: reg: 0x%08X, pos: %d, value: %d\n",address, pos, value);
            if (    address == STATUS_REG && 
                    pos     == 12 &&
                    value   == 0)
            {
                srio_write_reg(endpoint, CTRL_REG,  0x01);
            }
            
            
            res = SRIO_WAIT_ERROR;
        }
        
        usleep(timeout_us);
    }
    if (i == max_retry)
    {
        //printf("\nwait_flash exit: FAILED for max retry: %d\n",i);
        if (address != RX_FIFO_REG) 
        {
            printf("\nwait_flash exit: FAILED for max retry: %d\n",i);
            printf("\nWarning: SRIO WAIT: reg: 0x%08X, pos: %d, value_expected: %d\n",address, pos, value);
            printf("\nPROGRAM STOPPED !\n");
            exit(1);
        }
    }
    //else
        //printf("\nwait_flash exit: retry: %d\n",i);

    free(buffer);
    return res;

}


int srio_write_data(uint16_t endpoint, uint32_t address, uint32_t *data, uint32_t byte)         //fatto (per ora scrive una rampa ogni 256 byte)
{
    /*printf("Endpoint: 0x%04x\n", endpoint);
    printf("Address:  0x%08x\n", address);
    printf("Value:        %d\n", value);*/
    rio_result res;

    uint32_t address_offset = address & 0x000000FF;
    if (address_offset)
    {
        printf("\nsrio_write_data: Address 0x%08X non è multiplo di 256 byte",address);
        return INPUT_NOT_VALID;
    }

    uint32_t buffer_size = 256/sizeof(unsigned int);

    unsigned int* buffer;  
    buffer = (unsigned int*)malloc(256);
        if (!buffer) {
            perror("Errore nell'allocazione del buffer");
            free(buffer); 
            return GENERIC_ERROR;
        }

    if(data == NULL)
    {
        for (int i = 0; i < byte/4; i++)
            {
                buffer[i] = i;
            }
        //NWRITE_SRIO_TX
        res =  rio_nwrite(	srio_id, 				    //rio_id rid
                            endpoint,			        //uint16_t remote_endpoint_id
                            address,        	        //void* remote_addr (the virtual machine is a 64bit operating system)
                            buffer,	                    //void* sending_payload
                            buffer_size*4);             //numCount*sizeof(uint32_t));		//size_t payload_size  
    }
    else 
    {
        res =  rio_nwrite(	srio_id, 				    //rio_id rid
                            endpoint,			        //uint16_t remote_endpoint_id
                            address,        	        //void* remote_addr (the virtual machine is a 64bit operating system)
                            data,	                    //void* sending_payload
                            buffer_size*4);             //numCount*sizeof(uint32_t));		//size_t payload_size  
    }

    
    if (res != rio_ok)
    {
        printf("\nError writing to srio res=%d",res);        
        free(buffer);
        return SRIO_WRITE_ERROR;
    }                        

    // Cleanup
    free(buffer);

    return NO_ERROR;
}

int srio_read_reg(uint16_t endpoint, uint32_t address, uint32_t byte)     //fatto
{
    /*printf("Endpoint: 0x%04x\n", endpoint);
    printf("Address:  0x%08x\n", address);
    printf("byte:        %d\n", byte);*/
    rio_result res;

    uint32_t address_offset = address & 0x000000FF;
    if (address_offset % 4)
    {
        printf("\nAddress 0x%08X non è multiplo di 4",address);
        return INPUT_NOT_VALID;
    }

    uint32_t buffer_size = 256/sizeof(unsigned int);

    unsigned int* buffer = (unsigned int*)malloc(256);
    if (!buffer) {
        perror("Errore nell'allocazione del buffer");
        free(buffer); 
        return GENERIC_ERROR;
    }    

    uint32_t address_aligned = address & 0xFFFFFF00;

    res = rio_nread(srio_id, endpoint, address_aligned, buffer, buffer_size*4);
    if (res != rio_ok) {
        printf("\nErrore nella lettura da SRIO %d",res);
        free(buffer); 
        return SRIO_READ_ERROR;
    }           

    printf("\nRead Value: \n");
    for (int i = 0; i < buffer_size; i=i+4)
    {
        printf("0x%08X 0x%08X 0x%08X 0x%08X \n", buffer[i], buffer[i+1], buffer[i+2], buffer[i+3]);
    }

    // Cleanup
    free(buffer);

    return NO_ERROR;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////// MAIN MACRO ////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*
./SRIOwrite < SRIO ID > CTRL_REG 0x01
# aspetta che il bit#11 di STATUS_REG va a 1
*/
int start_request(uint16_t endpoint){           //fatto
    srio_write_reg(endpoint, CTRL_REG, 0x01);
    srio_wait_reg(endpoint,STATUS_REG,11,1);
    return NO_ERROR;
}

/*
# controlla che i bit #1 #4 #5 #6 #10 di STATUS_REG sono 0 altrimenti ferma tutto e riporta errore
./SRIOwrite < SRIO ID > CTRL_REG 0x00
# aspetta che il bit#11 di STATUS_REG va a 0
*/
int end_request(uint16_t endpoint){             //fatto
    srio_wait_reg(endpoint,STATUS_REG,1,0);  
    srio_wait_reg(endpoint,STATUS_REG,4,0);  
    srio_wait_reg(endpoint,STATUS_REG,5,0);  
    srio_wait_reg(endpoint,STATUS_REG,6,0);  
    srio_wait_reg(endpoint,STATUS_REG,10,0);
    srio_write_reg(endpoint, CTRL_REG, 0x00);
    srio_wait_reg(endpoint,STATUS_REG,11,0);
    return NO_ERROR;
}

/*
./SRIOwrite < SRIO ID > CTRL_REG 0x03
# aspetta che il bit#12 di STATUS_REG va a 1
./SRIOwrite < SRIO ID > CTRL_REG 0x01
# aspetta che il bit#12 di STATUS_REG va a 0
END_REQUEST
*/
int write_data(uint16_t endpoint){           //     fatto
    srio_write_reg(endpoint, CTRL_REG,  0x03);
    srio_wait_reg(endpoint,STATUS_REG,12,1);
    srio_write_reg(endpoint, CTRL_REG,  0x01);
    srio_wait_reg(endpoint,STATUS_REG,12,0);
    end_request(endpoint);
    return NO_ERROR;
}

/*
START_REQUEST
./SRIOwrite < SRIO ID > CTRL_REG 0x03
# aspetta che il bit#12 di STATUS_REG va a 1
./SRIOwrite < SRIO ID > CTRL_REG 0x01
# aspetta che il bit#12 di STATUS_REG va a 0
*/
int read_data(uint16_t endpoint){               //fatto
    start_request(endpoint);
    srio_write_reg(endpoint, CTRL_REG,  0x03);
    srio_wait_reg(endpoint,STATUS_REG,12,1);
    srio_write_reg(endpoint, CTRL_REG,  0x01);
    srio_wait_reg(endpoint,STATUS_REG,12,0);
    return NO_ERROR;
}

/*
START_REQUEST
./SRIOwrite < SRIO ID > CTRL_REG 0x03
# aspetta che il bit#12 di STATUS_REG va a 1
./SRIOwrite < SRIO ID > CTRL_REG 0x01
# aspetta che il bit#12 di STATUS_REG va a 0
END_REQUEST
*/
int send_request(uint16_t endpoint){        //fatto
    start_request(endpoint);
    srio_write_reg(endpoint, CTRL_REG,  0x03);
    srio_wait_reg(endpoint,STATUS_REG,12,1);
    srio_write_reg(endpoint, CTRL_REG,  0x01);
    srio_wait_reg(endpoint,STATUS_REG,12,0);
    end_request(endpoint);
    return NO_ERROR;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// GENERAL FUNCTIONS //////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*
./SRIOwrite < SRIO ID > MODE_REG 0x00
./SRIOwrite < SRIO ID > CMD_REG 0x06
SEND_REQUEST
./SRIOwrite < SRIO ID > MODE_REG 0x00
./SRIOwrite < SRIO ID > CMD_REG 0x61
START_REQUEST
./SRIOwrite < SRIO ID > TX_FIFO_REG 0x6F
WRITE_DATA
./SRIOwrite < SRIO ID > MODE_REG 0x02
./SRIOwrite < SRIO ID > CMD_REG 0x06
SEND_REQUEST
./SRIOwrite < SRIO ID > MODE_REG 0x02
./SRIOwrite < SRIO ID > CMD_REG 0xB7
*/
int op_init_qspi(uint16_t endpoint)                 //fatto
{
    printf("\nop_init_qspi endpoint: 0x%04X\n", endpoint);
    srio_write_reg(endpoint, MODE_REG,  0x00 + flashport);
    srio_write_reg(endpoint, CMD_REG,   0x06);
    send_request(endpoint);
    srio_write_reg(endpoint, MODE_REG,  0x00 + flashport);
    srio_write_reg(endpoint, CMD_REG,   0x61);
    start_request(endpoint);
    srio_write_reg(endpoint, TX_FIFO_REG, 0x6F);
    write_data(endpoint);
    srio_write_reg(endpoint, MODE_REG,  0x02 + flashport);
    srio_write_reg(endpoint, CMD_REG,   0x06);
    send_request(endpoint);
    srio_write_reg(endpoint, MODE_REG,  0x02 + flashport);
    srio_write_reg(endpoint, CMD_REG,   0xB7);
    send_request(endpoint);
    return NO_ERROR;
}

/*
./SRIOwrite < SRIO ID > MODE_REG 0x06
./SRIOwrite < SRIO ID > ADDR_REG < MEMORY ADDRESS >
./SRIOwrite < SRIO ID > NUM_BYTE_REG < NUM BYTE TO READ >
./SRIOwrite < SRIO ID > CMD_REG 0x0B
READ_DATA
./SRIOread < SRIO ID > RX_FIFO_REG < DATA TO READ >
END_REQUEST
*/
int read_flash(uint16_t endpoint, uint32_t address, uint32_t byte)          //fatto         
{
    printf("\nop_init_qspi endpoint: 0x%04X, address 0x%08X, byte: %d \n", endpoint, address, byte);
    srio_write_reg(endpoint, MODE_REG,  0x06 + flashport);
    srio_write_reg(endpoint, ADDR_REG,  address);
    srio_write_reg(endpoint, NUM_BYTE_REG,  byte);
    srio_write_reg(endpoint, CMD_REG,  0x0B);
    read_data(endpoint);
    srio_read_reg(endpoint, RX_FIFO_REG, byte);
    end_request(endpoint);
    return NO_ERROR;
}

/*
./SRIOwrite < SRIO ID > MODE_REG 0x06
./SRIOwrite < SRIO ID > CMD_REG 0x05
READ_DATA
# aspetta che il bit#0 di RX_FIFO_REG va a 0
END_REQUEST
*/
int wait_flash(uint16_t endpoint)          //fatto         
{
    int res = NO_ERROR;
    
    //printf("\nwait_flash...\n");
    res += srio_write_reg(endpoint, MODE_REG,  0x06 + flashport);
    res += srio_write_reg(endpoint, CMD_REG,  0x05);
    res += read_data(endpoint);
    res += srio_wait_reg(endpoint,RX_FIFO_REG,0,0);
    res += end_request(endpoint);
    return res;
}

int wait_flash_with_retry(uint16_t endpoint,int max_retry, int timeout_us)        
{
    int res = NO_ERROR;
    int i;

    for ( i = 0; i < max_retry; i++)
    {
        res = wait_flash(endpoint);
        if(res == NO_ERROR)         
            break;
        usleep(timeout_us);
    }
    if (i == max_retry)        printf("\nwait_flash exit: FAILED for max retry: %d\n",i);
    //else                       printf("\nwait_flash exit: retry: %d\n",i);

    return res;
}

/*
./SRIOwrite < SRIO ID > MODE_REG 0x02
./SRIOwrite < SRIO ID > CMD_REG 0x06
SEND_REQUEST
./SRIOwrite < SRIO ID > MODE_REG 0x06
./SRIOwrite < SRIO ID > ADDR_REG < MEMORY ADDRESS >
./SRIOwrite < SRIO ID > NUM_BYTE_REG < NUM BYTE TO WRITE >
./SRIOwrite < SRIO ID > CMD_REG 0x02
START_REQUEST
./SRIOwrite < SRIO ID > TX_FIFO_REG < DATA TO WRITE >
# Per esempio:
# ./SRIOwrite < SRIO ID > TX_FIFO_REG 0x12345678 0xAABBCCDD 0x00112233 0x24681357 0x12345678 0xAABBCCDD 0x00112233 0x24681357
WRITE_DATA
*/
int write_flash(uint16_t endpoint, uint32_t address, uint32_t *data, uint32_t byte)         //fatto     
{
    //printf("\nwrite_flash endpoint: 0x%04X, address 0x%08X, byte: %d \n", endpoint, address, byte);
    srio_write_reg(endpoint, MODE_REG,  0x02 + flashport);
    srio_write_reg(endpoint, CMD_REG,  0x06);
    send_request(endpoint);
    srio_write_reg(endpoint, MODE_REG,  0x06 + flashport);
    srio_write_reg(endpoint, ADDR_REG,  address);
    srio_write_reg(endpoint, NUM_BYTE_REG,  byte);
    srio_write_reg(endpoint, CMD_REG,  0x02);
    start_request(endpoint);
    srio_write_data(endpoint, TX_FIFO_REG,  data, 256);
    write_data(endpoint);
    return NO_ERROR;
}

/*
./SRIOwrite < SRIO ID > MODE_REG 0x02
./SRIOwrite < SRIO ID > CMD_REG 0x06
SEND_REQUEST
./SRIOwrite < SRIO ID > MODE_REG 0x06
./SRIOwrite < SRIO ID > ADDR_REG < MEMORY ADDRESS >
./SRIOwrite < SRIO ID > NUM_BYTE_REG 0x00
./SRIOwrite < SRIO ID > CMD_REG 0xD8
SEND_REQUEST
*/
int erase_section(uint16_t endpoint, uint32_t address)              //fatto          
{
    printf("\nerase_section endpoint: 0x%04X, address 0x%08X\n", endpoint, address);
    srio_write_reg(endpoint, MODE_REG,  0x02 + flashport);
    srio_write_reg(endpoint, CMD_REG,  0x06);
    send_request(endpoint);
    srio_write_reg(endpoint, MODE_REG,  0x06 + flashport);
    srio_write_reg(endpoint, ADDR_REG,  address);
    srio_write_reg(endpoint, NUM_BYTE_REG,  0x00);
    srio_write_reg(endpoint, CMD_REG,  0xD8);
    send_request(endpoint);
    return NO_ERROR;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int main(int argc, char* argv[])
{
	uint16_t endpoint;
    uint32_t address;
    uint32_t value;
    rio_result res;
    if (!parse_args(argc, argv, &endpoint, &address, &value)) {
        return 1; // errore nei parametri
    }

    printf("Endpoint: 0x%04x\n", endpoint);
    printf("Address:  0x%08x\n", address);
    printf("Value:        %d\n", value);

    initSrio(&srio_id);
    
    /*
    erase_section(endpoint, 0x01F00000);
    wait_flash_with_retry(endpoint, MAX_RETRY_READ, 1000);
    erase_section(endpoint, 0x01F10000);
    wait_flash_with_retry(endpoint, MAX_RETRY_READ, 1000);
    erase_section(endpoint, 0x01F20000);
    wait_flash_with_retry(endpoint, MAX_RETRY_READ, 1000);

    write_flash(endpoint,0x01F00000,NULL,256);
    wait_flash_with_retry(endpoint, MAX_RETRY_READ, 1000);
    write_flash(endpoint,0x01F00100,NULL,256);
    wait_flash_with_retry(endpoint, MAX_RETRY_READ, 1000);
    write_flash(endpoint,0x01F00200,NULL,256);
    wait_flash_with_retry(endpoint, MAX_RETRY_READ, 1000);
    
    read_flash(endpoint, 0x01F00000, 256);
    read_flash(endpoint, 0x01F00100, 256);
    read_flash(endpoint, 0x01F00200, 256);
    */

    std::cout << "insert download file: "<< std::endl;
    
    std::string filename;
    std::streamsize size = 0;

    std::getline(std::cin, filename);
    

    std::ifstream file(filename,std::ios::binary | std::ios::ate);
    if (!file)
    {
        std::cerr <<"impossibile aprire il file\n";
        close(srio_id);
        return 1;
    }
    else
    {
        size = file.tellg();
        std::cout << "File Dimension: " << size << "bytes\n";
    }
    
    std::cout << "insert flash number ( primary : 0  ,   secondary : 1): ";
    std::string line;
    std::getline(std::cin,line);
    try
    {
        flashport = std::stoul(line, nullptr,10);
        if(flashport !=0 && flashport !=1)
        {
            std::cerr << "Flash number errato!" << '\n';
            close(srio_id);
            file.close();
            exit(1);
        }
    }
    catch(...)
    {
        std::cerr << "Numero non valido!" << '\n';
        close(srio_id);
        file.close();
    }

    if(flashport == 1) flashport = 8;


    std::cout << "insert flash address (fomato esadecimale senza 0x): ";
    //std::string line;
    std::getline(std::cin,line);

    unsigned int start_address_to_dwl;
    try
    {
        start_address_to_dwl = std::stoul(line, nullptr,16);
    }
    catch(...)
    {
        std::cerr << "Numero esadecimale non valido!" << '\n';
        close(srio_id);
        file.close();
    }
    


    printf("\nIndirizzo inserito: 0x%08X\n",start_address_to_dwl);
    std::cout << "Procediamo? (Ctrl+C per annullare)";
    std::getline(std::cin,line);



    op_init_qspi(endpoint);
    op_init_qspi(endpoint);
    read_flash(endpoint, address, 256);

    std::cout << "Procediamo? (Ctrl+C per annullare)";
    std::getline(std::cin,line);


    //ERASE FULL SECTION
    std::cout << "\nErasing memory...\n\n";
    int i;
    unsigned long start_address_to_erase = start_address_to_dwl;   
    for ( i = 0; i < size; i = i + ERASE_BLOCK_SIZE)
    {
        erase_section(endpoint, start_address_to_erase);
        wait_flash_with_retry(endpoint, MAX_RETRY_READ, 1000);

        start_address_to_erase  += ERASE_BLOCK_SIZE;
        if (start_address_to_erase > start_address_to_dwl+size)
            start_address_to_erase = start_address_to_dwl+size;
        std::cout   << "\rErasing..  "
                    << i << " / " << size
                    << " byte"
                    << std::flush;
    }
    

    std::cout << "Procediamo? (Ctrl+C per annullare)";
    std::getline(std::cin,line);

    //WRITE DATA
    std::cout << "\nWriting memory...\n\n";
    
    file.seekg(0, std::ios::beg);       //puntiamo all'inizio del file
    
    address = start_address_to_dwl;
    std::streamsize bytes_read = 0;
    std::streamsize bytes_written  = 0;
    while (file) {
        file.read(reinterpret_cast<char*>(dwl_buffer), DWL_CHUNK_SIZE);
        bytes_read = file.gcount();

        if (bytes_read == 0)
            break;

        // Se l’ultimo blocco è < 256 byte, padding a zero
        if (bytes_read < DWL_CHUNK_SIZE) {
            std::memset(
                reinterpret_cast<char*>(dwl_buffer) + bytes_read,
                0,
                DWL_CHUNK_SIZE - bytes_read
            );
        }

        write_flash(endpoint, address, dwl_buffer, DWL_CHUNK_SIZE);
        usleep(WRITE_DELAY_US*value);
        wait_flash_with_retry(endpoint, MAX_RETRY_READ, 1000);
        usleep(WAITFLASH_DELAY_US*value);
        address += DWL_CHUNK_SIZE;

        bytes_written  += DWL_CHUNK_SIZE;
        if (bytes_written > size)
            bytes_written = size;
        std::cout   << "\rWriting "
                    << bytes_written << " / " << size
                    << " byte"
                    << " address: " << std::hex << address
                    << std::flush;
        
    }
    
    std::cout << std::endl;    
    
    
    file.close();

    close(srio_id);
    return 0;
}

/*
per tutte le altre "aspetta" bisogna rileggere lo stesso registro con nread, non rifacendo tutta la macro
mi devo fermare subito se non va mai al valore

nell'endrequest la "controlla" controlla solamente e se c'è qualche errore si blocca tutto
*/



