hard_sio.c

来自「串口芯片驱动程序 驱动芯片为16C554。」· C语言 代码 · 共 354 行

C
354
字号
//========================================================//
// Code Infomation:                                       //
//   This module defines the uart hard                    //
//   process functions for Board_DSP of MAIN_CONTROL      //
//   devices named 管理板CPU                              //
// Version: v1.01                                         //
// Programmer: Lejianxin                                  //
// Date:  Begined from 2005.02                            //
//        Last modified at                                //
// Copyright(c) 2002-2004  Shenzhen NARI Co.              //
//========================================================//

/* 程序修改记录(最新的放在最前面):                        *
 *  <修改日期>, <修改人员>: <修改功能概述>                *
 *========================================================*
  2.01 2005-02-28 10:25  Lejianxin modify
 *========================================================*/

#include "Macro.h"
#include "Variable.h"
#include "Function.h"

#include "Hardware.h"
#include "Sio_16C554.h"
#include "CPU_S3C44B0x.h"


BOOLEAN Hard_Uart_Init( BYTE byPortNo )
{
    tagPPortSet     ptPortSet;
    tagPParamSio    ptParamSio;
    tagWord_Byte2   tDevisor;
    BYTE            byLCR, byIndex;
    LPSTR           pAddr;

    byIndex = byPortNo - CN_PORT_BASE_SIO;
    if( byIndex >=CN_NUM_PORT_SIO )  return FALSE;
    ptPortSet  = g_ptPortSet[CN_PORT_BASE_SIO+byIndex];
    g_tPortVal[byPortNo].wResetTimes++;
    ptParamSio = (tagPParamSio)(ptPortSet->dwParam);

    // the devisor value is different due to the frequency
    switch( ptPortSet->byBaudRate )
    {
    case  EN_COM_BAUD_300   :   tDevisor.wWord = 384;     break;      //    300
    case  EN_COM_BAUD_600   :   tDevisor.wWord = 192;     break;      //    600
    case  EN_COM_BAUD_1200  :   tDevisor.wWord =  96;     break;      //   1200
    case  EN_COM_BAUD_2400  :   tDevisor.wWord =  48;     break;      //   2400
    case  EN_COM_BAUD_4800  :   tDevisor.wWord =  24;     break;      //   4800
    case  EN_COM_BAUD_9600  :   tDevisor.wWord =  12;     break;      //   9600
    case  EN_COM_BAUD_19200 :   tDevisor.wWord =   6;     break;      //  19200
    case  EN_COM_BAUD_38400 :   tDevisor.wWord =   3;     break;      //  38400
    case  EN_COM_BAUD_57600 :   tDevisor.wWord =   2;     break;      //  57600
    case  EN_COM_BAUD_115200:   tDevisor.wWord =   1;     break;      // 115200
    default                   :   tDevisor.wWord =  12;     break;      //   9600
    }
    byLCR = 0x80 | ((ptParamSio->byDataBit - 5) & 0x03);                // Data's Bit-Length
    if( 2 ==ptParamSio->byStopBit  )    byLCR = byLCR | 0x04;           // Stopping Bit-Length
    if( 1 ==ptParamSio->byParity   )    byLCR = byLCR | 0x08;           // odd  Parity & Parity enabled
    else if( 2 ==ptParamSio->byParity ) byLCR = byLCR | 0x18;           // even Parity & Parity enabled

    pAddr = (LPSTR)(ptPortSet->dwAddBase);
    *(pAddr + CN_SIO_IER) = 0x00;    // 关闭中断
    *(pAddr + CN_SIO_FCR) = 0x06;
    *(pAddr + CN_SIO_LCR) = byLCR;

    *(pAddr + CN_SIO_DLL) = tDevisor.cByte[0];
    *(pAddr + CN_SIO_DLM) = tDevisor.cByte[1];

    byLCR = byLCR  & 0x7F;
    *(pAddr + CN_SIO_LCR) = byLCR;
    *(pAddr + CN_SIO_FCR) = 0x81;
    *(pAddr + CN_SIO_MCR) = 0x03;
    if( CN_PORT_RS485 ==ptPortSet->byPortType )   *(pAddr + CN_SIO_MCR) = 0x01;
    *(pAddr + CN_SIO_IER) = 0x01;    // 仅开接收中断

    return TRUE;
}

