www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1997/07/28/19:18:13

From: e-mail DOT address AT end DOT of DOT text (Mike Collins)
Newsgroups: comp.os.msdos.djgpp
Subject: One PC shadows another (part 2)
Date: 22 Jul 1997 10:34:00 GMT
Organization: Storage Technology Limited
Lines: 391
Message-ID: <5r22ao$3bq@news.network.com>
NNTP-Posting-Host: 129.80.172.76
Mime-Version: 1.0
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp

/* Part-1 of this article contains the description of functions and the 
kb.h file. This part contains the kb.c file, which also contains a simple
demonstration in main(). Read part-1 first.

Hope it helps someone.

Mike Collins.
*/

//==============FILE : KB.C====================//

#include <stdio.h>
#include <go32.h>
#include <dpmi.h>
#include <dos.h>
#include <conio.h>
#include <sys/farptr.h>
#include <unistd.h>
#include "kb.h"

/* declare functions */
void Int09(void);
void Int0C(void);
void Int23(void);
void rs232_send(char ch);
void kb_putch(char ch);
void ResetInt(void);
void SetupInt(void);
char hex(char ch);

_go32_dpmi_seginfo KbInt09, KbOldInt09,
                   KbInt0C, KbOldInt0C,
                   KbInt23, KbOldInt23;

char ScanCode[256];
int CommsMode = STANDALONE;
int diffs;

#define TEST    // remove this line to use these routines with your program
#ifdef TEST
#define FUNC1   '\x3b' /* second character generated by F1 key */
#define FUNC10  '\x44' /* second character generated by F10 key */

main()
{ int i=0;
  char ch = '\0', str[80];
  clrscr();
  SetupInt();
  cprintf("Enter some characters on the MASTER or STANDALONE PC\n\r");
  cprintf("They will be displayed on it and on the SLAVE PC.\n\n\r");
  cprintf("To set this PC to STANDALONE, press ALT-CTL-1 (It defaults to this)\n\r");
  cprintf("To set this PC to MASTER,     press ALT-CTL-M\n\r");
  cprintf("To set this PC to SLAVE,      press ALT-CTL-S\n\n\r");

  while(1)
  { ch = kb_getch();
    if(ch == '\r')
      exit(0);
    else if(ch == '\0')
    { ch = kb_getch();
      if(ch >= FUNC1 && ch <= FUNC10)
         cprintf("<F%d>",ch-0x3a); // Second char of FUNC1 = 0x3b
      // Only the function keys are detected here, but all two-character sets
      // are sent through the serial link (cursor, delete, etc.)
    }
    else
      cprintf("%c", ch);
  }
}
#endif

char save21;

/* Interrupt 9 keyboard service (occurs when a key is pressed) */

void Int09(void)
{ int c;
  c = inportb(0x60);   // Get keyboard scan code from keyboard port
  if (c < 0x80) ScanCode[c] = 1;
  else ScanCode[c & 0x7F] = 0;

  if(ScanCode[0x1d] && ScanCode[0x38])
  { disable();
    { if(ScanCode[MASTER])
        CommsMode = MASTER;
      else if(ScanCode[SLAVE])
        CommsMode = SLAVE;
      else if(ScanCode[STANDALONE])
        CommsMode = STANDALONE;
    }
    enable();
  }
}

/* Interrupt 0C RS232 service (occurs when a character is received) */
void Int0C(void)
{ /* get a character from COM1 and put it into the keyboard buffer */
  char in_ch, gpc;

  disable();

  // Test for error conditions - see file "UART" for signal definitions
  // ScreenSetCursor(24, 60);
  // if(((gpc = inportb(0x3fa)) & 0x06) != 0x04) printf("3fa = %02x", gpc);
  // if(((gpc = inportb(0x3fd)) & 0x9f) != 0x01) printf("3fd = %02x", gpc);
  // if(((gpc = inportb(0x3fe)) & 0x0f) != 0x00) printf("3fe = %02x", gpc);

  in_ch = (char)inportb(0x3f8);
  outportb(0x20, 0x20);

  if((CommsMode == MASTER) && (in_ch & 0x80))
      diffs = in_ch & 0x7f;
  else if(CommsMode == SLAVE)
    kb_putch(in_ch);             //### lock kb_putch + all its variables
  enable();
}

void Int23(void)
{ exit(0);    /* perform normal exit so interrupt vectors can be reset */
}

void rs232_send(char ch)
{ while(!(inportb(0x3fd) & 0x20)); // wait for Tx buffer empty
  outportb(0x3f8, ch);
}

