CODE: [Copy to clipboard]
//这里是DownComm.Cpp文件
#include <string.h>
#include <dos.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys\\stat.h>
#include <io.h>
#include <conio.h>
#include <bios.h>
#include <symbol.h> //此文件可在“WinSail V2.0下载后获得”
#include <DownComm.h>
#define COMM_INTERRUPT_BUFFER_SIZE 1024
#define MEMORY_TIME_ADDRESS 0x46CL
#define COMM_TIME_DELAY 4L
COMMCONTROL Afx_CommControl3={3, 0x3F8, COMM_ERROR_SUCCESS, NULL};
COMMCONTROL Afx_CommControl4={4, 0x2F8, COMM_ERROR_SUCCESS, NULL};
//这是COMM口中断模式时的中断调用公共函数
void COMM_PublicInterruptFc (COMMCONTROL* pCommControl)
{
BYTE byData,byLin, byIIR;
int nCommBase = pCommControl->nBase;;
//Read and discard interrupt
byData = inportb(nCommBase + COMM_REGISTER_LSR);
//get interrupt status
byIIR = inportb(nCommBase + COMM_REGISTER_IIR);
//is interrupt?
if (!!(byIIR & 0x1))
{
return;
}
byData = ((byIIR >> 1) & 0x3);
if (byData == 0x2) //receive
{
if (!pCommControl->bFullR)
{
pCommControl->pBufferR[pCommControl->nTailR] =
inportb(nCommBase + COMM_REGISTER_RBR);
pCommControl->nTailR++;
if (pCommControl->nTailR >= pCommControl->nSizeR)
{
pCommControl->nTailR = 0;
}
if (pCommControl->nTailR == pCommControl->nHeadR)
{
pCommControl->bFullR = TRUE;
}
}
}
else if (byData == 0x1) //send
{
if (pCommControl->nHeadS != pCommControl->nTailS ||
pCommControl->bFullS)
{
outportb(nCommBase + COMM_REGISTER_RBR,
pCommControl->pBufferS[pCommControl->nHeadS]);
pCommControl->nHeadS++;
if (pCommControl->nHeadS >= pCommControl->nSizeS)
{
pCommControl->nHeadS = 0;
}
pCommControl->bFullS = FALSE;
}
//Is empty?
if (pCommControl->nHeadS == pCommControl->nTailS)// && !pCommControl->bFullW)
{
byLin = inportb(nCommBase + COMM_REGISTER_LCR);
byLin &= 0x7F;
outportb(nCommBase + COMM_REGISTER_LCR, byLin);
//force interrupt for send only
outportb(nCommBase + COMM_REGISTER_IER, 0x1);
}
pCommControl->bFullS = FALSE;
}
else if (byData == 0x0) //Model status interrupt
{
}
else if (byData == 0x3) //receive line status
{
}
return;
}
//IRQ3中断函数
void interrupt CMotorNet_NewInterruptFc3 (...)
{
asm mov ax, seg Afx_CommControl3
asm mov ds, ax
::COMM_PublicInterruptFc (&Afx_CommControl3);
outportb(0x20, 0x20);
return;
}
//IRQ4中断函数
void interrupt CMotorNet_NewInterruptFc4 (...)
{
asm mov ax, seg Afx_CommControl3
asm mov ds, ax
::COMM_PublicInterruptFc (&Afx_CommControl4);
outportb(0x20, 0x20);
return;
}
//获得通讯控制包结构指针
COMMCONTROL* CMotorNet::GetCommControl()
{
if (m_nIRQ == 3)
{
return (&Afx_CommControl3);
}
else
{
return (&Afx_CommControl4);
}
}
//CMotorNet类的构造函数
CMotorNet::CMotorNet()
{
m_bInterrupt = FALSE;
m_nIRQ = 3;
m_nErrorCode = COMM_ERROR_SUCCESS;
}
//CMotorNet类的析构函数
CMotorNet::~CMotorNet()
{
this->CloseInterrupt();
}
//在中断模式时,将中断模式转查询模式
void CMotorNet::CloseInterrupt()
{
BYTE byData;
COMMCONTROL* pCommControl = this->GetCommControl();
asm pushf
asm cli
if (m_bInterrupt)
{
//mask irq
byData = inportb(0x21);
byData |= (1 << m_nIRQ);
outportb(0x21, byData);
//clear IER access bit,disable 8250 interrupt
byData = inportb(pCommControl->nBase + COMM_REGISTER_LCR);
byData &= 0x7F;
outportb(pCommControl->nBase + COMM_REGISTER_LCR, byData);
outportb(pCommControl->nBase + COMM_REGISTER_IER, 0x0);
//other
inportb(pCommControl->nBase + COMM_REGISTER_RBR);
inportb(pCommControl->nBase + COMM_REGISTER_LSR);
inportb(pCommControl->nBase + COMM_REGISTER_IIR);
inportb(pCommControl->nBase + COMM_REGISTER_IER);
inportb(pCommControl->nBase + COMM_REGISTER_MSR);
//disable 8250 RTS, DTR, ...
outportb(pCommControl->nBase + COMM_REGISTER_MCR, 0);
outportb(pCommControl->nBase + COMM_REGISTER_MCR, 0);
if (pCommControl->pOldFc != NULL)
{
::_dos_setvect(8 + m_nIRQ, pCommControl->pOldFc);
pCommControl->pOldFc = NULL;
}
pCommControl->nHeadR = pCommControl->nHeadS = 0;
pCommControl->nTailR = pCommControl->nTailS = 0;
pCommControl->nSizeR = pCommControl->nSizeS = 0;
pCommControl->bFullR = pCommControl->bFullS = FALSE;
DELETE(pCommControl->pBufferR);
DELETE(pCommControl->pBufferS);
pCommControl->nErrorCode = COMM_ERROR_SUCCESS;
}
m_bInterrupt = FALSE;
asm popf
return;
}
//改变奇偶校验方式,特别适用于RS485传输时的“地址”和“数据”传输
void CMotorNet::ChangeParity(WORD wParity)
{
asm pushf
asm cli
COMMCONTROL* pCommControl = this->GetCommControl();
BYTE byAttrib = (BYTE)pCommControl->wAttrib;
byAttrib &= 0x7F;
if (wParity == NOPARITY) //B5,B4,B3 = xx0
{
byAttrib &= ~(1<<3); byAttrib &= ~(1<<4); byAttrib &= ~(1<<5);
}
else if(wParity == ODDPARITY) //B5,B4,B3 = 001
{
byAttrib |= (1<<3); byAttrib &= ~(1<<4); byAttrib &= ~(1<<5);
}
else if (wParity == EVENPARITY) //B5,B4,B3 = 011
{
byAttrib |= (1<<3); byAttrib |= (1<<4); byAttrib &= ~(1<<5);
}
else if (wParity == MARKPARITY) //B5,B4,B3 = 101
{
byAttrib |= (1<<3); byAttrib &= ~(1<<4); byAttrib |= (1<<5);
}
else if (wParity == SPACEPARITY) //B5,B4,B3 = 111
{
byAttrib |= (1<<3); byAttrib |= (1<<4); byAttrib |= (1<<5);
}
outportb(pCommControl->nBase + COMM_REGISTER_LCR, byAttrib);
pCommControl->wParity = byAttrib;
asm popf
return;
}
//串行口初始化
void CMotorNet::InitComm(int nBase,DWORD dwBaud,WORD wDataBit,
WORD wStartBit,WORD wStopBit,WORD wParity, BOOL bInterrupt)
{
BYTE byIRQMask;
m_nErrorCode = COMM_ERROR_SUCCESS;
if (m_bInterrupt)
{
this->CloseInterrupt();
}
//Modify IRQ
if (nBase == 0x3F8 || nBase == 0x3E8) m_nIRQ = 4; //Com1
if (nBase == 0x2F8 || nBase == 0x2E8) m_nIRQ = 3; //Com2
COMMCONTROL* pCommControl = this->GetCommControl();
//force interrupt
outportb(nBase + COMM_REGISTER_IER, 0x00);
//Set IRQ disable
byIRQMask = inportb(0x21);
outportb(0x21, byIRQMask | (1 << m_nIRQ));
//Modify Data Bit
if(wDataBit < 5u || wDataBit > 8u)
{
wDataBit = 8;
}
//Modify StartBit
wStartBit = 1;
//Modify StopBit
if (wStopBit != ONESTOPBIT &&
wStopBit != ONE5STOPBITS &&
wStopBit != TWOSTOPBITS)
{
wStopBit = ONESTOPBIT;
}
//Save Comm Attrib
pCommControl->nBase = nBase;
pCommControl->dwBaud = dwBaud;
pCommControl->wDataBit = wDataBit;
pCommControl->wStartBit = wStartBit;
pCommControl->wStopBit = wStopBit;
pCommControl->wParity = wParity;
m_bInterrupt = bInterrupt;
//Write Baud
outportb(nBase + COMM_REGISTER_LCR, 0x80); //baud-rate enable
outportb(nBase + COMM_REGISTER_BAUDL, LOBYTE((115200L/ dwBaud)));
outportb(nBase + COMM_REGISTER_BAUDH, HIBYTE((115200L/ dwBaud)));
//Calc LCR Value
BYTE byAttrib = 0u;
if (wDataBit==5) {byAttrib &= ~(1<<1); byAttrib &= ~(1<<0);}//00
if (wDataBit==6) {byAttrib &= ~(1<<1); byAttrib |= (1<<0);}//01
if (wDataBit==7) {byAttrib |= (1<<1); byAttrib &= ~(1<<0);}//10
if (wDataBit==8) {byAttrib |= (1<<1); byAttrib |= (1<<0);}//11
if (wStopBit == ONESTOPBIT) byAttrib &= ~(1<<2);
if (wStopBit == ONE5STOPBITS) byAttrib |= (1<<2);
if (wStopBit == TWOSTOPBITS) byAttrib |= (1<<2);
if (wParity == NOPARITY)
{
byAttrib &= ~(1<<3); byAttrib &= ~(1<<4); byAttrib &= ~(1<<5);
}
else if(wParity == ODDPARITY)
{
byAttrib |= (1<<3); byAttrib &= ~(1<<4); byAttrib &= ~(1<<5);
}
else if (wParity == EVENPARITY)
{
byAttrib |= (1<<3); byAttrib |= (1<<4); byAttrib &= ~(1<<5);
}
else if (wParity == MARKPARITY)
{
byAttrib |= (1<<3); byAttrib &= ~(1<<4); byAttrib |= (1<<5);
}
else if (wParity == SPACEPARITY)
{
byAttrib |= (1<<3); byAttrib |= (1<<4); byAttrib |= (1<<5);
}
//write start bit, stop bit, parity
outportb(nBase + COMM_REGISTER_LCR, byAttrib);
//Moden control 00000110B
outportb(nBase + COMM_REGISTER_MCR, 0x03);
if (bInterrupt)
{
COMMCONTROL* pCommControl = this->GetCommControl();
this->CloseInterrupt();
m_bInterrupt = TRUE;
asm pushf
asm cli
//Malloc buffer for read and write
pCommControl->nIRQ = m_nIRQ;
pCommControl->nBase = nBase;
pCommControl->nErrorCode = COMM_ERROR_SUCCESS;
pCommControl->pBufferR = new BYTE[COMM_INTERRUPT_BUFFER_SIZE];
pCommControl->pBufferS = new BYTE[COMM_INTERRUPT_BUFFER_SIZE];
pCommControl->nHeadR = pCommControl->nHeadS = 0;
pCommControl->nTailR = pCommControl->nTailS = 0;
pCommControl->nSizeR = pCommControl->nSizeS = COMM_INTERRUPT_BUFFER_SIZE;
pCommControl->bFullR = pCommControl->bFullS = FALSE;
asm cli
//get old vect
pCommControl->pOldFc = ::_dos_getvect(m_nIRQ + 8);
//Set Interrupt Fc
if (m_nIRQ == 3)
{
::_dos_setvect(m_nIRQ + 8, CMotorNet_NewInterruptFc3);
}
else
{
::_dos_setvect(m_nIRQ + 8, CMotorNet_NewInterruptFc4);
}
asm cli
//Set IRQ Enable
byIRQMask = inportb(0x21);
outportb(0x21, byIRQMask & (~(1 << m_nIRQ)));
//discard LSR
inportb(nBase + COMM_REGISTER_LSR);
//discard MSR
inportb(nBase + COMM_REGISTER_MSR);
//discard RBR
inportb(nBase + COMM_REGISTER_RBR);
//LCR Bit7->0
byAttrib = inportb(nBase + COMM_REGISTER_LCR);
byAttrib &= 0x7F;
outportb(nBase + COMM_REGISTER_LCR, byAttrib);
//permit interrupt for receive data ,00000001B
outportb(nBase + COMM_REGISTER_IER, 0x1);
//Model control,00001100B
outportb(nBase + COMM_REGISTER_MCR, 0xB);
//FIFO control,00000000B
outportb(nBase + COMM_REGISTER_FCR, 0x0);
asm popf
}
}
//中断模式时,用于清空输入缓冲区
void CMotorNet::ClearBufferR()
{
asm pushf
asm cli
COMMCONTROL* pCommControl = this->GetCommControl();
pCommControl->nHeadR = pCommControl->nTailR = 0;
pCommControl->bFullR = FALSE;
asm popf
}
//中断模式时,用于清空输出缓冲区
void CMotorNet::ClearBufferS()
{
asm pushf
asm cli
COMMCONTROL* pCommControl = this->GetCommControl();
pCommControl->nHeadS = pCommControl->nTailS = 0;
pCommControl->bFullS = FALSE;
asm popf
}
//判断是否有数据可读
BOOL CMotorNet::IsCommData()
{
COMMCONTROL* pCommControl = this->GetCommControl();
if (!m_bInterrupt)
{
return((inportb(pCommControl->nBase + COMM_REGISTER_LSR)&0x01));
}
else
{
if (pCommControl->nHeadR != pCommControl->nTailR ||
pCommControl->bFullR)
{
return (TRUE);
}
}
return(FALSE);
}
//在规定的时间内等待数据的到来,
BOOL CMotorNet::WaitCommData(DWORD dwWait)
{
DWORD far *pdwMemoryTime = (DWORD far *)MEMORY_TIME_ADDRESS;
DWORD dwTime = *pdwMemoryTime;
//This maybe dead lock, you need modify code!!!
while (!this->IsCommData())//(inportb(m_nCommBase+5) & 0x01))
{
if (*pdwMemoryTime - dwTime >= dwWait)
{
return(FALSE);
}
}
return(TRUE);
}
//接收一个字节
BYTE CMotorNet::ReceiveData()
{
m_nErrorCode = COMM_ERROR_SUCCESS;
if (!this->WaitCommData(COMM_TIME_DELAY))
{
m_nErrorCode = COMM_ERROR_TIME;
return(0);
}
COMMCONTROL* pCommControl = this->GetCommControl();
if (m_bInterrupt)
{
asm pushf
asm cli
BYTE byData = pCommControl->pBufferR[pCommControl->nHeadR];
pCommControl->nHeadR = pCommControl->nHeadR + 1;
if (pCommControl->nHeadR >= pCommControl->nSizeR)
{
pCommControl->nHeadR = 0;
}
pCommControl->bFullR = FALSE;
asm popf
return(byData);
}
else
{
return(inportb(pCommControl->nBase));
}
}
//发送一个字节
BOOL CMotorNet::SendData(BYTE nCh)
{
COMMCONTROL* pCommControl = this->GetCommControl();
if (!m_bInterrupt)
{
while (this->IsCommData())
{
this->ReceiveData();
}
DWORD far *pdwMemoryTime=(DWORD far *)MEMORY_TIME_ADDRESS;
DWORD dwTime = *pdwMemoryTime;
//DWORD dwCount=0;
while (!(inportb(pCommControl->nBase + COMM_REGISTER_LSR) & 0x20))
{
if (*pdwMemoryTime - dwTime > COMM_TIME_DELAY) //100
{
m_nErrorCode = COMM_ERROR_TIME;
return(FALSE);
}
}
outportb(pCommControl->nBase,nCh);
}
else
{
if (pCommControl->bFullS)
{
return (FALSE);
}
asm pushf
asm cli
pCommControl->pBufferS[pCommControl->nTailS] = nCh;
pCommControl->nTailS = pCommControl->nTailS + 1;
if (pCommControl->nTailS >= pCommControl->nSizeS)
{
pCommControl->nTailS = 0;
}
if (pCommControl->nTailS == pCommControl->nHeadS)
{
pCommControl->bFullS = TRUE;
}
//permit interrupt for receive and send data ,00000011B
outportb(pCommControl->nBase + COMM_REGISTER_IER, 0x3);
asm popf
}
return(TRUE);
}
//接收多个字节
int CMotorNet::ReceiveBuffer(BYTE* pBuffer, int nCount, DWORD dwTimeOut)
{
for (int i = 0; i < nCount; i++)
{
if (!this->WaitCommData(dwTimeOut))
{
return (i);
}
pBuffer[i] = this->ReceiveData();
}
return (nCount);
}
//发送多个字节
BOOL CMotorNet::SendBuffer(BYTE* pBuffer, int nCount)
{
for (int i = 0; i < nCount; i++)
{
if (!this->SendData(pBuffer[i]))
{
//在中断模式时,一直等到缓冲区不为空
if (m_bInterrupt && this->GetCommControl()->bFullS)
{
i--;
continue;
}
return (FALSE);
}
}
return (TRUE);
}
//判断总线是否忙
//常用于RS485发送端,一般情况下如果忙,须清空输入缓冲区
BOOL CMotorNet::IsBusy()
{
this->ClearLastCommError();
return (this->IsCommData());
}