ecu 0.0.0 → 0.0.1
raw patch · 6 files changed
+430/−20 lines, 6 filesdep +directorydep +processnew-component:exe:commitnew-component:exe:git2ccnew-component:exe:toesb
Dependencies added: directory, process
Files
- README +12/−5
- ecu.cabal +29/−3
- src/CANView.hs +17/−12
- src/Commit.hs +59/−0
- src/Git2CC.hs +227/−0
- src/ToESB.hs +86/−0
README view
@@ -1,12 +1,19 @@ Tools for Automotive ECU Development -tovcd - Converts several CAN formats to VCD.-todbc - Generate Vector DBC files from CAN specification.-probe - Extracts configuration and probed signals from ECU.-canview - View CAN traffic.-cansend - Send CAN message.+tovcd - Converts several CAN formats to VCD.+todbc - Generate Vector DBC files from CAN specification.+probe - Extracts configuration and probed signals from ECU.+canview - View CAN traffic.+cansend - Send CAN message.+git2cc - Bridge Git repositories to ClearCase.+commit - Git commits with ClearQuest activity annotations.++Future Tools:++toesb - Converts s-record ECU images to the Eaton Standard Binary format. vcdgrep - Search VCD files for signal patterns and assertion violations. brakedancer-layout - Generate a brakedancer signal layout from a VCD file.+ecush - ECU development shell. http://hackage.haskell.org/package/ecu
ecu.cabal view
@@ -1,14 +1,14 @@ name: ecu-version: 0.0.0+version: 0.0.1 category: Utils synopsis: Tools for automotive ECU development. description:- These are a collection of tools developed and used by Eaton's+ This is a collection of tools developed and used by Eaton's electro-hydraulic software engineers. Most tools is this - collection and for interacting with, and analyzing vehicle+ collection are for interacting with, and analyzing vehicle ECU data via a CAN bus. These tools require the Kvaser canlib library: http://www.kvaser.com/@@ -64,6 +64,32 @@ vcd >= 0.1.4 && < 2 ghc-options: -W extensions: ForeignFunctionInterface++executable toesb+ hs-source-dirs: src+ main-is: ToESB.hs+ build-depends: base >= 4.2 && < 5,+ bytestring >= 0.9.1 && < 0.9.2,+ digest >= 0.0.0.8 && < 0.0.1+ ghc-options: -W++executable commit+ hs-source-dirs: src+ main-is: Commit.hs+ build-depends: base >= 4.2 && < 5+ ghc-options: -W++executable git2cc+ hs-source-dirs: src+ main-is: Git2CC.hs+ build-depends: base >= 4.2 && < 5,+ directory >= 1.0.1 && < 1.1,+ process >= 1.0.1 && < 1.1+ ghc-options: -W++source-repository head+ type: git+ location: git://github.com/tomahawkins/ecu.git source-repository head type: git
src/CANView.hs view
@@ -1,5 +1,7 @@ module Main (main) where +import Control.Monad+import Data.Word import System.Environment import Text.Printf @@ -9,26 +11,27 @@ main = do args <- getArgs case args of- ["--std"] -> do+ ["-h"] -> help+ ["--help"] -> help+ "--std" : ids -> do initCAN bus <- openBus 0 Standard flushRxQueue bus- canview bus- [] -> do+ canview bus $ map read ids+ ids -> do initCAN bus <- openBus 0 Extended flushRxQueue bus- canview bus- _ -> help+ canview bus $ map read ids -canview :: Bus -> IO ()-canview bus = do+canview :: Bus -> [Word32] -> IO ()+canview bus ids = do m <- recvMsg bus case m of- Nothing -> canview bus- Just (t, m) -> do- putStrLn $ printf "%10i " t ++ show m- canview bus+ Nothing -> canview bus ids+ Just (t, m@(Msg id _)) -> do+ when (null ids || elem id ids) $ putStrLn $ printf "%10i " t ++ show m+ canview bus ids help :: IO () help = putStrLn $ unlines@@ -37,10 +40,12 @@ , " canview - listens to a CAN bus" , "" , "SYNOPSIS"- , " canview {argument}"+ , " canview [ --std ] { <id-filter> }" , "" , "ARGUMENTS" , " --std Set to standard CAN with 500K. Default is extended CAN with 250K."+ , ""+ , " <id-filter> If id filters are included, only matching ids will be displayed." , "" ]
+ src/Commit.hs view
@@ -0,0 +1,59 @@+module Main (main) where++import Data.Char+import Data.List+import System.Environment+import System.Exit+import System.Process++help :: IO ()+help = putStrLn $ unlines+ [ ""+ , "NAME"+ , " commit - Git commits with ClearQuest activities"+ , ""+ , "SYNOPSIS"+ , " commit [ --cqact=<activity id> ] { <git commit arguments> }"+ , ""+ , "DESCRIPTION"+ , " Performs a git commit with a comment to capture ClearQuest activity."+ , " Activity format must be: ETNnnnnnnnn"+ , ""+ , "OPTIONS"+ , " --cqact=<activity id> Overrides activity id set by CQACT environment variable."+ , ""+ ]++main :: IO ()+main = do+ args <- getArgs+ case args of+ [] -> help+ ("-h":_) -> help+ ("--help":_) -> help+ (a:args) | isPrefixOf "--cqact=" a -> if isActivity act then commit act args else error $ "invalid activity format: " ++ act+ where+ act = drop 8 a+ args -> do+ env <- getEnvironment+ case lookup "CQACT" env of+ Just a | isActivity a -> commit a args+ _ -> error "CQACT not set or not formated correctly"+ +isActivity :: String -> Bool+isActivity ('E':'T':'N':a) = length a == 8 && all isDigit a+isActivity _ = False++commit :: String -> [String] -> IO ()+commit activity args = do+ putStrLn cmd+ system cmd >>= exitWith+ where+ cmd = "git commit -m " ++ activity ++ " " ++ intercalate " " (map format args)++format :: String -> String+format a | any (flip elem " \"") a = "\"" ++ concat [ if c == '"' then "\\\"" else [c] | c <- a ] ++ "\""+ | otherwise = a+++
+ src/Git2CC.hs view
@@ -0,0 +1,227 @@+module Main (main) where++import Control.Monad+import Data.List+import Data.Maybe+import System.Directory+import System.Environment+import System.IO+import System.Process+import Text.Printf++help :: IO ()+help = putStrLn $ unlines+ [ ""+ , "NAME"+ , " git2cc - bridges git repository to ClearCase"+ , ""+ , "SYNOPSIS"+ , " git2cc <git-directory> <cc-view-directory>"+ , ""+ ]++{-+Git Notes++git clone -q -n rcs@foell.org:git/eaton # Index but no working tree.+git checkout -q -f <commit> # Populate working tree will to a commit.+git log --decorate # List tags next to commit.+ commit 123412341234 (HEAD, 1.0.3, ...+ commit 123412341234 (1.0.2)++git commit -m # Can do multiple -m <msg> arguments. Use one for ETN activity number.+-}++main :: IO ()+main = do+ args <- getArgs+ case args of+ [repo, '/':view] -> inDirectory repo $ push $ '/' : view+ [repo, view] -> do+ d <- getCurrentDirectory+ inDirectory repo $ push $ d ++ "/" ++ view+ _ -> help++push :: FilePath -> IO ()+push view = do+ lastCommit <- lastCommit view+ putStrLn $ "last commit: " ++ lastCommit+ hFlush stdout+ commits <- getCommits >>= return . reverse . takeWhile ((/= lastCommit) . commit)+ mapM_ (applyCommit view (status $ length commits)) $ zip [1..] commits++exec :: String -> IO ()+exec cmd = do+ putStrLn cmd+ hFlush stdout+ system cmd+ return ()++applyCommit :: FilePath -> (Int -> String) -> (Int, Commit) -> IO ()+applyCommit view status (i, c) = do+ printf "%s commit %s %s %s\n" (status i) (commit c) (activity c) (intercalate ", " $ tags c)+ hFlush stdout+ exec $ "git checkout -q -f " ++ commit c+ from <- hashDirectory view+ to <- hashDirectory "."+ let cmds = [SetAct (activity c)] ++ compileCommit "./" from to ++ [CO [".commit"], Version (commit c), CI [".commit"]] ++ map BL (tags c)+ mapM_ exec $ commands view cmds++status :: Int -> Int -> String+status a b = printf f b a+ where+ l = length $ show a+ f = "[%" ++ show l ++ "i of %" ++ show l ++ "i]"++lastCommit :: FilePath -> IO String+lastCommit view = inDirectory view $ do+ d <- getCurrentDirectory+ c <- getDirectoryContents d+ when (not $ elem ".commit" c) $ do+ putStrLn "creating blank .commit file ..."+ hFlush stdout+ exec "cleartool co -nc ."+ exec "touch .commit"+ exec "cleartool mkelem -nc .commit"+ exec "cleartool ci -identical -nc .commit"+ exec "cleartool ci -identical -nc ."+ a <- readProcess "cat" [".commit"] ""+ return $ if null a then a else init a++inDirectory :: FilePath -> IO a -> IO a+inDirectory path action = do+ home <- getCurrentDirectory+ setCurrentDirectory path+ a <- action+ setCurrentDirectory home+ return a++getCommits :: IO [Commit]+getCommits = readProcess "git" ["log", "--decorate=full"] "" >>= return . parseCommits+++data Cmd+ = SetAct String+ | BL String+ | CO [FilePath]+ | CI [FilePath]+ | RM FilePath+ | MK FilePath+ | Version String+ | Mkdir FilePath+ | CP FilePath+ | Note String++commands :: FilePath -> [Cmd] -> [String]+commands view cmds = map command cmds+ where+ command :: Cmd -> String+ command cmd = case cmd of+ SetAct a -> "cd " ++ view ++ " && cleartool setact " ++ a+ BL baseline -> "cd " ++ view ++ " && cleartool mkbl -all -identical -full " ++ baseline ++ " && cleartool chstream -recommended " ++ baseline ++ " -cview"+ CO files -> "cd " ++ view ++ " && cleartool co -nc " ++ intercalate " " files+ CI files -> "cd " ++ view ++ " && cleartool ci -identical -nc " ++ intercalate " " files+ RM file -> "cd " ++ view ++ " && cleartool rmname " ++ file ++ " && rm " ++ file+ MK file -> "cd " ++ view ++ " && cleartool mkelem -nc " ++ file+ Version commit -> "cd " ++ view ++ " && echo " ++ show commit ++ " > .commit"+ Mkdir dir -> "cd " ++ view ++ " && mkdir " ++ dir+ CP file -> "cp " ++ file ++ " " ++ view ++ "/" ++ file+ Note note -> "echo " ++ show note+++data Hash = Directory String [Hash] | File String String deriving (Show, Eq)++hashDirectory :: FilePath -> IO [Hash]+hashDirectory d = inDirectory d $ do+ a <- getDirectoryContents "."+ a <- mapM hashFile a+ return $ catMaybes a++hashFile :: FilePath -> IO (Maybe Hash)+hashFile file | elem file [".", "..", ".git", ".commit"] = return Nothing+hashFile file = do+ d <- doesDirectoryExist file+ if d+ then do+ a <- hashDirectory file+ return $ Just $ Directory file a+ else do+ checksum <- readProcess "md5sum" [file] ""+ return $ Just $ File file checksum++compileCommit :: FilePath -> [Hash] -> [Hash] -> [Cmd]+compileCommit path from to = concatMap patch' (align from to)+ where+ patch' :: (Maybe Hash, Maybe Hash) -> [Cmd]+ patch' (from, to) = case (from, to) of++ -- modifications+ (Just (Directory name a), Just (Directory _ b)) -> compileCommit (path ++ name ++ "/") a b+ (Just (File name a), Just (File _ b)) | a /= b -> [Note $ "modifying file: " ++ path ++ name, CO [path ++ name], CP (path ++ name), CI [path ++ name]]+ | otherwise -> []++ -- removals+ (Just (Directory name _), Nothing) -> [Note $ "removing directory: " ++ path ++ name, CO [path], RM (path ++ name), CI [path]]+ (Just (File name _), Nothing) -> [Note $ "removing file: " ++ path ++ name, CO [path], RM (path ++ name), CI [path]]++ -- additions+ (Nothing, Just (Directory name a)) -> [Note $ "adding directory: " ++ path ++ name, CO [path], Mkdir (path ++ name), MK (path ++ name), CI [path ++ name, path]] ++ compileCommit (path ++ name ++ "/") [] a+ (Nothing, Just (File name _)) -> [Note $ "adding file: " ++ path ++ name, CO [path], CP (path ++ name), MK (path ++ name), CI [path ++ name, path]]++ (a, b) -> error "patch: unexpected diff pair: " $ show (a, b)+ + +align :: [Hash] -> [Hash] -> [(Maybe Hash, Maybe Hash)]+align [] a = zip (replicate (length a) Nothing) (map Just a)+align a [] = zip (map Just a) (replicate (length a) Nothing)+align (file@(File name _) : a) b = (Just file, file') : align a b'+ where+ f (File n _) = n == name+ f _ = False+ (file', b') = getHash f b+align (dir@(Directory name _) : a) b = (Just dir, dir') : align a b'+ where+ f (Directory n _) = n == name+ f _ = False+ (dir', b') = getHash f b++getHash :: (Hash -> Bool) -> [Hash] -> (Maybe Hash, [Hash])+getHash _ [] = (Nothing, [])+getHash f (a:b) | f a = (Just a, b)+ | otherwise = (a', a:b') where (a', b') = getHash f b+++data Commit = Commit+ { commit :: String+ , activity :: String+ , tags :: [String]+ } deriving Show++-- Parse string from 'git log --decorate=full'.+parseCommits :: String -> [Commit]+parseCommits = parseCommits . lines+ where+ + parseCommits :: [String] -> [Commit]+ parseCommits [] = []+ parseCommits (a:b) | isPrefixOf "commit " a = Commit { commit = commit', activity = activity', tags = tags' } : commits+ | otherwise = parseCommits b+ where+ commit' = take 40 $ drop 7 $ a+ tags' = parseTags $ drop 47 a+ (activity', commits) = parseActivityCommits b++ parseTags :: String -> [String]+ parseTags [] = []+ parseTags a | isPrefixOf "refs/tags/" a = tag : parseTags rest+ | otherwise = parseTags $ tail a+ where+ tag = takeWhile (flip notElem ",)") $ drop 10 a+ rest = drop (10 + length tag) a++ parseActivityCommits :: [String] -> (String, [Commit])+ parseActivityCommits [] = ("ETN00000000", []) -- Misc activity.+ parseActivityCommits s@(a:b) | isPrefixOf " ETN" a = (take 11 $ drop 4 a, parseCommits b)+ | isPrefixOf "commit " a = (activity $ head $ parseCommits s, parseCommits s)+ | otherwise = parseActivityCommits b+
+ src/ToESB.hs view
@@ -0,0 +1,86 @@+module Main (main) where++import Data.Bits+import qualified Data.ByteString as BS+import Data.Char+import Data.Digest.CRC32+import Data.List+import Data.Word+import System.Environment+import Text.Printf++help :: IO ()+help = putStrLn $ unlines+ [ ""+ , " NAME"+ , " toesb - converts an s-record ecu image to the Eaton Standard Binary (ESB) format"+ , ""+ , " SYNOPSIS"+ , " toesb [ --nocrc ] <input-file>"+ , ""+ , " OPTIONS"+ , " --nocrc Ignore CRC checking on s-record."+ , ""+ ]+++main :: IO ()+main = do+ args <- getArgs+ case args of+ [i] -> readFile i >>= srec2esb (out i) True+ ["--nocrc", i] -> readFile i >>= srec2esb (out i) False+ _ -> help++out :: FilePath -> FilePath+out a = takeWhile (/= '.') a ++ ".esb"++srec2esb :: FilePath -> Bool -> String -> IO ()+srec2esb o checkCRC a = do+ printf "section address section length\n"+ sequence_ [ printf "0x%08X 0x%08X\n" a (length b) | (a, b) <- a3 ]+ putStrLn $ "writing " ++ o ++ " ..."+ BS.writeFile o $ BS.pack $ map fromIntegral file+ where+ a1 = [ (dehex $ init $ init $ drop 2 a, head $ dehex $ reverse $ take 2 $ reverse a) | l <- lines a, let a = filter isAlphaNum l, isPrefixOf "S3" a ]+ a2 = concatMap (addr checkCRC) a1+ a3 = [ (a, b) | (a, b) <- blocks a2, a >= 0x10000, a <= 0x7FFFF ]+ n = length a3+ allBlocks = le n ++ concatMap j1939Block a3+ fileCRC = fromIntegral $ crc32 $ (map fromIntegral allBlocks :: [Word8])+ file = [0xE5, 0x5B, 0xBE, 0xE5, 5, 0, 0, 0] ++ le fileCRC ++ allBlocks+ +addr :: Bool -> ([Int], Int) -> [(Int, Int)] -- (addr, byte)+addr checkCRC (a, checksum) = if checkCRC && complement (sum a) .&. 0xFF /= checksum then error $ "failed checksum: " ++ show (a, checksum) else zip addrs bytes+ where+ base = shiftL (a !! 1) 24+ + shiftL (a !! 2) 16+ + shiftL (a !! 3) 8+ + (a !! 4)+ addrs = [base ..]+ bytes = drop 5 a++blocks :: [(Int, a)] -> [(Int, [a])]+blocks [] = []+blocks ((addr, byte) : rest) = section : blocks rest'+ where+ (section, rest') = block (addr + 1) (addr, [byte]) rest++block :: Int -> (Int, [a]) -> [(Int, a)] -> ((Int, [a]), [(Int, a)])+block nextAddr (startingAddr, sofar) ((a, b):rest) | a == nextAddr = block (nextAddr + 1) (startingAddr, b : sofar) rest+block _ (a, b) rest = ((a, reverse b), rest)++dehex :: String -> [Int]+dehex "" = []+dehex (a:b:c) = read ("0x" ++ [a,b]) : dehex c+dehex _ = undefined+++j1939Block :: (Int, [Int]) -> [Int]+j1939Block (addr, d) = [3, 0, 0, 0] ++ le (shiftL (addr - 0x10000) 8 .&. 0xFFFFFF00 .|. 128) ++ le (length d) ++ d++le :: Int -> [Int]+le a = [ a .&. 0xFF]+ ++ [shiftR a 8 .&. 0xFF]+ ++ [shiftR a 16 .&. 0xFF]+ ++ [shiftR a 24 .&. 0xFF]