| Portability | portable |
|---|---|
| Stability | experimental |
| Maintainer | David Joyner <david@joynerhome.net> |
| Safe Haskell | Safe-Infered |
Network.Protocol.ZigBee.ZNet25.Encoder
Contents
Description
XBee ZNet 2.5 (ZigBee) frame encoder/decoder functions
- encode :: Frame -> [ByteString]
- data DecoderState
- initDecode :: DecoderState
- decode :: MonadState DecoderState m => ByteString -> m [Either String Frame]
Frame encoder
encode :: Frame -> [ByteString]Source
Serialize a Frame, escape control characters, and wrap the result with
framing bytes. Return an array of ByteString suitable for transmission
to the XBee modem.
Note that this function returns an array of ByteString. Encoding
takes place in a piece-wise manner and for efficiency's sake the individual
bits are not concatenated to form a single ByteString. Typically this is
a non-issue however if you need a single ByteString representation of the
Frame you can always obtain it by calling concat.
Here's an example that illustrates encode usage as well as the
on-the-wire frame format:
import qualified Data.ByteString as B import Network.Protocol.ZigBee.ZNet25 import Text.Printf main = hexdump $ B.concat $ encode (ATCommand 0 (commandName "ND") B.empty) hexdump = mapM_ (putStr . printf "%02x ") . B.unpack
This prints:
7e 00 04 08 00 4e 44 65
The leading 7e byte is the frame delimiter. This is followed by the 16-bit
frame length (4 bytes in this case), that many bytes of data (the
serialized ATCommand frame), and the final checksum byte.
Stateful frame decoder
data DecoderState Source
decode runs in the State monad. DecoderState tracks the
decoder's in/out-of frame state, current frame length, and other state
variables.
Instances
decode :: MonadState DecoderState m => ByteString -> m [Either String Frame]Source
Decode a ByteString in the State monad, reversing the encode
process. Once a frame delimiter byte is found, the inner frame payload is
unescaped, the checksum is verified, and finally a Frame is deserialized.
Note that this function may produce zero or more errors or Frames depending
on the DecoderState and input byte string. Errors will be reported for
checksum errors and Frame deserialization failures.
Here's a slightly more complex example that encodes two separate frames,
runs each array of ByteStrings through decode and prints the result
after running the State monad:
import Control.Monad.State
import qualified Data.ByteString as B
import Network.Protocol.ZigBee.ZNet25
main = putStrLn $ show $ evalState (mapM decode bs) initDecode
where
bs = concat $ map encode [atndCommand, txRequest]
atndCommand = ATCommand 1 (commandName "ND") B.empty
txRequest = ZigBeeTransmitRequest 2 addr nwaddr 0 0 $ B.singleton 0x55
addr = address $ B.pack [ 0xde, 0xad, 0xbe, 0xef, 0xba, 0xda, 0xba, 0xda ]
nwaddr = networkAddress $ B.pack [ 0x55, 0xaa ]
This prints:
[[],[],[],[Right (ATCommand 1 "ND" "")],[],[],[],[Right (ZigBeeTransmitRequest 2 de:ad:be:ef:ba:da:ba:da 55:aa 0 0 "U")]]
Note a few things:
- Each call to
encodeapparently produced four separateByteStrings. This is a by-product of theencodeimplementation as described above. -
decodewas only able to produce a result once the finalByteStringof eachFramewas processed. In this case the result wasRightFrame. If an error had occurred, we'd seeLeftStringinstead.