BOOLEAN Hard_Uart_TxStartup( BYTE byPortNo )
{
    tagPPortSet     ptPortSet;
    tagPSendCtrl    ptSendCtrl;
    BYTE            bySetIER, byIndex;
    LPSTR           pAddr;

    byIndex = byPortNo - CN_PORT_BASE_SIO;

    if( byIndex >=CN_NUM_PORT_SIO )  return 0;

    if( M_GET_BIT( g_tDbgCtrl.dwParam[byPortNo], EN_DBG_MSG_SEND) )
    { // message-watching
        ptSendCtrl = &(g_tPortVal[byPortNo].tSendCtrl);
        Dbg_SavePortMsg( byPortNo, EN_DBG_MSG_SEND, ptSendCtrl->wSendLen, ptSendCtrl->bySendBuf );
    }

    ptPortSet = g_ptPortSet[byPortNo];
    pAddr = (LPSTR)(ptPortSet->dwAddBase);
    if( CN_PORT_RS485 ==ptPortSet->byPortType )
    { // 如果是485口,则切换为发送模式
        *(pAddr + CN_SIO_MCR) = 0x02;
    }


    pAddr = (LPSTR)(pAddr + CN_SIO_IER );
    bySetIER = *pAddr;
    *pAddr = bySetIER & 0xFD;           // Clear  TX-INT: 1111-1101
    *pAddr = bySetIER | 0x02;           // Enable TX-INT: make sure to have TX-INT-pluse

    return( TRUE );
}

BYTE Hard_Uart_GetIIR( BYTE byIndex )
{
    tagPPortSet     ptPortSet;
    LPSTR   pAddr;
    BYTE    byPortNo;

    if( byIndex >=CN_NUM_PORT_SIO )  return 0;
    byPortNo = CN_PORT_BASE_SIO + byIndex;

    ptPortSet = g_ptPortSet[byPortNo];
    pAddr = (LPSTR)(ptPortSet->dwAddBase);

    return( *(pAddr + CN_SIO_IIR) );
}


BYTE Hard_Uart_GetLSR( BYTE byIndex )
{
    tagPPortSet     ptPortSet;
    LPSTR   pAddr;
    BYTE    byPortNo;

    if( byIndex >=CN_NUM_PORT_SIO )  return 0;
    byPortNo = CN_PORT_BASE_SIO + byIndex;

    ptPortSet = g_ptPortSet[byPortNo];
    pAddr = (LPSTR)(ptPortSet->dwAddBase);

    return( *(pAddr + CN_SIO_LSR) );
}


BYTE Hard_Uart_GetMSR( BYTE byIndex )
{
    tagPPortSet     ptPortSet;
    LPSTR   pAddr;
    BYTE    byPortNo;

    if( byIndex >=CN_NUM_PORT_SIO )  return 0;
    byPortNo = CN_PORT_BASE_SIO + byIndex;

    ptPortSet = g_ptPortSet[byPortNo];
    pAddr = (LPSTR)(ptPortSet->dwAddBase);

    return( *(pAddr + CN_SIO_MSR) );
}

void Hard_Uart_SetMCR( BYTE byIndex, BYTE byMCR )
{
    tagPPortSet     ptPortSet;
    LPSTR    pAddr;
    BYTE    byPortNo;

    if( byIndex >=CN_NUM_PORT_SIO )  return;
    byPortNo = CN_PORT_BASE_SIO + byIndex;

    ptPortSet = g_ptPortSet[byPortNo];
    pAddr = (LPSTR)(ptPortSet->dwAddBase);

    *(pAddr + CN_SIO_MCR) = byMCR;

    return;
}


