Skip to main content

  | मौसम…

411 समाचार
Public archive edition · Attributed source reporting with original dates · AI drafts are excluded

411 REFERENCE · Wikibooks

Oberon/ETH Oberon/PPPHDLC.Mod

Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.

(* ETH Oberon, Copyright 1990-2003 Computer Systems Institute, ETH Zurich, CH-8092 Zurich. Refer to the license.txt file provided with this distribution. *) (* $VCS 1, Edgar.Schwarz@z.zgs.de, 28 Feb 99, 22:13:54 $ *) MODULE PPPHDLC; (** non-portable *) (* $Log$ $ 1, Edgar.Schwarz@z.zgs.de, 28 Feb 99, 22:13:54 version for PPP 1.0.0 *) IMPORT Debug := PPPDebug, SYSTEM, T:=PPPTools, (*es*) Oberon, Ker:=Kernel, V24, PT := NetBase, Input, Out, Strings; (* Ker:=PPCXOKernel, P:=Peripherals; *) CONST HDLCAddress=0FFX; HDLCControl=03X; HDLCHeaderLen* = 4; (* Flag + Address, Protocol (2 Byte) *) EscSymbol = 7DX; FlagSymbol = 7EX; MTU*=1500; StartPos*=4; (* even if we received a packed Packet, we can send back an unpacked one, using the same array *) ArrayLength* = MTU+100; (* some bytes more needed *) TYPE Params* = POINTER TO ParamsDesc; ParamsDesc* = RECORD END; CallbackProc*=PROCEDURE (p:Params); TimeOut = POINTER TO TimeOutDesc; TimeOutDesc = RECORD time: LONGINT; callback: CallbackProc; params: Params; next: TimeOut; END; PPPUnit* = POINTER TO PPPUnitDesc; MyTask* = POINTER TO MyTaskDesc; MyTaskDesc = RECORD (*es*) (Oberon.TaskDesc) (* (Ker.MainEventDesc) (* Oberon.TaskDesc *) *) Config*:PPPUnit; END; PPPUnitDesc* = RECORD MTU*, MRU*:INTEGER; (* Maximum Transmit Unit, how big our packets are; M Receive U, how big he may send*) SendAsyncMap*:SET; (* Transmit AsyncMap; What characters have to be stuffed *) (*es*) c*: LONGINT; (* c*: P.SerialChannel; *) cname*:ARRAY 32 OF CHAR; task*: MyTask; data, data2*: ARRAY ArrayLength OF CHAR; TOqueue: TimeOut; TOempty: BOOLEAN; END; VAR (*es*) debug*: BOOLEAN; TOtask: Oberon.Task; (* check for timeout *) TOunit: PPPUnit; (* instead of extending task *) (*TOrecycle: TimeOut;*) FrameCount: INTEGER; (* pe: number frames for reference. *) (*es*) (* Save incomplete frames between calls to Receive *) receiveFrame: RECORD active: BOOLEAN; (* ready to receive data *) (*deadline: LONGINT; (* until we want to receive the end *)*) i: INTEGER; (* index of last received byte in receive buffer *) esc: BOOLEAN; (* last byte received was EscSymbol *) END; (**)PPPHandleReceive*: PROCEDURE (U:PPPUnit; prot:INTEGER; VAR p: ARRAY OF CHAR; pos, len:INTEGER; VAR prno: INTEGER; VAR item: PT.Item); PROCEDURE SendString(c: (*es*)LONGINT(*P.SerialChannel*); VAR s: ARRAY OF CHAR); VAR l0, l1, start: LONGINT; (*es*)res: LONGINT;(**) BEGIN l0 := 0; WHILE s[l0] # 0X DO INC(l0) END; l1 := l0; start := 0; (*es*) WHILE l0 > 0 DO V24.SendBytes(c, s, l1, res); DEC(l0, l1); END (* WHILE l0 > 0 DO c.Write(s, start, l1); DEC(l0, l1); INC(start, l1) END *) END SendString; (* Init *) PROCEDURE Init* (Config:PPPUnit; c:(*es*)LONGINT(* P.SerialChannel*); VAR cname, sstr, loginname, loginpasswd: ARRAY OF CHAR); VAR to:TimeOut; l: LONGINT; temp: ARRAY 4 OF CHAR; cr: ARRAY 2 OF CHAR; (*es*)res: LONGINT;(**) BEGIN Config.c := c; COPY(cname, Config.cname); (*es??? die V24 und Loginsachen macht doch der Dialer. Oder ? (* V24 login is handled by the Dialer, isn't it? *) WHILE V24.Available(c) > 0 DO V24.Receive(c, temp[0],res); END; (* WHILE c.Available > 0 DO l := 1; c.Read(temp, 0, l) END; *) (* send start string *) IF sstr[0] # 0X THEN SendString(c, sstr); (* consume some bytes (they contain the reply string from server) *) REPEAT WHILE c.Available > 0 DO l := 1; c.Read(temp, 0, l) END; Ker.Sleep(1, Ker.ONEsec) UNTIL c.Available = 0 END; IF loginname[0] # 0X THEN (* start normal unix-login procedure *) cr[0] := 0DX; cr[1] := 0X; (* send two CR *) SendString(c, cr); Ker.Sleep(1, Ker.ONEsec); SendString(c, cr); Ker.Sleep(5,Ker.ONEsec); (* send loginname *) SendString(c, loginname); SendString(c, cr); Ker.Sleep(1, Ker.ONEsec); (* send loginpasswd *) SendString(c, loginpasswd); SendString(c, cr); Ker.Sleep(1, Ker.ONEsec); END; REPEAT WHILE c.Available > 0 DO l := 1; c.Read(temp, 0, l); Debug.Int(ORD(temp[0]),4); IF (temp[0] >= 20X) & (temp[0] <= 7FX) THEN Debug.Char(9X); Debug.Char(temp[0]) END; Debug.Ln; END; Ker.Sleep(5,Ker.ONEsec); Debug.Ln; UNTIL c.Available = 0; es*) Debug.String("Starting receiving-loop"); Debug.Ln; NEW(Config.task); Config.task.Config:=Config; (*es???*) Debug.String("Pustekuchen, macht Devicepolling"); Debug.Ln; (* pe *) Debug.String("Begin communicating with the remote system."); Debug.Ln; Debug.String("Configure the timeout."); Debug.Ln; (*Ker.InitMain(Config.task);*) NEW(to); Config.TOqueue:=to; to.next:=to; to.time:=MAX(LONGINT); Config.TOempty:=TRUE; (* sentinel *) END Init; PROCEDURE CheckTimer((*es*)me: Oberon.Task(*C: PPPUnit*)); (* Called only when TOqueue is not empty *) VAR cur:TimeOut; BEGIN cur:=(*es*)TOunit(*C*).TOqueue; IF cur.time < (*es*)Input.Time()(*Ker.Time()*) THEN (*es*) Oberon.Remove(me); IF TOunit.cname # "" THEN (* output only if ppp is still running. See PPPMain.StopInst *) Out.String("PPP timeout"); Out.Ln; END; (**) (*es*)TOunit(*C*).TOempty:=TRUE; cur.callback(cur.params); END END CheckTimer; (* TimeOut Handling *) PROCEDURE TIMEOUT* (C: PPPUnit; callb:CallbackProc; p:Params; msec:LONGINT); (* msec: in microS-sec *) VAR cur:TimeOut; BEGIN cur:=C.TOqueue; cur.callback:=callb; cur.params:=p; cur.time:=(*es*) Input.Time(*Ker.Time*)()+msec; C.TOempty:=FALSE; (*es install timer task *) TOtask.safe := FALSE; TOtask.time := 0; TOtask.handle := CheckTimer; Oberon.Install(TOtask); TOunit := C; (**) END TIMEOUT; PROCEDURE UNTIMEOUT* (C: PPPUnit; callb:CallbackProc); BEGIN C.TOempty:=TRUE; (*es*) Oberon.Remove(TOtask); (**) END UNTIMEOUT; (* CheckPacket - Check a HDLC-Packet *) PROCEDURE CheckPacket(Config: PPPUnit; VAR p: ARRAY OF CHAR; pos, len:INTEGER; VAR prno: INTEGER; VAR item: PT.Item); (*es*)VAR timeStr: ARRAY 16 OF CHAR; time, date: LONGINT;(**) BEGIN IF debug THEN (* pe *) Debug.String('->->-> Frame '); Debug.Int(FrameCount, 5); Debug.String(' received from peer.'); Debug.Ln; INC(FrameCount); (* pe *) Oberon.GetClock(time, date); Strings.TimeToStr(time,timeStr); Debug.String(timeStr); Debug.String('CheckPacket: len = '); Debug.Int(len, 5); Debug.Ln; T.OutPacket(p, pos, len); END; IF len > HDLCHeaderLen+2 THEN (*[HDLC_Address+HDLC-Control+Protocol] + Checksum (2 Bytes)*) IF T.CheckFCS(p, pos, len) THEN (* CheckSum ok? The whole packet needed! *) IF (p[pos] = HDLCAddress) & (p[pos+1] = HDLCControl) THEN PPPHandleReceive(Config, T.GetInt(p, pos+2), p, pos+4, len-6, prno, item); ELSE (* silently discarded *) IF debug THEN Debug.String("Address, Code wrong"); Debug.Ln; END; END ELSE IF debug THEN Debug.String("Checksum failure"); Debug.Ln END END ELSE IF debug & (len > 0) THEN Debug.String("Length too short, length: "); Debug.Int(len, 6); Debug.Ln; END; END END CheckPacket; PROCEDURE XOR20(ch:LONGINT):LONGINT; BEGIN RETURN SYSTEM.VAL(LONGINT, (SYSTEM.VAL(SET, ch) / {5} )); END XOR20; (* ReceivePacket - ReceiveLoop: Task , needs extended Event (including PPPUnit)*) (*es*) (* ReceivePacket is indirectly called by NetBase.Polldevices when characters at the serial interface are available. So just read the characters into a buffer (Config.data) and return prno=0 (no handler installed for this protocol hopefully). When you get end of frame (FlagSymbol) then check it and return the stuff. *) (**)PROCEDURE ReceivePacket*(Config: PPPUnit; VAR prno: INTEGER; VAR item: PT.Item); VAR (*es*) (*i:INTEGER;*) ch: ARRAY 4 OF CHAR; l: LONGINT; (*es*)c, res, endTime: LONGINT; timeOut : TimeOut; (* c: P.SerialChannel; *) BEGIN c:=Config.c; (*es*)(* i:=StartPos; ch[0]:=0X; (* not Esc-Symbol *) *) (*es*)IF receiveFrame.active THEN prno := 0; ELSE (*receiveFrame.deadline := Input.Time() + 10(*s*) * Input.TimeUnit;*) receiveFrame.i := StartPos; receiveFrame.active := TRUE; receiveFrame.esc := FALSE; ch[0]:=0X; END; IF receiveFrame.esc THEN ch[0] := EscSymbol ELSE ch[0]:=0X; END; (**) LOOP IF (*es*)V24.Available(c)(*c.Available*)>0 THEN (* New chars in buffer ? *) IF ch[0] (* last received *) #EscSymbol THEN (*es*) V24.Receive(c, ch[0], res); (*l := 1; c.Read(ch, 0, l);*) IF ch[0] = FlagSymbol THEN (* end of frame received *) CheckPacket(Config, Config.data, StartPos, receiveFrame.i-StartPos, prno, item); (*es*) (* data now in item *) receiveFrame.active := FALSE; RETURN; (* receiveFrame.i:=StartPos; *) ELSE IF ch[0] # EscSymbol THEN Config.data[receiveFrame.i]:=ch[0]; INC(receiveFrame.i) ; (*es*) receiveFrame.esc := FALSE; ELSE receiveFrame.esc := TRUE; (**) END END; ELSE (*es*) V24.Receive(c, ch[0], res); receiveFrame.esc := FALSE; (*l := 1; c.Read(ch, 0, l);*) Config.data[receiveFrame.i]:=CHR(XOR20(ORD(ch[0]))); INC(receiveFrame.i); ch[0]:=0X; (* not Esc-,or Flag-Symbol *) END; IF receiveFrame.i>=ArrayLength THEN Debug.String("Array Overflow!!"); (*HALT(99);*) receiveFrame.active := FALSE; RETURN END; ELSE RETURN; (* pause until more characters are available *) (**) END; END END ReceivePacket; (* SendPacket - Send a packet to the V24 *) PROCEDURE SendPacket* (Config: PPPUnit; prot:INTEGER; VAR p:ARRAY OF CHAR; pos, len:INTEGER); VAR minpos, code, k, begin: INTEGER; ch: ARRAY 4 OF CHAR; l0, l1, start: LONGINT; x: CHAR; (*es*)c, res: LONGINT; timeStr: ARRAY 16 OF CHAR; time, date: LONGINT; (*c: P.SerialChannel;*) BEGIN c:=Config.c; minpos:=HDLCHeaderLen; IF pos<minpos THEN T.CopyString(p, pos, minpos, len); pos:=minpos; END; (* More space needed *) DEC(pos, HDLCHeaderLen); INC(len, HDLCHeaderLen); p[pos]:=0FFX; p[pos+1]:=03X; (* pos + 0: HDLC_Address = 0FFX; pos + 1: HDLC_Control =3X *) T.PutInt(prot, p, pos+2); (* pos + 2: Protocol *) code:=T.CalcFCS(p, pos, len); p[pos+len]:=CHR(code MOD 256); p[pos+len+1]:=CHR(SYSTEM.LSH(code, -8)); INC(len, 2); (* insert the checksum *) IF debug THEN (* pe *) Debug.String('<-<-<- Frame '); Debug.Int(FrameCount, 5); Debug.String(' going to peer.'); Debug.Ln; INC(FrameCount); (* pe *) Oberon.GetClock(time, date); Strings.TimeToStr(time,timeStr); Debug.String(timeStr); Debug.String(' SendPacket: len = '); Debug.Int(len, 5); Debug.Ln; T.OutPacket(p, pos, len); Debug.Ln END; (* send it to the V24 *) ch[0]:=FlagSymbol; l0 := 1; l1 := l0; start := 0; WHILE l0 > 0 DO (*es*)V24.Send(c,ch[start], res); (* c.Write(ch, start, l1); *) DEC(l0, l1); INC(start, l1) END; (* es auskommentiert: der Trick ist irgendwie alle Zeichen zu sammeln, die man ohne Maskierung (EscSymbol) senden kann. Wenn man dann auf eines trifft, verpackt man es und schickt die Dinger von zuvor auf weg. Das ist mir etwas zu undurchsichtig. Translation & remark from T.F. Section commented out: The trick is to somehow collect all the characters that can be sent without escaping (EscSymbol). Once we come across a character that needs escaping, we send all the previously collected characters followed by the escaped character. It is probably some kind of "optimized code" that was translated and when it did not work was finally replaced by the version below the commented-out code. From what I can tell the active code is better anyways (simpler). If optimization is needed, AosIO could be used to collect the characters in a much simpler way. *) (* begin:=pos; FOR k:=pos TO pos+len-1 DO x:=p[k]; IF ((ORD(x)<20H) & (ORD(x) IN Config.SendAsyncMap)) OR (x=EscSymbol) OR (x=FlagSymbol) THEN l0 :=k-begin; l1 := l0; start := begin; WHILE l0 > 0 DO c.Write(p, start, l1); DEC(l0,l1); INC(start,l1);END; begin:=k+1; ch[0]:=EscSymbol; ch[1]:=CHR(XOR20(ORD(x))); l0 := 2; l1 := l0; start := 0; WHILE l0 > 0 DO c.Write(ch, start, l1); DEC(l0,l1); INC(start,l1);END; END; END; p[pos+len]:=FlagSymbol; l0 := pos+len+1-begin; l1 := l0; start := begin; WHILE l0 > 0 DO c.Write(p, start, l1); DEC(l0, l1); INC(start, l1); END; *) (*es*) FOR k:=pos TO pos+len-1 DO x:=p[k]; IF ((ORD(x)<20H) & (ORD(x) IN Config.SendAsyncMap)) OR (x=EscSymbol) OR (x=FlagSymbol) THEN V24.Send(c,EscSymbol, res); IF res # 0 THEN HALT(99); END; V24.Send(c,CHR(XOR20(ORD(x))), res); IF res # 0 THEN HALT(99); END; ELSE V24.Send(c, x, res); IF res # 0 THEN HALT(99); END; END; END; (* frame complete: send end flag *) V24.Send(c,FlagSymbol, res); IF res # 0 THEN HALT(99); END; (**) END SendPacket; BEGIN (* pe *) FrameCount := 0; debug := FALSE; (*es*) receiveFrame.active := FALSE; NEW(TOtask); (*NEW(TOrecycle); TOrecycle.next:=TOrecycle; (* Sentinel *)*) END PPPHDLC.