Доброго времени суток! 
Пол года тому назад после очередного непонимания, почему не
работает порт в контроллере, мне пришлось разработать собственную библиотеку
работы с последовательными портами контроллера ADAM 5510. Многие из вас уже задавались
тем-же вопросом и просили у меня помощи в написание чего-то похожего. Поэтому я
выкладываю свой вариант для всеобщего обсуждения. 
Нечего особенного не изобретено, можете использовать в своих
коммерческих целях, просьба авторов не удалять из заголовка исходника. сделана для среды программирования watcom С++, по возможности можно перевести в Borland C заменив outpw на outport, outp на outportb, inpw на inport, inp на inportb, _enable() на enable(), _disable() на disable()
  Файл Sio.h /********************************************************************************************* Project : Version : Date    : 24.03.2011 Author  : Дьяконов О.Ю., Шиенков Д.И. Company : Comments: Библиотека для работы с последовательными портами в контроллерах ADAM 5510. **********************************************************************************************/
  /*! \file sio.h
    Аббревиатура модуля (файла) "sio" - Serial Input Output.
    Это заголовочный файл для модуля реализации "sio.cpp".   В этом заголовочном файле объявлен интерфейс для доступа и работы с последовательными   портами COM1 - COM4 ПЛК серии ADAM 5510, а также объявлены соответствующие типы данных. */
  #ifndef SIO_H #define SIO_H
  #ifdef __cplusplus extern "C" { #endif
  typedef unsigned char u8; typedef unsigned short u16; typedef unsigned long u32;
  typedef char s8; typedef short s16; typedef long s32;  /*! Включить поддержку порта программирования COM3 */ #define COM_PGM
  /*! \enum sio_com_t     Возможные (доступные) порты ПЛК. */ typedef enum SIO_COM {
      SIO_COM1    = 0, /*!< RS-232 COM1. */     SIO_COM2    = 1, /*!< RS-485 COM2. */
  #ifdef COM_PGM     SIO_COM_PGM = 2, /*!< RS232 COM3 - для программирования ПЛК (терминальный). */ #endif
      SIO_COM4    = 3  /*!< RS-232/485 COM4. */
  } sio_com_t;
  /*! \enum sio_dir_t     Направления данных. */ typedef enum SIO_DIR {     SIO_RX_DIRECTION = 0x01, /*!< Прием. */     SIO_TX_DIRECTION = 0x02  /*!< Передача. */ } sio_dir_t;
  /*! \enum sio_err_t     Коды ошибок при работе с портами. */ typedef enum SIO_ERR {     SIO_ERR_NONE                = 0, /*!< Нет ошибок. */     SIO_ERR_INVALID_PORT_NUM    = 1, /*!< Номер порта не поддерживается. */     SIO_ERR_NO_UART             = 2, /*!< Не обнаружена м/сх UART. */     SIO_ERR_PORT_ALREADY_OPEN   = 3, /*!< Порт уже открыт. */     SIO_ERR_PORT_NOT_OPEN       = 4, /*!< Порт не открыт. */     SIO_ERR_INVALID_BUFFER_SIZE = 5, /*!< Не поддерживаемый размер буфера. */     SIO_ERR_ILLEGAL_SETTING     = 6, /*!< Неверные параметры конфигурирования. */     SIO_ERR_UART_NOT_SUPPORTED  = 7, /*!< Данный тип м/сх UART не поддерживается. */     SIO_ERR_NOT_MEMORY          = 8  /*!< Нет памяти для создания буферов и т.п. */ } sio_err_t;
  /*! \enum sio_speed_t     Поддерживаемые скорости обмена. */ typedef enum SIO_SPEED {     SIO_BPS_50     = 2304, /*!< 50 бод. */     SIO_BPS_300    = 384,  /*!< 300 бод. */     SIO_BPS_600    = 192,  /*!< 600 бод. */     SIO_BPS_2400   = 48,   /*!< 2400 бод. */     SIO_BPS_4800   = 24,   /*!< 4800 бод. */     SIO_BPS_9600   = 12,   /*!< 9600 бод. */     SIO_BPS_19200  = 6,    /*!< 19200 бод. */     SIO_BPS_38400  = 3,    /*!< 38400 бод. */     SIO_BPS_57600  = 2,    /*!< 57600 бод. */     SIO_BPS_115200 = 1     /*!< 115200 бод. */ } sio_speed_t;
  /*! \enum sio_databits_t     Поддерживаемое кол-во бит данных в фрейме. */ typedef enum SIO_DATABITS {     SIO_DATA5 = 0x00, /*!< 5 бит. */     SIO_DATA6,        /*!< 6 бит. */     SIO_DATA7,        /*!< 7 бит. */     SIO_DATA8         /*!< 8 бит. */ } sio_databits_t;
  /*! \enum sio_parity_t     Поддерживаемые типы паритета в фрейме. */ typedef enum SIO_PARITY {     SIO_PAR_NONE = 0x00, /*!< Без контроля четности. */     SIO_PAR_EVEN = 0x18, /*!< Чет. */     SIO_PAR_ODD  = 0x08, /*!< Нечет. */     SIO_PAR_ZERO = 0x38, /*!< Пробел. */     SIO_PAR_ONE  = 0x28  /*!< Маркер. */ } sio_parity_t;
  /*! \enum sio_parity_t     Поддерживаемое кол-во стоп-бит фрейме. */ typedef enum SIO_STOPBITS {     SIO_STOP1 = 0x00, /*!< Один стоп-бит. */     SIO_STOP2 = 0x04  /*!< Два стоп-бита. */ } sio_stopbits_t;
  /*! \enum sio_mode_t     Режимы. */ typedef enum SIO_MODE {     SIO_BLOCK_MODE = 0, /*!< Блокирующий. */     SIO_UNBLOCK_MODE    /*!< Неблокирующий. */ } sio_mode_t;
  extern int sioerrno;
  int sio_open(sio_com_t nport, sio_mode_t mode, int tx_buf_size, int rx_buf_size); int sio_configure(sio_com_t nport, sio_speed_t baud, sio_parity_t parity, sio_databits_t databits, sio_stopbits_t stopbits); int sio_send(sio_com_t nport, const char *buf, int len); int sio_recv(sio_com_t nport, char *buf, int len); int sio_clear(sio_com_t nport, sio_dir_t dir); int sio_rx_available(sio_com_t nport); void sio_close(sio_com_t nport);
  #ifdef __cplusplus } #endif #endif // SIO_H
 
 
  
    
   
   
   | 
 
 
  | 
   
   
    
   
