summaryrefslogtreecommitdiff
path: root/Network/EBus/Layer2.hs
blob: c4f1d471e13b49d32e44833c8cd80d10112bcbf0 (plain)
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
module Network.EBus.Layer2 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 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
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,
  ebusPacketPayloadLength :: Word8,
  ebusPacketPayload :: [Word8],
  ebusPacketPayloadSlave :: Maybe [Word8]
  } deriving (Show)

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;

parser :: Parser EbusPacket
parser = do{ 
  C.skipMany $ word8 $ ebusConstant "SYN"
  ; source <- anyWord8
  ; destination <- anyWord8
  ; primaryCommand <- anyWord8
  ; secondaryCommand <- anyWord8
  ; payloadLength <- anyWord8
  ; payload <- C.count (fromIntegral payloadLength) parserPayload
  ; followup <-
    if destination == 0xfe then
      -- Broadcast
      do{ crc <- anyWord8
        ; {- syn -} word8 $ ebusConstant "SYN"
        ; return (EbusBroadcast, crc, Nothing)}
      <|>
      fail "Failed to parse Broadcast Paket"
    else
      -- Master-Master
      try( 
        do{ crc <- anyWord8
          ; {- ack -} word8 $ ebusConstant "ACK"
          ; {- syn -} word8 $ ebusConstant "SYN"
          ; return (EbusMasterMaster, crc, Nothing)})
      <|> 
      -- Master Slave
      try(
        do{ crc <- anyWord8
          ; {- ack -} word8 $ ebusConstant "ACK"
          ; payloadSlaveLength <- anyWord8
          ; payloadSlave <- C.count (fromIntegral payloadSlaveLength) parserPayload
          ; crcSlave <- anyWord8
          ; {- ackSlave -} word8 $ ebusConstant "ACK"
          ; {- synSlave -} word8 $ ebusConstant "SYN"
          ; return (EbusMasterSlave, crc, (Just (payloadSlave, crcSlave)))})
      <|> 
      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"}
    <|> fail "Failed to parse packet"
  }