[623] | 1 | HLCSTCP2 ;SFIRMFO/RSD - BI-DIRECTIONAL TCP ;09/13/2006
|
---|
| 2 | ;;1.6;HEALTH LEVEL SEVEN;**19,43,49,57,63,64,66,67,76,77,87,109,133**;Oct 13,1995;Build 13
|
---|
| 3 | ;Per VHA Directive 2004-038, this routine should not be modified.
|
---|
| 4 | ;Sender
|
---|
| 5 | ;Request connection, send outbound message(s) delimited by MLLP
|
---|
| 6 | ;Input : HLDP=Logical Link to use
|
---|
| 7 | ; Set up error trap
|
---|
| 8 | N $ETRAP,$ESTACK S $ETRAP="D ERROR^HLCSTCP2"
|
---|
| 9 | N HLMSG,HLPORT,HLRETRY,HLRETMG,HLTCPO,POP
|
---|
| 10 | ;HLRETRY=number of retranmission for this link,HLRETMG=alert sent
|
---|
| 11 | S HLTCPO=HLDP,HLMSG="",(HLRETRY,HLRETMG)=0
|
---|
| 12 | ;
|
---|
| 13 | ;set IO(0) to the null device
|
---|
| 14 | S IO(0)=$S(^%ZOSF("OS")["OpenM":$S($$OS^%ZOSV()["VMS":"_NLA0:",$$OS^%ZOSV()["UNIX":"/dev/null",1:$P),^%ZOSF("OS")["DSM":"_NLA0:",1:$P)
|
---|
| 15 | O IO(0) U IO(0)
|
---|
| 16 | ;
|
---|
| 17 | ;persistent conection, open connection first, HLPORT=open port
|
---|
| 18 | I $G(HLTCPLNK)["Y" F Q:$$OPEN G EXIT:$$STOP^HLCSTCP H 1
|
---|
| 19 | F D QUE Q:$$STOP^HLCSTCP D:'HLMSG Q:$G(HLCSOUT)
|
---|
| 20 | . ;no messages to send
|
---|
| 21 | . D MON^HLCSTCP("Idle") H 3
|
---|
| 22 | . ;persistent connection, no retention
|
---|
| 23 | . Q:$G(HLTCPLNK)["Y"
|
---|
| 24 | . D MON^HLCSTCP("Retention")
|
---|
| 25 | . N % I 0
|
---|
| 26 | . ;if message comes in or ask to stop
|
---|
| 27 | . F %=1:1:HLTCPRET H 1 I $$STOP^HLCSTCP!$O(^HLMA("AC","O",HLDP,0)) Q
|
---|
| 28 | . E S HLCSOUT=2 Q
|
---|
| 29 | . Q:$$STOP^HLCSTCP
|
---|
| 30 | . D MON^HLCSTCP("Idle")
|
---|
| 31 | ;Close port
|
---|
| 32 | I $D(HLPORT) D CLOSE^%ZISTCP K HLPORT
|
---|
| 33 | EXIT Q
|
---|
| 34 | ;
|
---|
| 35 | QUE ; -- Check "OUT" queue for processing IF there is a message do it
|
---|
| 36 | ; and then check the link if it open or not
|
---|
| 37 | N HL,HLN,HLARR,HLHDR,HLI,HLJ,HLMSA,HLRESP,HLRESLT,HLRETRM,HLTCP,HLTCPI,X,Z,HLREREAD
|
---|
| 38 | D MON^HLCSTCP("Check out")
|
---|
| 39 | ;HLMSG=next msg, set at tag DONE
|
---|
| 40 | I 'HLMSG S HLMSG=+$O(^HLMA("AC","O",HLDP,0)),HLRETRY=0 Q:'HLMSG
|
---|
| 41 | ;
|
---|
| 42 | ;**109**
|
---|
| 43 | ;Temporarily lock ^HLMA to flush buffer and ensure edits are complete
|
---|
| 44 | ;L +^HLMA(HLMSG):1 I '$T S HLMSG=0 Q
|
---|
| 45 | ;L -^HLMA(HLMSG)
|
---|
| 46 | ;
|
---|
| 47 | S HLI=+$G(^HLMA(HLMSG,0)),HLJ=$O(^("MSH",0)),HLTCP=""
|
---|
| 48 | ;don't have message text or MSH, kill x-ref and decrement 'to send'
|
---|
| 49 | I 'HLI!'HLJ K ^HLMA("AC","O",HLDP,HLMSG) D LLCNT^HLCSTCP(HLDP,3,1) S HLMSG=0 Q
|
---|
| 50 | ;update msg status to 'being transmitted'; if cancelled decrement link and quit
|
---|
| 51 | I '$$CHKMSG(1.5) D LLCNT^HLCSTCP(HLDP,3,1) S HLMSG=0 Q
|
---|
| 52 | ;number of retransmissions for message
|
---|
| 53 | S HLRETRM=+$P(^HLMA(HLMSG,"P"),U,5)
|
---|
| 54 | ;retries exceeded, HLRETRA:action i=ignore, r=restart, s=shutdown
|
---|
| 55 | ;quit if restart or shutdown, link is going down
|
---|
| 56 | I HLRETRY>HLDRETR D Q:"I"'[HLRETRA
|
---|
| 57 | . D MON^HLCSTCP("Error")
|
---|
| 58 | . ;only 1 alert per link up time, don't send if restart
|
---|
| 59 | . D:'HLRETMG&(HLRETRA'="R")
|
---|
| 60 | .. ;send alert
|
---|
| 61 | .. N XQA,XQAMSG,XQAOPT,XQAROU,XQAID,Z
|
---|
| 62 | .. ;get mailgroup from file 869.3
|
---|
| 63 | .. S HLRETMG=1,Z=$P($$PARAM^HLCS2,U,8) Q:Z=""
|
---|
| 64 | .. S XQA("G."_Z)="",XQAMSG=$$HTE^XLFDT($H,2)_" HL7 LL "_$P(^HLCS(870,HLDP,0),U)_" exceeded retries. LL will "_$S(HLRETRA="S":"shutdown.",HLRETRA="R":"restart.",1:"keep trying.")
|
---|
| 65 | .. D SETUP^XQALERT
|
---|
| 66 | . ;quit if action is ignore
|
---|
| 67 | . Q:"I"[HLRETRA
|
---|
| 68 | . ;this will shutdown this link
|
---|
| 69 | . S HLCSOUT=1
|
---|
| 70 | . ;action is shutdown, set shutdown flag so LM won't restart
|
---|
| 71 | . S:HLRETRA="S" $P(^HLCS(870,HLDP,0),U,15)=1
|
---|
| 72 | . D STATUS^HLTF0(HLMSG,4,103,"LLP Exceeded Retry Param")
|
---|
| 73 | I '$$OPEN Q
|
---|
| 74 | D MON^HLCSTCP("Send")
|
---|
| 75 | ; -- data passed in global array, success=1
|
---|
| 76 | I $$WRITE(HLMSG)<0 Q
|
---|
| 77 | S (HLTCP,HLTCPI)=HLMSG,HLRETRY=HLRETRY+1,HLRETRM=HLRETRM+1
|
---|
| 78 | ;update status to awaiting response, decrement link if cancelled
|
---|
| 79 | I '$$CHKMSG(1.7) D LLCNT^HLCSTCP(HLDP,3,1) S HLMSG=0 Q
|
---|
| 80 | ;set transmission count, get ACKTIMEOUT override
|
---|
| 81 | S $P(^HLMA(HLMSG,"P"),U,5)=HLRETRM I $P(^("P"),U,7) S HLN("ACKTIME")=+$P(^("P"),U,7)
|
---|
| 82 | ;get header of message just sent
|
---|
| 83 | K HLJ M HLJ=^HLMA(HLMSG,"MSH")
|
---|
| 84 | ;first component of sending app.
|
---|
| 85 | S HLN("ECH")=$$P^HLTPCK2(.HLJ,2),HLN("SAN")=$P($$P^HLTPCK2(.HLJ,3),$E(HLN("ECH")))
|
---|
| 86 | ;msg type, msg. id, commit ack, and app. ack parameter
|
---|
| 87 | S HLN("TYPE")=$$P^HLTPCK2(.HLJ,1),HLN("MID")=$$P^HLTPCK2(.HLJ,10),HLN("ACAT")=$$P^HLTPCK2(.HLJ,15),HLN("APAT")=$$P^HLTPCK2(.HLJ,16)
|
---|
| 88 | ;MSA segment, message is a response, can't have an a. ack.
|
---|
| 89 | S Z=$$MSA^HLTP3(+^HLMA(HLMSG,0)) I Z]"" S:HLN("ACAT")="" HLN("ACAT")="NE" S HLN("APAT")="NE"
|
---|
| 90 | ;for batch/file with commit ack, reset c. ack and a. ack variables
|
---|
| 91 | I "BHS,FHS"[HLN("TYPE") S Z=$E(HLJ(1,0),5),X=$$P^HLTPCK2(.HLJ,9),HLN("ACAT")=$P(X,Z,5),HLN("APAT")=$P(X,Z,6),HLN("MID")=$$P^HLTPCK2(.HLJ,11)
|
---|
| 92 | ;get event protocol
|
---|
| 93 | S HLN("EID")=+$P(^HLMA(HLMSG,0),U,8),X=$G(^ORD(101,HLN("EID"),770))
|
---|
| 94 | ;set link counter to msg sent
|
---|
| 95 | D LLCNT^HLCSTCP(HLDP,4)
|
---|
| 96 | ;commit and app. ack is never, update status to complete and hang UNI-DIRECTIONAL WAIT
|
---|
| 97 | I HLN("ACAT")="NE",HLN("APAT")="NE" D Q
|
---|
| 98 | .D DONE(3)
|
---|
| 99 | .;
|
---|
| 100 | .;
|
---|
| 101 | .H $G(HLDWAIT)
|
---|
| 102 | ;
|
---|
| 103 | ;do structure is to stack error
|
---|
| 104 | D
|
---|
| 105 | . N $ETRAP,$ESTACK S $ETRAP="D RDERR^HLCSTCP2"
|
---|
| 106 | . ;HL*1.6*87: Read acknowledgement.
|
---|
| 107 | . ;Loop to re-read from buffer when receiving incorrect ack.
|
---|
| 108 | . F D Q:'+$G(HLREREAD)
|
---|
| 109 | .. S HLREREAD=1
|
---|
| 110 | .. ;override ack timeout
|
---|
| 111 | .. I $G(HLN("ACKTIME")) N HLDBACK S HLDBACK=HLN("ACKTIME")
|
---|
| 112 | .. ;check for response, quit if no-response, msg will be resent
|
---|
| 113 | .. ;HLRESP=ien 773^ien 772 for response message
|
---|
| 114 | .. S HLRESP=$$READ^HLCSTCP1()
|
---|
| 115 | .. ;if no response, decrement counter and quit
|
---|
| 116 | .. I 'HLRESP D Q
|
---|
| 117 | ...D LLCNT^HLCSTCP(HLDP,4,1)
|
---|
| 118 | ...S HLREREAD="0^No Response"
|
---|
| 119 | ...;check if the port needs to be closed and re-opened before the next re-transmission attempt
|
---|
| 120 | ...I $G(HLDRETRY("CLOSE")) D CLOSE^%ZISTCP K HLPORT
|
---|
| 121 | .. ;X 0=re-read msg, 1=commit ack, 3=app ack success, 4=error
|
---|
| 122 | .. S X=$$RSP^HLTP31(HLRESP,.HLN)
|
---|
| 123 | .. ;X=0, re-read msg. Incorrect ack (bad MSH,MSA,msg id,or sending app)
|
---|
| 124 | .. Q:'X
|
---|
| 125 | .. ;commit ack - done
|
---|
| 126 | .. I X=1 D S HLREREAD="0^Commit Ack" Q
|
---|
| 127 | ... ;don't need app. ack, set status to complete
|
---|
| 128 | ... I "NE"[HLN("APAT") D Q
|
---|
| 129 | ....D DONE(3)
|
---|
| 130 | ....;
|
---|
| 131 | ... ;response is deferred, set status to awaiting ack
|
---|
| 132 | ... D DONE(2)
|
---|
| 133 | ...;
|
---|
| 134 | .. ;Error, HLRESLT=error number^error message from HLTP3
|
---|
| 135 | .. I X=4 D Q
|
---|
| 136 | ... D DONE(4,+$G(HLRESLT),$P($G(HLRESLT),U,2))
|
---|
| 137 | ...;
|
---|
| 138 | ... S HLREREAD="0^Error"
|
---|
| 139 | .. ;app ack was successful
|
---|
| 140 | .. D DONE(3) S HLREREAD="0^App Ack"
|
---|
| 141 | ..;
|
---|
| 142 | Q
|
---|
| 143 | ;
|
---|
| 144 | DCSEND ;direct connect
|
---|
| 145 | ; Set up error trap
|
---|
| 146 | N $ETRAP,$ESTACK S $ETRAP="D ERROR^HLCSTCP2"
|
---|
| 147 | ;override ack timeout
|
---|
| 148 | I $G(HLP("ACKTIME")) N HLDBACK S HLDBACK=HLP("ACKTIME")
|
---|
| 149 | I $$WRITE(HLMSG)<0 D:$G(HLERROR)]"" Q ;HL*1.6*77
|
---|
| 150 | . D STATUS^HLTF0(HLMSG,4,$P(HLERROR,"^"),$P(HLERROR,"^",2),1) ;HL*1.6*77
|
---|
| 151 | . D LLCNT^HLCSTCP(HLDP,3,1)
|
---|
| 152 | D LLCNT^HLCSTCP(HLDP,4)
|
---|
| 153 | ;do structure is to stack error
|
---|
| 154 | D
|
---|
| 155 | . N $ETRAP,$ESTACK S $ETRAP="D RDERR^HLCSTCP2"
|
---|
| 156 | . ;HLRESP=ien 773^ien 772 for response message
|
---|
| 157 | . S HLRESP=$$READ^HLCSTCP1()
|
---|
| 158 | ;
|
---|
| 159 | D DONE(3):$G(HLRESP),DONE(4,108,$S($G(HLERROR)]"":$P(HLERROR,"^",2),1:"No response")):'$G(HLRESP)
|
---|
| 160 | I $G(HLERROR)']"" D
|
---|
| 161 | .D MON^HLCSTCP("Idle")
|
---|
| 162 | .I '$G(HLRESP) S HLERROR="108^No response"
|
---|
| 163 | ;Close port
|
---|
| 164 | I $D(HLPORT) D CLOSE^%ZISTCP K HLPORT
|
---|
| 165 | Q
|
---|
| 166 | ;
|
---|
| 167 | DONE(ST,ERR,ERRMSG) ;set status to complete
|
---|
| 168 | ;ST=status, ERR=error ien, ERRMSG=error msg
|
---|
| 169 | D STATUS^HLTF0(HLMSG,ST,$G(ERR),$G(ERRMSG),1)
|
---|
| 170 | ;
|
---|
| 171 | ;**109**
|
---|
| 172 | D DEQUE^HLCSREP(HLDP,"O",HLMSG)
|
---|
| 173 | ;
|
---|
| 174 | ;check for more msg.
|
---|
| 175 | I $G(HLPRIO)'="I" S HLMSG=+$O(^HLMA("AC","O",HLDP,0)),HLRETRY=0
|
---|
| 176 | Q
|
---|
| 177 | ;
|
---|
| 178 | CHKMSG(HLI) ;check status of message and update if not cancelled
|
---|
| 179 | ;input: HLI=new status, HLMSG=ien of msg in 773
|
---|
| 180 | ;returns 1=msg was updated, 0=msg has been canceled
|
---|
| 181 | N X
|
---|
| 182 | ;
|
---|
| 183 | ;**109**
|
---|
| 184 | ;F L +^HLMA(HLMSG,"P"):1 Q:$T H 1
|
---|
| 185 | ;
|
---|
| 186 | ;
|
---|
| 187 | ; New HL*1.6*77 code starting here...
|
---|
| 188 | I '$D(^HLMA(HLMSG,"P")) D Q 0
|
---|
| 189 | . S HLERROR="2^Missing status field"
|
---|
| 190 | . D STATUS^HLTF0(HLMSG,4,$P(HLERROR,U),$P(HLERROR,U,2),1)
|
---|
| 191 | .;
|
---|
| 192 | .;**109**
|
---|
| 193 | . D DEQUE^HLCSREP(HLDP,"O",HLMSG)
|
---|
| 194 | .;L -^HLMA(HLMSG,"P")
|
---|
| 195 | ;**end 109**
|
---|
| 196 | ;
|
---|
| 197 | ; End of HL*1.6*77 modifications
|
---|
| 198 | ;
|
---|
| 199 | ;get status, quit if msg was cancelled
|
---|
| 200 | ;
|
---|
| 201 | ;**109**
|
---|
| 202 | ;S X=+^HLMA(HLMSG,"P") I X=3 L -^HLMA(HLMSG,"P") Q 0
|
---|
| 203 | S X=+^HLMA(HLMSG,"P") Q:X=3 0
|
---|
| 204 | ;
|
---|
| 205 | ;update status if it is different
|
---|
| 206 | I $G(HLI),HLI'=X D STATUS^HLTF0(HLMSG,HLI)
|
---|
| 207 | ;
|
---|
| 208 | ;**109**
|
---|
| 209 | ;L -^HLMA(HLMSG,"P")
|
---|
| 210 | ;
|
---|
| 211 | Q 1
|
---|
| 212 | ;
|
---|
| 213 | WRITE(HLDA) ; write message in HL7 format
|
---|
| 214 | ; HLDA - ien of message in 773
|
---|
| 215 | ; - start block $C(11)
|
---|
| 216 | ; - end block $C(28)
|
---|
| 217 | ; - record separator $C(13)
|
---|
| 218 | ;Output(s): 1 - Successful
|
---|
| 219 | ; -1 - Unsuccessful
|
---|
| 220 | ;
|
---|
| 221 | N HLDA2,HLAR,HLI,LINENO,X
|
---|
| 222 | ;set error trap, used when called from HLTP3
|
---|
| 223 | ;
|
---|
| 224 | ; New HL*1.6*77 code starts here...
|
---|
| 225 | N $ETRAP,$ESTACK S $ETRAP="D ERROR^HLCSTCP2"
|
---|
| 226 | I $G(^HLMA(HLDA,0))'>0 D Q -1
|
---|
| 227 | . S HLERROR="2^Message Text pointer missing"
|
---|
| 228 | S HLDA2=+$G(^HLMA(HLDA,0))
|
---|
| 229 | ; End of HL*1.6*77 modifications...
|
---|
| 230 | ;
|
---|
| 231 | Q:'$G(^HLMA(HLDA,0)) -1 ;HL*1.6*77
|
---|
| 232 | ; header is in ^HLMA(, message is in ^HL(772,
|
---|
| 233 | S LINENO=1,HLI=0,HLAR="^HLMA(HLDA,""MSH"")"
|
---|
| 234 | U IO
|
---|
| 235 | D W $C(13) S HLAR="^HL(772,HLDA2,""IN"")",HLI=0 D
|
---|
| 236 | . F S HLI=$O(@HLAR@(HLI)) Q:'HLI S X=$G(^(HLI,0)) D
|
---|
| 237 | .. ;first line, need start block char.
|
---|
| 238 | .. S:LINENO=1 X=$C(11)_X
|
---|
| 239 | .. I X]"" W X,!
|
---|
| 240 | .. ;send CR for blank lines
|
---|
| 241 | .. I X="" W $C(13)
|
---|
| 242 | .. S LINENO=LINENO+1
|
---|
| 243 | ; Sends end block for this message
|
---|
| 244 | S X=$C(28)_$C(13)
|
---|
| 245 | U IO W X,!
|
---|
| 246 | I $G(IO(0))'="",$G(IO(0))'=IO U IO(0) ;switch to null device if opened to prevent 'leakage'
|
---|
| 247 | Q 1
|
---|
| 248 | ;
|
---|
| 249 | OPEN() ; -- Open TCP/IP device (Client)
|
---|
| 250 | ;HLPORT=port, defined only if port is open
|
---|
| 251 | ;HLPORTA=number of attempted opens
|
---|
| 252 | I $D(HLPORT) S IO=HLPORT D Q 1
|
---|
| 253 | . U IO
|
---|
| 254 | . I HLOS["OpenM" X "U IO:(::""-M"")" ;use packet mode on Cache'
|
---|
| 255 | N HLDOM,HLI,HLIP,HLPORTA
|
---|
| 256 | G OPENA^HLCSTCP3
|
---|
| 257 | ;
|
---|
| 258 | RDERR D RDERR^HLCSTCP4 Q ; Exceeded 10,000 bytes, so split on 12/2/03-LJA
|
---|
| 259 | ERROR D ERROR^HLCSTCP4 Q ; Exceeded 10,000 bytes, so split on 12/2/03-LJA
|
---|
| 260 | ;
|
---|
| 261 | CC(X) ;cleanup and close
|
---|
| 262 | D MON^HLCSTCP(X)
|
---|
| 263 | I $D(HLPORT) D CLOSE^%ZISTCP K HLPORT
|
---|
| 264 | H 2
|
---|
| 265 | Q
|
---|