продолжаем 1 часть описания структур файл Sio.cpp
  /********************************************************************************************* Project : Version : Date    : 24.03.2011 Author  : Дьяконов О.Ю., Шиенков Д.И. Company : Comments: Библиотека для работы с последовательными портами в контроллерах ADAM 5510. **********************************************************************************************/
  /*! \file sio.cpp
      Аббревиатура модуля (файла) "sio" - Serial Input Output.
      В этом модуле реализован интерфейс для доступа и работы с последовательными     портами COM1 - COM4 ПЛК серии ADAM 5510. */
  #include <dos.h> #include <mem.h> #include <malloc.h> #include <conio.h> #include "sio.h"
  //test //#include <stdio.h>
  //--------------------------------------------------------------------------------------------------------// /*** ЛОКАЛЬНЫЕ ПЕРЕЧИСЛЕНИЯ АДРЕСОВ И ЗНАЧЕИЙ БИТОВ РЕГИСТРОВ ***/
  /*! \enum sio_offset_t     Смещения регистров UART от базового.     Всего в UART должно быть 12 регистров. */ typedef enum SIO_OFFSET {     SIO_OFFSET_THB  = 0, /*!< Transmitter Holding BuFFer,        wo, DLAB = 0. */     SIO_OFFSET_RB   = 0, /*!< Receiver BuFFer,                   ro, DLAB = 0. */     SIO_OFFSET_DLLB = 0, /*!< Divisor Latch Low Byte,            rw, DLAB = 1. */     SIO_OFFSET_IER  = 1, /*!< Interrupt Enable Register,         rw, DLAB = 0. */     SIO_OFFSET_DLHB = 1, /*!< Divisor Latch High Byte,           rw, DLAB = 1. */     SIO_OFFSET_IIR  = 2, /*!< Interrupt Identification Register, ro.           */     SIO_OFFSET_FCR  = 2, /*!< FIFO Control Register, ro.         wo.           */     SIO_OFFSET_LCR  = 3, /*!< Line Control Register,             rw.           */     SIO_OFFSET_MCR  = 4, /*!< Modem Control Register,            rw.           */     SIO_OFFSET_LSR  = 5, /*!< Line Status Register,              ro.           */     SIO_OFFSET_MSR  = 6, /*!< Modem Status Register,             ro.           */     SIO_OFFSET_SCR  = 7  /*!< Scratch Register,                  rw.           */ } sio_offset_t;
  /*! \enum sio_ier_b_t     Значения комбинаций битов регистра IER.     Доступ: rw, при DLAB = 0. */ typedef enum SIO_IER_B {     SIO_IER_ERDAI  = 0x01, /*!< Enable Received Data Available Interrupt,            > 0x00. */     SIO_IER_ETHREI = 0x02, /*!< Enable Transmitter Holding Register Empty Interrupt, > 0x00. */     SIO_IER_ELSI   = 0x04, /*!< Enable Receiver Line Status Interrupt,               > 0x00. */     SIO_IER_EMSI   = 0x08, /*!< Enable Modem Status Interrupt,                       > 0x00. */     SIO_IER_ESM    = 0x10, /*!< Enables Sleep Mode (16750),                          > 0x00. */     SIO_IER_ELPM   = 0x20, /*!< Enables Low Power Mode (16750),                      > 0x00. */     SIO_IER_RES1   = 0x40, /*!< Reserved.                                                    */     SIO_IER_RES2   = 0x80  /*!< Reserved.                                                    */ } sio_ier_b_t;
  /*! \enum sio_iir_b_t     Значения комбинаций битов регистра IIR.     Доступ: ro. */ typedef enum SIO_IIR_B {     SIO_IIR_IP      = 0x01, /*!< 0 = Interrupt Pending, 1 = No Interrupt Pending.      */     SIO_IIR_ID_MASK = 0x0E, /*!< Interrupt ID Mask.                                    */     SIO_IIR_MSI     = 0x00, /*!< Modem Status Interrupt,                       = 0x00. */     SIO_IIR_THREI   = 0x02, /*!< Transmitter Holding Register Empty Interrupt, = 0x02. */     SIO_IIR_RDAI    = 0x04, /*!< Received Data Available Interrupt,            = 0x04. */     SIO_IIR_RLSI    = 0x06, /*!< Receiver Line Status Interrupt,               = 0x06. */     SIO_IIR_RDTO    = 0x0C  /*!< Receiver Dtata timeout,                       = 0x0C. */ } sio_iir_b_t;
  /*! \enum sio_fcr_b_t     Значения комбинаций битов регистра FCR.     Доступ: wo. */ typedef enum SIO_FCR_B {     SIO_FCR_EF       = 0x01, /*!< Enable FIFO's,                      > 0x00. */     SIO_FCR_CRF      = 0x02, /*!< Clear Receive FIFO,                 > 0x00. */     SIO_FCR_CTF      = 0x04, /*!< Clear Transmit FIFO,                > 0x00. */     SIO_FCR_DMS      = 0x08, /*!< DMA Mode Select.                                   Change status of RXRDY & TXRDY pins                                   from mode 1 to mode 2 ,             > 0x00. */     SIO_FCR_RES      = 0x10, /*!< Reserved.                                   */     SIO_FCR_EBF64    = 0x20, /*!< Enable 64 Byte FIFO (16750 only),   > 0x00. */     SIO_FCR_ITL_MASK = 0xC0, /*!< Interrupt Trigger Level Mask.               */     SIO_FCR_ITL1     = 0x00, /*!< Interrupt Trigger Level 1 Byte,     = 0x00. */     SIO_FCR_ITL4     = 0x40, /*!< Interrupt Trigger Level 4 Byte,     = 0x40. */     SIO_FCR_ITL8     = 0x80, /*!< Interrupt Trigger Level 8 Byte,     = 0x80. */     SIO_FCR_ITL14    = 0xC0  /*!< Interrupt Trigger Level 14 Byte,    = 0xC0. */ } sio_fcr_b_t;
  /*! \enum sio_lcr_b_t     Значения комбинаций битов регистра LCR.     Доступ: rw. */ typedef enum SIO_LCR_B {     SIO_LCR_WL_MASK    = 0x03, /*!< Word Length Mask.                                       */     SIO_LCR_WL5        = 0x00, /*!< Word Length 5 bits,                             = 0x00. */     SIO_LCR_WL6        = 0x01, /*!< Word Length 6 bits,                             = 0x01. */     SIO_LCR_WL7        = 0x02, /*!< Word Length 7 bits,                             = 0x02. */     SIO_LCR_WL8        = 0x03, /*!< Word Length 8 bits,                             = 0x03. */     SIO_LCR_LSB        = 0x04, /*!< 0 = 1 Stop Bit,                                     1 = 2 Stop bits for words of length 6,7 or 8 bits                                           or 1.5 Stop Bits for Word lengths of 5 bits.      */     SIO_LCR_P_MASK     = 0x38, /*!< parity Mask.                                            */     SIO_LCR_NP         = 0x00, /*!< No parity ,                                     = 0x00. */     SIO_LCR_OP         = 0x08, /*!< Odd parity ,                                    = 0x08. */     SIO_LCR_EP         = 0x18, /*!< Even parity,                                    = 0x18. */     SIO_LCR_HP         = 0x28, /*!< High parity,                                    = 0x28. */     SIO_LCR_LP         = 0x38, /*!< Low parity,                                     = 0x38. */     SIO_LCR_SBE        = 0x40, /*!< Set Break Enable,                               = 0x40. */     SIO_LCR_DLAB       = 0x80  /*!< 0 = RB, THB, IER accessible,                                     1 = DLLB, DLHB accessible.                              */ } sio_lcr_b_t;
  /*! \enum sio_mcr_b_t     Значения комбинаций битов регистра MCR.     Доступ: rw. */ typedef enum SIO_MCR_B {     SIO_MCR_FDTR = 0x01, /*!< Force Data Terminal Ready,             > 0x00. */     SIO_MCR_FRS  = 0x02, /*!< Force Request to Send,                 > 0x00. */     SIO_MCR_AO1  = 0x04, /*!< Aux Output 1,                          > 0x00. */     SIO_MCR_AO2  = 0x08, /*!< Aux Output 2,                          > 0x00. */     SIO_MCR_LM   = 0x10, /*!< LoopBack Mode ,                        > 0x00. */     SIO_MCR_ACE  = 0x20, /*!< Autoflow Control Enabled (16750 only), > 0x00. */     SIO_MCR_RES1 = 0x40, /*!< Reserved,                              > 0x00. */     SIO_MCR_RES2 = 0x80  /*!< Reserved,                              > 0x00. */ } sio_mcr_b_t;
  /*! \enum sio_lsr_b_t     Значения комбинаций битов регистра LSR.     Доступ: ro. */ typedef enum SIO_LSR_B {     SIO_LSR_DR   = 0x01, /*!< Data Ready,                         > 0x00. */     SIO_LSR_OE   = 0x02, /*!< Overrun Error,                      > 0x00. */     SIO_LSR_PE   = 0x04, /*!< parity Error,                       > 0x00. */     SIO_LSR_FE   = 0x08, /*!< Framing Error,                      > 0x00. */     SIO_LSR_BI   = 0x10, /*!< Break Interrupt,                    > 0x00. */     SIO_LSR_ETHR = 0x20, /*!< Empty Transmitter Holding Register, > 0x00. */     SIO_LSR_EDHR = 0x40, /*!< Empty Data Holding Registers,       > 0x00. */     SIO_LSR_ERF  = 0x80  /*!< Error in Received FIFO,             > 0x00. */ } sio_lsr_b_t;
  /*! \enum sio_msr_b_t     Значения комбинаций битов регистра MSR.     Доступ: ro. */ typedef enum SIO_MSR_B {     SIO_MSR_DCS  = 0x01, /*!< Delta Clear to Send,          > 0x00. */     SIO_MSR_DDSR = 0x02, /*!< Delta Data Set Ready,         > 0x00. */     SIO_MSR_TERI = 0x04, /*!< Trailing Edge Ring Indicator, > 0x00. */     SIO_MSR_DDCD = 0x08, /*!< Delta Data Carrier Detect,    > 0x00. */     SIO_MSR_CTS  = 0x10, /*!< Clear To Send,                > 0x00. */     SIO_MSR_DSR  = 0x20, /*!< Data Set Ready,               > 0x00. */     SIO_MSR_RI   = 0x40, /*!< Ring Indicator ,              > 0x00. */     SIO_MSR_CD   = 0x80  /*!< Carrier Detect,               > 0x00. */ } sio_msr_b_t;
  //--------------------------------------------------------------------------------------------------------// /*** ЛОКАЛЬНЫЕ СТРУКТУРЫ ДАННЫХ ***/ /*! \struct sio_queue_t     Очередь I/O. */ typedef struct SIO_QUEUE {     char *data; /*!< Указатель на буфер очереди. */     u16 size;   /*!< Максимальный размер буфера \a data очереди. */     u16 in;     /* Index of where to store next character */     u16 out;    /* Index of where to retrieve next character */     u16 chars;  /* Count of characters in queue */ } sio_queue_t;
  /*! \struct sio_addr_t     Структура хранения адресов регистров UART. */ typedef struct SIO_ADDR {     u16 base;    /*!< Базовый адрес порта (буферы TX, RX, DLLB). */     u16 ier;     /*!< Базовый адрес IER/DLHB. */     u16 iir_fcr; /*!< Базовый адрес IIR/FCR. */     u16 lcr;     /*!< Базовый адрес LCR. */     u16 mcr;     /*!< Базовый адрес MCR. */     u16 lsr;     /*!< Базовый адрес LSR. */     u16 msr;     /*!< Базовый адрес MSR. */ } sio_addr_t;
  typedef enum FLAGS {     F_BLOCK_MODE = 0x0001 } flags_t;
  /*! \struct sio_uart_t     Структура UART. */ typedef struct SIO_UART {     sio_addr_t addr; /*!< Структура хранения адресов регистров UART. */     sio_queue_t rx;  /*!< Приемная очередь. */     sio_queue_t tx;  /*!< Передающая очередь. */     int flags;       /*!< Флаги (например влаги открытия и т.п.). */ } sio_uart_t;
 
 
  
    
   
   
   | 
 
 
  | 
   
   
    
   
