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

📄 kitlserial.c

📁 Windows CE 6.0 BSP for VOIP sample phone. Intel PXA270 platform.
💻 C
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
//------------------------------------------------------------------------------
//
//  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;

    KITL_RETAILMSG(ZONE_SEND, (
        "+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);
    }
    
        KITL_RETAILMSG(ZONE_SEND, ("-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;
    UINT8  cSum;

   
    KITL_RETAILMSG(ZONE_RECV, (
        "+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 ((cSum = ChkSum(pBuffer, HEADER_CHKSUM_SIZE)) != pHeader->crcHeader)
            {
                // Checksum failure, discard the packet
                    KITL_RETAILMSG(ZONE_WARNING, ("WARN: SerialRecv: "
                    "Header checksum error, Rec = 0x%02x, Calc'd = 0x%02x, discarded...\r\n",
                    pHeader->crcHeader,cSum
                ));
                recvCount = 0;
                continue;
            }
            else if (OAL_KITL_SERIAL_PACKET != pHeader->packetType)
            {
                // Checksum failure, discard the packet
                    KITL_RETAILMSG(ZONE_WARNING, ("WARN: SerialRecv: "
                    "Packet type wrong, Rec = 0x%02x, Desired = 0x%02x, discarded...\r\n",
                    pHeader->packetType,OAL_KITL_SERIAL_PACKET
                ));
                recvCount = 0;
                continue;
            }
            else if (KITL_MTU - sizeof(OAL_KITL_SERIAL_HEADER) < pHeader->payloadSize)
            {
                // Checksum failure, discard the packet
                    KITL_RETAILMSG(ZONE_WARNING, ("WARN: SerialRecv: "
                    "payload size error, Rec = %d > Max Desired = %d, discarded...\r\n",
                    pHeader->payloadSize, KITL_MTU - sizeof(OAL_KITL_SERIAL_HEADER)
                ));
                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) {
            KITL_RETAILMSG(ZONE_WARNING, ("WARN: SerialRecv: "
            "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) {
        KITL_RETAILMSG(ZONE_WARNING, ("ERROR: SerialRecv: "
            "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);
    }

        KITL_RETAILMSG(ZONE_RECV, ("-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;

    KITL_RETAILMSG(ZONE_KITL_OAL, (
        "+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) {
        KITL_RETAILMSG(ZONE_ERROR, ("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)) {
        KITL_RETAILMSG(ZONE_ERROR, ("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 = KITL_SYSINTR_NOINTR;
    } else {
        // Get IRQ, when interface is undefined use Pin as IRQ
        if (pArgs->devLoc.IfcType == InterfaceTypeUndefined) {
            irq = pArgs->devLoc.Pin;
        } else {
            if (!OEMIoControl(
                IOCTL_HAL_REQUEST_IRQ, &pArgs->devLoc, sizeof(pArgs->devLoc),
                &irq, sizeof(irq), NULL
            )) {                
                KITL_RETAILMSG(ZONE_WARNING, (
                    "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) {
            UINT32 aIrqs[3];
        
            aIrqs[0] = -1;
            aIrqs[1] = OAL_INTR_FORCE_STATIC;
            aIrqs[2] = irq;
            if (
                OEMIoControl(
                    IOCTL_HAL_REQUEST_SYSINTR, aIrqs, sizeof(aIrqs), &sysIntr,
                    sizeof(sysIntr), NULL
                ) && sysIntr != SYSINTR_UNDEFINED
            ) {                
                OEMInterruptEnable(sysIntr, NULL, 0);
            } else {
                KITL_RETAILMSG(ZONE_WARNING, (
                    "WARN: KITL can't obtain SYSINTR for IRQ %d\r\n", irq
                ));
                sysIntr = KITL_SYSINTR_NOINTR;
            }
        } else {
            sysIntr = KITL_SYSINTR_NOINTR;
        }
    }

    if(sysIntr == KITL_SYSINTR_NOINTR) {
        KITL_RETAILMSG(ZONE_WARNING, (
            "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:
    KITL_RETAILMSG(ZONE_KITL_OAL, ("-OALKitlSerialInit(rc = %d)\r\n", rc));
    return rc;
}

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

⌨️ 快捷键说明

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