summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Crypto/Tox.hs21
-rw-r--r--src/Data/PacketQueue.hs93
-rw-r--r--src/Network/Tox/Crypto/Handlers.hs73
-rw-r--r--src/Network/Tox/Crypto/Transport.hs16
4 files changed, 195 insertions, 8 deletions
diff --git a/src/Crypto/Tox.hs b/src/Crypto/Tox.hs
index 18cdb5d2..624da233 100644
--- a/src/Crypto/Tox.hs
+++ b/src/Crypto/Tox.hs
@@ -34,11 +34,13 @@ module Crypto.Tox
34 , decodePlain 34 , decodePlain
35 -- , computeSharedSecret 35 -- , computeSharedSecret
36 , lookupSharedSecret 36 , lookupSharedSecret
37 , lookupNonceFunction
37 , encrypt 38 , encrypt
38 , decrypt 39 , decrypt
39 , Nonce8(..) 40 , Nonce8(..)
40 , Nonce24(..) 41 , Nonce24(..)
41 , incrementNonce24 42 , incrementNonce24
43 , nonce24ToWord16
42 , addtoNonce24 44 , addtoNonce24
43 , Nonce32(..) 45 , Nonce32(..)
44 , getRemainingEncrypted 46 , getRemainingEncrypted
@@ -300,10 +302,19 @@ lookupSharedSecret :: TransportCrypto -> SecretKey -> PublicKey -> Nonce24 -> IO
300lookupSharedSecret crypto sk recipient nonce 302lookupSharedSecret crypto sk recipient nonce
301 = ($ nonce) <$> lookupNonceFunction crypto sk recipient 303 = ($ nonce) <$> lookupNonceFunction crypto sk recipient
302 304
305{-# INLINE lookupNonceFunction #-}
303lookupNonceFunction :: TransportCrypto -> SecretKey -> PublicKey -> IO (Nonce24 -> State) 306lookupNonceFunction :: TransportCrypto -> SecretKey -> PublicKey -> IO (Nonce24 -> State)
304lookupNonceFunction TransportCrypto{secretsCache} sk recipient = do 307lookupNonceFunction c@(TransportCrypto{secretsCache}) sk recipient = do
305 now <- getPOSIXTime 308 now <- getPOSIXTime
306 atomically $ do 309 atomically $ lookupNonceFunctionSTM now c sk recipient
310
311{-# INLINE lookupNonceFunctionSTM #-}
312-- | This version of 'lookupNonceFunction' is STM instead of IO, this means if some later part of
313-- of the transaction fails, we may end up forgoing a computation that could have been cached.
314-- Use with care. In most circumstances you probably want 'lookupNonceFunction'. It also commits
315-- us to using TVars to store the cache.
316lookupNonceFunctionSTM :: POSIXTime -> TransportCrypto -> SecretKey -> PublicKey -> STM (Nonce24 -> State)
317lookupNonceFunctionSTM now TransportCrypto{secretsCache} sk recipient = do
307 mm <- readTVar $ sharedSecret secretsCache 318 mm <- readTVar $ sharedSecret secretsCache
308 case MM.lookup' recipient mm of 319 case MM.lookup' recipient mm of
309 Nothing -> do 320 Nothing -> do
@@ -332,7 +343,10 @@ hsalsa20 k n = BA.append a b
332 343
333 344
334newtype Nonce24 = Nonce24 ByteString 345newtype Nonce24 = Nonce24 ByteString
335 deriving (Eq, Ord, ByteArrayAccess,Data) 346 deriving (Eq, Ord, ByteArrayAccess, Data)
347
348nonce24ToWord16 :: Nonce24 -> Word16
349nonce24ToWord16 (Nonce24 n24) = fromIntegral (B.index n24 23) + 256 * fromIntegral (B.index n24 22)
336 350
337addtoNonce24 :: Nonce24 -> Word -> IO Nonce24 351addtoNonce24 :: Nonce24 -> Word -> IO Nonce24
338addtoNonce24 (Nonce24 n24) n = Nonce24 <$> BA.copy n24 init 352addtoNonce24 (Nonce24 n24) n = Nonce24 <$> BA.copy n24 init
@@ -376,6 +390,7 @@ addtoNonce24 (Nonce24 n24) n = Nonce24 <$> BA.copy n24 init
376 pokeElemOff ptr 5 $ tBE32 (W# sum_) 390 pokeElemOff ptr 5 $ tBE32 (W# sum_)
377 init _ = error "incrementNonce24: I only support 64 and 32 bits" 391 init _ = error "incrementNonce24: I only support 64 and 32 bits"
378 392
393{-# INLINE incrementNonce24 #-}
379incrementNonce24 :: Nonce24 -> IO Nonce24 394incrementNonce24 :: Nonce24 -> IO Nonce24
380incrementNonce24 nonce24 = addtoNonce24 nonce24 1 395incrementNonce24 nonce24 = addtoNonce24 nonce24 1
381 396
diff --git a/src/Data/PacketQueue.hs b/src/Data/PacketQueue.hs
index b349bf4b..927d6c53 100644
--- a/src/Data/PacketQueue.hs
+++ b/src/Data/PacketQueue.hs
@@ -3,12 +3,19 @@
3-- be stored out of order, but from which they are extracted in the proper 3-- be stored out of order, but from which they are extracted in the proper
4-- sequence. 4-- sequence.
5{-# LANGUAGE NamedFieldPuns #-} 5{-# LANGUAGE NamedFieldPuns #-}
6{-# LANGUAGE FlexibleContexts #-}
6module Data.PacketQueue 7module Data.PacketQueue
7 ( PacketQueue 8 ( PacketQueue
8 , new 9 , new
9 , dequeue 10 , dequeue
10 , enqueue 11 , enqueue
11 , observeOutOfBand 12 , observeOutOfBand
13 , PacketOutQueue
14 , newOutGoing
15 , tryAppendQueueOutgoing
16 , dequeueOutgoing
17 , mapOutGoing
18 , OutGoingResult(..)
12 ) where 19 ) where
13 20
14import Control.Concurrent.STM 21import Control.Concurrent.STM
@@ -21,7 +28,7 @@ data PacketQueue a = PacketQueue
21 { pktq :: TArray Word32 (Maybe a) 28 { pktq :: TArray Word32 (Maybe a)
22 , seqno :: TVar Word32 29 , seqno :: TVar Word32
23 , qsize :: Word32 30 , qsize :: Word32
24 , buffend :: TVar Word32 31 , buffend :: TVar Word32 -- on incoming, highest packet number handled + 1
25 } 32 }
26 33
27-- | Create a new PacketQueue. 34-- | Create a new PacketQueue.
@@ -77,3 +84,87 @@ enqueue PacketQueue{ pktq, seqno, qsize, buffend } no x = do
77 84
78-- lookup :: PacketQueue a -> Word32 -> STM (Maybe a) 85-- lookup :: PacketQueue a -> Word32 -> STM (Maybe a)
79-- lookup PacketQueue{ pktq, seqno, qsize } no = _todo 86-- lookup PacketQueue{ pktq, seqno, qsize } no = _todo
87
88-----------------------------------------------------
89-- * PacketOutQueue
90--
91
92data PacketOutQueue extra msg toWire fromWire = PacketOutQueue
93 { pktoInPQ :: PacketQueue fromWire -- ^ reference to the incoming 'PacketQueue'
94 , pktoOutPQ :: PacketQueue (Word32,toWire)
95 , pktoPacketNo :: TVar Word32
96 , pktoToWireIO :: IO (STM extra)
97 , pktoToWire :: STM extra
98 -> Word32{-packet number we expect to recieve-}
99 -> Word32{- buffer_end -}
100 -> Word32{- packet number -}
101 -> msg
102 -> STM (Maybe (toWire,Word32{-next packet no-}))
103 }
104
105mapOutGoing :: ((Word32,towire) -> Maybe (Word32,towire)) -> PacketOutQueue extra msg towire fromwire -> STM ()
106mapOutGoing f q@(PacketOutQueue { pktoOutPQ=PacketQueue{ pktq } }) = do
107 (z,n) <- getBounds pktq
108 let ff i = do
109 e <- readArray pktq i
110 writeArray pktq i (e>>=f)
111 mapM_ ff [z .. n]
112
113newOutGoing :: PacketQueue fromwire
114 -- ^ Incoming queue
115 -> (STM io -> Word32 {-packet number we expect to recieve-} -> Word32{-buffer_end-} -> Word32{-packet number-} -> msg -> STM (Maybe (wire,Word32{-next packet no-})))
116 -- ^ toWire callback
117 -> IO (STM io)
118 -- ^ io action to get extra parameter
119 -> Word32 -- ^ packet number of first outgoing packet
120 -> Word32 -- ^ Capacity of queue.
121 -> Word32 -- ^ Initial sequence number.
122 -> STM (PacketOutQueue io msg wire fromwire)
123newOutGoing inq towire toWireIO num capacity seqstart = do
124 outq <- new capacity seqstart
125 numVar <- newTVar num
126 return $ PacketOutQueue
127 { pktoInPQ = inq
128 , pktoOutPQ = outq
129 , pktoPacketNo = numVar
130 , pktoToWireIO = toWireIO
131 , pktoToWire = towire
132 }
133
134data OutGoingResult = OGSuccess | OGFull | OGEncodeFail
135 deriving (Eq,Show)
136
137-- | Convert a message to packet format and append it to the front of a queue
138-- used for outgoing messages. (Note that ‘front‛ usually means the higher
139-- index in this implementation.)
140tryAppendQueueOutgoing :: STM extra -> PacketOutQueue extra msg wire fromwire -> msg -> STM OutGoingResult
141tryAppendQueueOutgoing getExtra q@(PacketOutQueue { pktoInPQ, pktoOutPQ, pktoPacketNo, pktoToWireIO, pktoToWire }) msg = do
142 be <- readTVar (buffend pktoOutPQ)
143 let i = be `mod` (qsize pktoOutPQ)
144 mbPkt <- readArray (pktq pktoOutPQ) i
145 pktno <- readTVar pktoPacketNo
146 nextno <- readTVar (seqno pktoInPQ)
147 mbWire <- pktoToWire getExtra nextno be pktno msg
148 case mbWire of
149 Just (pkt,pktno')
150 -> case mbPkt of
151 -- slot is free, insert element
152 Nothing -> do
153 modifyTVar' (buffend pktoOutPQ) (+1)
154 writeTVar pktoPacketNo $! pktno'
155 writeArray (pktq pktoOutPQ) i (Just (pktno,pkt))
156 return OGSuccess
157 -- queue is full, block until its not
158 _ -> return OGFull
159 -- don't know how to send this message
160 Nothing -> return OGEncodeFail
161
162dequeueOutgoing :: PacketOutQueue extra msg wire fromwire -> STM (Word32,wire)
163dequeueOutgoing (PacketOutQueue {pktoOutPQ=PacketQueue { pktq, seqno, qsize }}) = do
164 i0 <- readTVar seqno
165 let i = i0 `mod` qsize
166 x <- maybe retry return =<< readArray pktq i
167 -- writeArray pktq i Nothing -- not cleaning
168 modifyTVar' seqno succ
169 return x
170
diff --git a/src/Network/Tox/Crypto/Handlers.hs b/src/Network/Tox/Crypto/Handlers.hs
index edfcb260..6a79da1b 100644
--- a/src/Network/Tox/Crypto/Handlers.hs
+++ b/src/Network/Tox/Crypto/Handlers.hs
@@ -1,5 +1,6 @@
1{-# LANGUAGE NamedFieldPuns #-} 1{-# LANGUAGE NamedFieldPuns #-}
2{-# LANGUAGE TupleSections #-} 2{-# LANGUAGE TupleSections #-}
3{-# LANGUAGE TypeOperators #-}
3module Network.Tox.Crypto.Handlers where 4module Network.Tox.Crypto.Handlers where
4 5
5import Network.Tox.NodeId 6import Network.Tox.NodeId
@@ -22,6 +23,7 @@ import qualified Data.PacketQueue as PQ
22 ;import Data.PacketQueue (PacketQueue) 23 ;import Data.PacketQueue (PacketQueue)
23import Data.Serialize as S 24import Data.Serialize as S
24import Data.Word 25import Data.Word
26import qualified Data.Word64Map as W64
25import GHC.Conc (unsafeIOToSTM) 27import GHC.Conc (unsafeIOToSTM)
26import qualified Data.Set as Set 28import qualified Data.Set as Set
27import qualified Data.Array.Unboxed as A 29import qualified Data.Array.Unboxed as A
@@ -32,6 +34,7 @@ import System.Environment
32import System.Directory 34import System.Directory
33import Control.Concurrent 35import Control.Concurrent
34import GHC.Conc (labelThread) 36import GHC.Conc (labelThread)
37import System.IO.Unsafe(unsafeDupablePerformIO {- unsafeIOToSTM -})
35 38
36-- util, todo: move to another module 39-- util, todo: move to another module
37maybeToEither :: Maybe b -> Either String b 40maybeToEither :: Maybe b -> Either String b
@@ -45,7 +48,10 @@ data NetCryptoSessionStatus = Unaccepted | Accepted | Confirmed
45type IOHook addr x = addr -> x -> IO (Maybe (x -> x)) 48type IOHook addr x = addr -> x -> IO (Maybe (x -> x))
46type NetCryptoHook = IOHook NetCryptoSession CryptoData 49type NetCryptoHook = IOHook NetCryptoSession CryptoData
47type MsgTypeArray = A.UArray Word8 Word16 50type MsgTypeArray = A.UArray Word8 Word16
48 51type MsgOutMap = W64.Word64Map Word8
52-- type MsgOutMap = A.UArray Word64 Word8 -- if above is too slow, switch to this, but use reasonable bounds
53msgOutMapLookup :: Word64 -> MsgOutMap -> Maybe Word8
54msgOutMapLookup = W64.lookup
49 55
50-- | Information, that may be made visible in multiple sessions, as well 56-- | Information, that may be made visible in multiple sessions, as well
51-- as displayed in some way to the user via mutiple views. 57-- as displayed in some way to the user via mutiple views.
@@ -86,7 +92,7 @@ data NetCryptoSession = NCrypto { ncState :: TVar NetCryptoSessionStatu
86 -- may not be in ncHooks yet, but they should appear 92 -- may not be in ncHooks yet, but they should appear
87 -- here if ncUnrecognizedHook will add them to ncHooks 93 -- here if ncUnrecognizedHook will add them to ncHooks
88 -- on an as-need basis. 94 -- on an as-need basis.
89 , ncOutgoingTypeArray :: TVar MsgTypeArray 95 , ncOutgoingIdMap :: TVar MsgOutMap
90 , ncAllSessions :: NetCryptoSessions -- ^ may be needed if one net-crypto session 96 , ncAllSessions :: NetCryptoSessions -- ^ may be needed if one net-crypto session
91 -- needs to possibly start another, as is 97 -- needs to possibly start another, as is
92 -- the case in group chats 98 -- the case in group chats
@@ -94,6 +100,7 @@ data NetCryptoSession = NCrypto { ncState :: TVar NetCryptoSessionStatu
94 , ncPacketQueue :: PacketQueue CryptoData 100 , ncPacketQueue :: PacketQueue CryptoData
95 , ncBufferStart :: TVar Word32 101 , ncBufferStart :: TVar Word32
96 , ncDequeueThread :: Maybe ThreadId 102 , ncDequeueThread :: Maybe ThreadId
103 , ncOutgoingQueue :: PQ.PacketOutQueue (State,Nonce24,TVar MsgOutMap) CryptoMessage (CryptoPacket Encrypted) CryptoData
97 } 104 }
98 105
99data NetCryptoSessions = NCSessions { netCryptoSessions :: TVar (Map.Map SockAddr NetCryptoSession) 106data NetCryptoSessions = NCSessions { netCryptoSessions :: TVar (Map.Map SockAddr NetCryptoSession)
@@ -104,6 +111,7 @@ data NetCryptoSessions = NCSessions { netCryptoSessions :: TVar (Map.Map SockAdd
104 , sessionView :: SessionView 111 , sessionView :: SessionView
105 , msgTypeArray :: MsgTypeArray 112 , msgTypeArray :: MsgTypeArray
106 , inboundQueueCapacity :: Word32 113 , inboundQueueCapacity :: Word32
114 , outboundQueueCapacity :: Word32
107 , nextSessionId :: TVar SessionID 115 , nextSessionId :: TVar SessionID
108 } 116 }
109 117
@@ -168,6 +176,7 @@ newSessionsState crypto unrechook hooks = do
168 } 176 }
169 , msgTypeArray = allMsgTypes -- todo make this a parameter 177 , msgTypeArray = allMsgTypes -- todo make this a parameter
170 , inboundQueueCapacity = 200 178 , inboundQueueCapacity = 200
179 , outboundQueueCapacity = 400
171 , nextSessionId = nextSessionId0 180 , nextSessionId = nextSessionId0
172 } 181 }
173 182
@@ -208,6 +217,53 @@ newHandShakeData crypto basenonce (HParam {hpOtherCookie,hpMySecretKey,hpCookieR
208 , otherCookie = freshCookie' 217 , otherCookie = freshCookie'
209 }) freshCookie 218 }) freshCookie
210 219
220type XMessage = CryptoMessage -- todo
221
222ncToWire :: STM (State,Nonce24,TVar MsgOutMap)
223 -> Word32{- packet number we expect to recieve -}
224 -> Word32{- buffer_end -}
225 -> Word32{- packet number -}
226 -> XMessage
227 -> STM (Maybe (CryptoPacket Encrypted,Word32{-next packet no-}))
228ncToWire getState seqno bufend pktno msg = do
229 let typ = getMessageType msg
230 typ64 = toWord64 typ
231 let lsness msg =
232 case typ of
233 Msg mid -> lossyness mid
234 GrpMsg KnownLossy _ -> Lossy
235 GrpMsg KnownLossless _ -> Lossless
236 (state,n24,msgOutMapVar) <- getState
237 msgOutMap <- readTVar msgOutMapVar
238 case msgOutMapLookup typ64 msgOutMap of
239 Just outid -> do
240 let setMessageId (OneByte _) mid = OneByte (toEnum8 mid)
241 setMessageId (TwoByte _ x) mid = TwoByte (toEnum8 mid) x
242 setMessageId (UpToN _ x) mid = UpToN (toEnum8 mid) x
243 msg' = setMessageId msg outid
244 in case lsness msg of
245 UnknownLossyness -> return Nothing
246 Lossy -> let cd =
247 CryptoData
248 { bufferStart = seqno
249 , bufferEnd = bufend
250 , bufferData = msg'
251 }
252 plain = encodePlain cd
253 encrypted = encrypt state plain
254 pkt = CryptoPacket { pktNonce = nonce24ToWord16 n24, pktData = encrypted }
255 in return (Just (pkt, pktno))
256 Lossless -> let cd =
257 CryptoData
258 { bufferStart = seqno
259 , bufferEnd = pktno
260 , bufferData = msg'
261 }
262 plain = encodePlain cd
263 encrypted = encrypt state plain
264 pkt = CryptoPacket { pktNonce = nonce24ToWord16 n24, pktData = encrypted }
265 in return (Just (pkt, pktno+1))
266
211-- | called when we recieve a crypto handshake with valid cookie 267-- | called when we recieve a crypto handshake with valid cookie
212-- TODO set priority on contact addr to 0 if it is older than ForgetPeriod, 268-- TODO set priority on contact addr to 0 if it is older than ForgetPeriod,
213-- then increment it regardless. (Keep addr in MinMaxPSQ in Roster.Contact) 269-- then increment it regardless. (Keep addr in MinMaxPSQ in Roster.Contact)
@@ -250,10 +306,18 @@ freshCryptoSession sessions
250 ncHooks0 <- atomically $ newTVar (defaultHooks sessions) 306 ncHooks0 <- atomically $ newTVar (defaultHooks sessions)
251 ncUnrecognizedHook0 <- atomically $ newTVar (defaultUnrecognizedHook sessions) 307 ncUnrecognizedHook0 <- atomically $ newTVar (defaultUnrecognizedHook sessions)
252 ncIncomingTypeArray0 <- atomically $ newTVar (msgTypeArray sessions) 308 ncIncomingTypeArray0 <- atomically $ newTVar (msgTypeArray sessions)
253 ncOutgoingTypeArray0 <- atomically $ newTVar allMsgTypes 309 ncOutgoingIdMap0 <- atomically $ newTVar W64.empty
254 ncView0 <- atomically $ newTVar (sessionView sessions) 310 ncView0 <- atomically $ newTVar (sessionView sessions)
255 pktq <- atomically $ PQ.new (inboundQueueCapacity sessions) 0 311 pktq <- atomically $ PQ.new (inboundQueueCapacity sessions) 0
256 bufstart <- atomically $ newTVar 0 312 bufstart <- atomically $ newTVar 0
313 let toWireIO = do
314 f <- lookupNonceFunction crypto newsession theirSessionKey
315 atomically $ do
316 n24 <- readTVar ncMyPacketNonce0
317 let n24plus1 = unsafeDupablePerformIO (incrementNonce24 n24)
318 writeTVar ncMyPacketNonce0 n24plus1
319 return (return (f n24, n24, ncOutgoingIdMap0))
320 pktoq <- atomically $ PQ.newOutGoing pktq ncToWire toWireIO 0 (outboundQueueCapacity sessions) 0
257 let netCryptoSession0 = 321 let netCryptoSession0 =
258 NCrypto { ncState = ncState0 322 NCrypto { ncState = ncState0
259 , ncSessionId = sessionId 323 , ncSessionId = sessionId
@@ -270,11 +334,12 @@ freshCryptoSession sessions
270 , ncUnrecognizedHook = ncUnrecognizedHook0 334 , ncUnrecognizedHook = ncUnrecognizedHook0
271 , ncAllSessions = sessions 335 , ncAllSessions = sessions
272 , ncIncomingTypeArray = ncIncomingTypeArray0 336 , ncIncomingTypeArray = ncIncomingTypeArray0
273 , ncOutgoingTypeArray = ncOutgoingTypeArray0 337 , ncOutgoingIdMap = ncOutgoingIdMap0
274 , ncView = ncView0 338 , ncView = ncView0
275 , ncPacketQueue = pktq 339 , ncPacketQueue = pktq
276 , ncBufferStart = bufstart 340 , ncBufferStart = bufstart
277 , ncDequeueThread = Nothing -- error "you want the NetCrypto-Dequeue thread id, but is it started?" 341 , ncDequeueThread = Nothing -- error "you want the NetCrypto-Dequeue thread id, but is it started?"
342 , ncOutgoingQueue = pktoq
278 } 343 }
279 threadid <- forkIO $ do 344 threadid <- forkIO $ do
280 tid <- myThreadId 345 tid <- myThreadId
diff --git a/src/Network/Tox/Crypto/Transport.hs b/src/Network/Tox/Crypto/Transport.hs
index 386c2766..b89bde46 100644
--- a/src/Network/Tox/Crypto/Transport.hs
+++ b/src/Network/Tox/Crypto/Transport.hs
@@ -23,6 +23,7 @@ module Network.Tox.Crypto.Transport
23 , MessageType(..) 23 , MessageType(..)
24 , KnownLossyness(..) 24 , KnownLossyness(..)
25 , AsWord16(..) 25 , AsWord16(..)
26 , AsWord64(..)
26 -- feild name classes 27 -- feild name classes
27 , HasGroupChatID(..) 28 , HasGroupChatID(..)
28 , HasGroupNumber(..) 29 , HasGroupNumber(..)
@@ -420,6 +421,11 @@ class AsWord16 a where
420 toWord16 :: a -> Word16 421 toWord16 :: a -> Word16
421 fromWord16 :: Word16 -> a 422 fromWord16 :: Word16 -> a
422 423
424class AsWord64 a where
425 toWord64 :: a -> Word64
426 fromWord64 :: Word64 -> a
427
428
423toEnum8 :: (Enum a, Integral word8) => word8 -> a 429toEnum8 :: (Enum a, Integral word8) => word8 -> a
424toEnum8 = toEnum . fromIntegral 430toEnum8 = toEnum . fromIntegral
425fromEnum8 :: Enum a => a -> Word8 431fromEnum8 :: Enum a => a -> Word8
@@ -428,6 +434,9 @@ fromEnum8 = fromIntegral . fromEnum
428fromEnum16 :: Enum a => a -> Word16 434fromEnum16 :: Enum a => a -> Word16
429fromEnum16 = fromIntegral . fromEnum 435fromEnum16 = fromIntegral . fromEnum
430 436
437fromEnum64 :: Enum a => a -> Word64
438fromEnum64 = fromIntegral . fromEnum
439
431 440
432-- MessageType, for our client keep it inside 16 bits 441-- MessageType, for our client keep it inside 16 bits
433-- but we should extend it to 32 or even 64 on the wire. 442-- but we should extend it to 32 or even 64 on the wire.
@@ -440,6 +449,13 @@ instance AsWord16 MessageType where
440 fromWord16 x | x < 1024, x .|. 0x0200 == 0x0200 = GrpMsg (toEnum8 ((x - 512) `div` 256)) (toEnum8 x) 449 fromWord16 x | x < 1024, x .|. 0x0200 == 0x0200 = GrpMsg (toEnum8 ((x - 512) `div` 256)) (toEnum8 x)
441 fromWord16 x = error "Not clear how to convert Word16 to MessageType" 450 fromWord16 x = error "Not clear how to convert Word16 to MessageType"
442 451
452instance AsWord64 MessageType where
453 toWord64 (Msg msgID) = fromIntegral (fromIntegral (fromEnum16 msgID) :: Word8)
454 toWord64 (GrpMsg lsy msgName) = 512 + 256 * (fromEnum64 lsy) + fromIntegral (fromEnum8 msgName)
455 fromWord64 x | x < 256 = Msg (toEnum $ fromIntegral x)
456 fromWord64 x | x < 1024, x .|. 0x0200 == 0x0200 = GrpMsg (toEnum8 ((x - 512) `div` 256)) (toEnum8 x)
457 fromWord64 x = error "Not clear how to convert Word64 to MessageType"
458
443word16 :: (Functor f, AsWord16 x) => (Word16 -> f Word16) -> (x -> f x) 459word16 :: (Functor f, AsWord16 x) => (Word16 -> f Word16) -> (x -> f x)
444word16 = lens toWord16 (\_ x -> fromWord16 x) 460word16 = lens toWord16 (\_ x -> fromWord16 x)
445 461