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

📄 mbserial.c

📁 485串行通讯
💻 C
📖 第 1 页 / 共 3 页
字号:
/*---------------------------------------------------------------------------*/
/**
  @file		mbserial.c
  @brief	Example modbus serial API define file

  This file contains higher level modbus serial utility functions.
  It supports both RTU and ASCII protocol and converts them implicity.


  History:
  Date		Author			Comment
  08-02-2005	AceLan Kao.		Create it.

  @author AceLan Kao.(acelan_kao@moxa.com.tw)
 */
/*---------------------------------------------------------------------------*/

#include "mbserial.h"
#include "modbus_utils.h"

static struct MB_SERIAL_INFO MBSerialInfo[ MAX_PORT_NUM];

/*---------------------------------------------------------------------------*/
/**
  @brief	initializ serial port for modbus protocol
  @return	none
 */
/*---------------------------------------------------------------------------*/
void	MBSerialInit(void)
{
	int i= 0;

	for( i= 0; i< MAX_PORT_NUM; i++)
	{
		MBSerialInfo[ i].Protocol= -1;
		MBSerialInfo[ i].FrameTimeout= 3000;
		MBSerialInfo[ i].CharTimeout= 100;
		MBSerialInfo[ i].Timeout= 3;		///< in seconds
	}
}

/*---------------------------------------------------------------------------*/
/**
  @brief	open serial port for modbus protocol
  @param	port		port number
  @param	protocol	which protocol this port use
  @return	MB_OK for success, on error return error code
 */
/*---------------------------------------------------------------------------*/
int	MBSerialOpen(int port, int protocol)
{
	int RetValue;
	if( ( protocol != MB_RTU_PROTOCOL)
		&& ( protocol != MB_ASCII_PROTOCOL)
		&& ( protocol != MB_TCP_PROTOCOL))
		return ( MB_ERROR_PROTOCOL);

	RetValue= SerialOpen( port);
	if( RetValue < 0)
		return MB_ERROR_OPEN;

	SerialSetSpeed( port, 9600);
	SerialSetParam( port, 0, 8, 1);

	MBSerialInfo[ port].Protocol= protocol;

	return MB_OK;
}

/*---------------------------------------------------------------------------*/
/**
  @brief	read RTU data from port
  @param	port		port number
  @param	buf		buffer for store received data
  @param	len		buffer length
  @return	length of data actually read

  It will block to read data, and will return actually one frame of binary data
  It will verify the data, if format error, it return MB_ERROR_FORMAT
 */
/*---------------------------------------------------------------------------*/
int	MBSerialReadRTU( int port, u8 *buf, int len)
{
	u32 starttime, endtime;
	struct timeval tv;
	int readsocks, len1= 0, len2= 0;
	fd_set fdset;
	u16 crc, org_crc;

	tv.tv_sec = 0;					///< char timeout
	tv.tv_usec = MBSerialGetCharTimeout( port)* 1000;

	/// Serial timeout
	GETCLOCKSECOND( starttime);
	while( 1)
	{
		if( SerialDataInInputQueue( port) > 2)
			break;
		GETCLOCKSECOND( endtime);
		if( (endtime-starttime) > MBSerialGetTimeout( port))
			return 0;
	}

	len1= SerialBlockRead( port, (char *)buf, len);
	GETCLOCKMS( starttime);				///< for frame timeout

	FD_ZERO(&fdset);
	FD_SET( FindFD(port), &fdset);
	while( 1)
	{
		readsocks = select( FindFD(port)+ 1, &fdset, NULL, NULL, &tv);
		if(readsocks == 0)			///< char timeout
			break;

		len2= SerialBlockRead( port, (char *)buf+ len1, len- len1);
		len1+= len2;

		GETCLOCKMS( endtime);
		if( endtime > starttime)		///< frame timeout
		{
			if( endtime-starttime > MBSerialGetFrameTimeout( port))
				break;
		}
		else					///< number loop back
			if( ( U32_MAX_VALUE- starttime) + endtime > MBSerialGetFrameTimeout( port))
				break;
	}

	// Check CRC
	crc= CRC16( buf, len1- 2);
	GETU16( org_crc, buf+ len1- 2);
	if( crc != org_crc)
		return MB_ERROR_FORMAT;

	return len1;
}

/*---------------------------------------------------------------------------*/
/**
  @brief	read ASCII data from port
  @param	port		port number
  @param	buf		buffer for store received data
  @param	len		buffer length
  @return	length of data actually read

  It will block to read data, and will return actually one frame of binary data
  It will verify the data, if format error, it return MB_ERROR_FORMAT
 */
