home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************/
- /* modem.c */
- /* */
- /* modem code for Citadel bulletin board system */
- /* NB: this code is rather machine-dependent: it will typically */
- /* need some twiddling for each new installation. */
- /* 82Nov05 CrT */
- /************************************************************************/
-
- /************************************************************************/
- /* history */
- /* */
- /* 83Mar01 CrT FastIn() ignores LFs etc -- CRLF folks won't be trapped.*/
- /* 83Feb25 CrT Possible fix for backspace-in-message-entry problem. */
- /* 83Feb18 CrT fastIn() upload mode cutting in on people. Fixed. */
- /* 82Dec16 dvm modemInit revised for FDC-1, with kludge for use with */
- /* Big Board development system */
- /* 82Dec06 CrT 2.00 release. */
- /* 82Nov15 CrT readfile() & sendfile() borrowed from TelEdit.c */
- /* 82Nov05 CrT Individual history file established */
- /************************************************************************/
-
- #include "b:210ctdl.h"
-
- /************************************************************************/
- /* Contents */
- /* */
- /* BBSCharReady() returns true if user input is ready */
- /* # fastIn() kludge code compiling other stuff inline*/
- /* getCh() bottom-level console-input filter */
- /* # getMod() bottom-level modem-input filter */
- /* interpret() interprets a configuration routine */
- /* KBReady() returns TRUE if a console char is ready */
- /* getCh() returns a console char */
- /* iChar() top-level user-input function */
- /* interact() chat mode */
- /* modIn() returns a user char */
- /* modemInit() top-level initialize-all-modem-stuff */
- /* mOReady() returns true if modem can accept a char */
- /* oChar() top-level user-output function */
- /* # outMod() bottom-level modem output */
- /* pause() pauses for N/100 seconds */
- /* putChar() */
- /* recieve() read modem char or time out */
- /* readFile() accept a file using WC protocol */
- /* ringSysop() signal chat-mode request */
- /* sendWCChar() send file with WC-protocol handshaking */
- /* */
- /* # == routines you should certainly check when porting system */
- /************************************************************************/
-
- /************************************************************************/
- /* The principal dependencies: */
- /* */
- /* iChar modIn outMod */
- /* modIn getMod getCh mIReady kBReady outMod carrDetect */
- /* getMod */
- /* getCh */
- /* mIReady */
- /* kBReady */
- /* carrDetect */
- /* */
- /* oChar outMod */
- /* outMod mOReady */
- /************************************************************************/
-
-
- /************************************************************************/
- /* BBSCharReady() returns TRUE if char is available from user */
- /* NB: user may be on modem, or may be sysop in CONSOLE mode */
- /************************************************************************/
- char BBSCharReady()
- {
- char KBReady();
-
- return ((haveCarrier && interpret(pMIReady))
- || (whichIO==CONSOLE && KBReady() )
- );
- }
-
- /************************************************************************/
- /* fastIn() is a special kludge to read in text from the modem */
- /* as quickly as possible, to allow message upload without */
- /* handshaking. Hence we hand-compile some other routines inline */
- /* Called only from getText(), when whichIO==MODEM. */
- /* Externals: see below */
- /* */
- /* This code is probably overkill for 300 baud, but it may handle */
- /* 1200 baud as well. */
- /* */
- /* code being speed-optimized would normally be: */
- /* */
- /* while ( */
- /* !( (c=iChar()) == NEWLINE && buf[i-1] == NEWLINE ) */
- /* && i < lim */
- /* && (haveCarrier || whichIO == CONSOLE) */
- /* ) { */
- /* if (c != BACKSPACE) buf[i++] = c; */
- /* else { */
- /* / handle deletes: / */
- /* oChar(' '); */
- /* oChar(BACKSPACE); */
- /* if (i>0 && buf[i-1] != NEWLINE) i--; */
- /* else oChar(BELL); */
- /* } */
- /* } */
- /************************************************************************/
- #define cursor fpc1 /* external char * */
- #define BUFEND fpc2 /* external char * */
- #define tryCount fi1 /* external int */
- #define isFast fi2 /* external int */
- #define ch fc1 /* external char */
- #define lastWasNL fc2 /* external char */
- #define slow fc3 /* external char */
- fastIn(continuing)
- char continuing; /* TRUE if we are continuing a message */
- {
- char cache, notFinished;
- int tryStart, shortTime;
-
- isFast = 0;
-
- tryStart = 500*megaHz;
- shortTime = 480*megaHz;
- cursor = &msgBuf.mbtext[0 ];
- BUFEND = &msgBuf.mbtext[MAXTEXT-1];
-
- if (continuing) while (*cursor) ++cursor; /* find where we were */
-
- notFinished = TRUE;
- lastWasNL = FALSE;
-
- /* put newline at start of buffer to simplify BACKSPACE check: */
- cache = msgBuf.mbtext[-1];
- msgBuf.mbtext[-1] = NEWLINE;
-
- while (notFinished && cursor < BUFEND) {
- tryCount = tryStart; /* try to be waiting for each char */
- while (--tryCount && !interpret(pMIReady));
-
- if (tryCount>shortTime) isFast++;
- else isFast--;
-
- if (!tryCount) {
- /* no modem char -- take break to check other stuff */
- if (KBReady()) {
- if (getCh() == SPECIAL) {
- mprintf("\n system is now in CONSOLE mode.\n ");
- whichIO = CONSOLE;
- notFinished = FALSE;
- setUp(FALSE);
- }
- }
- if (!interpret(pCarrDetect)) {
- modIn(); /* let modIn() announce it etc */
- notFinished = FALSE;
- }
- } else {
- /* time to read modem char: */
- switch (ch = filter[ inp(mData) & 0x7F ]) {
- case NEWLINE:
- if (lastWasNL) {
- notFinished = FALSE;
- } else {
- lastWasNL = TRUE;
-
- *cursor++ = ch;
-
- if (isFast>0 || !termLF) ch = '\r';
- else {
- oChar('\r');
- while (!interpret(pMOReady)); /* for outp() */
- }
- }
- isFast = 0; /* figure speed of each line independently */
- break;
- case BACKSPACE:
- /* people don't upload backspaces -- one hopes! -- */
- /* so we don't worry about speed so much here: */
- if (*--cursor == NEWLINE) {
- /* trying to erase to previous line -- disallow */
- /* because we have no upline: */
- ch = BELL;
- cursor++;
- } else {
- oChar(BACKSPACE);
- oChar(' '); /* erase last char */
- }
- while (!interpret(pMOReady)); /* for outp() */
- break;
- case '\0':
- /* ignore unwanted chars completely: */
- break;
- default:
- lastWasNL = FALSE;
- *cursor++ = ch;
- break;
- }
- /* echo to console--expendable but nice: */
- if (thisRoom!=1 || whichIO==CONSOLE) putCh(ch);
- while (!interpret(pMOReady)); /* for outp() */
- outp(mData, ch); /* (was:)assume port is ready by now */
- }
- }
- *cursor = '\0'; /* tie off message */
-
- if (cursor == BUFEND) {
- mprintf("\n \7BUFFER OVERFLOW\n "); return;
- }
-
- msgBuf.mbtext[-1] = cache; /* return borrowed space */
- }
-
-
- /************************************************************************/
- /* getCh() reads a console char */
- /* In CONSOLE mode, CRs are changed to newlines */
- /* Rubouts are changed to backspaces */
- /* Returns: resulting char */
- /************************************************************************/
- char getCh()
- {
- char c;
- char bios();
-
- return bios(3);
- }
-
- /************************************************************************/
- /* getMod() is bottom-level modem-input routine */
- /* kills any parity bit */
- /* rubout -> backspace */
- /* CR -> newline */
- /* other nonprinting chars -> blank */
- /* Returns: result */
- /************************************************************************/
- char getMod() {
- char inp();
-
- return inp(mData) & 0x7F;
- }
-
- /************************************************************************/
- /* iChar() is the top-level user-input function -- this is the */
- /* function the rest of Citadel uses to obtain user input */
- /************************************************************************/
- char iChar() {
- char modIn();
- char c;
-
- if (justLostCarrier) return 0; /* ugly patch */
-
- c = filter[modIn()];
-
- switch (echo) {
- case BOTH:
- if (haveCarrier) {
- if (c == '\n') doCR();
- else outMod(c);
- }
- if (thisRoom!=1 || whichIO==CONSOLE) putCh(c);
- break;
- case CALLER:
- if (whichIO == MODEM) {
- if (c == '\n') doCR();
- else outMod(c);
- } else {
- putCh(c);
- }
- break;
- }
- return(c);
- }
-
- /************************************************************************/
- /* interact() allows the sysop to interact directly with */
- /* whatever is on the modem. dvm 9-82 */
- /************************************************************************/
- interact() {
- char c, lineEcho, lineFeeds, localEcho;
- char getMod(), getCh(), interpret();
-
- printf(" Direct modem-interaction mode\n");
- lineEcho = getYesNo("Echo to modem" );
- localEcho = getYesNo("Echo keyboard" );
- lineFeeds = getYesNo("Echo CR as CRLF" );
- printf("<ESC> to exit\n");
-
- /* incredibly ugly code. Rethink sometime: */
- while (c!=SPECIAL) {
- c = 0;
-
- if (c=interpret(pMIReady) ) {
- c = inp(mData) & 0x7F;
- if (c != '\r') c = filter[c];
- if (c != '\r') {
- if (lineEcho) outMod(c);
- putCh(c);
- } else {
- if (!lineFeeds) {
- if (lineEcho) outMod('\r');
- putCh('\r');
- } else {
- if (lineEcho) {
- outMod('\r');
- outMod('\n');
- }
- putCh('\r');
- putCh('\n');
- }
- }
- }
- if (KBReady()) {
- c = filter[getCh()];
- if (c != NEWLINE) {
- if (localEcho) putCh(c);
- outMod(c);
- } else {
- if (!lineFeeds) {
- if (localEcho) putCh('\r');
- outMod('\r');
- } else {
- if (lineEcho) {
- putCh('\r');
- putCh('\n');
- }
- outMod('\r');
- outMod('\n');
- }
- }
- }
- }
- }
-
- /************************************************************************/
- /* interpret() interprets a configuration routine */
- /* Returns byte value computed */
- /************************************************************************/
- char interpret(instr)
- union {
- char **pp;
- int *pi;
- char *pc;
- } instr;
- {
- char inp();
- char accum; /* our sole accumulator */
- char *prompt;
- int lowLim, topLim;
-
- while (TRUE) {
- switch (*instr.pc++) {
- case RET: return accum; break;
- case ANDI: accum &= *instr.pc++; break;
- case INP: accum = inp(*instr.pc++); break;
- case XORI: accum ^= *instr.pc++; break;
-
- case LOAD: accum = *(*instr.pp++); break;
- case LOADI: accum = *instr.pc++; break;
- case LOADX: accum = scratch[*instr.pc++]; break;
- case ORI: accum |= *instr.pc++; break;
- case OUTP: outp(*instr.pc++, accum); break;
- case PAUSEI: pause(*instr.pc++); break;
- case STORE: *(*instr.pp++) = accum; break;
- case STOREX: scratch[*instr.pc++] = accum; break;
- case OPRNUMBER:
- prompt = instr.pc;
- while(*instr.pc++); /* step over prompt */
- lowLim = *instr.pc++;
- topLim = *instr.pc++;
- accum = getNumber(prompt, lowLim, topLim);
- break;
- case OUTSTRING:
- while(*instr.pc) {
- pause(5); /* SmartModem can't handle 300 baud */
- outMod(*instr.pc++); /* output string */
- }
- instr.pc++; /* skip null */
- break;
- default:
- printf("intrp-no opcod%d", *(instr.pc-1));
- break;
- }
- }
- }
-
- /************************************************************************/
- /* KBReady() returns TRUE if a console char is ready */
- /************************************************************************/
- char KBReady()
- {
- char bios();
-
- return bios(2);
- }
-
- /************************************************************************/
- /* modemInit() is responsible for all modem-related initialization */
- /* at system startup */
- /* Globals modified: haveCarrier visibleMode */
- /* whichIO modStat */
- /* exitToCpm justLostCarrier */
- /* modified 82Dec10 to set FDC-1 SIO-B clock speed at */
- /* 300 baud -dvm */
- /************************************************************************/
- modemInit() {
- char c;
-
- newCarrier = FALSE;
- visibleMode = FALSE;
- exitToCpm = FALSE;
- justLostCarrier = FALSE;
-
- whichIO = CONSOLE;
-
- #ifdef FDC-1
- #define MONBASE 0xF800
- #define STSSP MONBASE+0x045
- call(STSSP, 0, 0, 0x0B, 0x05); /* 300 baud on SIO-B */
- #endif
-
- #ifdef VFC-2
- /* dummy call (to CONSTAT) to make code size equal for both systems */
- call(0xF006, 0, 0, 0x0B, 0x05);
- #endif
-
- if (!rcpm) {
- interpret(pInitPort);
- interpret(pHangUp);
- }
- haveCarrier = modStat = interpret(pCarrDetect);
- }
-
- /************************************************************************/
- /* modIn() toplevel modem-input function */
- /* If DCD status has changed since the last access, reports */
- /* carrier present or absent and sets flags as appropriate. */
- /* In case of a carrier loss, waits 20 ticks and rechecks */
- /* carrier to make sure it was not a temporary glitch. */
- /* If carrier is newly received, returns newCarrier = TRUE; if */
- /* carrier lost returns 0. If carrier is present and state */
- /* has not changed, gets a character if present and */
- /* returns it. If a character is typed at the console, */
- /* checks to see if it is keyboard interrupt character. If */
- /* so, prints short-form console menu and awaits next */
- /* keyboard character. */
- /* Globals modified: carrierDetect modStat haveCarrier */
- /* justLostCarrier whichIO exitToCpm */
- /* visibleMode */
- /* Returns: modem or console input character, */
- /* or above special values */
- /************************************************************************/
- char modIn() {
- char getMod(), getCh(), interpret(), KBReady();
- char c;
- unsigned hi, lo;
-
- hi = (HITIMEOUT * megaHz);
- lo = 0xFF;
- while (TRUE) {
- if ((whichIO==MODEM) && (c=interpret(pCarrDetect)) != modStat) {
- /* carrier changed */
- if (c) { /* carrier present */
- printf("Carr-detect\n");
- haveCarrier = TRUE;
- pause(200);
- modStat = c;
- newCarrier = TRUE;
- return(0);
- } else {
- pause(200); /* confirm it's not a glitch */
- if (!interpret(pCarrDetect)) { /* check again */
- printf("Carr-loss\n");
-
- haveCarrier = FALSE;
- modStat = FALSE;
- justLostCarrier = TRUE;
-
- /* while(interpret(pMIReady)) getMod(); eat garbage */
-
- return(0);
- }
- }
- }
-
- if (interpret(pMIReady)) {
- if (haveCarrier) {
- c = getMod();
- if (whichIO == MODEM) return c;
- }
- }
-
- if (KBReady()) {
- c = getCh();
- if (whichIO == CONSOLE) return(c);
- else {
- if (c == SPECIAL) {
- printf("CONSOLE mode\n ");
- whichIO = CONSOLE;
- setUp(FALSE);
- return 0;
- }
- }
- }
-
- /* check for no input. (Short-circuit evaluation, remember!) */
- if (whichIO==MODEM && haveCarrier && !--lo && !--hi) {
- mprintf("Sleeping? Call again :-)");
- interpret(pHangUp);
- }
- }
- }
-
- /************************************************************************/
- /* oChar() is the top-level user-output function */
- /* sends to modem port and console both */
- /* does conversion to upper-case etc as necessary */
- /* in "debug" mode, converts control chars to uppercase letters */
- /* Globals modified: prevChar */
- /************************************************************************/
- oChar(c)
- char c;
- {
- prevChar = c; /* for end-of-paragraph code */
- if (outFlag) return; /* s(kip) mode */
-
- if (termUpper) c = toupper(c);
- if (debug) c = visible(c);
- if (c == NEWLINE) c = ' '; /* doCR() handles real newlines */
-
- /* show on console */
- if (whichIO==CONSOLE || (thisRoom!=1 && echo!=CALLER)) putCh(c);
-
- if (haveCarrier) {
- if (!usingWCprotocol) {
- outMod(c); /* show on modem */
- } else {
- sendWCChar(c);
- }
- } else {
- if (usingWCprotocol) {
- sendWCChar(c);
- }
- }
- }
-
-
- /************************************************************************/
- /* outMod stuffs a char out the modem port */
- /************************************************************************/
- outMod(c)
- char c;
- {
- while(!interpret(pMOReady));
- outp(mData, c);
- }
-
- /************************************************************************/
- /* pause() busy-waits N/100 seconds */
- /************************************************************************/
- pause(i)
- int i;
- {
- int j;
-
- #define SECONDSFACTOR 55
- for (; i; i--) {
- for (j=(SECONDSFACTOR*megaHz); j; j--);
- }
- }
-
- /************************************************************************/
- /* putChar() */
- /************************************************************************/
- putChar(c)
- char c;
- {
- if (thisRoom!=1 || whichIO==CONSOLE) putCh(c);
- }
-
- /************************************************************************/
- /* receive() gets a modem character, or times out ... */
- /* Returns: char on success else ERROR */
- /************************************************************************/
- int receive(seconds)
- int seconds;
- {
- unsigned count;
-
- count = seconds * 100;
- while (!interpret(pMIReady) && --count) pause(1);
- if (count) return inp(mData);
-
- return(ERROR);
- }
-
- /************************************************************************/
- /* readFile() accepts a file from modem using Ward Christensen's */
- /* protocol. (ie, compatable with xModem, modem7, yam, modem2...) */
- /* Returns: TRUE on successful transfer, else FALSE */
- /************************************************************************/
- char readFile(pc)
- int (*pc)(); /* pc will accept the file one character at a time. */
- /* returns ERROR on any problem, and closes the file */
- /* when handed ERROR as an argument. */
- {
- int i, firstchar, lastSector, thisSector, thisComplement, tries;
- int toterr, checksum;
- char badSector, writeError;
- char sectBuf[SECTSIZE];
- char *nextChar;
-
- if (!getYesNo("Ready for WC transfer")) return FALSE;
-
- lastSector = 0;
- tries = 0;
- toterr = 0;
- writeError = FALSE;
-
- while (interpret(pMIReady)) inp(mData); /* clear garbage */
-
- printf("Awaiting #0 (Try=0, Errs=0) \r");
-
- do {
- badSector = FALSE;
-
- /* get synchronized: */
- do {
- firstchar = receive(10);
- } while (
- firstchar != SOH &&
- firstchar != EOT &&
- firstchar != ERROR
- );
-
- if (firstchar == ERROR) badSector = TRUE;
-
- if (firstchar == SOH) {
- /* found StartOfHeader -- read sector# in: */
- thisSector = receive (1);
- thisComplement = receive (1); /* 1's comp of thisSector */
-
- if ((thisSector + thisComplement) != 0xFF) badSector = TRUE;
- else {
- if (thisSect == lastSector +1) {
- /* right sector... let's read it in */
- checksum = 0;
- nextChar = sectBuf;
- for (i=SECTSIZE; i; i--) {
- *nextChar = receive (1);
- checksum = (checksum + *nextChar++) & 0xFF;
- }
-
- if (checksum != receive (1)) badSector = TRUE;
- else {
- tries = 0;
- lastSector = thisSector;
-
- printf("Awaiting #%d (Try=0, Errs=%d) \r",
- thisSector, toterr
- );
-
- if (tries && toterr) putchar('\n');
-
- /* write sector to where-ever: */
- nextChar = sectBuf;
- for (i=SECTSIZE; i; i--) {
- writeError &= (*pc)(*nextChar++) == ERROR;
- }
- if (!writeError) outMod(ACK);
- }
- } else {
- /* not expected sector... */
- if (thisSector != lastSector) badSector = TRUE;
- else {
- /* aha -- sender missed an ACK and resent last: */
- do; while (receive(1) != ERROR); /* eat it */
- outMod(ACK); /* back in synch! */
- }
- }
- } /* end of "if (thisSector + thisComplement == 255" */
- } /* end of "if (firstChar == SOH)" */
-
- if (badSector) {
- tries++;
- if (lastSector != 0) toterr++;
-
- while (receive (1) != ERROR);
- printf("Awaiting #%d (Try=%d, Errs=%d) \r",
- lastSector, tries, toterr
- );
- if (tries && toterr) putchar('\n');
- outMod(NAK);
- }
- } while (
- firstchar != EOT &&
- tries < ERRORMAX &&
- !writeError
- );
-
- if (firstchar != EOT || tries >= ERRORMAX) {
- printf("\naborting\n");
- return FALSE;
- } else {
- outMod(ACK);
- printf("\nfile reception complete.\n");
- return TRUE;
- }
- }
-
- /************************************************************************/
- /* ringSysop() signals a chat mode request. Exits on input from */
- /* modem or keyboard. */
- /************************************************************************/
- ringSysop() {
- char BBSCharReady();
- int i;
-
- mprintf("\n Ringing sysop.\n ");
-
- for (i=0; !BBSCharReady() && !KBReady(); i = ++i % 7) {
- /* play shave-and-a-haircut/two bits... as best we can: */
- oChar(BELL);
- pause(shave[i]);
- }
- if (KBReady()) {
- getCh();
- whichIO = CONSOLE;
- interact();
- whichIO = MODEM;
- }
- }
-
- /************************************************************************/
- /* sendWCChar() sends a file using Ward Christensen's protocol. */
- /* (i.e., compatable with xModem, modem7, modem2, YAM, ... ) */
- /* */
- /* C is an old, tired language which does not support coroutines */
- /* adequately. SendWCChar() has suffered as a result. SendWCChar() */
- /* and the disk-read routines pass control back and forth during */
- /* transmission. Being smaller, sendWCChar() is the one which gets to */
- /* stash all its variables as globals and play at subroutine. The */
- /* ugliest part is finding our place again each time we are called. */
- /* SFRunning is TRUE normally and FALSE while we're finding our place. */
- /* The usual indentation rules are deliberately suppressed in the case */
- /* of SFRunning, to leave the "real" program structure as untouched as */
- /* possible. Ignore the righthand SFRunning stuff and it will look ok. */
- /* Returns: FALSE for another char, TRUE on success, ERROR on abort */
- /************************************************************************/
- int sendWCChar(c)
- int c; /* character to output to MODEM, or ERROR on EOF */
- {
- /* Declared globally: */
- /* char SFcheckSum, SFeofSeen, SFRunning; */
- /* int SFi, SFthisChar, SFthisSector, SFerrorCount, SFtries; */
-
- if (outFlag) return ERROR;
- if (SFRunning) {
- while (interpret(pMIReady)) inp(mData); /* clear garbage off line */
-
- SFtries = 0;
- SFerrorCount= 0;
-
- printf("\n0Sending #0 (Try=0 Errs=0) \n");
-
- while ((receive (10) != NAK) && (SFtries < RETRYMAX)) {
- SFtries++;
- printf("\n1Sending #0 (Try=%d Errs=0) \r", SFtries);
- }
-
- if (SFtries >= RETRYMAX) {
- printf("\nTimed out awaiting initial NAK\n");
- outFlag = OUTSKIP;
- return ERROR;
- }
-
- SFtries = 0;
- SFthisSector= 1;
- SFthisChar = c;
- SFeofSeen = (c == ERROR);
-
- /* send the file: */ } /* SFRunning block */
- while (!SFeofSeen) {
- if (SFRunning) {
- SFtries = 0;
- } /* SFRunning block */
- /* send sector and look for ACK: */
- do {
- if (SFRunning) {
- printf("\n2Sending #%d (Try=%d Errs=%d) \n",
- SFthisSector, SFtries, SFerrorCount
- );
- if (SFtries && SFerrorCount) putchar('\n');
-
- /* send one sector: */
-
- /* maybe read next sector into SFBuf: */
- SFi =SECTSIZE; } /* SFRunning block */
- if (!SFtries) {
- for (; SFRunning ? SFi-- : TRUE; ) {
- if (SFRunning) {
- SFRunning = FALSE; /*
- SFthisChar = nextIn(); */ return FALSE;
- }
- SFthisChar = c;
- SFRunning = TRUE;
-
- if (SFthisChar == ERROR) {
- SFeofSeen = TRUE;
- SFthisChar = CPMEOF;
-
- /* if EOF is first char in block, don't send it: */
- if (SFi == (SECTSIZE-1)) break;
- }
- SFBuf[SFi] = SFthisChar;
- }
- }
-
- if (SFi == (SECTSIZE-1)) {
- /* don't send empty sector just for EOF: */
- break;
- } else {
- /* mail sector out: */
- outMod(SOH );
- outMod( SFthisSector);
- outMod(~SFthisSector);
-
- for (SFi=SECTSIZE, SFcheckSum=0; SFi--; ) {
- SFcheckSum = (SFcheckSum + SFBuf[SFi]) & 0xFF;
- outMod( SFBuf[SFi] );
- }
- outMod(SFcheckSum);
-
- while (interpret(pMIReady)) inp(mData); /* clear off line */
-
- SFtries++;
- SFerrorCount++;
- }
- } while ((receive(10) != ACK) && (SFtries < RETRYMAX));
- SFthisSector++;
- SFerrorCount--;
-
- if (SFtries >= RETRYMAX) break;
- }
-
- /* file sent, or not, as the case may be: */
- if (SFtries >= RETRYMAX) {
- printf("\nNo ACK on sector, aborting\n");
- outFlag = OUTSKIP;
- return ERROR;
- } else {
- /* tell recipient we're all finished: */
- SFtries = 0;
- do {
- outMod(EOT);
- while (interpret(pMIReady)) inp(mData); /* clear off line */
- SFtries++;
- } while ((receive(10) != ACK) && (SFtries < RETRYMAX));
-
- if (SFtries < RETRYMAX) {
- return TRUE;
- } else {
- printf("\nNo ACK on EOT, aborting\n");
- outFlag = OUTSKIP;
- return ERROR;
- }
- }
- }
-