📄 mbserial.c
字号:
/*---------------------------------------------------------------------------*/
/**
@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 + -