Доброго времени суток!
Пол года тому назад после очередного непонимания, почему не
работает порт в контроллере, мне пришлось разработать собственную библиотеку
работы с последовательными портами контроллера 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; }
|