/*---------------------------------------------------------------------------*/
int	MBSerialReadASCII( int port, u8 *buf, int len)
{
	u8 tmp[ MB_ASCII_ADU_MAX_LENGTH];
	int tmp_len= 0, ret_len= 0, end_flag= 0;
	u32 starttime, endtime;
	u8 ch;
	u8 lrc;

	struct timeval tv;
	int readsocks, len1= 0, len2= 0;
	fd_set fdset;

	tv.tv_sec = 1;					///< ascii char timeout
	tv.tv_usec = 0;

	/// Serial timeout
	GETCLOCKSECOND( starttime);
	while( 1)
	{
		if( SerialDataInInputQueue( port) > 2)
			break;
		GETCLOCKSECOND( endtime);
		if( (endtime-starttime) > MBSerialGetTimeout( port))
			return 0;
	}

	do
	{
		SerialBlockRead( port, (char *)&ch, 1);
	}while( ch != ':');

	FD_ZERO(&fdset);
	FD_SET( FindFD(port), &fdset);
	while( 1)
	{
		readsocks = select( FindFD(port)+ 1, &fdset, NULL, NULL, &tv);
		if(readsocks == 0)			// char timeout
			break;

		if( SerialBlockRead( port, (char *)&ch, 1))
		{
			if( ch == ':')			// a new frame start here!!
			{				// normally, we'll drop a frame
				tmp_len= 0;		// but it's better to read it in
			}
			else if( ch == 0x0d)		// prepare to stop
			{
				if( end_flag == 0)
					end_flag= 1;
				else			// receive two CR char
					return MB_ERROR_FORMAT;
			}
			else if( ch == 0x0a)
			{
				if( end_flag == 1)	// actually one frame receive
					break;
				else
					return MB_ERROR_FORMAT;
			}

			tmp[ tmp_len++]= ch;
		}
	}
	ret_len= MBASCIIToData( buf, tmp, tmp_len);

	// check LRC
	lrc= LRC( buf, ret_len- 1);
	if( lrc != buf[ ret_len- 1])
		return MB_ERROR_FORMAT;

	return ret_len;
}

/*---------------------------------------------------------------------------*/
/**
  @brief	block read data from port
  @param	port		port number
  @param	buf		buffer for store received data
  @param	len		buffer length
  @return	length of data actually read

  It blocks and reads data, and will return actually one frame of binary data
  On error return error code
 */
/*---------------------------------------------------------------------------*/
int	MBSerialBlockRead(int port, u8 *buf, int len)
{
	int ret_len= 0;
	if( MBSerialInfo[ port].Protocol == MB_RTU_PROTOCOL)
		ret_len= MBSerialReadRTU( port, buf, len);
	else if( MBSerialInfo[ port].Protocol == MB_ASCII_PROTOCOL)
		ret_len= MBSerialReadASCII( port, buf, len);
	else
		return MB_ERROR_PROTOCOL;

	return ret_len;
}

/*---------------------------------------------------------------------------*/
/**
  @brief	non-block read data from port
  @param	port		port number
  @param	buf		buffer for store received data
  @param	len		buffer length
  @return	length of data actually read
 */
/*---------------------------------------------------------------------------*/
int	MBSerialNonBlockRead(int port, u8 *buf, int len)
{
	return SerialNonBlockRead( port, (char *)buf, len);
}

/*---------------------------------------------------------------------------*/
/**
  @brief	write data to port
  @param	port		port number
  @param	pdu		PDU packet
  @param	len		PDU size
  @param	address		destination device id
  @return	length of data actually write, on error return error code
 */
/*---------------------------------------------------------------------------*/
int	MBSerialWrite(int port, u8 *pdu, int len, u8 address)
{
	u8 adu[ MB_ASCII_ADU_MAX_LENGTH];
	int adu_len;
	int i;

	adu_len= MBMakeADU( adu, MBSerialInfo[ port].Protocol, address, pdu, len, 0);

	printf("Port 2 Send Data:\n\t");
	for (i = 0; i<adu_len; i++)
		printf("%02x ", adu[i]);
	printf("\n");

	return SerialWrite( port, (char *)adu, adu_len);
}

/*---------------------------------------------------------------------------*/
/**
  @brief	close the serial port
  @param	port		port number
  @return	MB_OK for success, on error return error code
 */
/*---------------------------------------------------------------------------*/
int	MBSerialClose(int port)
{
	// TODO : need to do more checking before close
	return SerialClose( port);
}

