0

ポートを介したバイトの送信を変更する方法は?

  • だった: 割り込み。
  • 必要性: 世論調査によると。                                        

プラグイン -> http://pastie.org/3994352

クライアント:

#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include "comm.h"  // Connect module

void main(void)
{
   char cmd[128];

   /* Set the COM port */
   printf("Adjustable com-port ...\n");
   OpenSerial(COM_1, SER_BAUD_9600, SER_STOP_2 | SER_BITS_8 | SER_PARITY_EVEN);

   printf("Submitting a request for a connection ...\n");
   WriteSer(0xFF);

   while (1)
   {
      if (kbhit())
      {
         int c = getche();
         if (c == 13) putch(10);
         WriteSer(c);
      }

      if (DataReadyCount())
      {
         int c = ReadQueue();
         if (c == 0xFF) break;

         putch(c);
      }
   }

   printf("Ending a connection ...\n");
   CloseSerial();
}
4

1 に答える 1

0

少なくともポーリングと割り込み駆動のアプローチを紹介する上で、価値があるかもしれないサンプルをウェブ上で見つけました。setvect割り込みメソッドには、outportb、 、古い割り込みの保存と復元などの呼び出しが必要であることに注意してください。

次に TSR について尋ねないでください。:)

// http://ragestorm.net
// serial communications example
// interrupt driven/polled method
#include <dos.h>
#include <conio.h>
#include <stdio.h>

// serial port base addresses:
#define COM1 (0x3f8)
#define COM2 (0x2f8)

// stack size for interrupt
#define STACK_SIZE 1024

// serial ports registers:

// receive buffer
#define RBR (0x0)
// transmitter hold
#define THR (0x0)
// interrupt enable
#define IER (0x1)
// interrupt identification
#define IIR (0x2)
// fifo control
#define FCR (0x2)
// line control
#define LCR (0x3)
// modem control
#define MCR (0x4)
// line status
#define LSR (0x5)
// modem status
#define MSR (0x6)
// scratch-pad
#define SPR (0x7)

// divisor lsb byte
#define DIVLSB (0x0)
// divisor msb byte
#define DIVMSB (0x1)

// possible irqs for com ports
int com_irqs[4] = {4, 3, 4, 3};

// the com port addr being used
int used_com_addr = 0;

// the irq being used if interrupt driven
int used_com_irq = 0;

// interrupt driven or polling method?
int intr_used = 0;

// built in stack for interrupt usage
unsigned char recv_stack[STACK_SIZE];
unsigned char* next_char = recv_stack;

// old handler address
void interrupt (*old_handler)(...) = NULL;
void interrupt new_handler(...);

// get com address from bios
unsigned short get_com_addr(int com_no)
{
 if ((com_no <= 0) || (com_no >= 5)) return -1;

 // bios seg addr
 unsigned char* biosaddr = (unsigned char *)0x400;

 // set irq according to com number
 used_com_irq = com_irqs[com_no - 1];

 // retreive addresses bios
 return *(unsigned short*)&biosaddr[(com_no -  1) << 1];
}


// detect the uart type of the used com prot addr
// this is mainly to know if fifo is available.
// 0: no uart found, 1: 8250, 2: 16450 or 8250(with spr), 3: 16550, 4: 16550A
int detect_uart_type()
{
 char old_data = 0;

 // check UART presentation by checking loopback mode
 old_data = inportb(used_com_addr + MCR);
 outportb(used_com_addr + MCR, 0x10);
 if ((inportb(used_com_addr + MSR) & 0xf0)) return 0;
 outportb(used_com_addr + MCR, 0x1f);
 if ((inportb(used_com_addr + MSR) & 0xf0) != 0xf0) return 0;
 outportb(used_com_addr + MCR, old_data);

 // write values to scratch pad and readback
 old_data = inportb(used_com_addr + SPR);
 outportb(used_com_addr + SPR, 0x55);
 if (inportb(used_com_addr + SPR) != 0x55) return 1;
 outportb(used_com_addr + SPR, 0xAA);
 if (inportb(used_com_addr + SPR) != 0xAA) return 1;
 outportb(used_com_addr + SPR, old_data);

 // enable fifo and determine version by part identification
 outportb(used_com_addr + FCR, 1);
 old_data = inportb(used_com_addr + FCR);
 outportb(used_com_addr + FCR, 0);

 if ((~old_data & 0x80)) return 2; // 16450
 if ((~old_data & 0x40)) return 3; // 16550
 return 4; // 16550a +
}

