-- File: RS232CDriverA.mesa -- LastEdited: 20-Jan-82 12:42:17 By: Danielson -- This is the Monitor for RS232C Channel creation/deletion DIRECTORY Heap USING [FreeNode, MakeNode], OISTransporter USING [Destroy, Initialize], Process USING [InitializeMonitor], RS232C USING [ ChannelUseType, CommParamHandle, nullLineNumber, ReserveType, Suspend], RS232CControl USING [], RS232CFace USING [GetNextLine, GetStatus, Off, On, ResetLine], RS232CInternal USING [ asynchronousDefaults, autoRecognitionDefaults, bitSynchronousDefaults, byteSynchronousDefaults, ChannelStatus, ChannelStatusHandle, DeleteChannel]; RS232CDriverA: MONITOR IMPORTS Heap, OISTransporter, Process, RS232CFace, RS232CInternal, RS232C EXPORTS RS232C, RS232CControl = BEGIN ChannelHandle: PUBLIC TYPE = RS232CInternal.ChannelStatusHandle; firstChannel: ChannelHandle _ NIL; channelCreateDelete: CONDITION; driverStarted: BOOLEAN _ TRUE; ChannelAlreadyExists: PUBLIC ERROR = CODE; ChannelInUse: PUBLIC ERROR = CODE; InvalidLineNumber: PUBLIC ERROR = CODE; NoRS232CHardware: PUBLIC ERROR = CODE; UnimplementedFeature: PUBLIC ERROR = CODE; -- Old Channel Owner's preemptMe -- Never If Inactive Always -- New Never Don't Don't Don't -- preempt- if Inactive Don't Preempt Preempt -- Others Always Don't Preempt Preempt Create: PUBLIC ENTRY PROCEDURE [ lineNumber: CARDINAL, commParams: RS232C.CommParamHandle, useType: RS232C.ChannelUseType, preemptOthers, preemptMe: RS232C.ReserveType] RETURNS [channel: ChannelHandle] = BEGIN ENABLE UNWIND => IF channel # NIL THEN FreeChannelHandle[channel]; nextLine: CARDINAL _ RS232C.nullLineNumber; prevChannel: ChannelHandle; channel _ NIL; IF ~driverStarted OR RS232CFace.GetNextLine[nextLine] = nextLine THEN ERROR NoRS232CHardware; -- Check if line number valid UNTIL (nextLine _ RS232CFace.GetNextLine[nextLine]) = RS232C.nullLineNumber DO IF nextLine = lineNumber THEN EXIT; REPEAT FINISHED => ERROR InvalidLineNumber; ENDLOOP; -- If others in process of preempting, wait for them to finish UNTIL (prevChannel _ GetChannelHandle[lineNumber]) = NIL OR ~prevChannel.preemptInProgress DO WAIT channelCreateDelete; ENDLOOP; IF ~driverStarted THEN ERROR NoRS232CHardware; IF prevChannel # NIL THEN BEGIN preempt: BOOLEAN _ FALSE; SELECT preemptOthers FROM preemptNever => NULL; -- fail preemptInactive => SELECT prevChannel.lastPreemptMe FROM preemptInactive => -- if inactive, delete the old channel IF ~RS232CFace.GetStatus[prevChannel.face].dataSetReady THEN preempt _ TRUE; preemptAlways => preempt _ TRUE; ENDCASE => NULL; --fail preemptAlways => IF prevChannel.lastPreemptMe # preemptNever THEN preempt _ TRUE; ENDCASE; IF preempt THEN BEGIN ENABLE UNWIND => prevChannel.preemptInProgress _ FALSE; -- Give channel client a STRONG HINT to delete the channel at once. prevChannel.preemptInProgress _ TRUE; RS232C.Suspend[prevChannel, all]; UNTIL prevChannel.deleted DO WAIT channelCreateDelete ENDLOOP; prevChannel.preemptInProgress _ FALSE; END ELSE ERROR ChannelInUse; -- Copy previously used channel handle so we don't allocate a -- second one later channel _ prevChannel; END; -- Allocate and initialize a ChannelStatus record IF ~driverStarted THEN ERROR NoRS232CHardware; IF channel = NIL THEN BEGIN -- Allocate channel handle and add it to queue of channel handles channel _ Heap.MakeNode[, SIZE[RS232CInternal.ChannelStatus]]; channel.next _ firstChannel; firstChannel _ channel; END; -- set preemptInProgress first so any SIGNALS handle correctly channel.preemptInProgress _ FALSE; Process.InitializeMonitor[@channel.LOCK]; channel.parameterRecord _ SELECT commParams.lineType FROM bitSynchronous => RS232CInternal.bitSynchronousDefaults, byteSynchronous => RS232CInternal.byteSynchronousDefaults, asynchronous => RS232CInternal.asynchronousDefaults, autoRecognition => RS232CInternal.autoRecognitionDefaults, ENDCASE => ERROR; -- This should be logged as a system error. channel.parameterRecord.lineSpeed _ commParams.lineSpeed; channel.inputSuspended _ channel.outputSuspended _ channel.otherSuspended _ channel.deleted _ FALSE; channel.lastPreemptMe _ preemptMe; channel.lineNumber _ lineNumber; channel.statusWaitCount _ 0; channel.face _ RS232CFace.On[lineNumber]; IF RS232CFace.ResetLine[channel.face, @channel.parameterRecord] # success THEN BEGIN RS232CFace.Off[channel.face]; ERROR UnimplementedFeature; -- (e.g. autoRecognition) END; IF (channel.useType _ useType) = oisCommunication THEN OISTransporter.Initialize[lineNumber, channel, commParams^]; BROADCAST channelCreateDelete; END; Delete: PUBLIC PROCEDURE [channel: ChannelHandle] = BEGIN -- Client is responsible for avoiding the passing of an OLD channel handle. IF channel.useType = oisCommunication THEN OISTransporter.Destroy[channel]; RS232CInternal.DeleteChannel[channel]; -- modify/release channel status record under object monitor RS232CFace.Off[channel.face]; -- Release block to heap (cannot be done in DeleteChannel, -- since the MONITOR LOCK, which is in channel record, must still -- exist to be released at exit from DeleteChannel) GetLockAndFreeChannelHandle[channel]; END; RedefineChannelUse: PUBLIC ENTRY PROCEDURE [ channel: ChannelHandle, commParams: RS232C.CommParamHandle, useType: RS232C.ChannelUseType, preemptOthers, preemptMe: RS232C.ReserveType] = BEGIN ENABLE UNWIND => NULL; -- release monitor lock channel.lastPreemptMe _ preemptMe; -- we rely on client to set the line type correctly !! IF (channel.useType _ useType) = oisCommunication THEN OISTransporter.Initialize[channel.lineNumber, channel, commParams^]; END; GetNextLine: PUBLIC PROCEDURE [lineNumber: CARDINAL] RETURNS [nextLineNumber: CARDINAL] = BEGIN RETURN[RS232CFace.GetNextLine[lineNumber]]; END; GetChannelHandle: INTERNAL PROCEDURE [lineNumber: CARDINAL] RETURNS [channel: ChannelHandle] = BEGIN channel _ firstChannel; FOR channel _ firstChannel, channel.next UNTIL channel = NIL DO IF channel.lineNumber = lineNumber THEN EXIT; ENDLOOP; END; Start: PUBLIC ENTRY PROCEDURE = BEGIN driverStarted _ TRUE END; Stop: PUBLIC ENTRY PROCEDURE [suspendActiveChannels: BOOLEAN] = BEGIN channel: ChannelHandle _ NIL; driverStarted _ FALSE; IF suspendActiveChannels THEN FOR channel _ firstChannel, channel.next UNTIL channel = NIL DO RS232C.Suspend[channel, all]; ENDLOOP; UNTIL firstChannel = NIL DO WAIT channelCreateDelete ENDLOOP; END; GetLockAndFreeChannelHandle: ENTRY PROCEDURE [channel: ChannelHandle] = BEGIN ENABLE UNWIND => NULL; FreeChannelHandle[channel]; END; FreeChannelHandle: INTERNAL PROCEDURE [channel: ChannelHandle] = BEGIN IF channel.preemptInProgress THEN channel.deleted _ TRUE ELSE BEGIN prevChannel: ChannelHandle _ firstChannel; IF prevChannel = channel THEN firstChannel _ channel.next ELSE BEGIN UNTIL prevChannel.next = channel DO prevChannel _ prevChannel.next ENDLOOP; prevChannel.next _ channel.next; END; Heap.FreeNode[, channel]; END; BROADCAST channelCreateDelete; END; -- MAIN PROGRAM -- END. -- RS232CDriverA LOG Time: By: Action: Rubicon release Time: 20-Jul-81 17:22:01 By: Danielson Action: Combined RS232CManager and RS232C channel. Time: 19-Aug-81 16:48:50 By: Danielson Action: Hold monitor for less time (i.e. not during all of Delete and BROADCAST on channelCreateDelete whenever a channel is created or deleted. Time: 14-Sep-81 19:26:51 By: Danielson Action: RS232CControl.Start and .Stop Time: 13-Oct-81 16:32:54 By: Danielson Action: Make Stop wait until no more channels Time: 7-Jan-82 14:58:00 By: Danielson Action: Set line speed on Create Time: 20-Jan-82 11:41:49 By: Danielson Action: Pass lineNumber to Router