⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kitlserial.c

📁 Windows CE 6.0 BSP for VOIPAC Board (PXA270) Version 2b.
💻 C
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//------------------------------------------------------------------------------
//
//  File:  kitlserial.c
//
#include <windows.h>
#include <nkintr.h>
#include <kitl.h>
#include <oal.h>

//------------------------------------------------------------------------------

#define OAL_KITL_SERIAL_PACKET      0xAA

static const UINT8 g_kitlSign[] = { 'k', 'I', 'T', 'L' };

static struct {
    OAL_KITL_SERIAL_DRIVER *pDriver;
    KITL_SERIAL_INFO info;
    UINT32 recvBuffer[KITL_MTU/sizeof(UINT32)];
    UINT16 recvCount;
    UINT16 recvPayload;
} g_kitlSerialState;

#include <pshpack1.h>
typedef struct {
    UINT32 signature;
    UCHAR  packetType;
    UCHAR  reserved;
    USHORT payloadSize; // packet size, not including this header
    UCHAR  crcData;
    UCHAR  crcHeader;
} OAL_KITL_SERIAL_HEADER;
#include <poppack.h>

// header checksum size == size of the header minus the checksum itself
#define HEADER_CHKSUM_SIZE      (sizeof (OAL_KITL_SERIAL_HEADER) - sizeof (UCHAR))

//------------------------------------------------------------------------------
//
//  Function:  ChkSum
//
//  Calculate 8-bit check sum
//
static UINT8 ChkSum(UINT8 *pBuffer, UINT16 length)
{
    UINT8 sum = 0;
    int   nLen = length;

    while (nLen -- > 0) sum += *pBuffer++;
    return sum;
}

//------------------------------------------------------------------------------
//
//  Function:  SerialSend
//
//  This function is called by KITL to send packet over transport layer
//
static BOOL SerialSend(UINT8 *pData, UINT16 length)
{
    UINT16 bestSize = (UINT16)g_kitlSerialState.info.bestSize;
    UINT16 total = length;
    UINT16 toSend, sent;

    OALMSGS(OAL_KITL&&OAL_VERBOSE, (
        L"+SerialSend(0x%08x, %d)\r\n", pData, length
    ));

    // block until send is complete; no timeout
    while (total > 0) {
        toSend = (total > bestSize) ? bestSize : total;
        sent = g_kitlSerialState.pDriver->pfnSend(pData, toSend);
        total -= sent;
        pData += sent;
    }

    // notify driver packet end if function exist (USB serial would need this)
    if (g_kitlSerialState.pDriver->pfnSendComplete != NULL) {
        g_kitlSerialState.pDriver->pfnSendComplete(length);
    }
    
    OALMSGS(OAL_KITL&&OAL_VERBOSE, (L"-SerialSend(rc = 1)\r\n"));
    return TRUE;
}

//
// We'll retry a few times when there is no data on the wire before toggling the 
// flow control. Some desktop machines would gets interrupt-stormed if we toggle
// the control line too fast.
//
#define RECV_RETRY  200

