module System.Hardware.GPIO.Pin 
       where

import Data.Array

data Pin where 
  InPin :: Int -> Pin
  OutPin :: Int -> Pin
  PwmPin :: Int -> Pin
 deriving (Show, Eq)

num :: Pin -> Int
num (InPin n) = n
num (OutPin n) = n
num (PwmPin n) = n

dir :: Pin -> String
dir (InPin _) = "in"
dir (OutPin _) = "out"
dir (PwmPin _) = "pwm"

pinMapping :: Array Int Int
pinMapping = listArray (0,16) [17, 18, 21, 22, 23, 24, 25, 4, 0, 1, 8, 7, 10, 9, 11, 14, 15]


global_GPIO_PATH = "/sys/class/gpio"
global_EXPORT_PATH = global_GPIO_PATH ++ "/export"
global_UNEXPORT_PATH = global_GPIO_PATH ++ "/unexport"
global_DEVICE_PATH i = global_GPIO_PATH ++ "/gpio"++ (show i)
global_DIRECTION_PATH i = global_DEVICE_PATH i ++ "/direction"
global_VALUE_PATH i = global_DEVICE_PATH i ++ "/value"

init :: Pin -> IO ()
init pin = do 
  { let pn = pinMapping ! (num pin)
  ; writeFile global_EXPORT_PATH (show pn)
  ; writeFile (global_DIRECTION_PATH pn) (dir pin)
  ; case pin of 
       { OutPin _ -> set pin Zero
       ; _        -> return () 
       }
  }
           
close :: Pin -> IO ()
close pin = do
  { let pn = pinMapping ! (num pin)
  ; writeFile global_UNEXPORT_PATH (show pn)
  ; case pin of 
       { OutPin _ -> set pin Zero
       ; _        -> return () 
       }
  }

data Value = One | Zero deriving (Show, Eq)

read :: Pin -> IO Value
read pin = do 
  { let pn = pinMapping ! (num pin)
  ; s <- readFile (global_VALUE_PATH pn)
  ; if (s == "1") 
    then return One
    else return Zero
  }

  
set :: Pin -> Value -> IO ()
set pin@(OutPin n) value = do 
  { let pn = pinMapping ! n
  ; case value of 
       { One -> writeFile (global_VALUE_PATH pn) "1"
       ; Zero -> writeFile (global_VALUE_PATH pn) "0"
       }
  }