BYTE Hard_Uart_Fifo_Read( BYTE byIndex )
{
    LPSTR           pAddrLSR, pAddrRBR;
    tagPRecvCtrl    ptRecvCtrl;
    BYTE    byPortNo, byLen, byTempBuf[32], *pbyRecvBuf;
    WORD    wWrite, wRead;

    if( byIndex >=CN_NUM_PORT_SIO )  return 0;
    byPortNo = CN_PORT_BASE_SIO + byIndex;
    ptRecvCtrl = &g_tPortVal[byPortNo].tRecvCtrl;
    pbyRecvBuf = ptRecvCtrl->byRecvQue;
    wWrite  = ptRecvCtrl->wRecvWrite;
    wRead   = ptRecvCtrl->wRecvRead;
    if( wWrite >=CN_VOL_BUF_RECV )
    {
        wWrite = 0;
        wRead  = 0;
    }

    byLen = 0;
    pAddrLSR = (LPSTR)(g_ptPortSet[byPortNo]->dwAddBase + CN_SIO_LSR);
    pAddrRBR = (LPSTR)(g_ptPortSet[byPortNo]->dwAddBase + CN_SIO_RBR);

    while( 0 !=(*pAddrLSR & 0x01) )
    {
        pbyRecvBuf[wWrite] = *pAddrRBR;
        byTempBuf[byLen]   = pbyRecvBuf[wWrite];

        wWrite++;
        if( wWrite >=CN_VOL_BUF_RECV ) wWrite = 0;
        if( wWrite ==wRead )    // Receive Buffer overflow!!!
        {
            wRead++;
            if( CN_VOL_BUF_RECV <=wRead ) wRead = 0;
            //Fun_Msg( COM_BUFFER_OVERFLOW, byPortNo );
        }
        byLen++;
        if( byLen >=32 ) break; // prevent from infinite cycle
    }

    ptRecvCtrl->wRecvWrite = wWrite;
    ptRecvCtrl->wRecvRead  = wRead;
    Time_TimerBReset( &ptRecvCtrl->tTimerRecv );    // clear the timer

    // message-watching
    if( M_Dbg_RawDataRecv( byPortNo) )
    {
        Dbg_SavePortMsg( byPortNo, EN_DBG_DATA_RECV, byLen, byTempBuf );
    }

    return byLen;
}


BYTE Hard_Uart_Fifo_Write( BYTE byIndex )
{
    tagPSendCtrl    ptSendCtrl;
    BYTE    byPortNo, byLSR, byLen, byLoop, *pbySendBuf;
    WORD    wRead, wTimeout;
    LPSTR   pAddr, pAddrThr;


    if( byIndex >=CN_NUM_PORT_SIO )  return 0;
    byPortNo = CN_PORT_BASE_SIO + byIndex;
    pAddr = (LPSTR)(g_ptPortSet[byPortNo]->dwAddBase );

    byLSR = *(pAddr + CN_SIO_LSR);
    if( 0 ==(byLSR & 0x20) ) return 0;  // THR not empty!

    ptSendCtrl = &g_tPortVal[byPortNo].tSendCtrl;
    wRead = ptSendCtrl->wSendRead;
    if( (wRead >=CN_VOL_BUF_SEND) || ((wRead >=ptSendCtrl->wSendLen)&&(wRead!=0)) )    // ERROR
    {
        ptSendCtrl->wSendLen  = 0;
        ptSendCtrl->wSendRead = 0;
        ptSendCtrl->wSendFlag = CN_STATUS_SEND_IDLE;
        Time_TimerBStop ( &ptSendCtrl->tTimerAbandon );
        Time_TimerBReset( &ptSendCtrl->tTimerLineIdle );    // 用Reset便于不同规约使用不同的空闲间隔
    }

    if( CN_STATUS_SEND_BUSY !=ptSendCtrl->wSendFlag )
    {
        // 本报文已经发送完,关闭发送中断
        *(pAddr+CN_SIO_IER) = *(pAddr+CN_SIO_IER) & 0xFD;     // 1111-1101
        // 如果是485口, 则在发送完最后一字节后切换为接收模式
        if( CN_PORT_RS485 ==g_ptPortSet[byPortNo]->byPortType )
        {
            wTimeout = 0;
            while( (*(pAddr+CN_SIO_LSR)&0x40) != 0x40 )
            {
                wTimeout++;
                if( 0 ==wTimeout ) break;
            }
            *(pAddr + CN_SIO_MCR) = 0x01;        // 切换到接收
        }
        return 0;
    }

    byLen = 0;
    pAddrThr = pAddr + CN_SIO_THR;                  // the addr of 16C554 TX-buffer
    pbySendBuf = &ptSendCtrl->bySendBuf[wRead];     // the start position to be sent
    if( (wRead+12) <ptSendCtrl->wSendLen )
    {
        byLen = 12;
        ptSendCtrl->wSendRead = wRead + byLen;
    //  Time_TimerBReset( &ptSendCtrl->tTimerAbandon );
    }else
    {
        byLen = ptSendCtrl->wSendLen - wRead;

        ptSendCtrl->wSendLen  = 0;
        ptSendCtrl->wSendRead = 0;
        ptSendCtrl->wSendFlag = CN_STATUS_SEND_IDLE;
        Time_TimerBStop ( &ptSendCtrl->tTimerAbandon  );
        Time_TimerBReset( &ptSendCtrl->tTimerLineIdle );    // 用Reset便于不同规约使用不同的空闲间隔
    }

    for( byLoop=0; byLoop<byLen; byLoop++ )
    {
        *pAddrThr = pbySendBuf[byLoop];
    }

    // message-watching
    if( M_Dbg_RawDataSend( byPortNo) )
    {
        Dbg_SavePortMsg( byPortNo, EN_DBG_DATA_SEND, byLen, pbySendBuf );
    }

    return byLen;
}

void Hard_Uart_IntProcess( BYTE byIndex )
{
    LPSTR   pAddr;
    BYTE    byIIR, byTemp, byPortNo;


    if( byIndex >=CN_NUM_PORT_SIO ) return;

    byPortNo = CN_PORT_BASE_SIO + byIndex;
    pAddr = (LPSTR)(g_ptPortSet[byPortNo]->dwAddBase );

    byIIR = *(pAddr + CN_SIO_IIR) & 0x0F;
    if( (0x04==byIIR) || (0x0C==byIIR) )    // RI
    {
        Hard_Uart_Fifo_Read( byIndex );
        byIIR = *(pAddr + CN_SIO_IIR) & 0x0F;
    }
    if( 0x02 == byIIR )  // TI
    {
        Hard_Uart_Fifo_Write( byIndex );
        byIIR = *(pAddr + CN_SIO_IIR) & 0x0F;
    }
    if( 0x06 ==byIIR )          // ERROR: Read LSR to clear
    {
        byTemp = *(pAddr + CN_SIO_LSR);
//      Hard_Uart_Get_LSR( byIndex );
//      Hard_Uart_Init( byIndex + CN_PORT_BASE_SIO );
//      Com_ClearRevParaBuffer( byIndex + CN_PORT_BASE_SIO );
    }

    return;
}


void Sys_LedRUN( void )
{
    DWORD  dwValReg;

    M_CPU_REG_READ(  CN_CPU_PDATC, dwValReg );
    dwValReg = dwValReg ^ CN_LED_RUN_ON;             // 取反
    M_CPU_REG_WRITE(  CN_CPU_PDATC, dwValReg );

    return;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?