📄 mb_slv.c
字号:
//parse serial mode
tmp_value = atoi(argv[5]);
if((tmp_value<0) || (tmp_value>2))
{
result=-1;
goto END_PARSE_ARGS;
}
serial_mode = (unsigned char) tmp_value;
}//elseif(argc!=6)
END_PARSE_ARGS:
return result;
}
//***********************************************************
// CRC calculation routine
//***********************************************************
static unsigned int CRC16(unsigned char *puchMsg, unsigned int usDataLen)
{
unsigned char uchCRCHi = 0xFF ; /* high byte of CRC initialized */
unsigned char uchCRCLo = 0xFF ; /* low byte of CRC initialized */
unsigned int uIndex ; /* will index into CRC lookup table */
while (usDataLen--) /* pass through message buffer */
{
uIndex = uchCRCHi ^ *puchMsg++ ; /* calculate the CRC */
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
uchCRCLo = auchCRCLo[uIndex] ;
}
return ((uchCRCHi << 8) | uchCRCLo) ;
}
//***********************************************************
//Init/Deinit serial port for modbus communication
//***********************************************************
int mb_ser_init(int port,
long baud,
int parity,
unsigned char serial_mode)
{
if(0x1954!=fossil_init(port))
{
return MB_ERROR;
}
if(-1==fossil_setbaud(port,baud,parity,8,1))
{
return MB_ERROR;
}
switch(serial_mode)
{
case MB_RS485:
fossil_set_rs485(port, FOSSIL_RS485_HIGHACTIVE);
rs485=1; //set flag
break;
case MB_RS232_HWFLOW:
fossil_set_flowcontrol (port, FOSSIL_FLOWCTRL_RTSCTS );
break;
}
/* Calculate the silent_interval
Please note: the modbus serial spec. expects a max. time interval of 1.5 chars between two
incoming bytes inside of frame, without defining a tolerance of this interval.
At the @CHIP-RTOS, it is not possible to measure exctly 1,5 chars time interval:
Because of this behaviour, we set fixed silent_intervals in dependency of the baudrate
*/
switch(baudrate)
{
case 300: silent_interval = 34; //ms
break;
case 600: silent_interval = 18; //ms
break;
case 1200: silent_interval = 10; //ms
break;
case 2400: silent_interval = 6; //ms
break;
case 4800: silent_interval = 4; //ms
break;
default: silent_interval = 2; //ms
break;
}
frame_wait_interval = silent_interval *2;
return NO_ERROR;
}
//******************************************************************************
void mb_ser_deinit(int port)
{
fossil_deinit (port );
}
//******************************************************************************
//Wait and Receive a modbus request frame via serial fossil
//******************************************************************************
int mb_ser_recv_frame(unsigned char * buf) //buf must provide 256 bytes
{
int byte_count;
int ch=-1;
#ifdef MB_SER_DEBUG
printf("\r\nWait for first incoming byte of frame");
#endif
//1. Wait endless for the first incoming char: must be slave address
while(ch==-1)
{
ch=fossil_getbyte(port);
RTX_Sleep_Time(frame_wait_interval);
}
buf[0]=(unsigned char)ch;
#ifdef MB_SER_DEBUG
printf("\r\nFirst byte received %02X", (unsigned char)ch);
#endif
//2. Receive frame, until a timeout occurs
byte_count = 1;
while(byte_count<MB_SER_MAX_BUF)
{
ch=fossil_getbyte(port);
if(ch==-1)
{
//wait defined interval and try to receive again
RTX_Sleep_Time(silent_interval);
ch=fossil_getbyte(port);
if(ch==-1) break; //timeout reached: frame completely received or not?
}
if(ch!=-1) //Insert byte into recvbuf
{
buf[byte_count++]=(unsigned char)ch;
}
}
//Calculate crc checksum and see, if we got a complete modbus frame
if(byte_count>=4)
{
if(0!=CRC16(buf,byte_count))
{
#ifdef MB_SER_DEBUG
printf("\r\nReceive checksum error\r\n");
#endif
return MB_ERROR;
}
else
{
return MB_NO_ERROR;
}
}
#ifdef MB_SER_DEBUG
printf("\r\nInvalid frame received: Less than 4 bytes\n");
#endif
return MB_ERROR;
}
//******************************************************************************
// General send of a modbus frame via fossil
//******************************************************************************
int mb_ser_send( unsigned char * buf,
unsigned int length)
{
unsigned int result;
unsigned int tcnt;
int ch;
if(rs485)
{
fossil_purge_input (port);
}
result=
tcnt = 0;
//Wait until block, is completely placed into rtos tx serial queue
do
{
result+=fossil_writeblock(port,&buf[result],length-result);
if(result!=length)
{
RTX_Sleep_Time(1);
tcnt++;
if(tcnt>=SEND_QUEUE_TIMEOUT)
{
#ifdef MB_SER_DEBUG
printf("\r\nSend timeout");
#endif
return MB_ERROR;
}
}
else
{
break;
}
}while(result!=length);
//Wait until everything is out of tx queue
fossil_flush_output(port);
RTX_Sleep_Time(frame_wait_interval);
//Try to receive the own frame and check, if frame was correct send
if(rs485)
{
result=
tcnt = 0;
while(result!=length)
{
ch = fossil_getbyte(port);
if(ch==-1)
{
RTX_Sleep_Time(1);
tcnt+=1;
if(tcnt>=SEND_QUEUE_TIMEOUT)
{
#ifdef MB_SER_DEBUG
printf("\r\nRS485 send failed (timeout)\r\n");
#endif
return MB_ERROR;
}
}
else
{
//compare incoming character with send buffer
if((unsigned char)ch!= buf[result++])
{
#ifdef MB_SER_DEBUG
printf("\r\nRS485 send failed(no correct receive of own frame)\r\n");
#endif
return MB_ERROR;
}
}
}
}
return MB_NO_ERROR;
}
/*******************************************************************************
Process an incoming modbus request and send a reply to client
Input parameter: mb_request_buf: contains modbus request frame
********************************************************************************/
int mb_ser_process_request(unsigned char * mb_request_buf, unsigned char * mb_response_buf)
{
unsigned char function_code;
unsigned int response_length;
unsigned int start_address;
unsigned int checksum;
unsigned int output_value;
unsigned int quantity;
unsigned char read_dev_id_length;
unsigned char byte_count;
int result;
#ifdef MB_SER_DEBUG
int i;
#endif
//Check slave address
if((mb_request_buf[0]!=slave_address) && (mb_request_buf[0]!=MB_SER_BCAST))
{
//not for us
return MB_NO_ERROR;
}
function_code = mb_request_buf[1];
#ifdef MB_SER_DEBUG
printf("\r\nmb_ser_process: function 0x%02X\r\n",function_code);
#endif
//general preformat of responsebuffer
mb_response_buf[0]= mb_request_buf[0]; //take slave address
mb_response_buf[1]= mb_request_buf[1]; //take function code
//Preset length of response
response_length = 2; //slave address and function code
switch(function_code)
{
//************************************************************************
//Function code 0x01,0x02: read discrete input, coil
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -