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

📄 ps2socket.c

📁 基于Jennic公司Zigbee芯片JN5139做的无线键盘项目源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
 *
 * MODULE:             Wireless PS2 Bus, Host (Socket) Interface
 *
 * COMPONENT:          $RCSfile$
 *
 * VERSION:            $Name$
 *
 * REVISION:           $Revision$
 *
 * DATED:              $Date$
 *
 * STATUS:             $State$
 *
 * AUTHOR:             APV Ward
 *
 * DESCRIPTION:
 * Driver for a PS2 synchronous serial bus, host interface.
 * A PS2 host provides a socket service, ie presents a PS2 socket (probably as
 * a PC) for a keyboard, mouse or other PS2 device.
 * PS2 hosts (socket) act as clock slaves, the PS2 device (plug) controls
 * the clock line.
 *
 * CHANGE HISTORY:
 *
 * $Log$
 *
 * LAST MODIFIED BY:   $Author$
 *                     $Modtime$
 *
 ****************************************************************************
 *
 * This software is owned by Jennic and/or its supplier and is protected
 * under applicable copyright laws. All rights are reserved. We grant You,
 * and any third parties, a license to use this software solely and
 * exclusively on Jennic products. You, and any third parties must reproduce
 * the copyright and warranty notice and any other legend of ownership on each
 * copy or partial copy of the software.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS". JENNIC MAKES NO WARRANTIES, WHETHER
 * EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
 * ACCURACY OR LACK OF NEGLIGENCE. JENNIC SHALL NOT, IN ANY CIRCUMSTANCES,
 * BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, SPECIAL,
 * INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON WHATSOEVER.
 *
 * Copyright Jennic Ltd 2005, 2006. All rights reserved
 *
 ****************************************************************************/

/****************************************************************************/
/***        Include files                                                 ***/
/****************************************************************************/

#include "jendefs.h"
#include "ZKBconfig.h"
#include "PS2socket.h"
#include <AppHardwareApi.h>

/****************************************************************************/
/***        Macro Definitions                                             ***/
/****************************************************************************/

/* Clock and data-line control macros: easier to read */

#define vSET_CLOCK_HIGH	vAHI_DioSetDirection( PS2_DIO_CLOCK, (uint32) 0    )
#define vSET_CLOCK_LOW	vAHI_DioSetDirection( (uint32) 0,    PS2_DIO_CLOCK )

#define vSET_DATA_HIGH	vAHI_DioSetDirection( PS2_DIO_DATA,  (uint32) 0    )
#define vSET_DATA_LOW	vAHI_DioSetDirection( (uint32) 0,    PS2_DIO_DATA  )

#define	boCLOCK_IS_HIGH	  (u32AHI_DioReadInput() & PS2_DIO_CLOCK)
#define	boCLOCK_IS_LOW	(!(u32AHI_DioReadInput() & PS2_DIO_CLOCK))

#define	boDATA_IS_HIGH	  (u32AHI_DioReadInput() & PS2_DIO_DATA)
#define	boDATA_IS_LOW	(!(u32AHI_DioReadInput() & PS2_DIO_DATA))

/* for debug scope */
#define vSET_TRIG_HIGH	vAHI_DioSetDirection( DEBUG_EXT_TRIG, (uint32) 0    )
#define vSET_TRIG_LOW	vAHI_DioSetDirection( (uint32) 0,    DEBUG_EXT_TRIG )

/****************************************************************************/
/***        Type Definitions                                              ***/
/****************************************************************************/

/****************************************************************************/
/***        Local Function Prototypes                                     ***/
/****************************************************************************/

PRIVATE uint16 u16FindStartBit			(void);
PRIVATE uint16 u16FindDataBit			(void);
PRIVATE uint16 u16FindParityBit			(uint8);
PRIVATE uint16 u16FindStopBit			(void);
PRIVATE uint16 u16FindClkFallingEdge	(void);
PRIVATE void   vIdle                    (void);

/* Write byte functions */
PRIVATE void   vWait100us				(void);
PRIVATE bool_t boDeviceClkStarted		(void);
PRIVATE bool_t boDataBitClocked			(void);
PRIVATE bool_t boDataWentLow			(void);
PRIVATE bool_t boClockWentLow			(void);
PRIVATE bool_t boDataClkReleased		(void);

/****************************************************************************/
/***        Exported Functions                                            ***/
/****************************************************************************/


/****************************************************************************
 *
 * NAME: u16PS2socketInit
 *
 * DESCRIPTION:
 * Initialises the PS2 interface into a known state by setting the PS2
 * bus to idle.
 *
 * PARAMETERS: 	None.
 *
 * RETURNS:		PS2_STATUS_SUCCESS
 *
 ****************************************************************************/

PUBLIC uint16 u16PS2socketInit(void)
{
	/* set debug scope trigger as output and low */
	vAHI_DioSetOutput   ( (uint32) 0, DEBUG_EXT_TRIG);
	vAHI_DioSetDirection( (uint32) 0, DEBUG_EXT_TRIG);

	vIdle();
	return PS2_STATUS_SUCCESS;
}

/****************************************************************************
 *
 * NAME: u16PS2socketClose
 *
 * DESCRIPTION:
 * Closes the PS2 interface by setting the PS2 bus to idle.
 *
 * PARAMETERS: 	None.
 *
 * RETURNS:		PS2_STATUS_SUCCESS
 *
 ****************************************************************************/

PUBLIC void vPS2socketClose(void)
{
	vIdle();
}

/****************************************************************************
 *
 * NAME: vPS2socketBusEnable
 *
 * DESCRIPTION:
 * Enable the PS2 bus by releasing the open-collector clock line.
 *
 * PARAMETERS: 	None.
 *
 * RETURNS:		Void
 *
 ****************************************************************************/

PUBLIC void vPS2socketBusEnable(void)
{
	/* set clock and data lines as inputs */
	vAHI_DioSetDirection( (PS2_DIO_DATA | PS2_DIO_CLOCK), (uint32) 0);
}

/****************************************************************************
 *
 * NAME: vPS2socketBusDisable
 *
 * DESCRIPTION:
 * Disable the PS2 bus by pulling the open-collector clock line low.
 *
 * PARAMETERS: 	None.
 *
 * RETURNS:		Void
 *
 ****************************************************************************/

PUBLIC void vPS2socketBusDisable(void)
{
	vIdle();
}

/****************************************************************************
 *
 * NAME: boPS2socketBusReady
 *
 * DESCRIPTION:
 * Returns the current status of the PS2 clock and data lines.
 * Both lines low indicates bus active - also consistant with a start bit.
 *
 * PARAMETERS: 	None.
 *
 * RETURNS:		TRUE if both clock and data lines are low.
 *
 ****************************************************************************/

PUBLIC bool_t boPS2socketBusReady(void)
{
	/* if clock and data lines are low, then PS2 data burst has started */
	return (bool_t) ( ! (u32AHI_DioReadInput() & (PS2_DIO_CLOCK | PS2_DIO_DATA)) );
}

/****************************************************************************
 *
 * NAME: boPS2socketBusIdle
 *
 * DESCRIPTION:
 * Returns the current status of the PS2 clock and data lines.
 * Both lines high indicates bus idle.
 *
 * PARAMETERS: 	None.
 *
 * RETURNS:		TRUE if both clock and data lines are high (bus idle).
 *
 ****************************************************************************/

PUBLIC bool_t boPS2socketBusIdle(void)
{
	/* if BOTH clock and data lines are high, then PS2 bus is idle */
	return	(bool_t)( (u32AHI_DioReadInput() & (PS2_DIO_CLOCK | PS2_DIO_DATA))
	  	                                    == (PS2_DIO_CLOCK | PS2_DIO_DATA)
		            );
}

/****************************************************************************
 *
 * NAME: boPS2socketBusStarted
 *
 * DESCRIPTION:
 * Returns the current status of the PS2 clock and data lines.
 * Both lines low indicates bus active - also consistant with a start bit.
 * Scan lines for at least 100 us, return earlier if bus cycle starts.
 *
 * PARAMETERS: 	None.
 *
 * RETURNS:		TRUE if both clock and data lines are low.
 *
 ****************************************************************************/

PUBLIC bool_t boPS2socketBusStarted(void)
{
	vAHI_TimerStartSingleShot(PS2_SOCKET_TIMER, 100, 100);

	while ( ! (u8AHI_TimerFired(PS2_SOCKET_TIMER) & E_AHI_TIMER_INT_PERIOD) )
	{
		/* if clock and data lines are low, then PS2 data burst has started */
		if( ! (u32AHI_DioReadInput() & (PS2_DIO_CLOCK | PS2_DIO_DATA)) )
		{
			vAHI_TimerStop(PS2_SOCKET_TIMER);
			return TRUE;
		}
	}
	return FALSE;
}

/****************************************************************************
 *
 * NAME: u16PS2socketRead
 *
 * DESCRIPTION:
 * Read a data burst from the PS2 device.
 *
 * A full description of the PS2 bus protocol would not be appropriate here.
 * However, here is a simple overview of a read sequence:
 *
 * PS2 device drives the clock line, unless the line is already low(device disabled).
 * Falling edge of the clock line strobes valid date.
 * Data burst starts with an active low start bit,
 * followed by 8 data bits (LSB first)
 * followed by an ODD parity bit,
 * followed by an active high stop bit.
 *
 * At any stage a data burst can be aborted if the open-collector clock line
 * is pulled low for more than 100 uS.  If this happens before the 11th data bit
 * period has completed, then the data burst must be sent again (after the clock
 * line has been released for more than 50 uS).
 *
 * PARAMETERS: 	None.
 *
 * RETURNS:		uint16 - PS2 code (8 bits), or error code (16 bits)
 *
 ****************************************************************************/

PUBLIC uint16 u16PS2socketRead(void)
{
	uint8	u8Loop;
	uint8	u8Read = 0;
	uint8	u8ParityCount = 0;
	uint16	u16Status;

	/* enter here after detecting a falling edge on PS2 clock line */

	/* check for the start bit from the bus, abort if not present */
	u16Status = u16FindStartBit();
	if (u16Status != PS2_STATUS_START_BIT)
		return u16Status;

	/*	Now look for the data part of the transmission */
	for (u8Loop = 0; u8Loop < PS2_DATA_WIDTH; u8Loop++)
	{
		u16Status = u16FindDataBit(); /* look for single clocked-data bit */

		switch (u16Status)
		{
			case PS2_STATUS_DATA_1_BIT:
				u8Read |= (0x01 << u8Loop);
				u8ParityCount++;
				break;

			case PS2_STATUS_DATA_0_BIT:
				/* bit accumulator already 0 */
				break;

			case PS2_ERROR_DEVICE_CLK_DATA_TO: /* timeout */
				return u16Status;
				break;

			default:
				/* Error condition catch-all */
				return PS2_ERROR_UNKNOWN;
				break;
		}
	}

	/* look for the parity bit, abort if not correct */
	u16Status = u16FindParityBit(u8ParityCount);
	if (u16Status != PS2_STATUS_SUCCESS)
		return u16Status;

	/* look for a stop bit, abort if not present */
	u16Status = u16FindStopBit();
	if (u16Status == PS2_ERROR_NO_STOP_BIT)
		return u16Status;

	/* successful read from the PS2 bus, return code */
	return (uint16) u8Read;
}


/****************************************************************************
 *
 * NAME: u16PS2socketWrite
 *
 * DESCRIPTION:
 * PS2 bus write sequence.  The PS2 bus is bidirectional, for a PS2 keyboard
 * the back channel carries config and status commands (auto-repeat rates,
 * shift, caps lock LED control etc).
 *
 * This function NOT used in this keyboard demo application.
 *
 * PARAMETERS: 	None.
 *
 * RETURNS:		PS2_STATUS_SUCCESS if write successful, else these error coes
 *				PS2_ERROR_DEVICE_CLK_START_TO
 *				PS2_ERROR_DEVICE_CLK_DATA_TO
 *				PS2_ERROR_DEVICE_CLK_PARY_TO
 *				PS2_ERROR_DEVICE_ACK_0
 *				PS2_ERROR_DEVICE_ACK_1
 *				PS2_ERROR_DEVICE_ACK_2
 *
 ****************************************************************************/

PUBLIC uint16 u16PS2socketWrite(uint8 u8Datum)
{
	uint8 u8Loop;
	uint8 u8ParityCount = 0;

	/* DEBUG */
	vSET_TRIG_HIGH;

	// 1)   Bring the Clock line low for at least 100 microseconds.
	//      Both output latches low, but data is an input
	vIdle();
	vWait100us();

	// 2)   Bring the Data line low.
	vSET_DATA_LOW;

	// 3)   Release the Clock line.
	vSET_CLOCK_HIGH;

	// 4)   Wait for the device to bring the Clock line low.
	if ( ! boDeviceClkStarted() )
		return PS2_ERROR_DEVICE_CLK_START_TO;

	/* send data byte */
	for (u8Loop = 0; u8Loop < PS2_DATA_WIDTH; u8Loop++)
	{
		// 5)   Set/reset the Data line to send the first data bit
		if (u8Datum & (0x01 << u8Loop))
		{
			vSET_DATA_HIGH;
			u8ParityCount++;
		}
		else
		{
			vSET_DATA_LOW;
		}

		// 6)   Wait for the device to bring Clock high.
		// 7)   Wait for the device to bring Clock low.

⌨️ 快捷键说明

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