void kb_putch(char ch) // put character/scancode into key buffer
{ int chr_pt, scn_pt;
  static int special = 0;
  // A 'special' character is the first of a two-character set - used for
  // function keys, arrows, etc.
  unsigned int head, tail, base = 0x400;

  head = _farpeekw(_dos_ds, 0x41a);
  tail = _farpeekw(_dos_ds, 0x41c);

  chr_pt = tail+base;
  scn_pt = chr_pt+1;

  if(ch == '\0')
  { special = 1;
    return;
  }
  if(special)
  { special = 0;
    _farpokeb(_dos_ds, chr_pt, 0);
    _farpokeb(_dos_ds, scn_pt, ch);
  }
  else
  { _farpokeb(_dos_ds, chr_pt, ch);
    _farpokeb(_dos_ds, scn_pt, 0);
  }
  tail += 2;
  if(tail > 0x3c)
    tail = 0x1e;
  _farpokew(_dos_ds, 0x41c, tail);

  // SLAVE sends diffs to master
  if(CommsMode == SLAVE)
  { diffs = tail - head;
    if(diffs<0) diffs += 34;
    rs232_send((char)diffs | 0x80);
  }
}

/* Reset interrupt 9 & C vector */

void ResetInt(void)
{ _go32_dpmi_set_protected_mode_interrupt_vector(9, &KbOldInt09);
  _go32_dpmi_set_protected_mode_interrupt_vector(0x23, &KbOldInt23);
  _go32_dpmi_set_protected_mode_interrupt_vector(0x0C, &KbOldInt0C);
  _go32_dpmi_free_iret_wrapper(&KbInt0C);
  _go32_dpmi_free_iret_wrapper(&KbInt23);
  outp(0x20, 0x00); // clean up UART - these values read from a clean system
  outp(0x21, save21);
  outp(0x3f9, 0x00);
  outp(0x3fa, 0x00);
  outp(0x3fb, 0x03);
  outp(0x3fc, 0x00);
}

/* Interrupt 23 Ctrl Break service (gets control for Ctrl Break or Ctrl C) */

void SetupInt(void)
{ static char first_time = '\xff';
  union REGS regs;

  // Check to see if this is first time called
  if(first_time)
  { first_time = 0;

    diffs = 0;
    _go32_dpmi_lock_code(Int09, (unsigned long)(ResetInt - Int09));
    _go32_dpmi_lock_data(ScanCode, sizeof(ScanCode));
    _go32_dpmi_lock_data(&CommsMode, sizeof(CommsMode));
    _go32_dpmi_lock_data(&diffs, sizeof(diffs));

    /* Interrupt 9 keyboard service (occurs when a key is pressed) */
    _go32_dpmi_get_protected_mode_interrupt_vector(0x09, &KbOldInt09);
    KbInt09.pm_offset = (int)Int09;
    KbInt09.pm_selector = _go32_my_cs();

    _go32_dpmi_get_protected_mode_interrupt_vector(0x0C, &KbOldInt0C);
    KbInt0C.pm_offset = (int)Int0C;
    KbInt0C.pm_selector = _go32_my_cs();
    _go32_dpmi_allocate_iret_wrapper(&KbInt0C);

    /* perform normal exit if program interrupted by Ctrl C or Ctrl Break */
    _go32_dpmi_get_protected_mode_interrupt_vector(0x23, &KbOldInt23);
    KbInt23.pm_offset = (int)Int23;
    KbInt23.pm_selector = _go32_my_cs();
    _go32_dpmi_allocate_iret_wrapper(&KbInt23);
    _go32_dpmi_set_protected_mode_interrupt_vector(0x23, &KbInt23);

    atexit(ResetInt);


    /* set the comms port 0 to 9600, no parity, 1 stop bit, 8 data bits */
//    regs.h.ah = 0;
//    regs.h.al = 0xc7;   /* 9600bd, 1stop, NoPar, 8bits */
//    regs.w.dx = 0;
//    int86(14, &regs, &regs);
    outportb(0x3fb, 0x83);  /* set msb of Line Ctrl Reg */
    outportb(0x3f8, 12);    /* set BRD = 6 for 19200, 12 for 9600 */
    outportb(0x3fb, 0x03);  /* reset msb of Line Ctrl Reg */
    outportb(0x3fe, 0x00);
    /* Set UART Data Received interrupt on */
    outportb(0x3fc, 0x0f);
    outportb(0x3f9, 0x01);

    /* Trap RS232 interrupt 0x0C */
    _go32_dpmi_set_protected_mode_interrupt_vector(0x0C, &KbInt0C);

    /* unmask the PIC */
    save21 = (char)inportb(0x21);
    outportb(0x21, save21 & 0xEF);

    /* Trap keyboard interrupt 0x09 */
    _go32_dpmi_chain_protected_mode_interrupt_vector(0x09, &KbInt09);

  }
}

char hex(char ch)
{ if(ch >= 10) return('A'+ch-10);
  return('0'+ch);
}

void disp_kb_bfr(int period)
  // displays the buffer without updating anything
{ int pt;
  int head, tail;
  head = _farpeekw(_dos_ds, 0x41a)+0x400;
  tail = _farpeekw(_dos_ds, 0x41c)+0x400;
  ScreenSetCursor(4, 0);
  cprintf("\n\rHead = %02x    Tail = %02x", head, tail);
  for(pt = 0x41e; pt <= 0x43c; )
  { cprintf("\n\r   %02x - %02x ",_farpeekb(_dos_ds, pt), _farpeekb(_dos_ds, (pt+1)));
    if(pt == tail) cprintf("< |  %x", pt);
    else cprintf("  |  %x", pt);
    if(pt == head) cprintf("\r >");
    pt += 2;
  }
  sleep(period);
}

char kb_getch() // replaces getch() in your program (see 'main()' above)
{ int head, tail, chr_pt, scn_pt, base = 0x400;
  char hold, c_char, c_scan;
  static int special = 0, OldCommsMode;

//  cprintf("\nCommsMode - %02x",CommsMode);
  if(CommsMode != OldCommsMode)
  { diffs = 0;
    if(CommsMode == SLAVE)
    { outportb(0x03f9, 0x01);
      outportb(0x3fa, 0x00); // unhangs the RS232 when it gets hung up
      outportb(0x3fc, 0x0f); // (learned from analysis of other S/W)
    }
    OldCommsMode = CommsMode;
  }
  if(special)  // 'specials' are function keys, arrows, ALT-key, etc
  { hold = (char)special;
    special = 0;
    goto ts_getch_end;     // without updating 'head'
  }
  // wait till slave kb_buf contains less than 15 characters
  while(CommsMode == MASTER && diffs > 14) /* wait here */;

  // wait for key press then set pointers chr & scn get c_char, c_scan
  do { head = _farpeekw(_dos_ds, 0x41a);
       tail = _farpeekw(_dos_ds, 0x41c);
     } while(head == tail);

  chr_pt = base + head;
  scn_pt = chr_pt + 1;
  c_char = _farpeekb(_dos_ds, chr_pt);
  c_scan = _farpeekb(_dos_ds, scn_pt);

  if(c_char & 0x80 || c_char == 0)
  { special = c_scan;
    hold = 0;
  }
  else
    hold = c_char;

  head += 2;
  if(head > 0x3c)
     head = 0x1e;
  _farpokew(_dos_ds, 0x41a, head);

  ts_getch_end:

  // SLAVE sends diffs to master
  if(CommsMode == SLAVE)
  { diffs = tail - head;
    if(diffs<0) diffs += 34;
    { //cprintf("Point A");
      rs232_send((char)diffs | 0x80);
    }
  }
  if(CommsMode == MASTER)  // send it through the serial port - std DOS call
  { //cprintf("Point B");
    rs232_send(hold);
  }
  return hold;
}

void kb_ungetch(char ch) // puts character back into the keyboard buffer
{ int chr_pt, scn_pt;
  static int special = 0;
  unsigned int head, tail, base = 0x400;

  head = _farpeekw(_dos_ds, 0x41a);
  tail = _farpeekw(_dos_ds, 0x41c);

  if(ch == '\0')
  { special = 1;
    return;
  }

  if((head -= 2) < 0x1e)
    head = 0x3c;

  chr_pt = base + head;
  scn_pt = chr_pt + 1;

  if(special)
  { _farpokeb(_dos_ds, chr_pt, '\0');
    _farpokeb(_dos_ds, scn_pt, ch);
    special = 0;
  }
  else
  { _farpokeb(_dos_ds, chr_pt, ch);
    _farpokeb(_dos_ds, scn_pt, '\0');
  }
  _farpokew(_dos_ds, 0x41a, head);

}

int kb_hit(void) // tests to see if 'next' and 'last' pointers are equal
{ int head, tail;
  head = _farpeekw(_dos_ds, 0x41a);
  tail = _farpeekw(_dos_ds, 0x41c);

  return(tail>=head ? tail-head : head - tail);
}

void  kb_ungets(char *str)
{ char *pt;

  if(CommsMode != SLAVE)
  { if(str[0] == '\0') // if this is the first (zero) character of a function
    { kb_ungetch('\0');// key, there will only be two chars in all. Don't
      kb_ungetch(str[1]); // assume a zero length.
    }
    else
    { pt = str + strlen(str) - 1; // Otherwise, get ready to copy a string.
      while(pt >= str)
        kb_ungetch(*pt--);
    }
  }
}


-- 
Don't just hit "reply" - my E-mail address is bogus
to avoid automatic browsers from sending junk mail.
Please use collim'at'anubis'dot'network'dot'com
Actually, even this doesn't stop all of them ...

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019