📄 modbus.c
字号:
/******************************************************************************
*
* Copyright (c) 2008 Shanghai IS Software
*
* All rights reserved
*
* $Revision$
*
* $LastChangedBy$
* 1. lcj
*
* $LastChangedData$ :
* 2008/09/27 10:00
*
* Description: modbus RTU Protocol
*
* Revision History:
* 2008/08/28 14:33 by lcj
* #1.created
*****************************************************************************/
#include "md/md_manager.h"
#include "md/md_info.h"
#include "md/md_reg.h"
#include "modbus_rtu/modbus.h"
//#define DEBUG
#define MAKEWORD(a,b) ((((a) << 8) + (b)) & 0xffff)
unsigned char rx_count,tx_count;
unsigned char caddrcode;
unsigned char command;
unsigned char port_no;
char file_data[MAX_CONF_DATA][MAX_CONF];
char dev_name[MAX_DEV_NAME];
int speed;
int num;
int timeout;
int frequecy;
int dev_addr;
#ifdef DEBUG
#define pr_debug(fmt,arg...) \
printf(fmt,##arg)
#else
#define pr_debug(fmt,arg...) \
NULL
#endif
/**
* open uart device .
*
**/
int OpenDev(char *dev)
{
pr_debug("%s\n",dev);
int fd = open(dev, O_RDWR | O_NONBLOCK );
if ( -1 == fd )
{
pr_debug("Can't Open Serial Port!\n");
return -1;
}
else
return fd;
}
/**
* Uart initialize
*
**/
void uart_init(struct modbus mod)
{
set_speed(mod.fd,mod.speed);
if ( set_parity(mod.fd,8,1,'E') == FALSE )
{
pr_debug("Set Parity Error\n");
close(mod.fd);
exit(0);
}
}
/**
* modbus rtu protocol data CRC
*
**/
unsigned short crc_check(unsigned char *snd,unsigned char num)
{
unsigned char i,j;
unsigned short c,crc = 0xFFFF;
for ( i = 0; i < num; i++ )
{
c = snd[i] & 0x00FF;
crc ^= c;
for ( j = 0; j < 8; j++ )
{
if ( crc & 0x0001 )
{
crc >>= 1;
crc ^= 0xA001;
}
else
crc >>= 1;
}
}
return crc;
}
void delay(int time)
{
int i,j;
for ( i = 0; i < time; i++ )
for ( j = 0; j < 0x5000; j++ );
}
void set_fl(int fd, int flag)
{
int val;
if ( (val = fcntl(fd,F_GETFL,0)) < 0)
{
pr_debug("fcntl F_GETFL error!\n");
close(fd);
exit(0);
}
val |= flag;
if (fcntl(fd,F_SETFL,val) < 0 )
{
pr_debug("fcntl F_SETFL error!\n");
close(fd);
exit(0);
}
}
/**
* send modbus data
*
**/
void *do_modbus(void *arg)
{
int ret,i,j,k;
int oldtime,newtime;
struct timeval tv;
struct modbus *md = (struct modbus *)arg;
gettimeofday(&tv,NULL);
oldtime = tv.tv_usec;
for ( i = 0 ; md[i].count != 0; i++ )
j = md[i].count;
while ( 1 )
{
i = 0;
gettimeofday(&tv,NULL);
newtime = tv.tv_usec;
while( i < j )
{
if ( (newtime - oldtime) < 0 )
newtime = newtime + 1000000;
if ( (newtime - oldtime) / (md[i].time * 1000) != 0 )
{
md[i].send_flag = 1;
}
i++;
}
for ( i = 0; i < j; i++ )
{
if ( 1 == md[i].send_flag )
{
uart_init(md[i]);
set_fl(md[i].fd,O_RDWR);
pr_debug("Send Data");
for(k = 0; k < 8; k++ )
pr_debug("[0x%x]",md[i].tx_buf[k]);
pr_debug("\n");
ret = write(md[i].fd,md[i].tx_buf,8);
if ( ret < 0 )
{
pr_debug("send data error!\n");
close(md[i].fd);
exit(0);
}
md[i].send_flag = 0;
if(recvframe(&md[i]))
{
ms_sleep(200);
parseframe(md[i]);
}
}
}
}
}
/**
* recv modbus data
*
**/
int recvframe(struct modbus * md)
{
int i,n,max_fd,len,j;
fd_set input;
struct timeval timeout;
unsigned char buff[MAX_LEN];
unsigned char *ptr = buff;
unsigned short wcrc;
FD_ZERO(&input);
FD_SET(md->fd,&input);
max_fd = md->fd + 1;
rx_count = 0;
#if 0
len = md->tx_buf[5]*2+5;
n = read(md->fd,md->rx_buf,len);
if ( n != len )
{
printf("read data error!, errno = %d",errno);
exit(0);
}
wcrc = MAKEWORD(md->rx_buf[len-1],md->rx_buf[len-2]);
if (wcrc != crc_check(md->rx_buf,len -2))
{
#ifdef DEBUG
fprintf(stderr,"Recv Data Err!\n");
#endif
close(md->fd);
exit(0);
}
#else
while (1)
{
timeout.tv_sec = 0;
timeout.tv_usec = 500000; // 100ms
n = select(max_fd,&input,NULL,NULL,&timeout);
if ( n < 0 )
{
pr_debug("select failed");
break;
}
else if ( n == 0 )
{
pr_debug("\nTIMEOUT");
break;
}
else
{
ioctl(md->fd,FIONREAD,&len);
if ( !len )
{
#ifdef DEBUG
fprintf(stderr,"Communication closed by server!\n");
#endif
close(md->fd);
exit(0);
}
len = read(md->fd,ptr,len);
if ( len < 0 )
{
pr_debug("read fail !\n");
close(md->fd);
exit(0);
}
rx_count += len;
pr_debug("Recv Data:");
for ( i = 0; i < len; i++ )
{
md->rx_buf[i] = buff[i];
pr_debug("[%.2x] ",md->rx_buf[i]);
}
}
}
if(!rx_count)
return 0;
wcrc = MAKEWORD(md->rx_buf[len-1],md->rx_buf[len-2]);
if (wcrc != crc_check(md->rx_buf,len -2))
{
pr_debug("Recv Data Err!\n");
return 0;
}
#endif
return 1;
}
/**
* parse the recv of modbus data, and save to the share memory
*
**/
int parseframe(struct modbus md)
{
unsigned short number;
MD_reg_addr regs_addr[NUM_OF_REGS];
MD_reg_value regs_value[NUM_OF_REGS];
MD_info* info;
int i,j,len;
int result;
int status = MD_STATUS_NORMAL;
len = md.rx_buf[2] + 5;
for ( i = 0; i < MAX_FOR_REG_ADDR; i++ )
regs_addr[i] = (MD_reg_addr)i + 0x16;
for ( i = 0; i < MAX_FOR_REG_ADDR; i++ )
regs_value[i] = 0;
for (j = 4,i = 0; i < md.tx_buf[5]; i++,j+= 2 )
{
regs_value[i] = (MAKEWORD(md.rx_buf[j-1],md.rx_buf[j]))& 0xffff;
}
result = init_MD_manager(2, 5, 500);
if ( result )
{
info = create_MD_info(md.name,md.port_no,md.tx_buf[0], NUM_OF_REGS/2,regs_addr);
if(info)
{
if ( 0x01 == md.tx_buf[5])
set_MD_reg_value(info,MAKEWORD(md.tx_buf[2],md.tx_buf[3])+ 1, MAKEWORD(md.rx_buf[len -4],md.rx_buf[len - 3]),status);
else
set_MD_regs_value(info,MAKEWORD(md.tx_buf[2],md.tx_buf[3])+ 1,md.tx_buf[5],regs_value,status);
}
#ifdef DEBUG
print_MD_manager(get_MD_manager());
#endif
}
}
/**
* trim the config file item
*
**/
char *trim(char *str)
{
int len,i = 0;
char *pRet = str;
while ((' ' == (*pRet))||('\t' == (*pRet)))
{
pRet++;
}
len = strlen(pRet);
while (len > 0)
{
if ((' ' == pRet[len-1]) || ('\t' == pRet[len-1]) || ('\n' == pRet[len-1])|| ('\r' == pRet[len-1]))
len--;
else
{
break;
}
}
*(pRet + len) = '\0';
return pRet;
}
/**
* parse the config file item
*
**/
void do_string(char *str)
{
int len,j,i = 0;
char *pstr = str;
char *delim = "[ ]\t ";
char *p;
len = strlen(str);
if ((*pstr) != '[' || pstr[len - 1] != ']' )
{
pr_debug("config file error!\n");
exit(0);
}
strcpy(file_data[i++],strtok(pstr,delim));
while(p = strtok(NULL,delim))
{
strcpy(file_data[i++],p);
}
sscanf(file_data[0],"%x",&port_no);
sscanf(file_data[1],"%d",&speed);
strcpy(dev_name,file_data[2]);
sscanf(file_data[3],"%x",&dev_addr);
sscanf(file_data[4],"%d",&timeout);
sscanf(file_data[5],"%x",&command);
sscanf(file_data[6],"%x",&caddrcode);
sscanf(file_data[7],"%x",&num);
sscanf(file_data[8],"%d",&frequecy);
return ;
}
int main(int argc ,char **argv)
{
int fd;
int j, i = 0;
FILE *pFILE;
char linebuf[CONFIGMAXLINE];
char *pLine;
pthread_t ntid1,ntid2,ntid3;
int err;
int count = 0;
unsigned short crc;
struct modbus mod[MAX_CONF_ITEM];
pFILE = fopen(CONFIG_FILE,"r");
if ( NULL == pFILE )
{
pr_debug("fopen file error!\n");
exit(0);
}
while ( pLine = fgets(linebuf,CONFIGMAXLINE-1,pFILE) ) // read config file data
{
pLine = trim(pLine);
if ( strlen(pLine) < 3)
continue;
if ('#' == (*pLine))
continue;
do_string(pLine);
mod[count].tx_buf[0] = dev_addr;
mod[count].tx_buf[1] = command;
mod[count].tx_buf[2] = 0;
mod[count].tx_buf[3] = caddrcode;
mod[count].tx_buf[4] = 0;
mod[count].tx_buf[5] = num;
crc = crc_check(mod[count].tx_buf, 6);
mod[count].tx_buf[6] = crc & 0xff;
mod[count].tx_buf[7] = crc/0x100;
mod[count].time = frequecy;
mod[count].port_no = port_no;
strcpy(mod[count].name ,dev_name);
mod[count].fd = OpenDev("/dev/ttyS4");
mod[count].send_flag = 0;
mod[count].count = count + 1;
mod[count].speed = speed;
count++;
}
do_modbus(mod);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -