implementation module receiverdevice import StdBool, StdFunc, StdList, StdMisc, StdTuple import StdReceiver import devicefunctions, iostate, receiveraccess, receiverevent, receiverid from commondef import fatalError, uremove, :: UCond, strictSeq, accessList from StdPSt import appPIO, accPIO receiverdeviceFatalError :: String String -> .x receiverdeviceFatalError rule error = fatalError rule "receiverdevice" error receiverFunctions :: DeviceFunctions (PSt .l) receiverFunctions = { dDevice = ReceiverDevice , dShow = id , dHide = id , dEvent = receiverEvent , dDoIO = receiverIO , dOpen = receiverOpen , dClose = receiverClose } receiverOpen :: !(PSt .l) -> PSt .l receiverOpen pState=:{io=ioState} # (hasReceiver,ioState) = ioStHasDevice ReceiverDevice ioState | hasReceiver = {pState & io=ioState} | otherwise # ioState = ioStSetDevice (ReceiverSystemState {rReceivers=[]}) ioState # ioState = ioStSetDeviceFunctions receiverFunctions ioState = {pState & io=ioState} receiverClose :: !(PSt .l) -> PSt .l receiverClose pState=:{io=ioState} # ioState = callReceiverCloseFunctions ioState # ioState = ioStSetRcvDisabled True ioState # (found,rDevice,ioState) = ioStGetDevice ReceiverDevice ioState | not found = {pState & io=ioState} | otherwise # rHs = (receiverSystemStateGetReceiverHandles rDevice).rReceivers rIds = map (\{rHandle={rId}}->rId) rHs # (idtable,ioState) = ioStGetIdTable ioState # ioState = ioStSetIdTable (snd (removeIdsFromIdTable rIds idtable)) ioState # ioState = unbindRIds rIds ioState # ioState = ioStRemoveDeviceFunctions ReceiverDevice ioState = {pState & io=ioState} where callReceiverCloseFunctions :: !(IOSt .l) -> (IOSt .l) callReceiverCloseFunctions ioState # (found,rDevice,ioState) = ioStGetDevice ReceiverDevice ioState | not found = ioState | otherwise # rHs = (receiverSystemStateGetReceiverHandles rDevice).rReceivers # (funcs,rHs) = accessList getCloseFunc rHs # ioState = ioStSetDevice (ReceiverSystemState {rReceivers=rHs}) ioState = strictSeq funcs ioState where getCloseFunc :: !(ReceiverStateHandle (PSt .l)) -> (!IdFun (IOSt .l),!ReceiverStateHandle (PSt .l)) getCloseFunc rsH=:{rHandle={rInetInfo=Nothing, rConnected}} = (strictSeq (map closeReceiver rConnected),rsH) getCloseFunc rsH=:{rHandle={rInetInfo=Just (_,_,_,closeFun),rConnected}} = (appIOToolbox closeFun o strictSeq (map closeReceiver rConnected),rsH) /* The receiver handles three cases of message events (for the time being timers are not included in receivers): - QASyncMessage: this is a request to add the given asynchronous message to the indicated receiver. Globally the size of the asynchronous message queue has already been increased. - ASyncMessage: this is a request to handle the first asynchronous message available in the asynchronous message queue. Globally the size of the asynchronous message queue has already been decreased. - SyncMessage: this is a request to handle the given synchronous message. */ receiverIO :: !DeviceEvent !(PSt .l) -> (!DeviceEvent,!PSt .l) receiverIO deviceEvent pState=:{io=ioState} # (found,rDevice,ioState) = ioStGetDevice ReceiverDevice ioState | not found // This condition should not occur: dDoIO function should be applied only iff dEvent filters message = receiverdeviceFatalError "receiverIO" "could not retrieve ReceiverSystemState from IOSt" | otherwise # receivers = receiverSystemStateGetReceiverHandles rDevice = receiverIO deviceEvent receivers.rReceivers {pState & io=ioState} where receiverIO :: !DeviceEvent !*[ReceiverStateHandle (PSt .l)] !(PSt .l) -> (!DeviceEvent,!PSt .l) receiverIO deviceEvent=:(ReceiverEvent (QASyncMessage event)) rsHs pState = (deviceEvent,receiverASyncIO event rsHs pState) where receiverASyncIO :: !QASyncMessage !*[ReceiverStateHandle (PSt .l)] !(PSt .l) -> PSt .l receiverASyncIO event=:{qasmRecLoc={rlReceiverId},qasmMsg} rsHs pState=:{io=ioState} #! rsHs = qMessage rlReceiverId qasmMsg rsHs # ioState = ioStSetDevice (ReceiverSystemState {rReceivers=rsHs}) ioState # pState = {pState & io=ioState} = pState where qMessage :: !Id !SemiDynamic !*[ReceiverStateHandle .pst] -> *[ReceiverStateHandle .pst] qMessage rid msg [rsH=:{rHandle=rH}:rsHs] | receiverIdentified rid rH #! rH = receiverAddASyncMessage rid msg rH = [{rsH & rHandle=rH}:rsHs] | otherwise # rsHs = qMessage rid msg rsHs = [rsH:rsHs] qMessage _ _ [] = [] receiverIO deviceEvent=:(ReceiverEvent (ASyncMessage event)) rsHs pState = (deviceEvent,letOneReceiverDoIO rl rsHs pState) where rl = event.asmRecLoc letOneReceiverDoIO :: !RecLoc !*[ReceiverStateHandle (PSt .l)] !(PSt .l) -> PSt .l letOneReceiverDoIO {rlParentId} rsHs pState = pState2 where dummy = receiverdeviceFatalError "receiverIO (ReceiverEvent (ASyncMessage _))" "receiver could not be found" (_,rsH1,rsHs1) = uremove (identifyReceiverStateHandle rlParentId) dummy rsHs pState1 = appPIO (ioStSetDevice receivers) pState (rsH2,pState2) = letReceiverDoIO rsH1 pState1 receivers = ReceiverSystemState {rReceivers=rsHs1++[rsH2]} letReceiverDoIO :: !*(ReceiverStateHandle .pst) .pst -> (!*ReceiverStateHandle .pst,.pst) letReceiverDoIO rsH=:{rState=ls,rHandle=rH=:{rASMQ=[msg:tailQ],rFun}} pState # (ls,_,pState) = rFun msg (ls,pState) = ({rState=ls,rHandle={rH & rASMQ=tailQ}},pState) letReceiverDoIO _ _ = receiverdeviceFatalError "letReceiverDoIO" "message queue of target receiver is empty" receiverIO (ReceiverEvent (SyncMessage event)) rsHs pState # (lastProcess,pState) = accPIO ioStLastInteraction pState # (event,pState) = receiverSyncIO lastProcess event rsHs pState = (ReceiverEvent (SyncMessage event),pState) where receiverSyncIO :: !Bool !SyncMessage !*[ReceiverStateHandle (PSt .l)] !(PSt .l) -> (!SyncMessage,!PSt .l) receiverSyncIO lastProcess event rsHs pState | not found = (event1,pState2) with event1 = if lastProcess {event & smError=[ReceiverUnknown]} event | isEmpty error = ({event & smResp=resp}, pState2) | otherwise = ({event & smError=error},pState2) where pState1 = {pState & io=ioStSetDevice (ReceiverSystemState {rReceivers=rsHs1}) pState.io} (found,error,resp,rsHs1,pState2) = applyReceiverFunction event rsHs pState1 applyReceiverFunction :: !SyncMessage !*[ReceiverStateHandle .pst] .pst -> (!Bool,[MessageError],[SemiDynamic],*[ReceiverStateHandle .pst],.pst) applyReceiverFunction event=:{smRecLoc={rlReceiverId}} [rsH=:{rState=ls,rHandle=rH}:rsHs] ps | not (receiverIdentified rlReceiverId rH) = (found,error,resp,[rsH:rsHs1],ps1) with (found,error,resp,rsHs1,ps1) = applyReceiverFunction event rsHs ps | enabled rH.rSelect = (True,[],resp,[{rState=ls1,rHandle=rH1}:rsHs],ps1) with (resp,rH1,(ls1,ps1)) = receiverHandleSyncMessage event rH (ls,ps) | otherwise = (True,[ReceiverUnable],[],[rsH:rsHs],ps) applyReceiverFunction _ [] ps = (False,[],[],[],ps) // MW11.. receiverIO deviceEvent=:(InternetEvent event) rsHs pState = (deviceEvent,letOneReceiverDoInetEvent event rsHs pState) // ..MW11 receiverIO _ _ _ = receiverdeviceFatalError "receiverIO" "device event passed receiver event filter without handling" // MW11.. letOneReceiverDoInetEvent (eventCode,endpointRef,inetReceiverCategory,misc) rsHs pState # (opt_rsH,rsHs) = selectReceiver (endpointRef,inetReceiverCategory) rsHs = case opt_rsH of Nothing // PA: receiver device must be restored, because it is removed from the IOSt -> appPIO (ioStSetDevice (ReceiverSystemState {rReceivers=rsHs})) pState Just rsH # eventInfo = (eventCode,endpointRef,misc) # (rSelect,emptyASMQ,inetRId,rsH) = (\rsH=:{rHandle=rH=:{rSelect,rASMQ}}->(rSelect,isEmpty rASMQ,getInetReceiverRId rH,rsH)) rsH | enabled rSelect && emptyASMQ -> applyInetEvent eventInfo rsH rsHs pState // apply the event immediately // receiver is unable, so queue the event via asyncSend to handle it later # receivers = ReceiverSystemState {rReceivers=[rsH:rsHs]} // left at the beginning pState = appPIO (ioStSetDevice receivers) pState # (sR,pState) = asyncSend inetRId eventInfo pState | sR<>SendOk -> abort "receiverdevice: I have a bug (78)" | otherwise -> pState where selectReceiver :: !(!EndpointRef`,!InetReceiverCategory`) !*[ReceiverStateHandle .pst] -> (!*Maybe (ReceiverStateHandle .pst),!*[ReceiverStateHandle .pst]) selectReceiver receiverId=:(endpointRef,type) [rsH=:{rHandle={rInetInfo=Just (epr,tp,_,_)}}:rsHs] | endpointRef==epr && type==tp = (Just rsH,rsHs) | otherwise # (opt_rsH, rsHs) = selectReceiver receiverId rsHs = (opt_rsH,[rsH:rsHs]) selectReceiver receiverId [rsH:rsHs] # (opt_rsH, rsHs) = selectReceiver receiverId rsHs = (opt_rsH,[rsH:rsHs]) selectReceiver _ [] = (Nothing,[]) applyInetEvent :: !InetReceiverASMQType !*(ReceiverStateHandle *(PSt .l)) *[ReceiverStateHandle *(PSt .l)] !*(PSt .l) -> PSt .l applyInetEvent eventInfo rsH=:{rState,rHandle} rsHs pState = pState2 where pState1 = appPIO (ioStSetDevice receivers) pState (rState2,pState2) = receiverApplyInetEvent eventInfo rHandle (rState,pState1) receivers = ReceiverSystemState {rReceivers=[{rsH & rState=rState2}:rsHs]} // left at the beginning // ..MW11 identifyReceiverStateHandle :: !Id !(ReceiverStateHandle .pst) -> *(!Bool,!ReceiverStateHandle .pst) identifyReceiverStateHandle id rsH=:{rHandle={rId}} = (id==rId,rsH)