|
DataMuseum.dkPresents historical artifacts from the history of: RC3500 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about RC3500 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 23040 (0x5a00) Types: TextFileVerbose Names: »hlvlam«
└─⟦a41ae585a⟧ Bits:30001842 SW-save af projekt 1000, Alarm-system └─⟦72244f0ef⟧ └─⟦this⟧ »hlvlam«
process lamdriver(var lamsem: semaphore; lamlevel: integer); (* x.21 lam-driver and scanner for centernet. vers: 810408 hlv *) const revision= 100; scanner_size= 200; (* size in bytes of scanner process, *) (* to be optimized later *) init_linespec= line_status_type(?, 0, (* 110 bps *) 3, (* 8 bits *) true, (* 2 stop bits *) 3, (* no parity *) true,false,false, true,true,true, false,false); (* special characters *) brk= -1; (* conversion value for rec. break *) sub= 26; (* conversion value for pty errors *) xon= 17; xoff=19; (* internal error codes *) init1= 100; (* lamlevel not reservable *) init2= init1+1; (* copychm error *) init3= init2+1; (* create scanner troubles *) internal1= 110; (* xsem = nill and xmode = output_finis *) internal2= 111; (* xsem = nill and xmode = output or output_finis and output timeout *) \f var (* message pools *) scanpool: pool scanpoolsize; timerpool: pool 1; (* line descriptors *) line: linearraytype; lineref: array (firstline..lastline) of linereftype; lam, r, rw: reference; scansem: semaphore; (* scanner event pool *) scansh: shadow; curline: integer; lamout: lamouttype; lamcontrol: line_status_type; lamin: lamintype; lam_stat: lamstattype; datain: cycinputtype; spec_index, convchar: integer; i, (* local work of any kind *) cmode, (* conversion mode *) c, (* conversion lineno *) s: integer; (* local var for dyn. array dimension *) \f process scanner(var eventsem: semaphore; var line: linearraytype); (* scanner process executes on lam interrupt level and simulates intelligent dma. *) const chlost= stat_ovrun+stat_err; startscanner= -1; var lamin: lamintype; lamout: lamouttype; lam_stat: lamstattype; i,l: integer; r,lam: reference; schedule: boolean; \f begin (* scanner main program *) (* get channel message from main driver *) wait(lam,eventsem); channel lam do repeat (* scanner main loop: flying high forever *) schedule:= false; (* wait for work to do *) controlclr(startscanner,lam); inword(lamin,lam); if lamin.line <= lastline then with line(lamin.line) do begin if lamin.input then begin sense(lam_stat,lamin,lam); if (rmode <> idle) and (cycfirst = cyclast) then schedule:= true; i:= (cyclast+1) mod cyctop; if i <> cycfirst then with cycbuf(i) do begin (* deposit data in input buffer *) char:= lamin.char; stat:= lam_stat.stat; cyclast:= i; end (* depose value *) else begin (* input buffer overflow *) rstat:= rstat or chlost; schedule:= true; end; (* input buffer overflow *) end (* input *) \f else (* output *) case xmode of xidle,output_finis: ; (* no action *) output: begin (* output next char *) sensesem(r,xsem); if not nil(r) then begin i:= r^.size; lock r as ob: packed record first, last, next: integer; buf: array (6..i-1+i) of byte; end do with ob do begin lamout.line:= lamin.line; lamout.char:= buf(next); outword(lamout,lam); next:= next + 1; xtimer:= xtimer1; if next > last then xmode:= output_last; end; (* lock *) signal(r,xsem); end; (* not nill(r) *) end; (* output *) \f output_last: begin schedule:= true; xtimer:= 0; xmode:= output_finis; end; (* output_last *) xecho: begin (* echo finished *) schedule:= true; xtimer:= 0; xmode:= xidle; end; (* xecho *) end; (* case xmode *) if schedule then begin (* schedule main driver *) sensesem(r,eventsem); if not nil(r) then begin r^.u3:= lamin.line; return(r); end; end; end; (* with line *) until doom; end; (* scanner process *) \f procedure error(code: integer); (* fatal error termination routine. outputs errormessage and terminates with zero division *) begin trace(code); (* output error *) code:= 0; code:= code div code; (* send my regards to broadway *) end; (* error *) procedure outecho(char: byte); (* outputs char on curline as echo *) begin with line(curline) do begin lamout.char:= char; lamout.line:= curline; xmode:= xecho; xtimer:= xtimer1; outword(lamout,lam); end; (* with *) end; (* outecho *) procedure startscan; begin control(line_status_type(?,3,3,true,3,true,true,true,true, true,true,true,true),lam); end; \f procedure next_spec_echo; (* outputs next special echo char. *) begin with line(curline) do begin lock lineref(spec_echo_line).convbuf as spec_echo: array (-14..spec_echo_next) of byte do outecho(spec_echo(spec_echo_next)); spec_echo_next:= spec_echo_next + 1; echo_count:= echo_count - 1; end; (* with *) end; (* next_spec_echo *) procedure retbuf(var r: reference; stat: integer); (* returns r with u2 set to stat *) begin r^.u2:= stat; return(r); end; procedure retall(var sem: semaphore); (* returns all buffers at sem with u2= stat_notproc *) begin while open(sem) do begin wait(rw,sem); retbuf(rw,stat_notproc); end; end; (* retall *) \f procedure retrbuf(var r: reference; stat: integer); (* returns r with u2 = stat *) begin with line(curline) do begin if (rstat and stat_xoff) <> 0 then begin if xmode = xidle then begin if (r^.u1 and fatt) <> 0 then rmode:= att_echo else rmode:= input_echo; outecho(xoff); end else rstat:= rstat or stat_echoerr; rstat:= rstat xor stat_xoff; end else begin retbuf(r,stat or rstat); rmode:= idle; rtimer:= 0; rstat:= 0; end; end; (* with *) end; (* retrbuf *) procedure retxbuf(var r: reference; stat: integer); (* as retrbuf except that line.xmit is idled *) begin with line(curline) do begin retbuf(r,stat); xmode:= xidle; xtimer:= 0; end; (* with *) end; (* retxbuf *) \f procedure setrbuf; (* select next rec. buffer *) begin with line(curline) do with lineref(curline) do if nil(rcurbuf) then begin if open(rsem) then begin wait(rcurbuf,rsem); rmode:= input; rtimer:= rtimer1; end else if open(rattsem) then begin wait(rcurbuf,rattsem); rmode:= att; end; if not nil(rcurbuf) then begin lock rcurbuf as b: bufhead do b.next:= b.first; if (rcurbuf^.u1 and fcont) = 0 then begin (* not input continued *) cycfirst:= cyclast; rstat:= 0; end (* not input continued *) \f else begin (* input continued *) sensesem(rw,scansem); if not nil(rw) then begin rw^.u3:= curline; return(rw); end; (* not nill *) end; (* input continued *) if (rcurbuf^.u1 and fxon) <> 0 then begin rstat:= rstat or stat_xoff; rmode:= succ(rmode); outecho(xon); end; end; (* not nill(rcurbuf) *) end; (* with *) end; (* setrbuf *) \f procedure setcontrol; (* outputs modem control from line.linestatus *) begin lamcontrol:= line(curline).linestatus; with lamcontrol do begin if pty_mode = 1 then pty_mode:= 2; not_mr:= true; dcd:= (curline and 8) <> 0; rfs:= (curline and 4) <> 0; dsr:= (curline and 2) <> 0; b14:= (curline and 1) <> 0; scan:= false; end; control(lamcontrol,lam); end; (* setcontrol *) \f procedure sensemodem; (* updates incomming modem signals *) begin lamin.line:= curline; sense(lam_stat,lamin,lam); with line(curline) do begin if (lam_stat.stat and ls_dcd) = 0 then linestatus.dcd:= false; if (lam_stat.stat and ls_rfs) = 0 then linestatus.rfs:= false; if (lam_stat.stat and ls_dsr) = 0 then linestatus.dsr:= false; end; startscan; end; (* sensemodem *) procedure returnmodem(var r: reference); (* returns r with linestatus *) begin lock r as b: record f, l, n: integer; s: line_status_type; end do b.s:= line(curline).linestatus; retbuf(r,stat_ok); with line(curline).linestatus do begin dcd:= true; rfs:= true; dsr:= true; end; end; (* returnmodem *) \f procedure setxbuf; (* selects next output message and starts output. xmode must be idle, when called *) begin with line(curline) do begin sensesem(r,xsemqueue); if not nil(r) then begin (* start output *) s:= r^.size; lock r as ob: packed record first, last, next: integer; buf: array (6..s-1+s) of byte; end do with ob do begin lamout.line:= curline; lamout.char:= buf(first); next:= first + 1; xtimer:= xtimer1; if next > last then xmode:= output_last else xmode:= output; end; (* lock *) (* start scanner output *) signal(r,xsem); outword(lamout,lam); end; (* not nill (r) *) end; (* with *) end; (* setxbuf *) \f begin (* lam main program *) (* initialization *) (* reserve and reproduce lam channel *) if reservech(lam,lamlevel,lammask) <> 0 then error(init1); alloc(r,scanpool,scansem); if copychm(r,lam) <> 0 then error(init2); signal(r,scansem); (* init scanner event pool *) while openpool(scanpool) do begin alloc(r,scanpool,lamsem); signal(r,scansem); end; (* init timer for 1 sec ticks *) alloc(r,timerpool,lamsem); r^.u3:= timeru3; r^.u4:= timeru4; sendtimer(r); (* master reset the lam *) lamcontrol.not_mr:= false; control(lamcontrol,lam); \f (* init line descriptors *) for curline:= firstline to lastline do with line(curline) do begin rmode:= idle; rtimer:= 0; rtimer1:= 0; rtimer2:= 0; linestatus:= init_linespec; cycfirst:= 0; cyclast:= 0; convmode:= -2; rstat:= 0; xmode:= xidle; setcontrol; end; (* linedescriptor init loop *) (* start scanner process *) if create("lamscanner",scanner(scansem,line), scansh,scanner_size) <> 0 then error(init3); start(scansh,0); \f (* lam main loop and main waiting point *) repeat wait(r,lamsem); if ownertest(scanpool,r) then begin (* event from scanner *) curline:= r^.u3; signal(r,scansem); with line(curline) do with lineref(curline) do begin if ((rmode = input_echo) or (rmode = att_echo)) and (xmode = xidle) then begin (* echo char finished *) if echo_count <> 0 then next_spec_echo else begin if open(xsemqueue) then setxbuf; if (res.class and termination) <> 0 then begin (* last event for this message *) retrbuf(rcurbuf,rstat); setrbuf; end else rmode:= pred(rmode); end; (* not special echo *) end; (* echo char finished *) \f (* pick chars from the cyclic input buffer *) while ((rmode = input) or (rmode = att)) and (cycfirst <> cyclast) do begin rtimer:= rtimer2; cycfirst:= (cycfirst + 1) mod cyctop; datain:= cycbuf(cycfirst); (* preconvert special characters ( break and pty-err) *) convchar:= datain.char; if (datain.stat and ls_error) <> 0 then begin if ((datain.stat and ls_stop) <> 0) and (datain.char = 0) then convchar:= brk else if ((datain.stat and (ls_pty or ls_stop)) <> 0) and (linestatus.pty_mode <> 1) then begin convchar:= sub; rstat:= rstat or stat_pty; end; if (datain.stat and ls_ovrun) <> 0 then rstat:= rstat or (stat_ovrun or stat_err); end; (* datain.stat and ls_error *) (* update modem status *) if ((datain.stat and ls_dcd) = 0) then linestatus.dcd:= false; if ((datain.stat and ls_rfs) = 0) then linestatus.rfs:= false; if ((datain.stat and ls_dsr) = 0) then linestatus.dsr:= false; \f (* convchar now contains a legal char or break *) (* conversion *) cmode:= convmode; case cmode of -1: c:= curline; (* own conversion *) -2: ; (* no conversion *) firstline..lastline: begin (* borrow conversion *) c:= cmode; cmode:= line(c).convmode; end; otherwise cmode:= -2; end; (* case cmode *) \f if cmode = -1 then begin (* do conversion *) s:= lineref(c).convbuf^.size; lock lineref(c).convbuf as conv: record ?,?,?,?: integer; tab: array (-1..s-6) of convinteger; end do begin res:= conv.tab(convchar); if (res.class and normal_conv) = 0 then begin (* special conversion *) spec_index:= (res.class * 256) + res.char; res:= conv.tab(spec_index); res.class:= res.class and #b01111111; (* normal_conv=0 *) spec_echo_line:= c; spec_echo_next:= spec_index+spec_index; echo_count:= (conv.tab(spec_index+1).class * 256) + conv.tab(spec_index+1).char; if echo_count = 0 then res.class:= res.class or noecho; end; (* special conversion *) end; (* lock conv.tab *) end (* cmode = -1 *) else begin (* no conversion *) if convchar = brk then begin res.char:= sub; rstat:= rstat or stat_pty; end else res.char:= convchar; res.class:= normal_conv; end; (* no conversion *) \f (* decode conversion classes *) if (rstat and stat_ovrun) <> 0 then res.class:= res.class or termination; if (res.class and attention) <> 0 then begin (* stop input (later) *) rstat:= rstat or stat_att; res.class:= res.class or termination; (* stop output (now), if active *) sensesem(r,xsem); if not nil(r) then begin retxbuf(r,stat_att); setxbuf; end; (* stop output *) end; (* attention *) \f (* buffer actions *) if (rmode = input) or ((res.class and attention) <> 0) then begin if (res.class and erase_all) <> 0 then lock rcurbuf as b: bufhead do b.next:= b.first; if (res.class and erase_last) <> 0 then lock rcurbuf as b: bufhead do if b.next <> b.first then b.next:= b.next - 1 else res.class:= res.class or noecho; if ((res.class and blind) = 0) and ((rmode = input) or ((res.class and attention) <> 0)) then begin (* deliver value *) s:= rcurbuf^.size; lock rcurbuf as b: packed record first, last, next: integer; buf: array (6..s-1+s) of byte; end do with b do begin buf(next):= res.char; next:= next + 1; if next > last then res.class:= res.class or termination; end; (* lock *) if (res.class and mark) <> 0 then rstat:= rstat or stat_mark; end; (* deliver value *) \f if ((res.class and noecho) = 0) and ((rcurbuf^.u1 and fecho) <> 0) then begin (* start echo *) if xmode <> xidle then rstat:= rstat or stat_echoerr else begin (* reserve echo line *) rmode:= succ(rmode); xmode:= xecho; if (res.class and normal_conv) <> 0 then begin (* one char normal echo *) echo_count:= 0; outecho(res.char); end else next_spec_echo; end; (* reserve echo line *) end (* start echo *) else if (res.class and termination) <> 0 then begin retrbuf(rcurbuf,rstat); setrbuf; end; (* termination *) end; (* buffer actions *) end; (* while input ready *) \f (* output_finis action *) if xmode = output_finis then begin sensesem(r,xsem); if nil(r) then error(internal1) else begin retxbuf(r,stat_ok); setxbuf; end; (* not nil(r) *) end; (* output_finis action *) end; (* with *) end (* scanner event *) else \f (* timer action *) if ownertest(timerpool,r) then begin (* timer tick *) r^.u3:= timeru3; r^.u4:= timeru4; sendtimer(r); for curline:= firstline to lastline do with line(curline) do with lineref(curline) do begin if rtimer <> 0 then begin (* input timer active*) rtimer:= rtimer - 1; if (rtimer = 0) and ((rmode = input) or (rmode = input_echo)) then begin (* input timeout *) retrbuf(rcurbuf,stat_err + stat_timeout); setrbuf; end; (* input timeout *) end; (* input timer active *) \f if xtimer <> 0 then begin (* output timer active *) xtimer:= xtimer - 1; if xtimer = 0 then begin case xmode of xidle: ; (* no action *) output, output_last, output_finis: begin (* output timeout *) xmode:= xidle; sensesem(r,xsem); if nil(r) then error(internal2); retxbuf(r,stat_err+stat_timeout); setxbuf; end; (* output, output_finis *) xecho: begin (* echo error *) rstat:= rstat or stat_echoerr; (* simulate echo finish *) xmode:= xidle; sensesem(r,scansem); if not nil(r) then begin r^.u3:= curline; return(r); end; end; (* xecho *) end; (* case xmode *) startscan; end; (* if xtimer = 0 *) end; (* output timer active *) end; (* for all lines *) end (* timer tick *) else \f (* not event and not timer => real message *) begin curline:= r^.u3; if (curline < firstline) or (curline > lastline) then begin r^.u2:= stat_ill; return(r); end else with line(curline) do with lineref(curline) do case r^.u1 of 0: begin (* sense modem *) sensemodem; returnmodem(r); end; (* sense modem *) \f 4: begin (* line control *) lock r as b: record f,l,n: integer; ns, ac: line_status_type; end do with b do with linestatus do begin if ac.line_speed <> 0 then line_speed:= ns.line_speed; if ac.data_size <> 0 then data_size:= ns.data_size; if ac.stop_bits then stop_bits:= ns.stop_bits; if ac.pty_mode <> 0 then pty_mode:= ns.pty_mode; if ac.rts then rts:= ns.rts; if ac.dtr then dtr:= ns.dtr; end; (* lock *) (* set lam parameters *) setcontrol; sensemodem; returnmodem(r); end; (* line control *) \f 8: begin (* set conversion *) lock r as conv: record f,l,n,mode: integer; end do cmode:= conv.mode; convmode:= cmode; echo_count:= 0; (* stop special echo *) case cmode of -2: begin (* clear conversion *) push(r,convbuf); r :=: convbuf; end; (* clear conversion *) -1: (* set conversion table *) r :=: convbuf; firstline..lastline: (* set conversion link *) r :=: convbuf; otherwise begin (* illegal conv_control *) convmode:= -2; retbuf(r,stat_ill); end; (* illegal *) end; (* case cmode *) if not nil(r) then retbuf(r,stat_ok); end; (* set conversion *) \f 12: begin (* set timers *) lock r as b: record f,l,n: integer; it1, it2, ot1: integer; end do with b do begin rtimer1:= it1; rtimer2:= it2; xtimer1:= ot1; end; (* lock *) retbuf(r,stat_ok); end; (* set timers *) 16: begin (* reset, return all buffers *) if not nil(rcurbuf) then begin if (rstat and stat_xoff) <> 0 then begin outecho(xoff); rstat:= rstat xor stat_xoff; end; retrbuf(rcurbuf,stat_notproc); end; (* not nil(rcurbuf *) rmode:= idle; xmode:= xidle; echo_count:= 0; rtimer:= 0; xtimer:= 0; retall(rsem); retall(rattsem); retall(xsem); retall(xsemqueue); retbuf(r,stat_ok); end; (* reset *) \f (* tramsput messages *) 1,3,5,7,17,19,21,23: begin (* input *) signal(r,rsem); if nil(rcurbuf) then setrbuf else begin (* if att then suspend *) if (rcurbuf^.u1 and fatt) <> 0 then begin signal(rcurbuf,rattsem); setrbuf; end; (* suspend attention buffer *) end; (* not nil(rcurbuf) *) end; (* input *) 9,11,13,15,25,27,29,31: begin (* attention *) signal(r,rattsem); if nil(rcurbuf) then setrbuf; end; (* attention *) 2: begin (* output *) signal(r,xsemqueue); if not open(xsem) then setxbuf; end; otherwise retbuf(r,stat_ill); end; (* with case function *) end; (* real message *) until doom; end (* lam driver, farvel og tak *) . «eof»