#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <ctype.h>
#include <string.h>
#include <pthread.h>
#include <hot.h>
#include <kria.h>
#include "parserRL.hot"
#include "parserRL1.hot"

#define AXI_HPM0_FPD0 0xA0000000
#define AXI_HPM0_FPD1 0xA0010000
#define AXI_HPM0_FPD2 0xA0020000


int main(int argc, char *argv[]) {
// for each runtime hot file do this
parserRL_init();
parserRL1_init();

int fd0 = 0;
int fd1 = 0;
int fd2 = 0;
FILE *text_in;
FILE *text_out;
FILE *text_out1;
volatile uint64_t *mem0;
volatile uint64_t *mem1;
volatile uint64_t *mem2;
char iname[1024], oname[1024], oname1[1024];
strcpy (iname,argv[1]);
strcpy (oname,argv[2]);
strcpy (oname1,argv[3]);
//printf("%s %s\n",iname,oname); 
fd0 = open("/dev/mem", O_RDWR|O_SYNC);
if (fd0 > -1 ) printf("opened mem0\n");
else {printf("Cound not open mem0\n");exit(-1);}
fd1 = open("/dev/mem", O_RDWR|O_SYNC);
if (fd1 > -1 ) printf("opened mem1\n");
else {printf("Cound not open mem1\n");exit(-1);}
fd2 = open("/dev/mem", O_RDWR|O_SYNC);
if (fd2 > -1 ) printf("opened mem2\n");
else {printf("Cound not open mem2\n");exit(-1);}
// opens the HPM0_FPD bus
mem0 = (uint64_t *)mmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd0, AXI_HPM0_FPD0);
mem1 = (uint64_t *)mmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, AXI_HPM0_FPD1);
mem2 = (uint64_t *)mmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, AXI_HPM0_FPD2);

if (mem0 == (void *) -1) {printf("could not map mem\n"); exit(0);}
if (mem1 == (void *) -1) {printf("could not map mem\n"); exit(0);}
if (mem2 == (void *) -1) {printf("could not map mem\n"); exit(0);}
text_in = fopen(iname,"ra");
if (text_in == NULL) {
        printf("Could not open %s\n",iname);
        exit(1);
    }
fseek(text_in, 0L, SEEK_END);
uint64_t size = ftell(text_in);
int num_words = 0;
//go back to the start of the file
rewind(text_in);
num_words = size / 8;
//if (size%8 != 0) num_words = num_words + 1; 
printf("Read: size mod(8) = %ld \n",size);
printf("text.txt size: bytes = %ld, num_words (size/8) = %d\n",size,num_words);
//there will be less text out than text in
uint64_t volatile test_data[num_words + 1];
text_out = fopen(oname,"w");
if(text_out == NULL) {
printf("could not open %s\n",oname); 
exit(-1);
}
text_out1 = fopen(oname1,"w");
if(text_out1 == NULL) {
printf("could not open %s\n",oname1); 
exit(-1);
}
// read file and flip endianness, could be done in hardware
char *data = (char *) aligned_alloc(512,size+8);
for (int i = 0; i < size+8; i = i+8) 
	for (int j = 7; j >= 0; j--){
	fscanf(text_in,"%c",&data[i+j]);
	}

hot_reset(mem0 + 0x200);
loadsmdata (mem1,&parserRL);
loaduberLUT(mem2,&parserRL);

uint64_t write_done = 0;

ReadParams_t *ReadParams = (ReadParams_t *) aligned_alloc(512, sizeof(ReadParams_t));
ReadParams->data_out = (char *) test_data;
ReadParams->baseaddress = mem0;
ReadParams->statusbase =  mem1;
ReadParams->words_read = 0;
ReadParams->write_done = &write_done;
ReadParams->flush_char = 'A';

WriteParams_t *WriteParams = (WriteParams_t *) aligned_alloc(512, sizeof(WriteParams_t));
WriteParams->data_in = data;
WriteParams->baseaddress = mem0;
WriteParams->statusbase = mem1;
WriteParams->size_in_bytes = size;
WriteParams->fifo_size = 0x200;
WriteParams->write_done = &write_done;


pthread_t ReadThread, WriteThread;
pthread_create(&WriteThread,NULL,write_kria,(void *) WriteParams);
pthread_create(&ReadThread,NULL,read_kria,(void *) ReadParams);
pthread_join(ReadThread,NULL);
pthread_join(WriteThread,NULL);

printf("main:1 words read out %ld\n", ReadParams->words_read);

char *temp;

// write and flip endianness
for (int i = 0; i < ReadParams->words_read; i++) { 
	temp = (char*) &test_data[i];
	for (int j = 7; j >= 0; j--){
		fputc(temp[j],text_out);
        }
}


hot_reset(&mem0[0x200]);
loadsmdata (mem1,&parserRL1);
loaduberLUT(mem2,&parserRL1);

pthread_create(&WriteThread,NULL,write_kria,(void *) WriteParams);
pthread_create(&ReadThread,NULL,read_kria,(void *) ReadParams);
pthread_join(ReadThread,NULL);
pthread_join(WriteThread,NULL);

printf("main:2 words read out %ld\n", ReadParams->words_read);
// flip endianness
for (int i = 0; i < ReadParams->words_read; i++) { 
	temp = (char*) &test_data[i];
	for (int j = 7; j >= 0; j--){
		fputc(temp[j],text_out1);
        }
}


pthread_exit(NULL);
fclose(text_in);
fclose(text_out);
fclose(text_out1);
return(0);
}
