// File: /workspace/github_cpp_makefile_star2_O2/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
andl $0x0, 0x10(%rsp)
movq %rsi, %r14
andl $0x0, 0xc(%rsp)
movl %edi, %ebx
andl $0x0, 0x1c(%rsp)
movq $0x0, 0x50(%rsp)
leaq 0x20(%rsp), %rdi
xorl %esi, %esi
callq 0x482e
leaq 0x4080(%rip), %r13      # 0x8230
pushq $0x1
popq %rbp
leaq 0x3e4a(%rip), %r12      # 0x8004
movl $0x0, 0x14(%rsp)
movq $0x0, 0x38(%rsp)
movq $0x0, 0x30(%rsp)
movl $0x0, 0x18(%rsp)
movq $0x0, 0x48(%rsp)
movq $0x0, 0x40(%rsp)
xorl %eax, %eax
movq $0x0, 0x58(%rsp)
movl %eax, %r15d
movl %ebx, %edi
movq %r14, %rsi
movq %r13, %rdx
callq 0x3070
leal -0x70(%rax), %ecx
cmpl $0x7, %ecx
jbe 0x424a
cmpl $0x31, %eax
je 0x42be
cmpl $0x32, %eax
je 0x42f2
cmpl $0x64, %eax
je 0x431b
cmpl $0x68, %eax
je 0x42e6
cmpl $0x6a, %eax
jne 0x434a
movl %ebp, %eax
movq %rax, 0x30(%rsp)
movl %r15d, %eax
jmp 0x41f9
movslq (%r12,%rcx,4), %rcx
addq %r12, %rcx
movl %ebp, %eax
jmpq *%rcx
movq 0x9d6c(%rip), %rax      # 0xdfc8
movq (%rax), %rdi
testq %rdi, %rdi
je 0x4774
xorl %esi, %esi
xorl %edx, %edx
callq 0x32d0
decl %eax
movq %rax, 0x58(%rsp)
movl %r15d, %eax
jmp 0x41f9
movl %ebp, %eax
movq %rax, 0x38(%rsp)
movl %r15d, %eax
jmp 0x41f9
movq 0x9d32(%rip), %rax      # 0xdfc8
movq (%rax), %rsi
testq %rsi, %rsi
je 0x477d
leaq 0xc0(%rsp), %rdi
callq 0x31f0
movl %ebp, %eax
movq %rax, 0x48(%rsp)
movl %r15d, %eax
jmp 0x41f9
movq 0x9d03(%rip), %rax      # 0xdfc8
movq (%rax), %rdi
testq %rdi, %rdi
je 0x4762
callq 0x3320
movl %eax, 0x14(%rsp)
movl %eax, 0x10(%rsp)
movl %r15d, %eax
jmp 0x41f9
movl %ebp, 0x18(%rsp)
movl %r15d, %eax
jmp 0x41f9
movq 0x9ccf(%rip), %rax      # 0xdfc8
movq (%rax), %rdi
testq %rdi, %rdi
je 0x476b
callq 0x3320
movq %rax, 0x50(%rsp)
movl %eax, 0xc(%rsp)
movl %r15d, %eax
jmp 0x41f9
movq 0x9ca6(%rip), %rax      # 0xdfc8
movq (%rax), %rsi
testq %rsi, %rsi
je 0x4759
leaq 0xc0(%rsp), %rdi
callq 0x31f0
movl %ebp, %eax
movq %rax, 0x40(%rsp)
movl %r15d, %eax
jmp 0x41f9
cmpl $-0x1, %eax
jne 0x474c
cmpl $0x0, 0x18(%rsp)
sete %al
cmpl $0x1, %ebx
setne %cl
testb %al, %cl
je 0x43d1
movq 0x9c74(%rip), %rax      # 0xdfe0
movslq (%rax), %rax
cmpl %ebx, %eax
jge 0x4791
movq (%r14,%rax,8), %rsi
leaq 0x190(%rsp), %rbx
movq %rbx, %rdi
callq 0x31f0
pushq $0x2
popq %rsi
movq %rbx, %rdi
xorl %eax, %eax
callq 0x31a0
movl %eax, %ebx
testl %eax, %eax
js 0x479a
movq 0x30(%rsp), %rax
movq 0x38(%rsp), %rcx
addl %ecx, %eax
movq 0x40(%rsp), %rdx
movq 0x48(%rsp), %rsi
leal (%rsi,%rdx), %ecx
addl %eax, %ecx
addl %r15d, %ecx
cmpl $0x2, %ecx
jb 0x43f7
leaq 0x4e1b(%rip), %rdi      # 0x91e7
callq 0x3310
movq (%r14), %rdi
callq 0x4017
leaq 0x20(%rsp), %rdi
callq 0x4b00
xorl %eax, %eax
addq $0x788, %rsp            # imm = 0x788
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl %esi, %eax
orl %edx, %eax
movslq 0x58(%rsp), %r13
leaq 0x4ead(%rip), %rbp      # 0x92b4
movq %rdx, %rax
movq %rsi, %rcx
je 0x4453
movzwl (%rbp,%r13,2), %r12d
movl %ebx, %edi
movl %r12d, %esi
callq 0x350c
testl %eax, %eax
jne 0x47ac
leaq 0xc0(%rsp), %rdi
pushq $0x42
popq %rsi
movl $0x1b6, %edx            # imm = 0x1B6
xorl %eax, %eax
callq 0x31a0
movl %eax, %r12d
testl %eax, %eax
movq 0x40(%rsp), %rax
movq 0x48(%rsp), %rcx
js 0x47bf
testl %r15d, %r15d
je 0x44a4
leaq 0x10(%rsp), %rsi
leaq 0xc(%rsp), %rdx
movl %ebx, %edi
callq 0x37e7
testl %eax, %eax
jne 0x47a3
movl 0x10(%rsp), %esi
movl 0xc(%rsp), %edx
movl %ebx, %edi
callq 0x390e
testl %eax, %eax
jne 0x44c3
leaq 0x20(%rsp), %rdi
movl %ebx, %esi
callq 0x3a78
testl %eax, %eax
je 0x43d9
leaq 0x4cbd(%rip), %rdi      # 0x915c
jmp 0x4784
cmpl $0x0, 0x38(%rsp)
je 0x44cf
movl %ebx, %edi
movl 0x14(%rsp), %esi
movq 0x50(%rsp), %rdx
callq 0x390e
testl %eax, %eax
je 0x43d9
leaq 0x4caf(%rip), %rdi      # 0x9179
jmp 0x4784
cmpl $0x0, 0x30(%rsp)
je 0x4588
leaq 0x10(%rsp), %rsi
leaq 0xc(%rsp), %rdx
movl %ebx, %edi
callq 0x37e7
movl $0xfffffeb5, %eax       # imm = 0xFFFFFEB5
movl 0x10(%rsp), %ecx
addl %eax, %ecx
cmpl $0xffffff2d, %ecx       # imm = 0xFFFFFF2D
jb 0x4615
addl 0xc(%rsp), %eax
cmpl $0xffffff2c, %eax       # imm = 0xFFFFFF2C
jbe 0x4615
leaq 0x70(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x4b56
leaq 0x3d34(%rip), %rsi      # 0x825b
leaq 0x20(%rsp), %rdi
callq 0x484a
movq %rax, %rdi
xorl %esi, %esi
callq 0x496c
leaq 0x70(%rsp), %r14
movq %rax, %rdi
movq %r14, %rsi
callq 0x4ac0
movq %r14, %rdi
callq 0x4b00
leaq 0x60(%rsp), %rdi
leaq 0xc(%rsp), %rsi
callq 0x4b56
leaq 0x3cf2(%rip), %rsi      # 0x825b
leaq 0x20(%rsp), %rdi
callq 0x484a
pushq $0x1
popq %rsi
movq %rax, %rdi
callq 0x496c
leaq 0x60(%rsp), %r14
jmp 0x469f
testl %ecx, %ecx
je 0x4700
leaq 0x1c(%rsp), %rsi
pushq $0x2
popq %rdx
movl %r12d, %edi
callq 0x32f0
cmpq $0x2, %rax
jne 0x47c8
movslq 0x1c(%rsp), %r14
cmpq $0x527, %r14            # imm = 0x527
jge 0x47d1
movl %r12d, %edi
xorl %esi, %esi
xorl %edx, %edx
callq 0x33d0
leaq 0x260(%rsp), %rsi
movl %r12d, %edi
movq %r14, %rdx
callq 0x32f0
cmpq %r14, %rax
jne 0x47c8
movzwl (%rbp,%r13,2), %esi
leaq 0x260(%rsp), %rcx
movl %ebx, %edi
movl $0x8000, %edx           # imm = 0x8000
movl %r14d, %r8d
callq 0x368f
testl %eax, %eax
je 0x43d9
leaq 0x4b04(%rip), %rdi      # 0x9114
jmp 0x4784
leaq 0xa0(%rsp), %rsi
andl $0x0, (%rsi)
leaq 0x90(%rsp), %rdi
callq 0x4b3c
leaq 0x3c27(%rip), %rsi      # 0x825b
leaq 0x20(%rsp), %rdi
callq 0x484a
movq %rax, %rdi
xorl %esi, %esi
callq 0x496c
leaq 0x90(%rsp), %r14
movq %rax, %rdi
movq %r14, %rsi
callq 0x4ac0
movq %r14, %rdi
callq 0x4b00
leaq 0xa0(%rsp), %rsi
andl $0x0, (%rsi)
leaq 0x80(%rsp), %rdi
callq 0x4b3c
leaq 0x3bd9(%rip), %rsi      # 0x825b
leaq 0x20(%rsp), %rdi
callq 0x484a
pushq $0x1
popq %rsi
movq %rax, %rdi
callq 0x496c
leaq 0x80(%rsp), %r14
movq %rax, %rdi
movq %r14, %rsi
callq 0x4ac0
movq %r14, %rdi
callq 0x4b00
leaq 0x20(%rsp), %rdi
movl %ebx, %esi
callq 0x3a78
leaq 0xa0(%rsp), %rdi
leaq 0x20(%rsp), %rsi
pushq $-0x1
popq %rdx
pushq $0x20
popq %rcx
xorl %r8d, %r8d
callq 0x4b70
leaq 0xa0(%rsp), %rbx
movq (%rbx), %rdi
xorl %eax, %eax
callq 0x3040
movq %rbx, %rdi
callq 0x3110
pushq $0xa
popq %rdi
callq 0x32b0
jmp 0x43d9
testl %eax, %eax
je 0x43d1
movzwl (%rbp,%r13,2), %esi
leaq 0x260(%rsp), %rdx
movl %ebx, %edi
callq 0x376b
testl %eax, %eax
js 0x47da
movl %eax, %ebx
leaq 0x260(%rsp), %rsi
movl %r12d, %edi
movq %rbx, %rdx
callq 0x30b0
cmpq %rbx, %rax
je 0x43d9
leaq 0x4992(%rip), %rdi      # 0x90dc
jmp 0x4784
cmpl $0x3f, %eax
movq (%r14), %rdi
callq 0x4017
jmp 0x4789
leaq 0x4adf(%rip), %rdi      # 0x923f
jmp 0x4784
leaq 0x4b2d(%rip), %rdi      # 0x9296
jmp 0x4784
leaq 0x4b07(%rip), %rdi      # 0x9279
jmp 0x4784
leaq 0x4aa7(%rip), %rdi      # 0x9222
jmp 0x4784
leaq 0x4ad8(%rip), %rdi      # 0x925c
callq 0x3310
pushq $0x1
popq %rdi
callq 0x3260
leaq 0x492f(%rip), %rdi      # 0x90c7
jmp 0x4784
leaq 0x4a68(%rip), %rdi      # 0x9209
jmp 0x4784
leaq 0x4a02(%rip), %rdi      # 0x91ac
jmp 0x4784
leaq 0x3a8c(%rip), %rdi      # 0x823f
movl %r12d, %esi
xorl %eax, %eax
callq 0x3040
jmp 0x4789
leaq 0x4a0a(%rip), %rdi      # 0x91d0
jmp 0x4784
leaq 0x4971(%rip), %rdi      # 0x9140
jmp 0x4784
leaq 0x4955(%rip), %rdi      # 0x912d
jmp 0x4784
leaq 0x4915(%rip), %rdi      # 0x90f6
jmp 0x4784
jmp 0x4818
movq %rax, %rbx
leaq 0x80(%rsp), %rdi
jmp 0x4811
movq %rax, %rbx
leaq 0x60(%rsp), %rdi
jmp 0x4811
movq %rax, %rbx
leaq 0x90(%rsp), %rdi
jmp 0x4811
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x4b00
jmp 0x481b
movq %rax, %rbx
leaq 0x20(%rsp), %rdi
callq 0x4b00
movq %rbx, %rdi
callq 0x33b0
nop