Category : Communication (modem) tools and utilities
Archive   : JMODM311.ZIP
Filename : JMODEM_E.C

 
Output of file : JMODEM_E.C contained in archive : JMODM311.ZIP
/****************************************************************************/
/* FILE JMODEM_E.C */
/* Created 11-JAN-1990 Richard B. Johnson */
/* 405 Broughton Drive */
/* Beverly, Massachusetts 01915 */
/* BBS (508) 922-3166 */
/* open_chan(); */
/* close_chan(); */
/* read_chan(); */
/* write_chan(); */
/* Communications I/O procedures */
/* These procedures will have to be replaced for JMODEM to execute on */
/* a system other than a MS_DOS computer. They are VERY hardware-specific. */
/* These procedures are grouped so that they can be replaced as a unit. */
/* You must replace the following: */
/* (1) OPEN a communications channel. */
/* (2) CLOSE the opened channel. */
/* (3) READ [variable] bytes from the channel. */
/* (4) WRITE [variable] bytes to the channel. */
/* */
/* When attempting to READ bytes, some sort of time-out must be provided */
/* within the routine to prevent a "wait-forever" syndrome. */
/* */
/* VAX/VMS, QIO routines are ideal! */
/* */
/****************************************************************************/
#include /* For FILE structure */
#include /* For _inp() and _outp() */
#include /* For _enable() and _disable() */
#include "jmodem.h" /* JMODEM equates */
#include "uart.h" /* 8250 UART equates */
#if defined (TURBOC)
#include
#define _enable enable
#define _disable disable
#define _dos_setvect setvect
#define _dos_getvect getvect
#else
#include /* _memcpy(); */
#endif
/****************************************************************************/
/* Structures and templates */
/****************************************************************************/
typedef struct {
word base; /* Base port address */
word mask; /* Interrupt controller mask */
word int_num; /* Interrupt number */
} PORTS;