//------------------------------------------------------------------------------
//
//  Function:  SerialRecv
//
//  This function is called by KITL to receive packet from transport layer
//
static BOOL SerialRecv(UINT8 *pData, UINT16 *pLength)
{
    UINT8 *pBuffer = (UINT8*)g_kitlSerialState.recvBuffer;
    OAL_KITL_SERIAL_HEADER *pHeader = (OAL_KITL_SERIAL_HEADER*)pBuffer;
    UINT16 bestSize = (UINT16)g_kitlSerialState.info.bestSize;
    UINT16 recvCount = g_kitlSerialState.recvCount;
    UINT16 recvPayload = g_kitlSerialState.recvPayload;
    UINT16 count, rc = 0;
    DWORD  dwRetry = 0;

   
    OALMSGS(OAL_KITL&&OAL_VERBOSE, (
        L"+SerialRecv(0x%08x, %d)\r\n", pData, *pLength
    ));


    if (g_kitlSerialState.pDriver->pfnFlowControl) {
        g_kitlSerialState.pDriver->pfnFlowControl (TRUE);
    }

    // Loop till there are data or we received a full packet
    while (recvCount < (sizeof(OAL_KITL_SERIAL_HEADER) + recvPayload)) {

        // Call driver read function, with best size
        count = g_kitlSerialState.pDriver->pfnRecv(
            &pBuffer[recvCount], bestSize
        );

        // Break loop when no are avaiable
        if (count == 0) {

            if (g_kitlSerialState.pDriver->pfnFlowControl
                && (dwRetry ++ < RECV_RETRY)) {
                continue;
            }
            break;
        }

        // Update amount of data received
        recvCount += count;

        // When we already know packet payload we can try next read
        if (recvPayload != 0) continue;
        
        // If we don't get full header just verify header
        while (recvCount >= sizeof(OAL_KITL_SERIAL_HEADER)) {
            // When we get full signature break loop and continue
            if (memcmp(g_kitlSign, pBuffer, sizeof(g_kitlSign)) == 0) break;
            // Shift buffer by one byte and try again
            for (count = 1; count < recvCount;  count++) {
                pBuffer[count - 1] = pBuffer[count];
            }
            recvCount--;
        }            

        // Did we received header?
        if (recvCount >= sizeof(OAL_KITL_SERIAL_HEADER)) {
            // Validate header checksum, when we just received the full header
            if (
                ChkSum(pBuffer, HEADER_CHKSUM_SIZE) != pHeader->crcHeader ||
                OAL_KITL_SERIAL_PACKET != pHeader->packetType || 
                KITL_MTU - sizeof(OAL_KITL_SERIAL_HEADER) < pHeader->payloadSize
            ) {
                // Checksum failure, discard the packet
                OALMSGS(OAL_WARN, (L"WARN: SerialRecv: "
                    L"Header checksum error, discarded...\r\n"
                ));
                recvCount = 0;
                continue;
            }
            // Now we know how large payload should be
            recvPayload = pHeader->payloadSize;
        }
    }

    // Did we receive full packet? If no leave for now...
    if (
        recvPayload == 0 ||
        recvCount < (sizeof(OAL_KITL_SERIAL_HEADER) + recvPayload)
    ) goto cleanUp;


    // Received the full packet, calculate checksum
    if (ChkSum(
        pBuffer + sizeof(OAL_KITL_SERIAL_HEADER), recvPayload
    ) != pHeader->crcData) {
        OALMSGS(OAL_WARN, (L"WARN: SerialRecv: "
            L"Packet checksum error, discarded...\r\n"
        ));
        recvCount = recvPayload = 0;
        goto cleanUp;
    }

    // Valid packet received, check length requested
    if (*pLength < sizeof(OAL_KITL_SERIAL_HEADER) + recvPayload) {
        OALMSGS(OAL_WARN, (L"ERROR: SerialRecv: "
            L"Received packet too large, discarded...\r\n"
        ));
        recvCount = recvPayload = 0;
        goto cleanUp;
    }        

    // We have complete packet, indicate it up...
    memcpy(pData, pBuffer, sizeof(OAL_KITL_SERIAL_HEADER) + recvPayload);
    rc = sizeof(OAL_KITL_SERIAL_HEADER) + recvPayload;
    recvCount = recvPayload = 0;

cleanUp:

    // Save state variable
    g_kitlSerialState.recvCount = recvCount;
    g_kitlSerialState.recvPayload = recvPayload;
    *pLength = rc;

    if (g_kitlSerialState.pDriver->pfnFlowControl) {
        g_kitlSerialState.pDriver->pfnFlowControl (FALSE);
    }

    OALMSGS(OAL_KITL&&OAL_VERBOSE, (L"-SerialRecv(*pLength = %d)\r\n", rc));
    return rc != 0;
}

//------------------------------------------------------------------------------
//
//  Function:  SerialEndcode
//
//  This function encode packet for serial transport. It simply add header
//  structure at the start of frame.
//
static BOOL SerialEncode(UINT8 *pFrame, UINT16 size)
{
    OAL_KITL_SERIAL_HEADER *pHeader = (OAL_KITL_SERIAL_HEADER*)pFrame;

    memcpy(&pHeader->signature, g_kitlSign, sizeof(pHeader->signature));
    pHeader->packetType = OAL_KITL_SERIAL_PACKET;
    pHeader->payloadSize = size;
    pHeader->crcData = ChkSum(pFrame + sizeof(OAL_KITL_SERIAL_HEADER), size);
    pHeader->crcHeader = ChkSum(pFrame, HEADER_CHKSUM_SIZE);
    return TRUE;
}

//------------------------------------------------------------------------------
//
//  Function:  SerialDecode
//
//  This function decode packet from serial transport. It verified packet
//  header and return pointer to packet body plus body size.
//
static UINT8* SerialDecode(UINT8 *pFrame, UINT16 *pSize)
{
    UINT8 *pData;
    
    *pSize -= sizeof(OAL_KITL_SERIAL_HEADER);
    pData = pFrame + sizeof(OAL_KITL_SERIAL_HEADER);
    return pData;
}

//------------------------------------------------------------------------------
//
//  Function:  SerialEnableInt
//
//  This function is called by KITL to enable and disable the KITL transport
//  interrupt if the transport is interrupt-based
//
static void SerialEnableInt(BOOL enable)
{
    if (enable) {
        g_kitlSerialState.pDriver->pfnEnableInts();
    } else {
        g_kitlSerialState.pDriver->pfnDisableInts();
    }        
}

//------------------------------------------------------------------------------
//
//  Function:  SerialGetDevCfg
//
//  This function is called by KITL to get information about transport layer.
//  There is nothing useful for serial.
//
static BOOL SerialGetDevCfg(UINT8 *pBuffer, UINT16 *pSize)
{
    *pSize = 0;
    return TRUE;
}

//------------------------------------------------------------------------------
//
//  Function:  SerialGetDevCfg
//
//  This function is called by KITL to with information sent by
//  host in negotiation. There is nothing useful for serial.
//
static BOOL SerialSetHostCfg(UINT8 *pData, UINT16 size)
{
     return TRUE;
}

