ecu 0.0.2 → 0.0.3
raw patch · 3 files changed
+168/−36 lines, 3 files
Files
- README +2/−2
- ecu.cabal +2/−2
- src/CCP.hs +164/−32
README view
@@ -1,17 +1,17 @@ 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. ccp - CAN Configuration Protocol master.+toesb - Converts s-record ECU images to the Eaton Standard Binary format. 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.+todbc - Generate Vector DBC files from CAN specification. 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.
ecu.cabal view
@@ -1,5 +1,5 @@ name: ecu-version: 0.0.2+version: 0.0.3 category: Embedded, Utils @@ -61,7 +61,7 @@ extra-libraries: canlib build-depends: base >= 4.0 && < 5 ghc-options: -W- extensions: ForeignFunctionInterface+ extensions: ForeignFunctionInterface, FlexibleInstances executable probe hs-source-dirs: src
src/CCP.hs view
@@ -1,8 +1,10 @@ module Main (main) where import Control.Monad+import Data.IORef import Data.Word import System.Environment+import System.IO import Text.Printf import CAN@@ -17,11 +19,12 @@ , " ccp command { option } { argument }" , "" , "COMMANDS"- , " upload { option } address Upload 4 bytes from the ECU. Address must be 32-bit aligned."- , " upload { option } address length Upload a memory region from the ECU. Address must be 32-bit aligned."+ , " download address data Download data to ECU. Data must be even number of hex characters."+ , " upload address Upload 4 bytes from the ECU."+ , " upload address size Upload a memory region from the ECU." , "" , "OPTIONS"- , " --std Set to standard CAN with 500K. Default is extended CAN with 250K."+ , " -v Print message transactions and diagnostic messages." , "" , "ENVIRONMENT VARIABLES" , " CCP_ID_MASTER CAN identifier for master device (this configuration tool)."@@ -35,39 +38,168 @@ f args = case args of ["-h"] -> help ["--help"] -> help- ["upload", addr] -> f ["upload", addr, "4"]- ["upload", "--std", addr] -> f ["upload", "--std", addr, "4"]- ["upload", "--std", addr, size] -> do- initCAN- bus <- openBus 0 Standard- ids <- ids- upload bus ids (read addr) (read size)- closeBus bus+ ["download", addr, bytes] -> do+ bytes <- parseBytes bytes+ connection <- connect False+ download connection (read addr) bytes+ disconnect connection+ ["download", "-v", addr, bytes] -> do+ bytes <- parseBytes bytes+ connection <- connect True+ download connection (read addr) bytes+ disconnect connection+ ["upload", "-v", addr] -> f ["upload", "-v", addr, "4"]+ ["upload", "-v", addr, size] -> do+ connection <- connect True+ upload connection (read addr) (read size)+ disconnect connection+ ["upload", addr] -> f ["upload", addr, "4"] ["upload", addr, size] -> do- initCAN- bus <- openBus 0 Extended- ids <- ids- upload bus ids (read addr) (read size)- closeBus bus+ connection <- connect False+ upload connection (read addr) (read size)+ disconnect connection _ -> help -canview :: Bus -> [Word32] -> IO ()-canview bus ids = do- m <- recvMsg bus- case m of- 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+data Connection = Connection+ { cBus :: Bus+ , cMaster :: Word32+ , cSlave :: Word32+ , cCounter :: IORef Word8+ , cVerbose :: Bool+ } -ids :: IO (Word32, Word32)-ids = do- master <- getEnv "CCP_ID_MASTER"- slave <- getEnv "CCP_ID_SLAVE"- return (read master, read slave)+connect :: Bool -> IO Connection+connect verbose = do+ initCAN+ bus <- openBus 0 Extended+ flushRxQueue bus+ master <- getEnv "CCP_ID_MASTER"+ slave <- getEnv "CCP_ID_SLAVE"+ counter <- newIORef 0+ return Connection+ { cBus = bus+ , cMaster = read master+ , cSlave = read slave+ , cCounter = counter+ , cVerbose = verbose+ } -upload :: Bus -> (Word32, Word32) -> Word32 -> Word32 -> IO ()-upload bus (master, slave) address size = do- printf "%08x %08x\n" master slave+disconnect :: Connection -> IO ()+disconnect c = closeBus $ cBus c++transact :: Connection -> Word8 -> [Word8] -> IO (Maybe [Word8])+transact c command payload = do+ counter <- readIORef $ cCounter c+ writeIORef (cCounter c) $ counter + 1+ let msg = Msg (cMaster c) $ take 8 $ command : counter : payload ++ repeat 0xff+ when (cVerbose c) $ do+ printf "send: %s\n" $ show msg+ hFlush stdout+ sendMsg (cBus c) msg+ time <- busTime' $ cBus c+ recv counter time+ where+ recv :: Word8 -> Int -> IO (Maybe [Word8])+ recv counter time = do+ m <- recvMsgWait (cBus c) 25 + case m of+ Nothing -> return Nothing+ Just (t, m@(Msg id payload))+ | id == cSlave c && length payload == 8 && payload !! 0 == 0xff && payload !! 2 == counter -> do+ if payload !! 1 == 0+ then do+ when (cVerbose c) $ do+ printf "recv: %s\n" (show m)+ hFlush stdout+ return $ Just $ drop 3 payload+ else error $ printf "error code: %02x\n" $ payload !! 1+ | t - time > 25 -> return Nothing+ | otherwise -> recv counter time++transactRetry :: Int -> Connection -> Word8 -> [Word8] -> IO [Word8]+transactRetry n c cmd payload+ | n <= 0 = error "transactRetry failed to complete"+ | otherwise = do+ a <- transact c cmd payload+ case a of+ Nothing -> do+ when (cVerbose c) $ do+ putStrLn "retrying transaction"+ hFlush stdout+ transactRetry (n - 1) c cmd payload+ Just a -> return a++setMTA0 :: Connection -> Word32 -> IO ()+setMTA0 c address = do+ transactRetry 5 c 0x02 $ 0 : 0 : fromWord32 address return ()++upload :: Connection -> Word32 -> Word32 -> IO ()+upload c address size = do+ bytes <- upload0 address size+ sequence_ [ printf "%08x %s\n" address value | (address, value) <- zip [address, address + 4 ..] (pack $ map (printf "%02x") bytes :: [String]) ]+ where+ upload0 :: Word32 -> Word32 -> IO [Word8]+ upload0 address size+ | size <= 5 = do+ a <- transact c 0x0f $ fromIntegral size : 0 : fromWord32 address+ case a of+ Nothing -> do+ when (cVerbose c) $ do+ printf "upload restart at address %08x\n" address+ hFlush stdout+ upload0 address size+ Just payload -> return $ take (fromIntegral size) payload+ | otherwise = do+ setMTA0 c address+ upload1 address size++ upload1 :: Word32 -> Word32 -> IO [Word8]+ upload1 address size = if size == 0 then return [] else do+ a <- transact c 0x04 [if size > 5 then 5 else fromIntegral size]+ case a of+ Nothing -> do+ when (cVerbose c) $ do+ printf "upload restart at address %08x\n" address+ hFlush stdout+ upload0 address size+ Just payload -> do+ a <- upload1 (address + min size 5) (max size 5 - 5)+ return $ take (fromIntegral size) payload ++ a++ pack :: [String] -> [String]+ pack (a0 : a1 : a2 : a3 : rest) = concat [a0, a1, a2, a3] : pack rest+ pack [] = []+ pack a = [concat a]+ +parseBytes :: String -> IO [Word8]+parseBytes a = if odd $ length a then error "hex string has odd number of characters, not byte aligned" else return $ parseBytes' a+ where+ parseBytes' :: String -> [Word8]+ parseBytes' ('0' : 'x' : bytes) = parseBytes' bytes+ parseBytes' [] = []+ parseBytes' [_] = error "hex string has odd number of characters, not byte aligned"+ parseBytes' (a : b : c) = read ("0x" ++ [a, b]) : parseBytes' c+++download :: Connection -> Word32 -> [Word8] -> IO ()+download c address bytes = download0 address bytes+ where+ download0 :: Word32 -> [Word8] -> IO ()+ download0 address bytes = do+ setMTA0 c address+ download1 address bytes++ download1 :: Word32 -> [Word8] -> IO ()+ download1 address bytes = if null bytes then return () else do+ a <- transact c (if n == 6 then 0x23 else 0x03) (if n == 6 then take 6 bytes else fromIntegral n : take n (bytes ++ [0xFF ..]))+ case a of+ Nothing -> do+ when (cVerbose c) $ do+ printf "download restart at address %08x\n" address+ hFlush stdout+ download0 address bytes+ Just _ -> download1 (address + fromIntegral n) (drop n bytes)+ where+ n = min 6 $ length bytes