PORTS port_pars[] = {
{
0x3F8 , /* Base port address COM1 */
0xEF , /* IRQ4 11101111B COM1 */
0x0C , /* Interrupt number */
} ,
{
0x2F8 , /* Base port address COM2 */
0xF7 , /* IRQ3 11110111B COM2 */
0x0B , /* Interrupt number */
} ,
{
0x3E8 , /* Base port address COM3 */
0xEF , /* IRQ4 11101111B COM3 */
0x0C , /* Interrupt number */
} ,
{
0x2E8 , /* Base port address COM4 */
0xF7 , /* IRQ3 11110111B COM4 */
0x0B , /* Interrupt number */
}
};
/****************************************************************************/
/* Global allocation */
/****************************************************************************/
byte *write_ptr; /* Interrupt buffer */
byte *read_ptr; /* Interrupt buffer */
byte *buff_limit; /* End of interrupt buffer */
word port; /* Port number */
word old_mask; /* Old interrupt control mask */
word old_ier; /* Old interrupt enable regis */
word old_stat; /* Modem status for flow-contr */
word carrier; /* Carrier detect */
word timer; /* Global timer */
word hardware_port; /* Physical port */
/****************************************************************************/
/* Function prototypes */
/****************************************************************************/
void interrupt far fatal_abort(void); /* Abort vector */
void interrupt far com_int(void); /* Interrupt service routine */
void interrupt far tim_int(void); /* Timer interrupt */
void (interrupt far *old_tim)(); /* Pointer to old timer intr. */
void (interrupt far *old_com)(); /* Pointer to old commu intr. */
void (interrupt far *old_brk)(); /* Pointer to old break key. */
/****************************************************************************/
/* Open the communications channel */
/* */
/* Under MS-DOS this involves saving the com-port vector, interrupt */
/* controller mask, and the user-tick timer vector. */
/* New vectors and masks and patched for the communications interrupt */
/* service routine and the local timer. These vectors will be restored */
/* within the CLOSE channel routine. */
/* */
/****************************************************************************/
word open_chan (word user_port) /* Port offset ( 1-4 ) */
{
short i;
buff_limit = int_buffer + DAT_LEN-1; /* Set up buffer end pointer */
flush(); /* Initialize the interrupt buffer */
if (user_port > 4) /* If absolute port and IRQ */
{
port_pars[0].base =
(user_port & 0x0FFF); /* Extract absolute port */
port_pars[0].int_num = /* Use as a temporary variable */
(user_port >> 12); /* Extract the IRQ number */
port_pars[0].mask = /* Create the controller mask */
((~(0x01 << port_pars[0].int_num)) & 0xFF);
port_pars[0].int_num += 0x08; /* IRQ number to ABS interrupt */
user_port = 1; /* For following instruction */
}
user_port--; /* Convert to an offset */
hardware_port =
port_pars[user_port].base; /* Set hardware port */
old_ier = inp(hardware_port +IER); /* Get interrupt enable regis */
old_brk = _dos_getvect(0x1B); /* Get old break key vector */
old_mask = inp(0x21); /* Save old interrupt mask */
old_tim = _dos_getvect(0x1C); /* Get old DOS timer-tick vector */
old_com = _dos_getvect(
port_pars[user_port].int_num); /* Get old communications vector */
_dos_setvect(0x1B,fatal_abort); /* Set fatal abort vector (1) */
_dos_setvect(0x23,fatal_abort); /* Set fatal abort vector (2) */
_dos_setvect(0x1C,tim_int); /* Set new timer interrupt */
_dos_setvect(
port_pars[user_port].int_num, /* Set new communications vector */
com_int);
outp(0x21,old_mask &
port_pars[user_port].mask); /* Set interrupt enable mask */
outp(hardware_port+MCR, MOD_ENA); /* Turn on DTR, RTS, IRQ enable */
outp(hardware_port+IER, IER_ERBFI); /* Enable received data available */
for (i=0; i<8; i++) /* Edge-triggering, read the ports */
inp(hardware_port + i); /* Port to clear */
outp(0x20,0x20); /* Reset the hardware controller */
timer=9; /* 1/2 second wait */
while (timer); /* Wait 1/2 second */
flush(); /* Clear interrupt buffer again */
i = inp(hardware_port+MSR); /* Get current modem status */
old_stat = i & MSR_CHK; /* Get current modem control */
carrier = i & MSR_RLSD; /* Get any modem carrier */
return JM_NRM;
}
/****************************************************************************/
/* Close the communications channel */
/* */
/* Under MS-DOS this involves restoring the interrupt vectors and */
/* controller mask that was saved during the OPEN routine. */
/* */
/****************************************************************************/
word close_chan (word user_port)
{
if (user_port > 4) user_port = 1; /* Absolute port address */
user_port--; /* Convert to an offset */
outp(hardware_port+IER,old_ier); /* Set old interrupt enable */
outp(0x21,old_mask); /* Restore old interrupt mask */
_dos_setvect(
port_pars[user_port].int_num, /* Set old communications vector */
old_com);
_dos_setvect(0x1C,old_tim); /* Set old timer interrupt */
_dos_setvect(0x1B,old_brk); /* Set old break interrupt */
return JM_NRM;
}
/****************************************************************************/
/* Read from the communications channel */
/* */
/* This involves transferring data from the interrupt buffer and */
/* maintaining the interrupt buffer pointers. A timeout is established. */
/* */
/****************************************************************************/
word read_chan (word bytes, /* Bytes requested */
register byte *buffer) /* Pointer to user's buffer */
{
word count; /* Byte count */
word avail; /* Bytes available */
timer = TIMOUT; /* Set initial timeout value */
count = bytes; /* Set byte-count */

while (count && timer) /* If byte request or no timeout */
{
avail = write_ptr - read_ptr; /* Bytes available */
if (avail) /* If bytes available */
{
if (avail > count) /* If more bytes than we need */
avail = count; /* Take only what we need */
memcpy (buffer , /* User's buffer */
read_ptr , /* Interrupt buffer pointer */
avail) ; /* Copy to user's buffer */
count -= avail; /* Update count */
read_ptr +=avail; /* Update read pointer */
buffer +=avail; /* Update write pointer */
timer = TIMOUT; /* Set new timer value */
}
_disable(); /* Clear interrupts */
if (read_ptr == write_ptr) /* If no bytes available */
read_ptr = write_ptr /* Initialize the interrupt buffer */
= int_buffer;
_enable(); /* Enable interrupts */
}
return(bytes - count); /* Actual characters received */
}
/****************************************************************************/
/* Flush the interrupt buffer */
/****************************************************************************/
void flush()
{
_disable();
read_ptr = write_ptr = int_buffer; /* Initialize the interrupt buffer */
_enable();
}
/****************************************************************************/
/* Communications transmit routine */
/* Write 'bytes' bytes from buffer to the UART. Don't return until done */
/* unless the carrier failed or the hardware broke. */
/****************************************************************************/
word write_chan (word bytes, /* Bytes to send */
register byte *buffer) /* Pointer to the buffer */
{
word status;
byte *sav_sta;
byte *old_sta;

sav_sta = old_sta = syst.s_sta; /* Save current status */
timer = TIMOUT;
while ((bytes && timer) && !user_abort ) /* Bytes, no abort, no timout */
{
while (
( status = /* Get modem status */
( inp (hardware_port+MSR) /* from modem status register */
& MSR_CHK ) /* Check CTS and DSR only */
) != old_stat) /* If not the same as before */
{ /* Flow control loop */
if ( (status & MSR_RLSD ) /* ...check modem carrier */
!= carrier) /* ... if not same as before */
{
user_abort = 0x0FFFF; /* Set the abort flag */
return JM_ABT; /* ... and get out */
}
syst.s_sta = flow; /* Set flow-control status */
if ( syst.s_sta != old_sta ) /* If we haven't already */
{
screen (SCR_FLG,&syst); /* Show flow-control status */
old_sta = syst.s_sta; /* Flag that we did it */
}
}
syst.s_sta = sav_sta; /* Set previous status */
if ( syst.s_sta != old_sta )
{
screen (SCR_FLG,&syst); /* Show previous status */
old_sta = syst.s_sta; /* Flag that we did it */
}
status = inp(hardware_port+LSR); /* Get line-status */
if (status & LSR_THRE) /* If TX holding reg empty */
{
outp(hardware_port, *buffer++); /* Send the byte */
bytes--; /* Bump the byte-count */
timer = TIMOUT; /* Set new timer-value */
}
}
return JM_NRM;
}