// inits the serial com port with a specific baud rate,
// using interrupt or polling method.
void init_com_port(int com_no, long baudrate, int intr = 0)
{
 // calculate divisor relative to the baudrate
 short divisor = (long)115200 / baudrate;

 used_com_addr = get_com_addr(com_no);

 if (used_com_addr == 0) {

    printf("no valid com port!\n");
    return ;
 }
 printf("serial com port addr 0x%x", used_com_addr);
 if (intr)
    printf(" [irq %d, ", used_com_irq);
 else printf("[");

 int uart_type = detect_uart_type();
 switch(uart_type) {
    //case 0: break; // port must be found already by bios.
    case 1: printf("8250"); break;
    case 2: printf("16450"); break;
    case 3: printf("16550"); break;
    case 4: printf("16550a"); break;
 }

 printf("] is initialized!\n");

 intr_used = intr;

 disable();

 // turn off interrupts
 outportb(used_com_addr + 1, 0);

 // set dlab bit, so we can update the divisor
 outportb(used_com_addr + LCR, 0x80);

 // set divisor lsb
 outportb(used_com_addr + DIVLSB, divisor & 0xff);
 // set msb
 outportb(used_com_addr + DIVMSB, (divisor >> 8) & 0xff);

 // frame: 8 data bits, no parity and 1 stop bit
 outportb(used_com_addr + LCR, 0x3);

 // set RTS | DTR | OUT2(if intr) to inform remote system that we are ready
 outportb(used_com_addr + MCR, 0x3 | ((intr == 1) << 3));

 // support interrupt?
 if (intr) {

    // save old serial port interrupt handler address
    old_handler = getvect(8 + used_com_irq);
    setvect(8 + used_com_irq, new_handler);

    // enable serial port irq at pic
    outportb(0x21, inportb(0x21) & ~(1 << used_com_irq));

    // let the interrupt be triggered upon data arrival
    outportb(used_com_addr + IER, 1);

 } else {
    // no interrupt should be triggered
    outportb(used_com_addr + IER, 0);
 }

 // does the uart support fifo?
 if (uart_type == 4) {
    // set fifo buffer of 14 bytes, clear receive and transmit fifo's
    outportb(used_com_addr + FCR, 0xc7);
 }

 // clear delta bits
 inportb(used_com_addr + LSR);

 // clear incoming byte
 inportb(used_com_addr + RBR);

 enable();
}

// the serial port interrupt handler
// called upon received data only
// saves data in a stack
void interrupt new_handler(...)
{
 unsigned char status = 0;
 disable();

 // read iir and msr to acknowledge the uart
 inportb(used_com_addr + IIR);
 inportb(used_com_addr + MSR);

 // as long as data is arriving, put it in the stack
 do {
    // read status register
    status = inportb(used_com_addr + LSR) & 0x1;

    if (status & 1) {
     // read data from com port to the stack
     *next_char++ = inportb(used_com_addr + RBR);
     // overlap offset in case the stack is full
     next_char = ((next_char - recv_stack) % STACK_SIZE) + recv_stack;
    }
 }while (status & 1);

 enable();
 // let the pic know we are done
 outportb(0xa0, 0x20);
 outportb(0x20, 0x20);
}

// send a byte to the initialized com port
void send_byte(unsigned char ch)
{
 // make sure the connection is alive
 if (inportb(used_com_addr + MSR) & 0x80 == 0) return;

 // make sure the transmit hold register is empty
 while (inportb(used_com_addr + LSR) & 0x20 == 0) ;

 // send the character
 outportb(used_com_addr + THR, ch);
}

// receive a byte from the initialized com port
unsigned char recv_byte(int* is_read)
{
 int i;

 *is_read = 0;
 if (intr_used)
    if (next_char > recv_stack)
    {
     *is_read = 1;
     return *--next_char;
    } else return 0;

 // is data set ready high?
 for (i = 5; i > 0; i--)
    if (inportb(used_com_addr + MSR) & 0x20) break;
 if (!i) return -1;

 // is there anything to read?
 for (i = 5; i > 0; i--)
    if (inportb(used_com_addr + LSR) & 0x1) break;
 if (!i) return -2;

 *is_read = 1;
 return inportb(used_com_addr + RBR);
}

// enter loop-mode for debugging and testing.
void enter_loop_mode()
{
 outportb(used_com_addr + MCR, inportb(used_com_addr + MCR) | 0x10);
}

// exit a loop mode, change to transimtter/receiver mode
void exit_loop_mode()
{
 outportb(used_com_addr + MCR, inportb(used_com_addr + MCR) & ~0x10);
}

// shut down serial port connection
void shutdown_com_port()
{
 disable();

 if (intr_used) {

    // set the old handler
    setvect(8 + used_com_irq, old_handler);

    // disable used serial port interrupt at pic
    outportb(0x21, inportb(0x21) | (1 << used_com_irq));
 }

 // disable serial port interrupt
 outportb(used_com_addr + IER, 0);

 // disable interrupt, RTS and DTR
 outportb(used_com_addr + MCR, 0);

 outportb(used_com_addr + FCR, 0);

 enable();
}

int main()
{
 clrscr();
 init_com_port(1, 9600, 1);

 for(;;) {
    if (kbhit()) {
     int c = getch();
     if (c == 27) break;
     printf("%c", c);
     send_byte(c);
    }
    int b = 0;
    unsigned char c = recv_byte(&b);
    if (b) printf("%c", c);
 }

 shutdown_com_port();
 return 1;
}
于 2012-05-30T10:42:18.243 に答える