1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
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"
}
|