#! /usr/bin/perl


$err = open (CFG, "config.h");
if (!$err) { $err = open(CFG, "../config.h"); }

if (!$err) {
    print "Can't find config.h.";
    exit(0);
}

while (<CFG>) {
    if (/#define\s+[\w\d]+\s+(.*)\s*(\/\/|\/\*)/) { 
	$_ =~ s/\s*(\/\/|\/\*).*//;
    }

    if (/#define\s+Fosc\s+(.*)/) { $Fosc = $1; }
    elsif (/#define\s+Fcclk\s+(.*)/) { $Fcclk = $1; }
    elsif (/#define\s+Fcco\s+(.*)/) { $Fcco = $1; }
    elsif (/#define\s+Fpclk\s+(.*)/) { $Fpclk = $1; }
    elsif (/#define\s+UART_SPEED\s+(.*)/) { $baud = $1; }
}
close(CFG);

$Fcclk =~ s/([a-zA-Z_]+)/\$\1/g;
$Fcclk = eval($Fcclk);
$Fcco =~ s/([a-zA-Z_]+)/\$\1/g;
$Fcco = eval($Fcco);
$Fpclk =~ s/([a-zA-Z_]+)/\$\1/g;
$Fpclk = eval($Fpclk);
$baud =~ s/([a-zA-Z_]+)/\$\1/g;
$baud = eval($baud);

$realx = int(($Fpclk / 16 ) / $baud);

$besterr = 1000000000;
for ($x = $realx + 1; $x>($realx/16); $x--) {
    for ($m = 1; $m < 16; $m++) {
	for ($d = 0; $d < 16; $d++) {
	    $err = abs($Fpclk*$m - 16*$baud*$x*($m+$d));
	    if ($err<$besterr) {
		$xbest = $x;
		$mbest = $m;
		$dbest = $d;
		if (err) {
		    $besterr = $err;
		} else {
		    $x = 0;
		    $m = 16;
		    $d = 16;
		}
	    }
	}
    }
}

$realbaud = ( $Fpclk * $mbest ) / ( 16 * $xbest * ($mbest + $dbest));
$error = 100*abs($realbaud - $baud) / $baud;

print "Fdiv = $xbest, DivAddVal = $dbest, MulVal = $mbest\n";
print "Required Baud Rate: $baud, Real Baud Rate: $realbaud, ";
printf("Error: %.3f%\n", $error);