//------------------------------------------------------------------------------
//
//  Function:  OALKitlSerialInit
//
//  This function initialize serial transport layer. It is called from
//  OEMKitlInit for serial class KITL devices.
//
BOOL OALKitlSerialInit(
    LPSTR deviceId, OAL_KITL_DEVICE *pDevice, OAL_KITL_ARGS *pArgs, 
    KITLTRANSPORT *pKitl
) {
    BOOL rc = FALSE;
    OAL_KITL_SERIAL_DRIVER *pDriver;
    KITL_SERIAL_INFO *pInfo = &g_kitlSerialState.info;
    UINT32 irq, sysIntr, count;

    OALMSGS(OAL_KITL&&OAL_FUNC, (
        L"+OALKitlSerialInit('%S', '%s', 0x%08x, 0x%08x)\r\n",
        deviceId, pDevice->name, pArgs, pKitl
    ));

    // Cast driver config parameter
    pDriver = (OAL_KITL_SERIAL_DRIVER*)pDevice->pDriver;
    if (pDriver == NULL) {
        OALMSGS(OAL_ERROR, (L"ERROR: KITL device driver is NULL\r\n"));
        goto cleanUp;
    }        
    // initialize serial kitl information
    pInfo->pAddress = (UINT8*)pArgs->devLoc.PhysicalLoc;
    pInfo->baudRate = pArgs->baudRate;
    pInfo->dataBits = pArgs->dataBits;
    pInfo->stopBits = pArgs->stopBits;
    pInfo->parity   = pArgs->parity;
    pInfo->bestSize = 1;

    // Call pfnInit
    if (!pDriver->pfnInit(pInfo)) {
        OALMSGS(OAL_ERROR, (L"ERROR: KITL call to pfnInit failed\r\n"));                
        goto cleanUp;
    }

    // Best size can't be larger than MTU
    if (pInfo->bestSize > KITL_MTU) pInfo->bestSize = KITL_MTU;

    // Map and enable interrupt
    if ((pArgs->flags & OAL_KITL_FLAGS_POLL) != 0) {
        sysIntr = (UINT16)KITL_SYSINTR_NOINTR;
    } else {
        // Get IRQ, when interface is undefined use Pin as IRQ
        if (pArgs->devLoc.IfcType == InterfaceTypeUndefined) {
            irq = (UINT16)pArgs->devLoc.Pin;
        } else {
            count = 1;
            if (!OALIntrRequestIrqs(&pArgs->devLoc, &count, &irq)) {
                OALMSGS(OAL_WARN, (
                    L"WARN: KITL can't obtain IRQ for KITL device\r\n"
                ));
                irq = OAL_INTR_IRQ_UNDEFINED;
            }                    
        }
        // Get SYSINTR for IRQ
        if (irq != OAL_INTR_IRQ_UNDEFINED) {
            sysIntr = OALIntrRequestSysIntr(1, &irq, OAL_INTR_TRANSLATE);
            if (sysIntr != SYSINTR_UNDEFINED) {
                OEMInterruptEnable(sysIntr, NULL, 0);
            } else {
                OALMSGS(OAL_WARN, (
                    L"WARN: KITL can't obtain SYSINTR for IRQ %d\r\n", irq
                ));
                sysIntr = KITL_SYSINTR_NOINTR;
            }
        } else {
            sysIntr = KITL_SYSINTR_NOINTR;
        }        
    }

    OALMSGS(OAL_WARN&&(sysIntr == KITL_SYSINTR_NOINTR), (
        L"WARN: KITL will run in polling mode\r\n"
    ));

    //-----------------------------------------------------------------------
    // Initalize KITL transport structure
    //-----------------------------------------------------------------------

    memcpy(pKitl->szName, deviceId, sizeof(pKitl->szName));
    pKitl->Interrupt     = (UCHAR)sysIntr; 
    pKitl->WindowSize    = OAL_KITL_WINDOW_SIZE;
    pKitl->FrmHdrSize    = sizeof(OAL_KITL_SERIAL_HEADER);
    pKitl->dwPhysBuffer  = 0;
    pKitl->dwPhysBufLen  = 0;
    pKitl->pfnEncode     = SerialEncode;
    pKitl->pfnDecode     = SerialDecode;
    pKitl->pfnSend       = SerialSend;
    pKitl->pfnRecv       = SerialRecv;
    pKitl->pfnEnableInt  = SerialEnableInt;
    pKitl->pfnGetDevCfg  = SerialGetDevCfg;
    pKitl->pfnSetHostCfg = SerialSetHostCfg;

    //-----------------------------------------------------------------------
    // Initalize state structure
    //-----------------------------------------------------------------------

    g_kitlSerialState.pDriver = pDriver;

    // Done
    rc = TRUE;
    
cleanUp:
    OALMSGS(OAL_KITL&&OAL_FUNC, (L"-OALKitlSerialInit(rc = %d)\r\n", rc));
    return rc;
}

//------------------------------------------------------------------------------

⌨️ 快捷键说明

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