// File: /workspace/github_cpp_makefile_star2_O1/SYZYGYfpga[P]brain-tools/src/smartvio-brain.cpp
// Function: main
int main (int argc, char *argv[])
{
	// Options flags
	int rflag = 0;
	int sflag = 0;
	int jflag = 0;
	int hflag = 0;
	int wflag = 0;
	int dflag = 0;
	uint32_t svio1 = 0;
	uint32_t svio2 = 0;
	char i2c_filename[200];
	char dna_filename[200];
	uint8_t dna_buf[1320];
	int i2c_file;
	int dna_file;
	int dna_length = 0;
	int periph_num = 0;
	int curr_opt;
	json json_handler;
	uint16_t peripheral_address[] = {0x30, 0x31, 0x32, 0x33};

	// Parse args
	while ((curr_opt = getopt(argc, argv, "rsj1:2:w:d:p:h")) != -1) {
		switch(curr_opt)
		{
			case 'r':
				rflag = 1;
				break;
			case 's':
				sflag = 1;
				break;
			case 'j':
				jflag = 1;
				break;
			case '1':
				if (optarg){ 
					svio1 = atoi(optarg);
				} else {
					printf("No argument specified for -1\n");
					exit(EXIT_FAILURE);
				}
				break;
			case '2':
				if (optarg){ 
					svio2 = atoi(optarg);
				} else {
					printf("No argument specified for -2\n");
					exit(EXIT_FAILURE);
				}
				break;
			case 'w':
				wflag = 1;
				if (optarg){ 
					strcpy(dna_filename, optarg);
				} else {
					printf("No argument specified for -w\n");
					exit(EXIT_FAILURE);
				}
				break;
			case 'd':
				dflag = 1;
				if (optarg){ 
					strcpy(dna_filename, optarg);
				} else {
					printf("No argument specified for -d\n");
					exit(EXIT_FAILURE);
				}
				break;
			case 'p':
				if (optarg){ 
					periph_num = strtol(optarg, NULL, 0) - 1;
				} else {
					printf("No argument specified for -p\n");
					exit(EXIT_FAILURE);
				}
				break;
			case 'h':
				hflag = 1;
				break;
			case '?':
				printHelp(argv[0]);
				exit(EXIT_FAILURE);
			default:
				printHelp(argv[0]);
				exit(EXIT_FAILURE);
		}
	}

	if ((hflag == 1) || (argc == 1)) {
		printHelp(argv[0]);
		return 0;
	}

	// Extract i2c device
	if (optind < argc) {
		strcpy(i2c_filename, argv[optind]);
	} else {
		printf("I2C Device required.\n");
		exit(EXIT_FAILURE);
	}

	// Open I2C file
	i2c_file = open(i2c_filename, O_RDWR);
	if (i2c_file < 0) {
		printf("Error opening i2c device\n");
		exit(EXIT_FAILURE);
	}

	if ((rflag + sflag + jflag + hflag + wflag + dflag) > 1) {
		printf("Invalid set of options specified.\n");
		printHelp(argv[0]);
		return 0;
	}

	if ((wflag == 1) || (dflag == 1)) {
		if (i2cDetect(i2c_file, peripheral_address[periph_num]) != 0) {
			printf("Peripheral at %X not found\n", peripheral_address[periph_num]);
			exit(EXIT_FAILURE);
		}

		dna_file = open(dna_filename, O_RDWR | O_CREAT, 0666);
		if (dna_file < 0) {
			printf("Error opening DNA file\n");
			exit(EXIT_FAILURE);
		}
	}

	if (rflag == 1) { // Run the main SmartVIO procedure
		if (readDNA(i2c_file, &svio1, &svio2) != 0) {
			printf("Error obtaining a SmartVIO solution\n");
			exit(EXIT_FAILURE);
		}

		if (applyVIO(i2c_file, svio1, svio2) != 0) {
			printf("Error applying SmartVIO settings to power supplies\n");
			exit(EXIT_FAILURE);
		}

		if (printVIOStrings(json_handler, i2c_file) != 0) {
			printf("Error retrieving DNA strings\n");
			exit(EXIT_FAILURE);
		}
	} else if (sflag == 1) { // Apply a user specified VIO
		if (applyVIO(i2c_file, svio1, svio2) != 0) {
			printf("Error applying SmartVIO settings to power supplies\n");
			exit(EXIT_FAILURE);
		}
	} else if (jflag == 1) {
		readDNA(i2c_file, &svio1, &svio2);

		// Bounds check on the svio ranges
		if ((svio1 < 120) || (svio1 > 330) || (svio2 < 120) || (svio2 > 330)) {
			json_handler["vio"][0] = 0;
			json_handler["vio"][1] = 0;
		} else {
			json_handler["vio"][0] = svio1;
			json_handler["vio"][1] = svio2;
		}

		printVIOStrings(json_handler, i2c_file);

		printf(json_handler.dump().c_str());
		printf("\n");
	} else if (wflag == 1) { // Write DNA from a file to a peripheral
		if (read(dna_file, &dna_length, 2) != 2) {
			printf("Error reading from DNA file\n");
			exit(EXIT_FAILURE);
		}

		if (dna_length > 1318) {
			printf("Invalid DNA Length\n");
			exit(EXIT_FAILURE);
		}

		lseek(dna_file, 0, SEEK_SET);
		if (read(dna_file, dna_buf, dna_length) != dna_length) {
			printf("Error reading from DNA file\n");
			exit(EXIT_FAILURE);
		}

		if (writeMCU(i2c_file, peripheral_address[periph_num], 0x8000,
		             dna_buf, dna_length) != 0) {
			printf("Error writing to the MCU\n");
			exit(EXIT_FAILURE);
		}
	} else if (dflag == 1) { // Dump DNA from a peripheral to a file
		dna_length = dumpDNA(i2c_file, peripheral_address[periph_num], dna_buf);

		if (dna_length < 0) {
			printf("Error reading DNA from device\n");
			exit(EXIT_FAILURE);
		}
		
		if (write(dna_file, dna_buf, dna_length) != dna_length) {
			printf("Error writing to DNA file\n");
			exit(EXIT_FAILURE);
		}
	} else {
		printHelp(argv[0]);
		return 0;
	}

	return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x778, %rsp            # imm = 0x778
movq %rsi, %r14
movl %edi, %ebx
xorl %eax, %eax
movl %eax, 0xc(%rsp)
movl %eax, 0x8(%rsp)
movq $0x0, 0x48(%rsp)
movl %eax, 0x10(%rsp)
leaq 0x20(%rsp), %r15
movb $0x0, (%r15)
movq $0x0, 0x8(%r15)
movq %r15, %rdi
callq 0x6efc
movq %r15, %rdi
callq 0x6efc
leaq 0x4e22(%rip), %r12      # 0x91fc
movq 0x9be7(%rip), %r13      # 0xdfc8
leaq 0x4c1c(%rip), %r15      # 0x9004
movq $0x0, 0x40(%rsp)
movl $0x0, 0x14(%rsp)
movq $0x0, 0x30(%rsp)
movq $0x0, 0x38(%rsp)
xorl %eax, %eax
movq $0x0, 0x18(%rsp)
movl %eax, %ebp
movl %ebx, %edi
movq %r14, %rsi
movq %r12, %rdx
callq 0x3070
cmpl $0x67, %eax
jle 0x4461
leal -0x70(%rax), %ecx
cmpl $0x7, %ecx
ja 0x449f
movl $0x1, %eax
movslq (%r15,%rcx,4), %rcx
addq %r15, %rcx
jmpq *%rcx
movq (%r13), %rdi
testq %rdi, %rdi
je 0x499b
xorl %esi, %esi
xorl %edx, %edx
callq 0x32d0
decl %eax
movq %rax, 0x18(%rsp)
movl %ebp, %eax
jmp 0x4416
cmpl $0x31, %eax
jle 0x44c2
cmpl $0x32, %eax
je 0x44e5
cmpl $0x64, %eax
jne 0x4973
movq (%r13), %rsi
testq %rsi, %rsi
je 0x4989
leaq 0xb0(%rsp), %rdi
callq 0x31f0
movl $0x1, %eax
movq %rax, 0x38(%rsp)
movl %ebp, %eax
jmp 0x4416
cmpl $0x68, %eax
je 0x453e
cmpl $0x6a, %eax
jne 0x4976
movl $0x1, %eax
movq %rax, 0x40(%rsp)
movl %ebp, %eax
jmp 0x4416
jne 0x454d
movq (%r13), %rdi
testq %rdi, %rdi
je 0x4992
callq 0x3320
movl %eax, 0xc(%rsp)
movl %ebp, %eax
jmp 0x4416
movq (%r13), %rdi
testq %rdi, %rdi
je 0x4980
callq 0x3320
movl %eax, 0x8(%rsp)
movl %ebp, %eax
jmp 0x4416
movq (%r13), %rsi
testq %rsi, %rsi
je 0x49a4
leaq 0xb0(%rsp), %rdi
callq 0x31f0
movl $0x1, %eax
movq %rax, 0x30(%rsp)
movl %ebp, %eax
jmp 0x4416
movl $0x1, %eax
movq %rax, 0x48(%rsp)
movl %ebp, %eax
jmp 0x4416
movl $0x1, 0x14(%rsp)
movl %ebp, %eax
jmp 0x4416
cmpl $-0x1, %eax
jne 0x4976
cmpl $0x0, 0x14(%rsp)
sete %al
cmpl $0x1, %ebx
setne %cl
testb %al, %cl
je 0x45d7
movq 0x9a71(%rip), %rax      # 0xdfe0
movslq (%rax), %rax
cmpl %ebx, %eax
jge 0x49ba
movq (%r14,%rax,8), %rsi
leaq 0x180(%rsp), %rbx
movq %rbx, %rdi
callq 0x31f0
movq %rbx, %rdi
movl $0x2, %esi
xorl %eax, %eax
callq 0x31a0
movq 0x48(%rsp), %r15
movq 0x40(%rsp), %r13
movl %eax, %ebx
testl %eax, %eax
js 0x49c3
movq 0x30(%rsp), %rdx
movq 0x38(%rsp), %rsi
leal (%rdx,%rsi), %ecx
addl %r13d, %ecx
addl %r15d, %ecx
addl %ebp, %ecx
cmpl $0x2, %ecx
jb 0x45fd
leaq 0x5a8f(%rip), %rdi      # 0xa061
callq 0x3310
movq (%r14), %rdi
callq 0x422e
leaq 0x20(%rsp), %rdi
callq 0x4db0
xorl %eax, %eax
addq $0x778, %rsp            # imm = 0x778
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl %edx, %eax
orl %esi, %eax
movq %rsi, %rax
je 0x4652
movslq 0x18(%rsp), %rax
leaq 0x5b1c(%rip), %rcx      # 0xa12e
movzwl (%rcx,%rax,2), %r12d
movl %ebx, %edi
movl %r12d, %esi
callq 0x350c
testl %eax, %eax
jne 0x49d5
leaq 0xb0(%rsp), %rdi
movl $0x42, %esi
movl $0x1b6, %edx            # imm = 0x1B6
xorl %eax, %eax
callq 0x31a0
movl %eax, %r12d
testl %eax, %eax
movq 0x38(%rsp), %rax
js 0x49e8
testl %ebp, %ebp
je 0x46a2
leaq 0xc(%rsp), %rsi
leaq 0x8(%rsp), %rdx
movl %ebx, %edi
callq 0x3812
testl %eax, %eax
jne 0x49cc
movl 0xc(%rsp), %esi
movl 0x8(%rsp), %edx
movl %ebx, %edi
callq 0x3936
testl %eax, %eax
jne 0x46be
leaq 0x20(%rsp), %rdi
movl %ebx, %esi
callq 0x3ad1
testl %eax, %eax
je 0x45df
leaq 0x5939(%rip), %rdi      # 0x9fd6
jmp 0x49ab
testl %r15d, %r15d
je 0x46ca
movl 0xc(%rsp), %esi
movl 0x8(%rsp), %edx
movl %ebx, %edi
callq 0x3936
testl %eax, %eax
je 0x45df
leaq 0x592e(%rip), %rdi      # 0x9ff3
jmp 0x49ab
testl %r13d, %r13d
je 0x4783
leaq 0xc(%rsp), %rsi
leaq 0x8(%rsp), %rdx
movl %ebx, %edi
callq 0x3812
movl $0xfffffeb5, %eax       # imm = 0xFFFFFEB5
movl 0xc(%rsp), %ecx
addl %eax, %ecx
cmpl $0xffffff2d, %ecx       # imm = 0xFFFFFF2D
jb 0x481f
addl 0x8(%rsp), %eax
cmpl $0xffffff2c, %eax       # imm = 0xFFFFFF2C
jbe 0x481f
leaq 0x60(%rsp), %rdi
leaq 0xc(%rsp), %rsi
callq 0x4e26
leaq 0x4b07(%rip), %rsi      # 0x9227
leaq 0x20(%rsp), %rdi
callq 0x4a54
movq %rax, %rdi
xorl %esi, %esi
callq 0x4bd6
leaq 0x60(%rsp), %r14
movq %rax, %rdi
movq %r14, %rsi
callq 0x4d70
movq %r14, %rdi
callq 0x4db0
leaq 0x50(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x4e26
leaq 0x4ac5(%rip), %rsi      # 0x9227
leaq 0x20(%rsp), %rdi
callq 0x4a54
movl $0x1, %esi
movq %rax, %rdi
callq 0x4bd6
leaq 0x50(%rsp), %r14
jmp 0x48ab
cmpl $0x0, 0x30(%rsp)
je 0x4919
leaq 0x10(%rsp), %rsi
movl $0x2, %edx
movl %r12d, %edi
callq 0x32f0
cmpq $0x2, %rax
jne 0x49f1
movslq 0x10(%rsp), %r14
cmpq $0x527, %r14            # imm = 0x527
jge 0x49fa
movl %r12d, %edi
xorl %esi, %esi
xorl %edx, %edx
callq 0x33c0
leaq 0x250(%rsp), %rsi
movl %r12d, %edi
movq %r14, %rdx
callq 0x32f0
cmpq %r14, %rax
jne 0x49f1
movslq 0x18(%rsp), %rax
leaq 0x593e(%rip), %rcx      # 0xa12e
movzwl (%rcx,%rax,2), %esi
leaq 0x250(%rsp), %rcx
movl %ebx, %edi
movl $0x8000, %edx           # imm = 0x8000
movl %r14d, %r8d
callq 0x369d
testl %eax, %eax
je 0x45df
leaq 0x5774(%rip), %rdi      # 0x9f8e
jmp 0x49ab
leaq 0x90(%rsp), %rsi
movl $0x0, (%rsi)
leaq 0x80(%rsp), %rdi
callq 0x4dfe
leaq 0x49e6(%rip), %rsi      # 0x9227
leaq 0x20(%rsp), %rdi
callq 0x4a54
movq %rax, %rdi
xorl %esi, %esi
callq 0x4bd6
leaq 0x80(%rsp), %r14
movq %rax, %rdi
movq %r14, %rsi
callq 0x4d70
movq %r14, %rdi
callq 0x4db0
leaq 0x90(%rsp), %rsi
movl $0x0, (%rsi)
leaq 0x70(%rsp), %rdi
callq 0x4dfe
leaq 0x4998(%rip), %rsi      # 0x9227
leaq 0x20(%rsp), %rdi
callq 0x4a54
movl $0x1, %esi
movq %rax, %rdi
callq 0x4bd6
leaq 0x70(%rsp), %r14
movq %rax, %rdi
movq %r14, %rsi
callq 0x4d70
movq %r14, %rdi
callq 0x4db0
leaq 0x20(%rsp), %rdi
movl %ebx, %esi
callq 0x3ad1
leaq 0x90(%rsp), %rdi
leaq 0x20(%rsp), %rsi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
movl $0x20, %ecx
xorl %r8d, %r8d
callq 0x4e4c
leaq 0xa0(%rsp), %rbx
movq -0x10(%rbx), %rdi
xorl %eax, %eax
callq 0x3040
movq -0x10(%rbx), %rdi
cmpq %rbx, %rdi
je 0x490a
callq 0x3200
movl $0xa, %edi
callq 0x32b0
jmp 0x45df
testl %eax, %eax
je 0x45d7
movslq 0x18(%rsp), %rax
leaq 0x5801(%rip), %rcx      # 0xa12e
movzwl (%rcx,%rax,2), %esi
leaq 0x250(%rsp), %rdx
movl %ebx, %edi
callq 0x378d
movl %eax, 0x10(%rsp)
testl %eax, %eax
js 0x4a03
movl %eax, %ebx
leaq 0x250(%rsp), %rsi
movl %r12d, %edi
movq %rbx, %rdx
callq 0x30c0
cmpq %rbx, %rax
je 0x45df
leaq 0x55e5(%rip), %rdi      # 0x9f56
jmp 0x49ab
cmpl $0x3f, %eax
movq (%r14), %rdi
callq 0x422e
jmp 0x49b0
leaq 0x576c(%rip), %rdi      # 0xa0f3
jmp 0x49ab
leaq 0x5729(%rip), %rdi      # 0xa0b9
jmp 0x49ab
leaq 0x5777(%rip), %rdi      # 0xa110
jmp 0x49ab
leaq 0x56fa(%rip), %rdi      # 0xa09c
jmp 0x49ab
leaq 0x572b(%rip), %rdi      # 0xa0d6
callq 0x3310
movl $0x1, %edi
callq 0x3280
leaq 0x5580(%rip), %rdi      # 0x9f41
jmp 0x49ab
leaq 0x56b9(%rip), %rdi      # 0xa083
jmp 0x49ab
leaq 0x5653(%rip), %rdi      # 0xa026
jmp 0x49ab
leaq 0x482f(%rip), %rdi      # 0x920b
movl %r12d, %esi
xorl %eax, %eax
callq 0x3040
jmp 0x49b0
leaq 0x565b(%rip), %rdi      # 0xa04a
jmp 0x49ab
leaq 0x55c2(%rip), %rdi      # 0x9fba
jmp 0x49ab
leaq 0x55a6(%rip), %rdi      # 0x9fa7
jmp 0x49ab
leaq 0x5566(%rip), %rdi      # 0x9f70
jmp 0x49ab
jmp 0x4a3e
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
jmp 0x4a37
movq %rax, %rbx
leaq 0x50(%rsp), %rdi
jmp 0x4a37
movq %rax, %rbx
leaq 0x80(%rsp), %rdi
jmp 0x4a37
movq %rax, %rbx
leaq 0x60(%rsp), %rdi
callq 0x4db0
jmp 0x4a41
movq %rax, %rbx
leaq 0x20(%rsp), %rdi
callq 0x4db0
movq %rbx, %rdi
callq 0x3390
nop