📄 gpsdevicedriver.cpp
字号:
/*******************************************************************************
*------------------------------------------------------------------------------
* Global Locate Inc.
*------------------------------------------------------------------------------
*
* Copyright 2004, 2005, 2006 by GlobalLocate Inc. All Rights Reserved.
* This file contains company confidential and proprietary information.
* This information may not be disclosed to any unauthorized individual.
*
*------------------------------------------------------------------------------
*
* NAME: GpsDeviceDriver.cpp
*
* DESCRIPTION: GpsDeviceDriver using SPI.
*
* NOTES:
*------------------------------------------------------------------------------
*
******************************************************************************/
#include "stdafx.h"
#include "trace.h"
#include <windows.h>
#include <ceddk.h>
#include "xllp_gpio.h"
#include "xllp_ssp.h"
#include "cust_debug.h"
#include "gpsDeviceDriver.h"
#include "spiDriver.h"
#include <pkfuncs.h>
//------------------------------------------------------------------------------
//
// Types
//
//------------------------------------------------------------------------------
// typedef unsigned char UINT8;
// typedef unsigned short UINT16;
// typedef unsigned long int UINT32;
// typedef UINT32 DWORD;
extern volatile XLLP_GPIO_T *v_pGPIORegs;
#ifdef SPI_DONE_INTERRUPT // Use ISR to detect the SPI done
extern HANDLE ghRxDone;
#endif
// See below for a description of how this structure is used.
typedef struct RingBuffer
{
unsigned char* pHead;
unsigned char* pTail;
unsigned char* pEnd;
unsigned char rb[2048];
char* name;
} RingBuffer;
#define BIT(b) (1L << (b))
static DWORD lastReadSR = 0;
static DWORD lastWriteSR = 0;
#define SET_SR(sr) (static_cast<DWORD> (sr) | BIT(31))
bool spiDevClosed;
//------------------------------------------------------------------------------
//
// Customer Configuration.
//
// The run-time environment must define three customer interfaces:
// 1) SPI hardware
// 2) Debug and logging
// 3) OS interfaces
//
//------------------------------------------------------------------------------
#include "cust_debug.h" // debug environment
#include "cust_os.h" // OS environment
#include "cust_hw_spi.h" // SPI hardware
//------------------------------------------------------------------------------
//
// Data
//
// Globals are:
// uiGpsSpiUnderRunErrors - error count
// uiGpsSpiOverRunErrors - error count
//
//------------------------------------------------------------------------------
unsigned int uiGpsSpiUnderRunErrors;
unsigned int uiGpsSpiOverRunErrors;
static RingBuffer Orb; // output ring buffer
static RingBuffer Irb; // input ring buffer
static UINT8 desiredMask; // next copy of the control register.
static UINT8 currentMask; // local copy of the control register.
#include "gpsSerialControl.h"
/*******************************************************************************
*
* Ring Buffer Procedures
*
* Low-level details about the ring buffers.
*
******************************************************************************/
//------------------------------------------------------------------------------
//
// Ring Buffer Structure
//
// We put data into the ring buffer at the HEAD and remove data from the TAIL.
// Empty is when HEAD == TAIL.
// The ring buffer is 4K.
//
// Some illustrations of the HEAD and TAIL for various cases:
//
// Empty Ring Buffer:
// +----------------------------------------------------------+
// | _ |
// +----------------------------------------------------------+
// ^ ^ ^
// | | |
// rb rbTail rbEnd
// ^
// |
// rbHead
//
//
// Partially filled Ring Buffer:
// +----------------------------------------------------------+
// | AXXXXXXXXXXXXXXXX_ |
// +----------------------------------------------------------+
// ^ ^ ^ ^
// | | | |
// rb rbTail rbHead rbEnd
//
//
// Another partially filled Ring Buffer:
// +----------------------------------------------------------+
// |XXXXXXXXXX_ AXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
// +----------------------------------------------------------+
// ^ ^ ^ ^
// | | | |
// rb rbHead rbTail rbEnd
//
//
// Another partially filled Ring Buffer:
// +----------------------------------------------------------+
// |_ AXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
// +----------------------------------------------------------+
// ^ ^ ^
// | \ | |
// | rbHead rbTail rbEnd
// rb
//
//
// Filled Ring Buffer:
// +----------------------------------------------------------+
// |XXXXXXXXXXXXXXXXX0AXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
// +----------------------------------------------------------+
// ^ ^^ ^
// | || |
// rb rbHead rbTail rbEnd
//
// A denotes the next byte to be removed from the ring buffer.
// X denotes the other bytes in the ring buffer.
// _ denotes the location of the next byte to be put into the ring buffer.
// 0 denotes a byte that won't ever be filled.
//
//------------------------------------------------------------------------------
static void
rb__RingBuffer(RingBuffer* pThis, char* pName)
{
pThis->name = pName;
pThis->pHead = pThis->rb;
pThis->pTail = pThis->rb;
pThis->pEnd = pThis->rb + sizeof(pThis->rb);
}
//------------------------------------------------------------------------------
// Compute the count of contiguous bytes in the rb starting at
// the tail. This is not the total data bytes in the rb.
//------------------------------------------------------------------------------
static int
rb__readByteCount(RingBuffer* pThis)
{
if (pThis->pHead >= pThis->pTail)
{
return pThis->pHead - pThis->pTail;
}
return pThis->pEnd - pThis->pTail;
}
//------------------------------------------------------------------------------
// Compute the total count of all bytes in the rb.
//------------------------------------------------------------------------------
static int
rb__readTotalByteCount(RingBuffer* pThis)
{
if (pThis->pTail <= pThis->pHead)
{
return pThis->pHead - pThis->pTail;
}
return (pThis->pEnd - pThis->pTail) + (pThis->pHead - pThis->rb);
}
//------------------------------------------------------------------------------
// Compute the space remaining to the end of the rb.
// This is not the total free space in the rb.
//------------------------------------------------------------------------------
static int
rb__writeByteCount(RingBuffer* pThis)
{
if (pThis->pHead < pThis->pTail)
{
return pThis->pTail - pThis->pHead - 1;
}
int result = pThis->pEnd - pThis->pHead;
if (pThis->pTail == pThis->rb)
{
--result;
}
return result;
}
//------------------------------------------------------------------------------
// We have written some bytes into the RB,
// so bump pointers & counters, etc.
//------------------------------------------------------------------------------
static void
rb__haveWrittenBytes(RingBuffer* pThis, int nBytes)
{
pThis->pHead += nBytes;
ASSERT(pThis->pHead <= pThis->pEnd);
if (pThis->pHead == pThis->pEnd)
{
pThis->pHead = pThis->rb;
}
}
//------------------------------------------------------------------------------
// We have read some bytes from the RB,
// so bump pointers & counters, etc.
//------------------------------------------------------------------------------
static void
rb__haveReadBytes(RingBuffer* pThis, int nBytes)
{
pThis->pTail += nBytes;
ASSERT(pThis->pTail <= pThis->pEnd);
if (pThis->pTail == pThis->pEnd)
{
pThis->pTail = pThis->rb;
}
}
/*******************************************************************************
*
* S P I L a y e r
*
* The next few procedures with names "SPI_<name>" touch the SPI hardware.
*
* The main algorithm to poll for data, send GL controls, write data,
* and handle errors is made clear here.
*
* If your SPI hardware has DMA support, a deep FIFO, etc., then these
* routines will need extensive changes.
*
******************************************************************************/
// OAL/Nkintr.h and link with Nk.lib contains these assembly functions.
// For GL, they are packaged into cpregXsc2.obj.
extern "C" void INTERRUPTS_ON1(void);
extern "C" void INTERRUPTS_OFF1(void);
#if 0 // { see interrupt.s for this:
asm_interrupt_off()
{
LEAF_ENTRY INTERRUPTS_OFF
mrs r0, cpsr
bic r1,r0,#0x80
msr cpsr, r1
RETURN
}
asm_interrupt_on()
{
LEAF_ENTRY INTERRUPTS_OFF
mrs r0, cpsr
orr r1,r0,#0x80
msr cpsr, r1
RETURN
}
#endif // }
//----------------------------------------------------------------------------
//
// SPI_Exchange_Bytes()
//
// Send a command and N bytes of data to the SPI port.
// Return the first byte read from the SPI port at the same time.
// Fill the buffer with the data we read.
//
// Set sizeIn to the amount of data actually transferred.
// If the SPI bus transaction is prematurely terminated, then
// sizeIn will be less than requested.
//
// NOTE: Tune this subroutine for maximum performance, as
// it is the core of the SPI driver. Specifically:
// 1) Use register variables.
// 2) Remove as many debugs as possible.
// 3) Tune the OS_WAIT_US(10) value.
//
//----------------------------------------------------------------------------
UINT8
SPI_Exchange_Bytes(UINT8 cmd, const UINT8* pIn, UINT8* pOut, DWORD& sizeIn)
{
DWORD origSizeIn = sizeIn;
if (sizeIn > 15) sizeIn = 15; // limit ourselves to 1 FIFO of data.
TRACE(TR_SW, sizeIn);
DWORD SpiSR;
HW_SPI_TYPE pSpi = HW_SPI_PTR;
//--------------------------------------------------------------
//
// Send all the data.
//
//--------------------------------------------------------------
bool sentCmd = false;
if (sizeIn > 0)
{
SpiSR = pSpi->ssr;
TRACE(TR_SPI_SR, SpiSR);
if (!(SpiSR & XXLP_SSSP_TNF))
{
TRACE(TR_SW, SpiSR); // Error!
}
else // transmit fifo NOT full
{
sentCmd = true;
// Transmitter is not full - compute the number of bytes
// we can send (plues one for the GPS command byte).
DWORD txSpace = 16 - ((SpiSR >> 8) & 0xF);
if (txSpace < (1+sizeIn))
{
sizeIn = txSpace-1;
}
// else if (sizeIn < txSpace) just xfer sizeIn
const UINT8* pInOrig = pIn;
const UINT8* pInEnd = pIn + sizeIn;
// This code is the same as HW_CHIP_SELECT_ON(), except
// that the interrupts are turned off before we do
// the write to the SPI register.
// The trace is done before the interrupts are off.
DWORD tmp = v_pSPIRegs->sscr0 | XLLP_SSCR0_SSE;
TRACE(TR_SPI_CMD, tmp);
INTERRUPTS_OFF1(); // BEGIN CRITICAL REGION (((
{
v_pSPIRegs->sscr0 = tmp;
HW_SPI_WRITE(pSpi, cmd);
for (; pIn < pInEnd; ++pIn)
{
HW_SPI_WRITE(pSpi, *pIn);
}
SpiSR = pSpi->ssr;
}
#ifdef SHORT_INTERRUPT_OFF_TIME
INTERRUPTS_ON1(); // END CRITICAL REGION )
#endif
#ifdef ENABLE_TRACE // {
TRACE(TR_WR_CMD, cmd);
for (pIn = pInOrig; pIn < pInEnd; ++pIn)
{
TRACE(TR_WR_DATA, *pIn);
}
TRACE(TR_SPI_SR, SpiSR);
#endif // }
}
}
if (!sentCmd)
{
sizeIn = 0;
DWORD tmp = v_pSPIRegs->sscr0 | XLLP_SSCR0_SSE;
TRACE(TR_SPI_CMD, tmp);
INTERRUPTS_OFF1(); // BEGIN CRITICAL REGION (
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -