packages feed

ecu 0.0.2 → 0.0.3

raw patch · 3 files changed

+168/−36 lines, 3 files

Files

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