/******* The following interrupt service routines are in JMODEM_G.ASM *******/
#ifdef DOIT_IN_C
/****************************************************************************/
/* Communications adapter hardware interrupt */
/* This is very simple because we interrupt on receive only. Since we */
/* must wait until the entire block has been received and checked be- */
/* for doing anything else, the transmitter is polled. */
/* */
/****************************************************************************/
void interrupt far com_int()
{
*write_ptr = (byte)
inp(hardware_port); /* Put byte in buffer */
outp(0x20,0x20); /* Reset hardware controller */
if (write_ptr < buff_limit) /* Check buffer for overflow */
write_ptr++; /* Bump pointer if room */
}
/****************************************************************************/
/* Timer interrupt */
/* A WORD (timer) gets decremented every timer-tick if it is not already */
/* zero. This is used to set time-out values in the communication pro- */
/* cedures so that a "wait-forever" can't occur. */
/* */
/****************************************************************************/
void interrupt far tim_int()
{
if (timer) /* If NZ */
timer--; /* Bump the timer */
outp(0x20,0x20); /* Reset the hardware controller */
_enable(); /* Allow network interrupts */
#if !defined (TURBOC)
_chain_intr(old_tim); /* Go to old timer-tick routine */
#endif
}
#endif
/****************************************************************************/

/****************************************************************************/
/* A B O R T trap */
/* Control-C and control-break vectors are set to point here so that */
/* a user-break harmlessly sets a flag so that interrupt vectors may */
/* properly restored upon program exit. */
/* */
/****************************************************************************/
void interrupt far fatal_abort()
{
user_abort = 0xFFFF; /* Set abort flag */
timer = 0; /* Provoke timout */
}
/****************************************************************************/
/******************** E N D O F M O D U L E *****************************/


  3 Responses to “Category : Communication (modem) tools and utilities
Archive   : JMODM311.ZIP
Filename : JMODEM_E.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/