// File: /workspace/github_cpp_makefile_star2_O3/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 $0x788, %rsp            # imm = 0x788
movq %rsi, %r14
movl %edi, %ebx
xorl %eax, %eax
movl %eax, 0x10(%rsp)
movl %eax, 0xc(%rsp)
movq $0x0, 0x58(%rsp)
movl %eax, 0x1c(%rsp)
leaq 0x28(%rsp), %r15
movb $0x0, (%r15)
movq $0x0, 0x8(%r15)
movq %r15, %rdi
callq 0x6f20
movq %r15, %rdi
callq 0x6f20
leaq 0x4e19(%rip), %r13      # 0x91fc
movq 0x9bde(%rip), %r12      # 0xdfc8
leaq 0x4c13(%rip), %rbp      # 0x9004
movl $0x0, 0x18(%rsp)
movq $0x0, 0x50(%rsp)
movq $0x0, 0x48(%rsp)
movl $0x0, 0x14(%rsp)
movq $0x0, 0x38(%rsp)
movq $0x0, 0x40(%rsp)
xorl %eax, %eax
movq $0x0, 0x20(%rsp)
movl %eax, %r15d
movl %ebx, %edi
movq %r14, %rsi
movq %r13, %rdx
callq 0x3070
cmpl $0x67, %eax
jle 0x447e
leal -0x70(%rax), %ecx
cmpl $0x7, %ecx
ja 0x44c1
movl $0x1, %eax
movslq (%rbp,%rcx,4), %rcx
addq %rbp, %rcx
jmpq *%rcx
movq (%r12), %rdi
testq %rdi, %rdi
je 0x49cf
xorl %esi, %esi
xorl %edx, %edx
callq 0x32d0
decl %eax
movq %rax, 0x20(%rsp)
movl %r15d, %eax
jmp 0x4430
cmpl $0x31, %eax
jle 0x44e5
cmpl $0x32, %eax
je 0x450d
cmpl $0x64, %eax
jne 0x49a7
movq (%r12), %rsi
testq %rsi, %rsi
je 0x49bd
leaq 0xc0(%rsp), %rdi
callq 0x31f0
movl $0x1, %eax
movq %rax, 0x40(%rsp)
movl %r15d, %eax
jmp 0x4430
cmpl $0x68, %eax
je 0x456e
cmpl $0x6a, %eax
jne 0x49aa
movl $0x1, %eax
movq %rax, 0x48(%rsp)
movl %r15d, %eax
jmp 0x4430
jne 0x457e
movq (%r12), %rdi
testq %rdi, %rdi
je 0x49c6
callq 0x3320
movl %eax, 0x18(%rsp)
movl %eax, 0x10(%rsp)
movl %r15d, %eax
jmp 0x4430
movq (%r12), %rdi
testq %rdi, %rdi
je 0x49b4
callq 0x3320
movq %rax, 0x58(%rsp)
movl %eax, 0xc(%rsp)
movl %r15d, %eax
jmp 0x4430
movq (%r12), %rsi
testq %rsi, %rsi
je 0x49d8
leaq 0xc0(%rsp), %rdi
callq 0x31f0
movl $0x1, %eax
movq %rax, 0x38(%rsp)
movl %r15d, %eax
jmp 0x4430
movl $0x1, %eax
movq %rax, 0x50(%rsp)
movl %r15d, %eax
jmp 0x4430
movl $0x1, 0x14(%rsp)
movl %r15d, %eax
jmp 0x4430
cmpl $-0x1, %eax
jne 0x49aa
cmpl $0x0, 0x14(%rsp)
sete %al
cmpl $0x1, %ebx
setne %cl
testb %al, %cl
je 0x4608
movq 0x9a40(%rip), %rax      # 0xdfe0
movslq (%rax), %rax
cmpl %ebx, %eax
jge 0x49ee
movq (%r14,%rax,8), %rsi
leaq 0x190(%rsp), %rbx
movq %rbx, %rdi
callq 0x31f0
movq %rbx, %rdi
movl $0x2, %esi
xorl %eax, %eax
callq 0x31a0
movq 0x50(%rsp), %r12
movq 0x48(%rsp), %rbp
movl %eax, %ebx
testl %eax, %eax
js 0x49f7
movq 0x38(%rsp), %rdx
movq 0x40(%rsp), %rsi
leal (%rdx,%rsi), %ecx
addl %ebp, %ecx
addl %r12d, %ecx
addl %r15d, %ecx
cmpl $0x2, %ecx
jb 0x462e
leaq 0x5a53(%rip), %rdi      # 0xa056
callq 0x3310
movq (%r14), %rdi
callq 0x4237
leaq 0x28(%rsp), %rdi
callq 0x4e06
xorl %eax, %eax
addq $0x788, %rsp            # imm = 0x788
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl %edx, %eax
orl %esi, %eax
movq %rsi, %rax
je 0x4683
movslq 0x20(%rsp), %rax
leaq 0x5adf(%rip), %rcx      # 0xa122
movzwl (%rcx,%rax,2), %r13d
movl %ebx, %edi
movl %r13d, %esi
callq 0x350c
testl %eax, %eax
jne 0x4a09
leaq 0xc0(%rsp), %rdi
movl $0x42, %esi
movl $0x1b6, %edx            # imm = 0x1B6
xorl %eax, %eax
callq 0x31a0
movl %eax, %r13d
testl %eax, %eax
movq 0x40(%rsp), %rax
js 0x4a1c
testl %r15d, %r15d
je 0x46d4
leaq 0x10(%rsp), %rsi
leaq 0xc(%rsp), %rdx
movl %ebx, %edi
callq 0x380f
testl %eax, %eax
jne 0x4a00
movl 0x10(%rsp), %esi
movl 0xc(%rsp), %edx
movl %ebx, %edi
callq 0x393f
testl %eax, %eax
jne 0x46f1
leaq 0x28(%rsp), %rdi
movl %ebx, %esi
callq 0x3ada
testl %eax, %eax
je 0x4610
leaq 0x58fc(%rip), %rdi      # 0x9fcb
jmp 0x49df
testl %r12d, %r12d
je 0x46fd
movl %ebx, %edi
movl 0x18(%rsp), %esi
movq 0x58(%rsp), %rdx
callq 0x393f
testl %eax, %eax
je 0x4610
leaq 0x58f0(%rip), %rdi      # 0x9fe8
jmp 0x49df
testl %ebp, %ebp
je 0x47b5
leaq 0x10(%rsp), %rsi
leaq 0xc(%rsp), %rdx
movl %ebx, %edi
callq 0x380f
movl $0xfffffeb5, %eax       # imm = 0xFFFFFEB5
movl 0x10(%rsp), %ecx
addl %eax, %ecx
cmpl $0xffffff2d, %ecx       # imm = 0xFFFFFF2D
jb 0x4851
addl 0xc(%rsp), %eax
cmpl $0xffffff2c, %eax       # imm = 0xFFFFFF2C
jbe 0x4851
leaq 0x70(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x4e78
leaq 0x4ad5(%rip), %rsi      # 0x9227
leaq 0x28(%rsp), %rdi
callq 0x4a8a
movq %rax, %rdi
xorl %esi, %esi
callq 0x4c16
leaq 0x70(%rsp), %r14
movq %rax, %rdi
movq %r14, %rsi
callq 0x4dc6
movq %r14, %rdi
callq 0x4e06
leaq 0x60(%rsp), %rdi
leaq 0xc(%rsp), %rsi
callq 0x4e78
leaq 0x4a93(%rip), %rsi      # 0x9227
leaq 0x28(%rsp), %rdi
callq 0x4a8a
movl $0x1, %esi
movq %rax, %rdi
callq 0x4c16
leaq 0x60(%rsp), %r14
jmp 0x48e3
cmpl $0x0, 0x38(%rsp)
je 0x4951
leaq 0x1c(%rsp), %rsi
movl $0x2, %edx
movl %r13d, %edi
callq 0x32f0
cmpq $0x2, %rax
jne 0x4a25
movslq 0x1c(%rsp), %r14
cmpq $0x527, %r14            # imm = 0x527
jge 0x4a2e
movl %r13d, %edi
xorl %esi, %esi
xorl %edx, %edx
callq 0x33c0
leaq 0x260(%rsp), %rsi
movl %r13d, %edi
movq %r14, %rdx
callq 0x32f0
cmpq %r14, %rax
jne 0x4a25
movslq 0x20(%rsp), %rax
leaq 0x5900(%rip), %rcx      # 0xa122
movzwl (%rcx,%rax,2), %esi
leaq 0x260(%rsp), %rcx
movl %ebx, %edi
movl $0x8000, %edx           # imm = 0x8000
movl %r14d, %r8d
callq 0x369a
testl %eax, %eax
je 0x4610
leaq 0x5737(%rip), %rdi      # 0x9f83
jmp 0x49df
leaq 0xa0(%rsp), %rsi
movl $0x0, (%rsi)
leaq 0x90(%rsp), %rdi
callq 0x4e54
leaq 0x49b4(%rip), %rsi      # 0x9227
leaq 0x28(%rsp), %rdi
callq 0x4a8a
movq %rax, %rdi
xorl %esi, %esi
callq 0x4c16
leaq 0x90(%rsp), %r14
movq %rax, %rdi
movq %r14, %rsi
callq 0x4dc6
movq %r14, %rdi
callq 0x4e06
leaq 0xa0(%rsp), %rsi
movl $0x0, (%rsi)
leaq 0x80(%rsp), %rdi
callq 0x4e54
leaq 0x4963(%rip), %rsi      # 0x9227
leaq 0x28(%rsp), %rdi
callq 0x4a8a
movl $0x1, %esi
movq %rax, %rdi
callq 0x4c16
leaq 0x80(%rsp), %r14
movq %rax, %rdi
movq %r14, %rsi
callq 0x4dc6
movq %r14, %rdi
callq 0x4e06
leaq 0x28(%rsp), %rdi
movl %ebx, %esi
callq 0x3ada
leaq 0xa0(%rsp), %rdi
leaq 0x28(%rsp), %rsi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
movl $0x20, %ecx
xorl %r8d, %r8d
callq 0x4e9c
leaq 0xb0(%rsp), %rbx
movq -0x10(%rbx), %rdi
xorl %eax, %eax
callq 0x3040
movq -0x10(%rbx), %rdi
cmpq %rbx, %rdi
je 0x4942
callq 0x3200
movl $0xa, %edi
callq 0x32b0
jmp 0x4610
testl %eax, %eax
je 0x4608
movslq 0x20(%rsp), %rax
leaq 0x57bd(%rip), %rcx      # 0xa122
movzwl (%rcx,%rax,2), %esi
leaq 0x260(%rsp), %rdx
movl %ebx, %edi
callq 0x378a
testl %eax, %eax
js 0x4a37
movl %eax, %ebx
leaq 0x260(%rsp), %rsi
movl %r13d, %edi
movq %rbx, %rdx
callq 0x30c0
cmpq %rbx, %rax
je 0x4610
leaq 0x55a6(%rip), %rdi      # 0x9f4b
jmp 0x49df
cmpl $0x3f, %eax
movq (%r14), %rdi
callq 0x4237
jmp 0x49e4
leaq 0x572d(%rip), %rdi      # 0xa0e8
jmp 0x49df
leaq 0x56ea(%rip), %rdi      # 0xa0ae
jmp 0x49df
leaq 0x5738(%rip), %rdi      # 0xa105
jmp 0x49df
leaq 0x56bb(%rip), %rdi      # 0xa091
jmp 0x49df
leaq 0x56ec(%rip), %rdi      # 0xa0cb
callq 0x3310
movl $0x1, %edi
callq 0x3280
leaq 0x5541(%rip), %rdi      # 0x9f36
jmp 0x49df
leaq 0x567a(%rip), %rdi      # 0xa078
jmp 0x49df
leaq 0x5614(%rip), %rdi      # 0xa01b
jmp 0x49df
leaq 0x47fb(%rip), %rdi      # 0x920b
movl %r13d, %esi
xorl %eax, %eax
callq 0x3040
jmp 0x49e4
leaq 0x561c(%rip), %rdi      # 0xa03f
jmp 0x49df
leaq 0x5583(%rip), %rdi      # 0x9faf
jmp 0x49df
leaq 0x5567(%rip), %rdi      # 0x9f9c
jmp 0x49df
leaq 0x5527(%rip), %rdi      # 0x9f65
jmp 0x49df
jmp 0x4a75
movq %rax, %rbx
leaq 0x80(%rsp), %rdi
jmp 0x4a6e
movq %rax, %rbx
leaq 0x60(%rsp), %rdi
jmp 0x4a6e
movq %rax, %rbx
leaq 0x90(%rsp), %rdi
jmp 0x4a6e
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x4e06
jmp 0x4a78
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x4e06
movq %rbx, %rdi
callq 0x3390