#!/usr/bin/env python

import math
import os
import sys

frequencies = (
	1.8432,
	2.0,
	2.4576,
	3.579545,
	3.58,
	3.6864,
	4.0,
	4.096,
	4.194304,
	4.433619,
	4.5,
	4.608,
	4.897,
	4.9152,
	5.0,
	6.0,
	6.144,
	6.4,
	6.7458,
	6.775,
	7.15909,
	7.2,
	7.3728,
	7.6,
	7.68,
	8.0,
	8.192,
	9.0,
	9.216,
	9.6,
	9.8304,
	10.0,
	10.24,
	10.245,
	10.25,
	11.0,
	11.0592,
	11.2896,
	12.0,
	12.288,
	12.8,
	13.0,
	13.5,
	13.56,
	14.0,
	14.31818,
	14.7456,
	15.0,
	16.0,
	16.384,
	16.9344,
	17.28,
	17.73447,
	18.0,
	18.432,
	18.816,
	19.2,
	19.6608,
	20.0,
	20.250,
	20.48,
	21.47727,
	22.1184,
	22.5792,
	24.0,
	24.576,
	25.0,
	26.0,
	26.59,
	26.64,
	26.601712,
	27.0,
	27.042,
	27.045,
	27.120,
	27.145,
	28.0,
	28.224,
	28.375,
	28.8,
	29.4912,
	29.498928,
	30.0,
	32.0,
	32.768,
	33.0,
	33.1772,
	33.8688,
	35.328,
	36.0,
	38.0,
	48.0,
	49.152,
	49.86,
	50.0,
	54.0,
	64.0,
)

baudrates = (
	9600,
	19200,
	38400,
	57600,
	115200,
	230400,
	460800,
	921600,
)

def factorize( f ):
	ifd = os.popen( "factor %d" % f, "r" )
	line = ifd.read( 1000 )
	ifd.close()
	factors = []
	for factor in line.split()[1:]:
		factor = int(factor)
		if len(factors) > 0 and factors[-1][0] == factor:
			factors[-1] = ( factor, factors[-1][1] + 1 )
		else:
			factors.append( ( factor, 1 ) )
	return factors

def calc_ubrr( f, b ):
	ubrrn = (f / b / 8 - 1) / 2
	ubrrd = (f / b / 4 - 1) / 2
	if ubrrn < 0:
		ubrrn = 0
	if ubrrd < 0:
		ubrrd = 0
	ff = float(f)
	fbn = ff / float( 16 * (ubrrn + 1) )
	fbd = ff / float( 8 * (ubrrd + 1) )
	fb = float(b)
	percn = 100.0 * (fbn / fb - 1.0)
	percd = 100.0 * (fbd / fb - 1.0)
	apercn = math.fabs( percn )
	apercd = math.fabs( percd )
	if apercn < 0.01:
		percn = 0.0
	if apercd < 0.01:
		percd = 0.0
	if apercn <= apercd:
		return ubrrn, False, percn
	else:
		return ubrrd, True, percd

def generate_freq( ofd, freq, bauds ):
	f = int((freq * 1000000.0) + 0.1)
	factors = factorize( f )
	factorstr = ""
	pfx = ""
	for factor, exp in factors:
		factorstr += " %s %d" % ( pfx, factor )
		if exp > 1:
			factorstr += "<sup>%d</sup>" % exp
		pfx = "*"
	b9600 = "&nbsp;"
	b115200 = "&nbsp;"
	if f % 9600 == 0:
		b9600 = "%d" % (f / 9600)
	if f % 115200 == 0:
		b115200 = "%d" % (f / 115200)
	rows = [
		"<tr>",
		"  <td>%f</td>" % freq,
		"  <td>%s</td>" % factorstr,
		"  <td>%s</td>" % b9600,
		"  <td>%s</td>" % b115200,
		"</tr>",
		""
	]
	for b in bauds:
		ubrr, dblspeed, perc = calc_ubrr( f, b )
		if dblspeed:
			ubrr = "%d D" % ubrr
		else:
			ubrr = "%d N" % ubrr
		color = ""
		pstr = ""
		if perc != 0.0:
			aperc = math.fabs( perc )
			if aperc < 1.25:
				color = ""
			elif aperc < 2.5:
				color = "green"
			elif aperc < 5.0:
				color = "yellow"
			else:
				color = "red"
			if color != "":
				color = " style=\"color: %s;\"" % color
			pstr = " %+.2f%%" % perc
		rows.insert( -2, "  <td%s>%s%s</td>\n" % ( color, ubrr, pstr ) )
	ofd.write( "\n".join( ( rows ) ) )

def generate( filename, freqs, bauds ):
	ofd = open( filename, "w" )
	ofd.write( "\n".join( (
		"<html>",
		"<head>",
		"<title></title>",
		"</head>",
		"<body bgcolor=\"#000000\" text=\"#FFFFFF\" link=\"CCCCFF\" vlink=\"CCFFFF\" alink=\"CCCCFF\">",
		"<h1>crystals</h1>",
		"<table border=\"1\">",
		"<tr>",
		"  <th rowspan=\"2\" valign=\"top\">Frequency<br />[MHz]</th>",
		"  <th rowspan=\"2\" valign=\"top\">Factors</th>",
		"  <th rowspan=\"2\" valign=\"top\">f/9600</th>",
		"  <th rowspan=\"2\" valign=\"top\">f/115200</th>",
		"  <th colspan=\"%d\">AVR UBRR Value</th>" % len(bauds),
		"</tr>",
		"<tr>",
		""
	) ) )
	for b in bauds:
		ofd.write( "  <th>%d</th>\n" % b )
	ofd.write( "</tr>\n" )
	for freq in freqs:
		generate_freq( ofd, freq, bauds )
	ofd.write( "\n".join( (
		"</table>",
		"<p><b>UBRR:</b>",
		"<br />N = Normal mode, U2Xn = 0"
		"<br />D = Double speed mode, U2Xn = 1"
		"<br />white = less than 1.25% difference, works fine"
		"<br />green = less than 2.5% difference, will often work fine"
		"<br />yellow = less than 5% difference, probably makes troubles"
		"<br />red = 5% difference or more, does not work"
		"</p>"
		"<p>This table was generated by <a href=\"crystals.py\">crystals.py</a>.</p>",
		"</body>",
		"</html>",
		""
	) ) )

if __name__ == "__main__":
	if len(sys.argv) != 1:
		print "usage: crystals.py"
		print "generates crystals.html"
	else:
		generate( "crystals.html", frequencies, baudrates )