/*---------------------------------------------------------------------------*/
/**
  @brief	set flow control
  @param	port		port number
  @param	control		HW_FLOW_CONTROL or SW_FLOW_CONTROL
  @return	MB_OK for success, on error return error code
 */
/*---------------------------------------------------------------------------*/
int	MBSerialFlowCtrl(int port, int control)
{
	return SerialFlowControl( port, control);
}

/*---------------------------------------------------------------------------*/
/**
  @brief	set serial port parameter
  @param	port		port number
  @param	parity		parity check, 0: none, 1: odd, 2: even, 3: space
  @param	databits	data bits
  @param	stopbit		stop bit
  @return	return MB_OK for success, on error return error code
 */
/*---------------------------------------------------------------------------*/
int	MBSerialSetParam( int port, int parity, int databits, int stopbit)
{
	return SerialSetParam( port, parity, databits, stopbit);
}

/*---------------------------------------------------------------------------*/
/**
  @brief	send adu packet through serial port
  		and wait response adu from slave
  @param	port		port number
  @param	buf		input buffer for receive adu from slave
  @param	pdu		pdu data prepare to send to slave
  @param	len		pdu length
  @param	address		slave id
  @return	MB_OK for success, on error return error code
 */
/*---------------------------------------------------------------------------*/
int	MBSerialSendAndWaitResponse(int port, u8 *buf, u8 *pdu, int len, u8 address)
{
	int ret_len= 0;

	MBSerialWrite( port, pdu, len, address);

	if( MBSerialInfo[ port].Protocol == MB_ASCII_PROTOCOL)
		ret_len= MBSerialReadASCII( port, buf, MB_ASCII_ADU_MAX_LENGTH);
	else if( MBSerialInfo[ port].Protocol == MB_RTU_PROTOCOL)
		ret_len= MBSerialReadRTU( port, buf, MB_RTU_ADU_MAX_LENGTH);
	else
		return MB_ERROR_PROTOCOL;

	// Multiple slave devices connect to the same serial port
	// TODO: make the response data useable
	//if( MBGetAddress( buf) != address)
	//	return MB_ERROR_EXECPTION;

	return ret_len;
}

/*---------------------------------------------------------------------------*/
/**
  @brief	get frame timeout
  @param	port		port number
  @return	frame timeout value
 */
/*---------------------------------------------------------------------------*/
u32	MBSerialGetFrameTimeout(int port)
{
	return MBSerialInfo[ port].FrameTimeout;
}

/*---------------------------------------------------------------------------*/
/**
  @brief	set frame timeout
  @param	port		port number
  @param	timeout		new frame timeout value
  @return	none
 */
/*---------------------------------------------------------------------------*/
void	MBSerialSetFrameTimeout(int port, u32 timeout)
{
	MBSerialInfo[ port].FrameTimeout= timeout;
}

/*---------------------------------------------------------------------------*/
/**
  @brief	get char timeout
  @param	port		port number
  @return	char timeout value
 */
/*---------------------------------------------------------------------------*/
u32	MBSerialGetCharTimeout(int port)
{
	return MBSerialInfo[ port].CharTimeout;
}

/*---------------------------------------------------------------------------*/
/**
  @brief	set char timeout
  @param	port		port number
  @param	timeout		new frame timeout value
  @return	none
 */
/*---------------------------------------------------------------------------*/
void	MBSerialSetCharTimeout(int port, u32 timeout)
{
	MBSerialInfo[ port].CharTimeout= timeout;
}

/*---------------------------------------------------------------------------*/
/**
  @brief	get response timeout
  @param	port		port number
  @return	timeout value
 */
/*---------------------------------------------------------------------------*/
u32	MBSerialGetTimeout(int port)
{
	return MBSerialInfo[ port].Timeout;
}

/*---------------------------------------------------------------------------*/
/**
  @brief	set new response timeout
  @param	port		port number
  @param	timeout		new response timeout value
  @return	none
 */
/*---------------------------------------------------------------------------*/
void	MBSerialSetTimeout(int port, u32 timeout)
{
	MBSerialInfo[ port].Timeout= timeout;
}

/*---------------------------------------------------------------------------*/
/**
  @brief	get device address from ADU
  @param	adu		ADU data
  @return	none
 */
/*---------------------------------------------------------------------------*/
u8	MBSerialGetAddress( const u8 *adu)
{
	return MBGetAddress( adu);
}

/*---------------------------------------------------------------------------*/
/**

⌨️ 快捷键说明

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