module Ham.CAT.SerialCAT (SerialCAT(..)
                         ,serialGet
                         ,serialSend) where

import Ham.Internal.Data
import System.Hardware.Serialport
import Data.Attoparsec.ByteString.Char8
import qualified Data.ByteString.Char8 as B
import Control.Concurrent (threadDelay)


-- | Interface for radios that are communicating via serial interface.
data SerialCAT = SerialCAT {
    serialGetFrequency :: SerialPort -> IO (Maybe Frequency)
  , serialGetMode      :: SerialPort -> IO (Maybe QsoMode)
  , serialSetPowerSSB  :: SerialPort -> Int -> IO ()
  , serialGetPowerSSB  :: SerialPort -> IO (Maybe Int)
  , serialIdentify     :: SerialPort -> IO Bool
}


-- | Get a value from a radio connected to a serial port.
-- This uses a format that seems to be used by more than one manufacturer, such as Yaesu and Elecraft.
-- The command format is "XY;" for getting something, where XY is a string. XY is given as second argument to this function.
serialGet :: SerialPort
         -> String                     -- ^ Command; e.g. FA for getting frequency of VFO A.
         -> (B.ByteString -> Parser a) -- ^ Decoder for the resulting answer from the radio.
         -> IO (Maybe a)
serialGet s cmd parser = do
  let cmd' = B.pack cmd <> B.pack ";"
  send s cmd'
  -- Wait for 100ms to give the transceiver some time to answer;
  -- I have not found a better way to do this at the moment with the serialport library.
  -- It seems to set all operations to non-blocking.
  -- Set the radio's CAT TOT to 10msec (minimum).
  threadDelay 100000
  a <- recv s 100
  -- putStrLn $ B.unpack a

  return $
      let r = parse (parser $ B.pack cmd) a
      in maybeResult r


-- | Send a string to the radio.
serialSend :: SerialPort -> String -> IO ()
serialSend s value =  do
    send s $ B.pack value
    threadDelay 100000
    _ <- recv s 100
    return ()
    -- putStrLn $ B.unpack a