module System.Command.AVRDUDE
( MemType(..)
, Dir(..)
, Op(..)
, Format(..)
, ActionsM
, Actions
, action
, r, v, w, imm
, encodeActions
, actionFiles
, avrdude
) where
import Control.Applicative
import Control.Monad.Writer
import Data.GADT.Compare
import Data.List
import Data.Monoid
import Data.Word
import System.Exit
import System.Process
import Text.Printf
data MemType
= Calibration
| EEPROM
| EFuse
| Flash
| Fuse
| HFuse
| LFuse
| Lock
| Signature
| FuseN !Integer
| Application
| AppTable
| Boot
| ProdSig
| UserSig
| OtherMemType !String
encodeMemType :: MemType -> String
encodeMemType Calibration = "calibration"
encodeMemType EEPROM = "eeprom"
encodeMemType EFuse = "efuse"
encodeMemType Flash = "flash"
encodeMemType Fuse = "fuse"
encodeMemType HFuse = "hfuse"
encodeMemType LFuse = "lfuse"
encodeMemType Lock = "lock"
encodeMemType Signature = "signature"
encodeMemType (FuseN n) = "fuse" ++ show n
encodeMemType Application = "application"
encodeMemType AppTable = "apptable"
encodeMemType Boot = "boot"
encodeMemType ProdSig = "prodsig"
encodeMemType UserSig = "usersig"
encodeMemType (OtherMemType other) = other
data Dir = In | Out
data Op dir where
R :: Op Out
V :: Op Out
W :: Op In
encodeOp :: Op dir -> Char
encodeOp R = 'r'
encodeOp V = 'v'
encodeOp W = 'w'
data Format dir t where
IHex :: Format dir FilePath
SRec :: Format dir FilePath
Raw :: Format dir FilePath
Immediate :: Format In [Word8]
Auto :: Format dir FilePath
Dec :: Format Out FilePath
Hex :: Format Out FilePath
Oct :: Format Out FilePath
Bin :: Format Out FilePath
encodeFormat :: Format dir t -> (Char, Maybe (t := FilePath), t -> String)
encodeFormat IHex = ('i', Just Refl, id)
encodeFormat SRec = ('s', Just Refl, id)
encodeFormat Raw = ('r', Just Refl, id)
encodeFormat Immediate = ('m', Nothing, encodeImmediate)
encodeFormat Auto = ('a', Just Refl, id)
encodeFormat Dec = ('d', Just Refl, id)
encodeFormat Hex = ('h', Just Refl, id)
encodeFormat Oct = ('o', Just Refl, id)
encodeFormat Bin = ('b', Just Refl, id)
encodeImmediate :: [Word8] -> String
encodeImmediate = intercalate "," . map encodeHex
encodeHex :: Word8 -> String
encodeHex = printf "0x%02x"
data Action where
Action :: MemType -> Op dir -> t -> Format dir t -> Action
encodeAction :: Action -> String
encodeAction (Action memType op name format) =
intercalate ":"
[ encodeMemType memType
, [encodeOp op]
, encodeName name
, [encodedFormat]
]
where
(encodedFormat, _, encodeName) = encodeFormat format
actionFile :: Action -> Maybe FilePath
actionFile (Action _ _ name format) = case encodeFormat format of
(_, Just Refl, _) -> Just name
(_, Nothing, _) -> Nothing
actionNeedsFile :: Action -> Bool
actionNeedsFile (Action _ W _ _) = True
actionNeedsFile (Action _ V _ _) = True
actionNeedsFile _ = False
newtype ActionsM t = ActionsM (Writer [Action] t)
deriving (Monad, Functor, Applicative)
type Actions = ActionsM ()
instance Monoid t => Monoid (ActionsM t) where
mempty = pure mempty
mappend = liftA2 mappend
runActions :: Actions -> [Action]
runActions (ActionsM x) = execWriter x
action :: MemType -> Op dir -> t -> Format dir t -> Actions
action memType op name format = ActionsM (tell [Action memType op name format])
r :: MemType -> FilePath -> Actions
r memType path = action memType R path Auto
v :: MemType -> FilePath -> Actions
v memType path = action memType V path Auto
w :: MemType -> FilePath -> Actions
w memType path = action memType W path Auto
imm :: MemType -> [Word8] -> Actions
imm memType path = action memType W path Immediate
encodeActions :: Actions -> [String]
encodeActions = map (("-U" ++) . encodeAction) . runActions
actionFiles :: Actions -> ([FilePath], [FilePath])
actionFiles actions = (map snd needed, map snd produced)
where
~(needed, produced) = partition fst
[ (actionNeedsFile action, file)
| action <- runActions actions
, Just file <- [actionFile action]
]
avrdude :: [String] -> Actions -> IO ExitCode
avrdude args actions = rawSystem "avrdude" (args ++ encodeActions actions)