/************************************************************************/ /* */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* *************** *************** */ /* ***************** ***************** */ /* *************** *************** */ /* ***** ***** TheNetNode */ /* ***** ***** Portable */ /* ***** ***** Network */ /* ***** ***** Software */ /* */ /* File os/go32/tokenrng.c (maintained by: ???) */ /* */ /* This file is part of "TheNetNode" - Software Package */ /* */ /* Copyright (C) 1998 - 2008 NORD> (token_sent + TOKENTIMEOUT)) /* Tokenring im Timeout */ { clear_rs232(tkcom); /* RS232 Buffer loeschen */ clear_rs232(tkcom); /* RS232 Buffer loeschen */ clear_rs232(tkcom); /* RS232 Buffer loeschen */ rx_state = 0; /* RX-State auf FEND */ if (lost_token++ >= 400) HALT("tokenring"); /* Rechner neu starten */ if ((lost_token % 100) == 0) /* neue Baudrate probieren */ { switch (tkbaud) { case 96: tkbaud = 192; break; /* no luck, try 19200 Baud */ case 192: tkbaud = 384; break; /* no luck, try 38400 Baud */ case 384: tkbaud = 96; break; /* go back to 9600 Baud */ } setbaud(tkcom, tkbaud); xprintf ("*** Autobaud - Token ring: %u00 bit/s. \n",tkbaud); } send_token(); /* Neues Token auf den Ring legen */ token_sent = tic10; /* Zeit merken wann Token gesendet */ recovery_count++; /* Dieser Wert wird auch bei STAT angezeigt! */ for (port = 0; port < L2PNUM; port++) if (portpar[port].major == tok_major) commandflag[port] = TRUE; /* neue Parameter an TNC, RESET.. */ tr_cmd = 2; /* Flag setzen "es ist was zu tun" */ if (!incnt && show_recovery == TRUE) { xprintf("*** Token-Recovery (%ld) : %s", lost_token, ctime(&sys_time)); notify(1, "*** Token-Recovery (%lu)", lost_token); } } } else lost_token = 0; } /************************************************************************/ /* tokenring_put_frame() - Frame(s) im Ringpuffer ablegen */ /* Beschleunigte Variante nach DL1XAO */ /*----------------------------------------------------------------------*/ static void tokenring_put_frame(void) { int port; UBYTE ch, *out; WORD *kp = kick; PORTINFO *pp = portpar; LHEAD *l2flp = txl2fl; MBHEAD *txfhdl; for (port = 0; port < L2PNUM; port++, pp++, kp++, l2flp++) { if ( pp->major != tok_major || *kp == FALSE ) /* Port hat nichts zum Senden */ continue; cd_timer[port] = tic10; /* Wir senden, Belegt-Timer starten */ ulink((LEHEAD *)(txfhdl = (MBHEAD *) l2flp->head));/*Zeiger holen*/ TX_BEG(); /* Sender bereit */ TX_CHAR(FEND); /* Frame beginnt */ TX_CHAR(port); /* Port */ TX_CHAR(0x00); /* Datenframe */ while (txfhdl->mbgc < txfhdl->mbpc) /* solange Daten vorhanden sind */ switch(ch = getchr(txfhdl)) { case FEND: TX_CHAR(FESC); TX_CHAR(TFEND); break; case FESC: TX_CHAR(FESC); TX_CHAR(TFESC); break; default: TX_CHAR(ch); } TX_CHAR(FEND); /* Frame bendet */ rs232_write(tkcom, blkbuf, out); /* und senden... */ relink((LEHEAD *)txfhdl, /* als gesendet betrachten und in */ (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ *kp = (l2flp->head != l2flp); } /* for */ } /************************************************************************/ /* tokenring_get_frame() - Frame(s) aus Ringbuffer holen */ /*----------------------------------------------------------------------*/ static void tokenring_get_frame(void) { static WORD k; static int port; static MBHEAD *rxfhd = NULL; UBYTE ch, *in = blkbuf; int n; n = rs232_read(tkcom, blkbuf, BLOCKSIZE); while (n) { /* Zeichen auswerten */ ch = *in++; /* Zeichen holen */ n--; switch (rx_state) /* ueber Status verzweigen */ { case WFEND: /* Frame Anfang erwartet */ if (ch == FEND) rx_state = GPORT; /* Frameanfang entdeckt */ continue; case GPORT: switch (ch) /* zuletzt FEND bekommen */ { case FEND: continue; /* noch ein FEND: uebergehen */ case 0xFF: rx_state = TOKEN; /* Token Anfang */ continue; default: port = ch & 0x7F; /* Port von TNC */ /* Ueberpruefen ob der Port ueberhaupt gueltig ist */ if ( ( port >= L2PNUM || portpar[port].major != tok_major) && portpar[port].major != NO_MAJOR) { rx_state = WFEND; /* wieder auf Frame warten */ bad_frames++; continue; /* gleich abbrechen.. */ } rx_state = GTYPE; /* next state: */ } continue; case GTYPE: /* Port bekannt: */ switch (ch) /* nun auswerten... */ { case 0x00: rx_state = GFRAM; /* es folgen [].. */ if (rxfhd) /* wenn Frame aktiv, auf den Muell */ relink((LEHEAD *)rxfhd, (LEHEAD *)trfl.tail); (rxfhd = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2port = port; continue; case 0x0C: k = 0; /* Port hat RESET gemacht */ rx_state = RESET; continue; case 0x0E: rx_state = DAMAP; /* DAMA Frame sent, PTT */ continue; default: rx_state = WFEND; /* Kommando unbekannt. */ } continue; case GFRAM: /* vom TNC holen */ switch (ch) { case FEND: /* nur wenn Frame aktiv, */ if (rxfhd) { /* Befehl ausfuehren */ relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); rxfhd = NULL; /* kein RX-Frame aktiv */ } rx_state = WFEND; /* Das war's.. fertig! */ continue; case FESC: rx_state++; /* FESC wird zu FESC-TFESC */ continue; /* Rueckwandlung.. */ } /* noch mehr... */ break; case GFRMT: switch (ch) /* TFEND/TFESC-Rueckwandlung */ { case TFEND: ch = FEND; break; case TFESC: ch = FESC; break; default: rx_state = WFEND; continue; } rx_state--; break; case TOKEN: /* Token-Anfang gefunden */ switch (ch) /* wird immer an Port 0xff gesendet */ { case 6: rx_state = TOKN2; /* Token OK */ continue; default: rx_state = WFEND; /* ungueltig, kein Token! */ } continue; case TOKN2: if (ch == FEND) /* gueltiges Token empfangen */ { token_count++; if (tr_res) /* Ist TNC zu resetten? */ tokenring_reset_tnc(); if (tr_cmd) if (--tr_cmd == 0) /* Ist TNC zu konfigurieren? */ tokenring_config_tnc(); if (tr_tst) /* Test-Folge zu senden? */ tokenring_send_test(); tokenflag = TRUE; tokenring_put_frame(); send_token(); token_sent = tic10; /* Zeit merken */ } rx_state = WFEND; continue; case RESET: /* Port hat RESET gemacht */ switch (ch) { case FEND: tr_cmd = commandflag[port] = TRUE; portstat[port].reset_count++; rx_state = WFEND; continue; default: if (++k > 6) rx_state = WFEND; } continue; case DAMAP: /* DAMA Frame gesendet, PTT */ if (ch == FEND) cd_timer[port] = 0; /* Kanal frei: Timer stoppen */ rx_state = WFEND; continue; } /* switch(rxstate) */ putchr(ch, rxfhd); /* Zeichen in Frame */ if (rxfhd->mbpc > L2MFLEN) /* Framelaengencheck */ rx_state = WFEND; } } /************************************************************************/ /* Token auf Ring legen */ /*----------------------------------------------------------------------*/ void send_token(void) { static UBYTE token[6] = { FEND, 0xFF, 0x06, FEND, 0, 0 }; rs232_write(tkcom, token, &token[4]); } /************************************************************************/ /* Jeden TNC mit Parametern versorgen */ /*----------------------------------------------------------------------*/ void tokenring_config_tnc(void) { UBYTE port, *out; WORD *cf = commandflag; PORTINFO *pp = portpar; for (port = 0; port < L2PNUM; port++, pp++, cf++) { if ( pp->major != tok_major || *cf != TRUE /* der nicht... */ ) continue; /* ..ueberspringen */ TX_BEG(); /* Sendung starten */ TX_CHAR(FEND); /* TX-Delay einstellen */ TX_CHAR(port); TX_CHAR(1); TX_CHAR(pp->txdelay); TX_CHAR(FEND); TX_CHAR(FEND); /* Persistance einstellen */ TX_CHAR(port); TX_CHAR(2); TX_CHAR(pp->persistance); TX_CHAR(FEND); TX_CHAR(FEND); /* Slottime einstellen */ TX_CHAR(port); TX_CHAR(3); TX_CHAR(pp->slottime); TX_CHAR(FEND); TX_CHAR(FEND); /* Tailtime einstellen */ TX_CHAR(port); TX_CHAR(4); TX_CHAR(TAILTIME); TX_CHAR(FEND); TX_CHAR(FEND); /* Fullduplex an/aus */ TX_CHAR(port); TX_CHAR(5); TX_CHAR((pp->l1mode & MODE_d) != 0 ? 1 : 0); TX_CHAR(FEND); TX_CHAR(FEND); /* DAMA an/aus */ TX_CHAR(port); TX_CHAR(6); TX_CHAR(dama(port) ? 1 : 0); TX_CHAR(FEND); rs232_write(tkcom, blkbuf, out); /* und senden... */ *cf = FALSE; } tr_cmd = 0; } /************************************************************************/ /* Reset Befehl an alle TNCs geben */ /*----------------------------------------------------------------------*/ static void tokenring_reset_tnc(void) { int port; UBYTE *out; PORTINFO *pp = portpar; for (port = 0; port < L2PNUM; port++, pp++) /* Alle TNCs durchgehen */ { if ( pp->major != tok_major || pp->reset_port != TRUE /* soll dieser Reset bekommen? */ ) continue; TX_BEG(); TX_CHAR(FEND); TX_CHAR(port); TX_CHAR(0x0D); TX_CHAR(FEND); rs232_write(tkcom, blkbuf, out); /* und senden... */ pp->reset_port = FALSE; } tr_res = FALSE; /* RESET erledigt... */ } /************************************************************************/ /* TEST-Befehl ausfuehren, dazu 4 KByte L/H-Folgen senden (Keine Flags!)*/ /*----------------------------------------------------------------------*/ void tokenring_send_test(void) { UBYTE port, *out; WORD *tf = testflag; UWORD count; PORTINFO *pp = portpar; for (port = 0; port < L2PNUM; port++, pp++, tf++) { if ( pp->major != tok_major /* Nicht fuer uns... */ || *tf != TRUE /* der nicht... */ ) continue; /* ..ueberspringen */ TX_BEG(); TX_CHAR(FEND); TX_CHAR(port); /* der TEST Port */ TX_CHAR(0x00); rs232_write(tkcom, blkbuf, out); /* und senden... */ count = pp->speed / 8 * 10; /* 10 sec lang */ if (count < 1024) count = 1024; memset(blkbuf, 0x00, (size_t)(BLOCKSIZE - 2)); while (count) { /* und senden... */ if (count > BLOCKSIZE - 2) { rs232_write(tkcom, blkbuf, &blkbuf[BLOCKSIZE - 1]); count -= (BLOCKSIZE - 2); } else { out = &blkbuf[count]; TX_CHAR(FEND); count = 0; } } TX_CHAR(FEND); rs232_write(tkcom, blkbuf, out); *tf = FALSE; /* TEST erledigt.. */ } tr_tst = FALSE; } static WORD tokenring_dcd(PORTINFO *port) { int minor = port->minor; ULONG *cdt; cdt = &cd_timer[minor]; if ( dama(minor) && *cdt) { /* belegt.. */ if ((tic10 - *cdt) > CD_TIMEOUT) /* Timeout abgelaufen? */ *cdt = 0; /* Timer stoppen */ if (*cdt) /* Timer laeuft: Port ist belegt..*/ return(PTTFLAG); /* Einen belegten Port gefunden! */ } return(FALSE); /* keine Kanalkontrolle */ } static int tokenring_attach(int port, int unused_minor, BOOLEAN check_only) { if (tkcom > -1) { /* Geraetekanal bereit? */ if (!check_only) /* Minor wird auf Untergeraet (TNC) gesetzt, es wird aber nur ein Ring unterstuezt. Eigentlich waeren die Ringe die Minors ... */ portpar[port].minor = port; return(1); } return(0); /* versuchte Doppeleintragung */ } static void tokenring_info(int what, int port, MBHEAD *mbp) { switch (what) { case HW_INF_STAT : if (tkcom >= -1) { putstr("\rTokenring-Statistics:\r\r", mbp); putprintf(mbp, " Tokens/sec: %8lu %8lu %8lu\r", token_min_sec, token_pro_sec, token_max_sec); if (token_max_sec) putprintf(mbp, " TOKENRING load: %lu%%\r", 100 - (((ULONG)token_pro_sec)*100L) / ((ULONG)token_max_sec)); putprintf(mbp, "\r Token ring speed: %u00 Bit/s.\r" " Token-Recoveries: %u\r" " Bad-Frames: %u\r", tkbaud, recovery_count, bad_frames); } break; case HW_INF_CLEAR : token_max_sec = token_min_sec = 0; recovery_count = bad_frames = 0; /* durchfallen! */ default : default_l1info(what, port, mbp); break; } } static void tokenring_timer(UWORD ticks) { static UWORD delay = 0; delay += ticks; if (delay > 6000) { /* eine Minute vergangen */ token_pro_sec = (token_count / 60L); if (token_max_sec && token_min_sec) { token_max_sec = token_pro_sec > token_max_sec ? token_pro_sec : token_max_sec; token_min_sec = token_pro_sec > token_min_sec ? token_min_sec : token_pro_sec; } else token_min_sec = token_max_sec = token_pro_sec; token_count = 0; delay %= 6000; } } static int register_tokenring(void) { MAJOR *m; if (tokenring_l1init()) { m = register_major(); m->name = "TOKENRING"; m->exit = tokenring_exit; m->handle = tokenring; m->ctl = tokenring_ctl; m->dcd = tokenring_dcd; m->info = tokenring_info; m->timer = tokenring_timer; m->attach = tokenring_attach; return(tok_major = num_major); } return(0); } /* End of os/go32/tokenrng.c */