--
-- Copyright (C) 2007 by Mark Pustjens
--
-- This file is part of Binary Clock.
-- Visit
-- for more information.
--
-- Binary Clock Firmware is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- Binary Clock Firmware is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see .
--
-- How to use this file?
--
-- Make sure the file `Fraction.hs' and `binclock.hs' are
-- in the current directory.
--
-- Start hugs in a terminal:
--
-- $ hugs binclock.hs
--
-- You will no see a prompt. Enter the comman `calculate '
-- to calculate timer values.
--
-- Main> calculate 13533500
-- Drift: 79/60416 tr0_reloads: 56 t0_ticks: 236
-- Drift: 79/57344 tr0_reloads: 59 t0_ticks: 224
-- Drift: 79/30208 tr0_reloads: 112 t0_ticks: 118
-- Drift: 79/28672 tr0_reloads: 118 t0_ticks: 112
-- Drift: 79/15104 tr0_reloads: 224 t0_ticks: 59
-- Drift: 79/14336 tr0_reloads: 236 t0_ticks: 56
-- Drift: 79/8192 tr0_reloads: 413 t0_ticks: 32
-- Drift: 79/7168 tr0_reloads: 472 t0_ticks: 28
-- Drift: 847/46336 tr0_reloads: 73 t0_ticks: 181
-- Drift: 79/4096 tr0_reloads: 826 t0_ticks: 16
--
-- Quit the program using the command `:q'
import Fraction
-- quicksort algorithm
qsort :: Ord a => (a -> a -> Bool) -> [a] -> [a]
qsort p [] = []
qsort p [x] = [x]
qsort p (x:xs) = qsort p lesser ++ [x] ++ qsort p greater
where
greater = [ y | y <- xs, p x y ]
lesser = [ y | y <- xs, not (p x y) ]
-- for sorting on the minimum amount of drift
orrd :: (Fraction,Fraction,Integer) -> (Fraction,Fraction,Integer) -> Bool
orrd (x,_,_) (y,_,_) = x <= y
-- convert an integer to a fraction
tofrac :: Integer -> Fraction
tofrac a = a:-:1
-- reduces the numerator of a fraction to be less
-- than 1. (the distance to the nearest integer)
distance :: Fraction -> Fraction
distance (x:-:y) = (x `mod` y):-:y
-- take the floor of a fraction
myfloor :: Fraction -> Fraction
myfloor x = x - (distance x)
-- determines drift
drift :: Fraction -> Fraction
drift x | a < (1:-:2) = a
| otherwise = 1 - a
where a = distance x
da :: [(Fraction, Integer)] -> [(Fraction, Fraction, Integer)]
da [] = []
da ((x,y):xs) = (drift x, myfloor x, y) : da xs
-- converts a Fraction to a Float
tofloat :: Fraction -> Float
tofloat (x:-:y) = (fromInteger x) / (fromInteger y)
-- converts the first to elements of a triplet to Float
twotofloat :: (Fraction, Fraction,Integer) -> (Float, Float, Integer)
twotofloat (x,y,z) = (tofloat x, tofloat y, z)
-- tree pretty printing functions
showCalc :: (Fraction, Fraction, Integer) -> String
showCalc (drift, tr0_reloads, t0_ticks) = "Drift: " ++ show drift ++ " tr0_reloads: " ++ show tr0_reloads ++ " t0_ticks: " ++ show t0_ticks
showsCalc :: [(Fraction, Fraction, Integer)] -> [String]
showsCalc [] = []
showsCalc (x:xs) = showCalc x : showsCalc xs
printAll :: [String] -> IO ()
printAll [] = return ()
printAll (x:xs) = do putStrLn x
printAll xs
-- calculates the amount of drift and timer reloads based
-- on user supplied values for t0_ticks
docalc :: Integer -> [Integer] -> [(Fraction, Fraction, Integer)]
docalc frequency [] = []
docalc frequency (x:xs) = (drift interrupts, tr0_reloads, t0_ticks) : docalc frequency xs
where interrupts = ((1000000 / interrupt) / (x//1))
t0_ticks = (x)
tr0_reloads = (myfloor interrupts)
interrupt = (instruction * 256)
instruction = (4000000 // frequency)
-- sorts the results of docalc based of the lowest drift
sortcalc frequency xs = qsort (orrd) (docalc frequency xs)
calculate :: Integer -> IO ()
calculate freq = printAll (take 10 (showsCalc (sortcalc freq [1..256])))