/************************************************************************/ /* */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* *************** *************** */ /* ***************** ***************** */ /* *************** *************** */ /* ***** ***** TheNetNode */ /* ***** ***** Portable */ /* ***** ***** Network */ /* ***** ***** Software */ /* */ /* File os/go32/kiss.c (maintained by: ???) */ /* */ /* This file is part of "TheNetNode" - Software Package */ /* */ /* Copyright (C) 1998 - 2008 NORD>dev = open_rs232(dev,adr,irq,KI_BUFFERSIZE,KI_BUFFERSIZE); kp->active = (kp->dev != -1); } else kp->active = FALSE; #endif /* PC */ #ifdef ST read_envdev(str, device, ""); kp->active = ((*device && (kp->dev = open_rs232(device)) > 0)); #endif /* ST */ if (kp->active) { bd = setbaud(kp->dev, 96); setstopbits(kp->dev, 1); printf(" setting to %u00 8N1.\n", bd); } kp->kisslinkport = -1; kp->rx_state = 0; kp->rxfhd = NULL; if (kp->active) numactive++; } return(numactive); } /************************************************************************/ /* Level1 Exit */ /************************************************************************/ static void kiss_exit(void) { int kiss; for (kiss = 0; kiss < MAXKISS; kiss++) if (kissdev[kiss].active) close_rs232(kissdev[kiss].dev); } /* Berechnung eines Teil-CRC 16 nach SMACK Methode */ /**************************************************************************/ static UBYTE smack_crc(UWORD *crc, UBYTE c) { static const UWORD crc_table[] = { 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 }; *crc = (*crc >> 8) ^ crc_table[(*crc ^ c) & 0xFF]; return(c); } /* Berechnung eines Teil-CRC 16 nach RMNC Methode */ /**************************************************************************/ static UBYTE rmnc_crc(UWORD *crc, UBYTE c) { static const UWORD Crc_rmnc_table[] = { 0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38, 0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770, 0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9, 0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1, 0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a, 0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672, 0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb, 0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3, 0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c, 0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574, 0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd, 0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5, 0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e, 0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476, 0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf, 0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7, 0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30, 0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378, 0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1, 0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9, 0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32, 0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a, 0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3, 0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb, 0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34, 0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c, 0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5, 0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd, 0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36, 0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e, 0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7, 0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff }; *crc = (*crc << 8) ^ Crc_rmnc_table[((*crc >> 8) ^ c) & 0xff]; return(c); } /* dies ist eine Inline-Code-Sequence, die benutzt wird, um ein Zeichen */ /* Slip-kodiert auszugeben. Da es ein Macro ist, darf ch nur einmal */ /* abgefragt werden. tmp ist eine Registervariable und speichert ch */ /* fuer eine 2. Abfrage zwischen. */ /* Dies wuerde sauberer mit einem inline tag gehen, aber Borland kennt */ /* soetwas nicht. */ #define slip_encode(ch) switch ((tmp=ch)&0xFF) { \ case FEND: TX_CHAR(FESC); \ TX_CHAR(TFEND); \ break; \ case FESC: TX_CHAR(FESC); \ TX_CHAR(TFESC); \ break; \ default: TX_CHAR(tmp); } /************************************************************************/ /* kisslink_put_frame() - Frame(s) im Ringpuffer ablegen */ /*----------------------------------------------------------------------*/ static void kisslink_put_frame(__kiss_struct *kp) { UWORD crc; LHEAD *l2flp; MBHEAD *txfhdl; UBYTE *out; UBYTE register tmp; l2flp = &txl2fl[kp->kisslinkport]; /* Nur senden wenn letztes Frame raus ist */ if (!rs232_out_status(kp->dev)) { portpar[kp->kisslinkport].reset_port = commandflag[kp->kisslinkport] = testflag[kp->kisslinkport] = FALSE; if (kick[kp->kisslinkport]) { ulink((LEHEAD *)(txfhdl = (MBHEAD *) l2flp->head));/*Zeiger holen*/ TX_BEG(); /* Sender bereit */ TX_CHAR(FEND); /* neues Frame */ /* das Frame nach der SMACK-Methode einpacken und senden */ if (kp->use_crc == SMACK) { crc = 0; TX_CHAR(smack_crc(&crc, 0x80)); while (txfhdl->mbgc < txfhdl->mbpc) /* solange Daten vorhanden sind */ slip_encode(smack_crc(&crc, getchr(txfhdl))); slip_encode(crc); slip_encode(crc >> 8); } else /* das Frame nach der RMNC-Methode einpacken und senden */ if (kp->use_crc == RMNC) { crc = 0xFFFF; TX_CHAR(rmnc_crc(&crc, 0x20)); while (txfhdl->mbgc < txfhdl->mbpc) /* solange Daten vorhanden sind */ slip_encode(rmnc_crc(&crc, getchr(txfhdl))); slip_encode(crc >> 8); slip_encode(crc); } else { /* das Frame ohne CRC einpacken und senden */ TX_CHAR(0x00); while (txfhdl->mbgc < txfhdl->mbpc) /* solange Daten vorhanden sind */ slip_encode(getchr(txfhdl)); } TX_CHAR(FEND); /* Frame bendet */ rs232_write(kp->dev, blkbuf, out); /* und an die RS232 damit */ relink((LEHEAD *)txfhdl, /* als gesendet betrachten und in */ (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ kick[kp->kisslinkport] = ((LHEAD *)l2flp->head != l2flp); } } } /************************************************************************/ /* kisslink_get_frame() - Frame(s) aus Ringbuffer holen */ /*----------------------------------------------------------------------*/ static void kisslink_get_frame(__kiss_struct *kp) { UBYTE ch, *in = blkbuf; int state; int n; int use_crc; UWORD rx_crc; MBHEAD *rxfhd; /* mit if() abzubrechen ist quatsch, while (n) ist auch nurn if() */ /* ich hab mir angeschaut was mein compiler macht, keine Vorteile */ if ((n = rs232_read(kp->dev, blkbuf, BLOCKSIZE))==0) return; /* das war allerdings bevor ich state,rxfhd,rx_crc und use_crc rein- */ /* genommen habe ... sri odo */ state = kp->rx_state; rxfhd = kp->rxfhd; rx_crc = kp->crc; use_crc = kp->use_crc; while (n) /* Zeichen auswerten */ { ch = *in++; /* Zeichen holen */ n--; switch (state) /* ueber Status verzweigen */ { case WFEND: /* Frame Anfang erwartet */ if (ch == FEND) state = GTYPE; /* Frameanfang entdeckt */ continue; case GTYPE: if (ch != FEND) /* zuletzt FEND bekommen */ { if ((ch & 0x0F) > 0) { state = WFEND; /* Kommandos */ continue; } state = GFRAM; /* Daten */ if (rxfhd) /* wenn Frame aktiv, auf den Muell */ relink((LEHEAD *)rxfhd, (LEHEAD *)trfl.tail); (rxfhd = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2port = kp->kisslinkport; switch (use_crc = kp->use_crc) { case SMACK : rx_crc = 0; smack_crc(&rx_crc, 0x80); break; case RMNC : rx_crc = 0xFFFF; rmnc_crc(&rx_crc, 0x20); break; } } continue; case GFRAM: /* vom TNC holen */ switch (ch) { case FEND: state = WFEND; /* Frame-Ende = Anfang fuer nextes */ if (rxfhd) { /* nur wenn ein Frame aktiv */ switch (use_crc) { case SMACK : if (rxfhd->mbpc > 2) rxfhd->mbpc -= 2; if (rx_crc) { kp->crcerrors++; continue; /* wirklich Fehler */ } relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); rxfhd = NULL; /* kein RX-Frame aktiv */ break; case RMNC : if (rxfhd->mbpc > 2) rxfhd->mbpc -= 2; if ((rx_crc & 0xffff) != 0x7070) { kp->crcerrors++; continue; /* wirklich Fehler */ } default: relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); rxfhd = NULL; /* kein RX-Frame aktiv */ } } continue; /* Das war's.. fertig! */ case FESC: state++; /* FESC wird zu FESC-TFESC */ continue; /* Rueckwandlung.. */ } break; case GFRMT: switch (ch) /* TFEND/TFESC-Rueckwandlung */ { case TFEND: ch = FEND; break; case TFESC: ch = FESC; break; default: kp->sliperrors++; state = WFEND; continue; } state--; break; } /* switch(state) */ switch (use_crc) { case SMACK : smack_crc(&rx_crc, ch); break; case RMNC : rmnc_crc(&rx_crc, ch); break; } putchr(ch, rxfhd); /* Zeichen in Frame */ if (rxfhd->mbpc > L2MFLEN) /* Framelaengencheck */ state = WFEND; } /* solange Zeichen in der RS232 */ kp->rx_state = state; kp->rxfhd = rxfhd; kp->crc = rx_crc; } /************************************************************************/ /* Level1 RX/TX fuer KISSLINK */ /* wird staendig in der main() Hauptschleife aufgerufen. */ /************************************************************************/ static void kisslink(void) { int kiss; __kiss_struct *kp; for (kiss = 0, kp = kissdev; kiss < MAXKISS; kiss++, kp++) { if ((kp->kisslinkport != -1) && kp->active) { kisslink_get_frame(kp); kisslink_put_frame(kp); } } } static WORD kiss_dcd(PORTINFO *port) { __kiss_struct *kp; int state = 0; kp = &kissdev[port->minor]; if (rs232_out_status(kp->dev)) state |= PTTFLAG; if (kp->rx_state > 1) state |= DCDFLAG; return(state); } static void kiss_ctl(int req, int port) { __kiss_struct *kp; int minor; minor = portpar[port].minor; kp = &kissdev[minor]; switch (req) { case L1CCMD : case L1CRES : portpar[kp->kisslinkport].speed = setbaud(kp->dev, portpar[kp->kisslinkport].speed); /* macht setbaud automatisch */ #ifndef MC68K setstopbits(kp->dev,1); #else /* statttdessen crc-mode vorbereiten */ setkissmode(port); #endif break; } default_l1ctl(req, port); /* Flags loeschen */ }; #define MINOR_SMACK_FLAG (SMACK << 8) #define MINOR_RMNC_FLAG (RMNC << 8) #define MINOR_MASK (0xFF) static int kiss_istome(int major, char *devname) { char name[21], *cp; int minor = 0; strncpy(name, devname, 20); /* Minor bestimmen und abschneiden */ name[20] = 0; for (cp = name; isalpha(*cp); cp++); /* Zahl suchen */ if (isdigit(*cp)) minor = atoi(cp); *cp = 0; /* kann nicht schaden */ if (minor < 1 || minor > MAXKISS) return(NO_MINOR); /* falscher Geraetekanal (minor) */ minor--; if (strnicmp(name, "KISS", strlen(name))==0) return(minor); else if (strnicmp(name, "SMACK", strlen(name))==0) return(minor|MINOR_SMACK_FLAG); else if (strnicmp(name, "RKISS", strlen(name))==0) return(minor|MINOR_RMNC_FLAG); return(NO_MINOR); } static int kiss_attach(int port, int minor, BOOLEAN check_only) { __kiss_struct *kp; int use_crc; use_crc = (minor >> 8); minor &= MINOR_MASK; kp = &kissdev[minor]; if (kp->active) { /* Geraetekanal bereit? */ if (kp->kisslinkport == -1) { if (!check_only) { kp->kisslinkport = port; kp->use_crc = use_crc; portpar[port].minor = minor; clear_rs232(minor); } return(1); } if (kp->kisslinkport == port) return(1); } return(0); /* versuchte Doppeleintragung */ } static int kiss_detach(int port) { int kiss = portpar[port].minor; kissdev[kiss].kisslinkport = -1; return(1); } static void kiss_info(int what, int port, MBHEAD *mbp) { char *name[] = {"KISS", "SMACK", "RKISS"}; /* SMACK=1, RMNC=2 */ int minor, cnt; __kiss_struct *kp; minor = portpar[port].minor; switch (what) { case HW_INF_IDENT : case HW_INF_INFO : putprintf(mbp, "%s%u", name[kissdev[minor].use_crc], minor+1); break; case HW_INF_STAT : for (minor = cnt = 0, kp = kissdev; minor < MAXKISS; minor++, kp++) if (kp->kisslinkport != -1) { if (cnt++ == 0) putstr("\rKISS-Statistics:\r\r", mbp); putprintf(mbp, " KISS%u RxCRC: %5u RxErr: %5u\r", minor+1, kp->crcerrors, kp->sliperrors); } break; case HW_INF_CLEAR : /* durchfallen */ default: default_l1info(what, port, mbp); } } static int register_kiss(void) { MAJOR *m; if (kiss_init()) { m = register_major(); m->name = "KISS/SMACK/RKISS"; m->istome = kiss_istome; m->exit = kiss_exit; m->handle = kisslink; m->ctl = kiss_ctl; m->dcd = kiss_dcd; m->attach = kiss_attach; m->detach = kiss_detach; m->info = kiss_info; return(kiss_major = num_major); } return(0); } /*----------------------------------------------------------------------*/ /* End of os/go32/kiss.c */