продолжаем 2 часть переменные и обработчик прерваний
  продолжение файла sio.cpp
  //--------------------------------------------------------------------------------------------------------// /*** ЛОКАЛЬНЫЕ ПЕРЕМЕННЫЕ ***/
  /* Базовые адреса, номера прерываний и маски прерываний портов. */ static const int bases[4] = {0x03F8, 0x02F8, 0x00, 0x03E8};     /*!< Базовые адреса портов COM1,COM2,COM_PGM,COM4. */ static const char intnums[4] = {0x0C, 0x0E, 0x14, 0x0C};        /*!< Номера прерываний от портов COM1,COM2,COM_PGM,COM4. */ static const int intmasks[4] = {0x0010, 0x0040, 0x0400, 0x010}; /*!< Маски прерываний от портов COM1,COM2,COM_PGM,COM4                                                                      для контроллера прерываний. */
  static sio_uart_t *uarts[4] = {0, 0, 0, 0};            /*!< Пользовательский массив структур конфигураций COM1,COM2,COM_PGM,COM4. */ static void (__interrupt *old_vecs[2])(void) = {0, 0}; /*!< Массив указателей на сохраненные векторы прерываний. */
  #ifdef COM_PGM static void (__interrupt *old_vec_pgm)(void); static int old_ier = 0; static int old_lcr = 0; static int old_brd = 0; #endif
  //--------------------------------------------------------------------------------------------------------// /*** ПАБЛИК ПЕРЕМЕННЫЕ ***/
  int sioerrno = SIO_ERR_NONE; /*!< Код последней ошибки. */
  //--------------------------------------------------------------------------------------------------------// /*** ЛОКАЛЬНЫЕ ФУНКЦИИ ***/
  /*! \fn void com_vce_isr(sio_com_t nport)     Под-обработчик прерывания конкретного порта \a nport.     \param nport Номер порта. */ static void com_vce_isr(sio_com_t nport) {     int r;     while (!(SIO_IIR_IP & (r = inp(uarts[nport]->addr.iir_fcr)))) {
          switch (SIO_IIR_ID_MASK & r) {
              /* Modem Status Interrupt */         case SIO_IIR_MSI:             inp(uarts[nport]->addr.msr); // Just clear the interrupt             break;
              /* Receiver Line Status Register */         case SIO_IIR_RLSI:             inp(uarts[nport]->addr.lsr); // Just clear the interrupt             break;
              /* Empty Transmitter Holding Register */         case SIO_IIR_THREI:             if (SIO_LSR_ETHR & inp(uarts[nport]->addr.lsr)) {                 //передача 16 байт максимум                 //экономим и используем r как итератор                 for (r = 0; (r < 16) && (uarts[nport]->tx.chars > 0); ++r, uarts[nport]->tx.chars--) {                     outp(uarts[nport]->addr.base, uarts[nport]->tx.data[uarts[nport]->tx.out++]);                     if (uarts[nport]->tx.out == uarts[nport]->tx.size)                         uarts[nport]->tx.out = 0;//количество байт в буфере tx_queue                 }             }             break;
              //case SIO_IIR_RDAI: /* Received Data Ready */             //читаем из FIFO предположительно 14 байт, т.к. прерывание настроено через каждые 14 байт             //   for (int i = 0; i < 14; ++i) {             //        char c = inp(uarts[nport]->addr.base);//читаем символ из Rx             //        if (uarts[nport]->rx.chars < uarts[nport]->rx.size) {             //             //            uarts[nport]->rx.data[uarts[nport]->rx.in++] = c;             //             //            if (uarts[nport]->rx.in == uarts[nport]->rx.size)             //                uarts[nport]->rx.in = 0;             //             //            uarts[nport]->rx.chars++;             //        }             //        if (0 == (inp(uarts[nport]->addr.lsr) & SIO_LSR_DR))             //            break; /*Data Ready > 0x00. */             //   }             //    break;
 
              /* Received Data Ready or Receive Data time out */         case SIO_IIR_RDAI:         case SIO_IIR_RDTO:             while (SIO_LSR_DR & inp(uarts[nport]->addr.lsr)) { // Data Ready > 0x00                 //экономим и используем r как результат чтения                 r = inp(uarts[nport]->addr.base);//читаем символ из Rx                 if (uarts[nport]->rx.chars < uarts[nport]->rx.size) {                     uarts[nport]->rx.data[uarts[nport]->rx.in++] = (char)r;                     if (uarts[nport]->rx.in == uarts[nport]->rx.size)                         uarts[nport]->rx.in = 0;                     uarts[nport]->rx.chars++;                 }             }             break;
          default:;         }//sw
      }//while }
  /*! \fn void void interrupt handler1_4(__CPPARGS)     Обработчик прерываний портов COM1/COM4. */ static void __interrupt handler1_4(void) {     _enable();     if (uarts[SIO_COM1]) { com_vce_isr(SIO_COM1); }     if (uarts[SIO_COM4]) { com_vce_isr(SIO_COM4); }     outpw(0xFF22, 0x000C);//сброс внешнего прерывания от INT0 UART, где 0x000C - EOI (End Of Interrupt) }
  /*! \fn void void interrupt handler2(__CPPARGS)     Обработчик прерываний порта COM2. */ static void __interrupt handler2(void) {     _enable();     if (uarts[SIO_COM2]) { com_vce_isr(SIO_COM2); }     outpw(0xFF22, 0x000E);//сброс внешнего прерывания от INT2 UART, где 0x000E - EOI (End Of Interrupt) }
  #ifdef COM_PGM
  /*! \fn void interrupt handler_pgm(__CPPARGS)     Обработчик прерываний порта COM3 (для программирования, PGM). */ static void __interrupt handler_pgm(void) {     _enable();     int r = inpw(uarts[SIO_COM_PGM]->addr.lsr);     if ((0x000F & r) == 0) {         //новое         //передача         if (0x0060 & r) {             if ( 0 == uarts[SIO_COM_PGM]->tx.chars)                 outpw(uarts[SIO_COM_PGM]->addr.lcr, inpw(uarts[SIO_COM_PGM]->addr.lcr) & 0xF7FF);//конец передачи             else {                 outp(uarts[SIO_COM_PGM]->addr.iir_fcr, uarts[SIO_COM_PGM]->tx.data[uarts[SIO_COM_PGM]->tx.out++]);                 if (uarts[SIO_COM_PGM]->tx.out == uarts[SIO_COM_PGM]->tx.size)                     uarts[SIO_COM_PGM]->tx.out = 0;//количество байт в буффере tx_queue                 uarts[SIO_COM_PGM]->tx.chars--;             }         }         //прием         if (0x0010 & r) {             r = inpw(uarts[SIO_COM_PGM]->addr.base);             if (uarts[SIO_COM_PGM]->rx.chars < uarts[SIO_COM_PGM]->rx.size) {                 uarts[SIO_COM_PGM]->rx.data[uarts[SIO_COM_PGM]->rx.in++] = (char)r;                 if (uarts[SIO_COM_PGM]->rx.in == uarts[SIO_COM_PGM]->rx.size)                     uarts[SIO_COM_PGM]->rx.in = 0;                 uarts[SIO_COM_PGM]->rx.chars++;             }         }     }     else         outpw(uarts[SIO_COM_PGM]->addr.lsr, 0x00F0 & r);//если есть ошибки то их сбросить
      outpw(0xFF22, 0x0014);//сброс прерывания от внутреннего UART CPU , где 0x0014 - EOI (End Of Interrupt) }
  #endif //COM_PGM
  
    
   
   
   | 
 
 
  | 
   
   
    
   
   
   
   
   
продолжаем 3 часть открытие порта
  продолжение файла sio.cpp
  //--------------------------------------------------------------------------------------------------------// /*** ПАБЛИК ФУНКЦИИ ***/
  /*! \fn int sio_open(sio_com_t nport, sio_mode_t mode, int tx_buf_size, int rx_buf_size)     Открывает порт \a nport и создает для него буферы I/O:     передающий размером \a tx_buf_size и приемный размером \a rx_buf_size.     \param nport Номер порта.     \param mode Режим открытия.     \param tx_buf_size Размер передающего буфера порта, в байтах.     \param rx_buf_size Размер приемного буфера порта, в байтах.     \return -1 при ошибке. */ int sio_open(sio_com_t nport, sio_mode_t mode, int tx_buf_size, int rx_buf_size) {     if (uarts[nport]) {         sioerrno = SIO_ERR_PORT_ALREADY_OPEN;         return -1;     }
      uarts[nport] = (sio_uart_t *)calloc(1, sizeof(sio_uart_t));//создать структуру     if (!uarts[nport]) { //структура не создана?         sioerrno = SIO_ERR_NOT_MEMORY;//ошибка         return -1;     }
      uarts[nport]->tx.data = (char *)calloc(1, tx_buf_size);//создать буфер TX     if (uarts[nport]->tx.data) {//буфер создан?         uarts[nport]->rx.data = (char *)calloc(1, rx_buf_size);//создать буфер RX         if (!uarts[nport]->rx.data) {//буфер не создан?             free(uarts[nport]->tx.data);//освободить буфере TX             uarts[nport]->tx.data = 0;         }     }
      if (!(uarts[nport]->tx.data)) {//буфер RX или TX не созданы?         free(uarts[nport]);         uarts[nport] = 0;         sioerrno = SIO_ERR_NOT_MEMORY;//ошибка         return -1;     }
      uarts[nport]->rx.size = rx_buf_size;//сохранить размер буфера     uarts[nport]->tx.size = tx_buf_size;
      sioerrno = SIO_ERR_NONE;
      //установить режим     if (SIO_BLOCK_MODE == mode) { uarts[nport]->flags |= F_BLOCK_MODE; }
  #ifdef COM_PGM // конфигурация порта PGM
      if (SIO_COM_PGM == nport) {         //адреса регистров регистров RX TX         uarts[SIO_COM_PGM]->addr.base = 0xFF86;//Serial Port Receive Register         uarts[SIO_COM_PGM]->addr.iir_fcr = 0xFF84;//Serial Port Transmit Register         //адреса управляющих регистров         uarts[SIO_COM_PGM]->addr.ier = 0xFF44; //Serial Port Interrupt Control Register         uarts[SIO_COM_PGM]->addr.lcr = 0xFF80; //Serial Port Control Register         uarts[SIO_COM_PGM]->addr.lsr = 0xFF82; //Serial Port Status Register         uarts[SIO_COM_PGM]->addr.mcr = 0xFF88; //Serial Port Baud Rate Divisor Register         _disable();         //здесь хранятся старые значения регистров         old_ier = inpw(uarts[SIO_COM_PGM]->addr.ier);         old_lcr = inpw(uarts[SIO_COM_PGM]->addr.lcr);         old_brd = inpw(uarts[SIO_COM_PGM]->addr.mcr);//сохранить старую скорость         //прерывание         outpw(0xFF28, (inpw(0xFF28) | intmasks[SIO_COM_PGM]));//запретить прерывание         _enable();         old_vec_pgm = _dos_getvect(intnums[SIO_COM_PGM]);//сохранить старый вектор прерывание         _dos_setvect(intnums[SIO_COM_PGM], handler_pgm);//установить новое прерывание         //конфигурация         outpw(uarts[SIO_COM_PGM]->addr.lcr, 0x0417);//RXIE, WLGN, TMOD, RSIE, RMODE         outpw(0xFF22, 0x0014);//сброс прерывание от UART         outpw(uarts[SIO_COM_PGM]->addr.ier, 0x0017);// Interrupt enable         outpw(0xFF28, inpw(0xFF28) & (~intmasks[SIO_COM_PGM]));//разрешить прерывание от UART         return 0;     }
  #endif
      uarts[nport]->addr.base = bases[nport];//адреса регистров     uarts[nport]->addr.ier = bases[nport] + SIO_OFFSET_IER;     uarts[nport]->addr.iir_fcr = bases[nport] + SIO_OFFSET_IIR;     uarts[nport]->addr.lcr = bases[nport] + SIO_OFFSET_LCR;     uarts[nport]->addr.mcr = bases[nport] + SIO_OFFSET_MCR;     uarts[nport]->addr.lsr = bases[nport] + SIO_OFFSET_LSR;     uarts[nport]->addr.msr = bases[nport] + SIO_OFFSET_MSR;
      outp(uarts[nport]->addr.ier, 0x00);//disable interrupt     if (inp(uarts[nport]->addr.ier)) {         free(uarts[nport]->tx.data);//освободить буфер TX         free(uarts[nport]->rx.data);//освободить буфер RX         free(uarts[nport]);//освободить структуру         uarts[nport] = 0;         sioerrno = SIO_ERR_NO_UART;         return -1;     }
      //установить FIFO     outp(uarts[nport]->addr.iir_fcr, SIO_FCR_CRF | SIO_FCR_CTF);//очистить FIFO     outp(uarts[nport]->addr.iir_fcr, 0xC0);//установить trigger level = 14     outp(uarts[nport]->addr.iir_fcr, SIO_FCR_EF);//включить
      /// ДОДЕЛАТЬ ПОТОМ!!!!     /*if (var_2 == 1)     {         _disable();         if ((inp(0x0178) & 0x80)==0)         {             if (inp( uarts[nport]->addr.lcr) != 0xBF)             {                 outp(var_e, 0x00);                 outp(var_10, 0x18);             }         }         _enable();     }*/
      /* настроить прерывания uart */     //Enable Received Data Available Interrupt, Enable Transmitter Holding Register Empty Interrupt     outp(uarts[nport]->addr.ier, SIO_IER_ERDAI | SIO_IER_ETHREI);
      // COM1 и/или COM4     if (((SIO_COM1 == nport) && (!uarts[SIO_COM4]))             || ((SIO_COM4 == nport) && (!uarts[SIO_COM1]))) {
          _disable();         outpw(0xFF22, 0x0C);////сброс внешние прерывание от INT0         outpw(0xFF28, (inpw(0xFF28) | intmasks[nport]));//отключить внешнее прерывание         _enable();
          old_vecs[0] = _dos_getvect(intnums[nport]);//сохранить старый вектор прерывания         _dos_setvect(intnums[nport], handler1_4);//установить новое прерывание
          _disable();         outpw(0xFF38, (inpw(0xFF38) | 0xCF));//прерывание инициировано нижним уровнем к высокому краю, Включите специальному полностью вложенному режиму INT0         outpw(0xFF28, (inpw(0xFF28) & (~intmasks[nport]))); //включить внешнее прерывание от INT0         _enable();
          uarts[nport]->flags |= F_BLOCK_MODE;         return 0;     }
      // COM2     if (SIO_COM2 == nport) {         _disable();         outpw(0xFF22,0x0E);//сброс внешние прерывание от INT2         outpw(0xFF28, (inpw(0xFF28) | intmasks[nport]));//отключить внешнее прерывание         _enable();
          old_vecs[1] = _dos_getvect(intnums[nport]);//сохранить старый вектор прерывание         _dos_setvect(intnums[nport],handler2);//установить новое прерывание
          _disable();         outpw(0xFF28, (inpw(0xFF28) & (~intmasks[nport]))); //включить внешнее прерывание от INT2         _enable();     }     return 0; } 
    
   
   
   | 
 
 
  | 
   
   
    
   
   
   
   
   
   
   
   
   
продолжаем 4 часть конфигурация порта
  продолжение файла sio.cpp
  /*! \fn int sio_configure(sio_com_t nport, sio_speed_t baud, sio_parity_t parity, sio_databits_t databits, sio_stopbits_t stopbits)     Конфигурирует открытый порт \a nport, т.е. устанавливает:     скорость \a baud, паритет \a parity, кол-во бит данных \a databits, кол-во стоп-бит \a stopbits.     \param nport Номер порта.     \param baud Скорость.     \param parity Паритет.     \param databits Биты данных.     \param stopbits Стоп биты.     \return -1 при ошибке. */ int sio_configure(sio_com_t nport, sio_speed_t baud, sio_parity_t parity, sio_databits_t databits, sio_stopbits_t stopbits) {     if (!uarts[nport]) { return -1; }
      sioerrno = SIO_ERR_ILLEGAL_SETTING;//ошибка
  #ifdef COM_PGM // конфигурация порта PGM
      if (SIO_COM_PGM == nport) {         _disable();         switch (baud) {//установка baud         case SIO_BPS_50: outpw(uarts[SIO_COM_PGM]->addr.mcr, 24999); break;         case SIO_BPS_300: outpw(uarts[SIO_COM_PGM]->addr.mcr, 4165); break;         case SIO_BPS_600: outpw(uarts[SIO_COM_PGM]->addr.mcr, 2082); break;         case SIO_BPS_2400: outpw(uarts[SIO_COM_PGM]->addr.mcr, 519); break;         case SIO_BPS_4800: outpw(uarts[SIO_COM_PGM]->addr.mcr, 259); break;         case SIO_BPS_9600: outpw(uarts[SIO_COM_PGM]->addr.mcr, 129); break;         case SIO_BPS_19200: outpw(uarts[SIO_COM_PGM]->addr.mcr, 64); break;         case SIO_BPS_38400: outpw(uarts[SIO_COM_PGM]->addr.mcr, 31); break;         case SIO_BPS_57600: outpw(uarts[SIO_COM_PGM]->addr.mcr, 20); break;         case SIO_BPS_115200: outpw(uarts[SIO_COM_PGM]->addr.mcr, 9); break;         default:;         }
          int r = inpw(uarts[SIO_COM_PGM]->addr.lcr) & 0xFF87; //очистка битов         switch (parity) {//установка parity         case SIO_PAR_NONE: break;         case SIO_PAR_EVEN: r |= 0x0060; break;         case SIO_PAR_ODD: r |= 0x0040; break;         default: return -1;         }
          switch (databits) {//установка databits         case SIO_DATA7: break;         case SIO_DATA8: r |= 0x0010; break;         default: return -1;         }
          switch (stopbits) {//установка stopbits         case SIO_STOP1: break;         case SIO_STOP2: r |= 0x0008; break;         default:;         }
          outpw (uarts[SIO_COM_PGM]->addr.lcr, r);//записать установки         _enable();
          sioerrno = SIO_ERR_NONE;         return 0;     }
  #endif
      _disable();     outp(uarts[nport]->addr.lcr, (inp(uarts[nport]->addr.lcr) | SIO_LCR_DLAB));/*1 = DLLB, DLHB accessible.*/     outpw(uarts[nport]->addr.base, baud);//установить скорость     outp(uarts[nport]->addr.lcr, (inp(uarts[nport]->addr.lcr) & (~SIO_LCR_DLAB)));/*0 = RB accessible*/     _enable();
      _disable();     outp(uarts[nport]->addr.lcr, (parity | databits | stopbits));//остальные настройки порта     _enable();
      sioerrno = SIO_ERR_NONE;     return 0; } 
    
   
   
   |