diff options
-rw-r--r-- | Network/EBus/Layer2.hs | 94 | ||||
-rw-r--r-- | ebus.cabal | 3 | ||||
-rw-r--r-- | exec/ebus-dump-layer2.hs | 39 |
3 files changed, 67 insertions, 69 deletions
diff --git a/Network/EBus/Layer2.hs b/Network/EBus/Layer2.hs index c4f1d47..b194ee6 100644 --- a/Network/EBus/Layer2.hs +++ b/Network/EBus/Layer2.hs @@ -1,56 +1,10 @@ -module Network.EBus.Layer2 where +module Network.EBus.Layer2( + ebusParserLayer2, + EbusPacket) where -import Control.Applicative -import Data.Attoparsec -import Data.Attoparsec.Enumerator (iterParser) -import Data.Attoparsec.Combinator as C -import Data.ByteString (ByteString) -import Data.Enumerator -import Data.Enumerator.Binary (enumHandle) +import Control.Applicative ((<|>)) +import Data.Attoparsec (anyWord8, count, skipMany, try, Parser, word8) import Data.Word (Word8) -import System.IO (hSetBinaryMode,stdin) - --- ebus :: Parser EbusPacket --- ebus = do{ skipMany1 $ char '\xaa' --- ; source <- anyChar --- ; destination <- anyChar --- ; primaryCommand <- anyChar --- ; secondaryCommand <- anyChar --- ; payloadLength <- anyChar --- ; payload <- count (fromEnum payloadLength) ebusPayload --- ; followup <- --- if destination == '\xfe' then --- -- Broadcast - no further data --- do{ crc <- anyChar --- ; syn <- char '\xaa' --- ; return "broadcast" --- <|> fail "Failed to parse Broadcast Packet" --- } --- else --- try( -- Master-Master - no further data --- do{ crc <- anyChar --- ; ack <- char '\x00' -- ACK OK --- ; syn <- char '\xaa' --- ; return "master-master" --- }) --- <|> --- try( -- Master Slave --- do{ crc <- anyChar --- ; ack <- char '\x00' --- ; payloadSlaveLength <- anyChar --- ; payloadSlave <- count (fromEnum payloadSlaveLength) ebusPayload --- ; crcSlave <- anyChar --- ; ackSlave <- char '\x00' --- ; synSlave <- char '\xaa' --- ; return "master-slave" --- }) --- <|> fail "Failed to parse Master-Master/Master-Slave Packet" --- ; return $ EbusPacket --- source destination --- primaryCommand secondaryCommand --- payloadLength followup [] --- } - -- | Ebus Layer2 Constants ebusConstant :: String -> Word8 @@ -75,11 +29,11 @@ data EbusPacket = EbusPacket { ebusPacketDestination :: Word8, ebusPacketPrimaryCommand :: Word8, ebusPacketSecondaryCommand :: Word8, - ebusPacketPayloadLength :: Word8, ebusPacketPayload :: [Word8], ebusPacketPayloadSlave :: Maybe [Word8] } deriving (Show) +-- | Ebus Binary Escape Sequences for payload data parserPayload :: Parser Word8 parserPayload = do{ word8 $ ebusConstant "ESCAPE" ; word8 $ ebusConstant "ESCAPE_ESCAPE" @@ -91,21 +45,25 @@ parserPayload = do{ word8 $ ebusConstant "ESCAPE" <|> anyWord8; -parser :: Parser EbusPacket -parser = do{ - C.skipMany $ word8 $ ebusConstant "SYN" +-- | Parse one Ebus Packet, skips leading SYNs +ebusParserLayer2 :: Parser EbusPacket +ebusParserLayer2 = do{ + skipMany $ word8 $ ebusConstant "SYN" ; source <- anyWord8 ; destination <- anyWord8 ; primaryCommand <- anyWord8 ; secondaryCommand <- anyWord8 ; payloadLength <- anyWord8 - ; payload <- C.count (fromIntegral payloadLength) parserPayload + ; payload <- count (fromIntegral payloadLength) parserPayload ; followup <- if destination == 0xfe then -- Broadcast do{ crc <- anyWord8 ; {- syn -} word8 $ ebusConstant "SYN" - ; return (EbusBroadcast, crc, Nothing)} + ; if True then -- CHECK CRC + return $ EbusPacket EbusMasterMaster source destination primaryCommand secondaryCommand payload Nothing + else + fail "Broadcast: CRC Check failed"} <|> fail "Failed to parse Broadcast Paket" else @@ -114,25 +72,27 @@ parser = do{ do{ crc <- anyWord8 ; {- ack -} word8 $ ebusConstant "ACK" ; {- syn -} word8 $ ebusConstant "SYN" - ; return (EbusMasterMaster, crc, Nothing)}) + ; if True then -- CHECK CRC + return $ EbusPacket EbusMasterMaster source destination primaryCommand secondaryCommand payload Nothing + else + fail "Master-Master: CRC Check failed"}) <|> -- Master Slave try( do{ crc <- anyWord8 ; {- ack -} word8 $ ebusConstant "ACK" ; payloadSlaveLength <- anyWord8 - ; payloadSlave <- C.count (fromIntegral payloadSlaveLength) parserPayload + ; payloadSlave <- count (fromIntegral payloadSlaveLength) parserPayload ; crcSlave <- anyWord8 ; {- ackSlave -} word8 $ ebusConstant "ACK" ; {- synSlave -} word8 $ ebusConstant "SYN" - ; return (EbusMasterSlave, crc, (Just (payloadSlave, crcSlave)))}) + ; if True then -- Check CRC + return $ EbusPacket EbusMasterSlave source destination primaryCommand secondaryCommand payload (Just payloadSlave) + else + fail "Master-Slave: CRC Check failed"}) + <|> fail "Failed to parse Master-Master/Master-Slave Packet" - ; do { - if True then --CHECK CRC - return $ EbusPacket EbusMasterMaster source destination primaryCommand secondaryCommand payloadLength payload (Just []) - else - fail "CRC Check failed"} + ; return followup <|> fail "Failed to parse packet" - } - + }
\ No newline at end of file @@ -32,4 +32,5 @@ Test-Suite test-network-ebus Executable ebus-dump-layer2 Main-Is: exec/ebus-dump-layer2.hs - Build-Depends: base >=4 && < 5, ebus + Build-Depends: base >=4 && < 5, ebus, + bytestring, attoparsec >= 0.10.1.1, attoparsec-enumerator >= 0.3, enumerator >= 0.4.18 diff --git a/exec/ebus-dump-layer2.hs b/exec/ebus-dump-layer2.hs index 84d72e2..c8fd1b5 100644 --- a/exec/ebus-dump-layer2.hs +++ b/exec/ebus-dump-layer2.hs @@ -1,4 +1,41 @@ module Main(main) where + +import Network.EBus.Layer2 +import Data.Enumerator (Enumerator, Iteratee, run, ($$)) +import Data.Enumerator.Binary (enumHandle) +import System.IO (hSetBinaryMode,stdin) +import Data.ByteString (ByteString) +import Data.Attoparsec.Enumerator (iterParser) main = do - print "Hello ebus-dump-layer" + -- * Select binary mode (True) or text mode (False) on a open handle. (See also openBinaryFile.) + hSetBinaryMode stdin True + -- * run + -- Run an iteratee until it finishes, and return either the final value (if it succeeded) or the error (if it failed). + -- * run_ + -- Like run, except errors are converted to exceptions and thrown. Primarily useful for small scripts or other simple cases. + + loop 100 + +loop :: Int -> IO() +loop 0 = do + print "finished" +loop n = do + readAndDumpPacket + loop (n - 1) + +readAndDumpPacket :: IO() +readAndDumpPacket = do + maybePacket <- run( enumSource $$ runParser ) + case maybePacket of + Right result -> print result + Left error -> print error + + +enumSource :: Enumerator ByteString IO a +enumSource = enumHandle 1 stdin + +runParser :: Iteratee ByteString IO EbusPacket +runParser = do + p <- iterParser ebusParserLayer2 + return p |