module Network.EBus.Layer2( ebusParserLayer2, EbusPacket) where import Control.Applicative ((<|>)) import Data.Attoparsec (anyWord8, count, skipMany, try, Parser, word8) import Data.Word (Word8) -- | Ebus Layer2 Constants ebusConstant :: String -> Word8 ebusConstant "SYN" = 0xaa ebusConstant "ACK" = 0x00 ebusConstant "BROADCAST" = 0xff ebusConstant "ESCAPE" = 0xa9 ebusConstant "ESCAPE_ESCAPE" = 0x00 ebusConstant "ESCAPE_SYN" = 0x01 ebusConstant _ = 0x00 -- | Ebus Packet Types data EbusType = EbusBroadcast | EbusMasterMaster | EbusMasterSlave deriving (Show) -- | Ebus Packet representation data EbusPacket = EbusPacket { ebusPacketType :: EbusType, ebusPacketSource :: Word8, ebusPacketDestination :: Word8, ebusPacketPrimaryCommand :: Word8, ebusPacketSecondaryCommand :: 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" ; return $ ebusConstant "ESCAPE"} <|> do{ word8 $ ebusConstant "ESCAPE" ; word8 $ ebusConstant "ESCAPE_SYN" ; return $ ebusConstant "SYN"} <|> anyWord8; -- | 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 <- count (fromIntegral payloadLength) parserPayload ; followup <- if destination == 0xfe then -- Broadcast do{ crc <- anyWord8 ; {- syn -} word8 $ ebusConstant "SYN" ; 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 -- Master-Master try( do{ crc <- anyWord8 ; {- ack -} word8 $ ebusConstant "ACK" ; {- syn -} word8 $ ebusConstant "SYN" ; 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 <- count (fromIntegral payloadSlaveLength) parserPayload ; crcSlave <- anyWord8 ; {- ackSlave -} word8 $ ebusConstant "ACK" ; {- synSlave -} word8 $ ebusConstant "SYN" ; 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" ; return followup <|> fail "Failed to parse packet" }