1. 声 明
软件著作权登记号:2019SR0183260
Copyright: Wu HaiMeng. All rights reserved.Protected by international copyright laws.
Programmer : Wu YuanFu
Version : V2.40
wModbus is provided in source form for FREE short-term evaluation, for educational use or for peaceful research. If you plan or intend to use wModbus in a commercial application/ product then, you need to contact Wu YuanFu240697738@qq.com to properly license wModbusfor its use in your application/product. The fact that the source is provided does NOT mean that you can use it commercially without paying a licensing fee.
Knowledge of the source code may NOT be used to develop a similar product.
捐助支付宝账号 :240697738@qq.com(吴远福) ,有了你的支持,我才能更好的发展,谢谢!
源码地址https://github.com/wuyuanfu240697738/wModbus
1. 背景
Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气 Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。
FreeMODBUS 是一个奥地利人写的Modbus协议栈。它是一个针对嵌入式应用的一个免费的通用MODBUS协议的移植。目前免费版本仅有Slave功能,都支持RTU/ASCII模式。
FreeMODBUS网址:https://www.embedded-solutions.at/en/freemodbus/
uC/MODBUS 是由Micrium公司写的Modbus协议栈。它是一个针对嵌入式应用的一个收费的通用MODBUS协议的移植。目前有Slave和Master功能,都支持RTU/ASCII模式。
Micrium公司网址:https://www.micrium.com/
这两个协议栈最大的特点是每发送一个字节或是接收一个字节就需引入相关的中断处理程序,比如说主机发送01 03 00 02 00 01 25 CA,从机回传01 03 02 12 34 B5 33。不管是对于主机还是从机功能,这两个协议栈都至少需要中断15次。经过测试,在单一的串口处理系统中不会有什么问题,但是需多串口进行modbus通信或是其它类型的串口通信功能,就容易造成串口间的中断冲突,使得通信容易出错。经过测试,在单台嵌入式设备里同时实现主机及从机功能时,主机丢包率在30%以上。
2. 特点
- 减少中断次数,同时减少单个中断程序时间,通信测试达到无错误。
- 以一帧完整的报文为中断响应基础。当发送一帧完整的报文完成后响应一次中断,或是接收到到一帧完整的报文后也响应一次中断。
- 在单嵌入式设备硬件允许的情况下,可同时实现任意多个主机与从机功能。
- 进一步减少RAM内存占用,把接收数据串地址与发送数据串进行合并。
- 提高代码利用率,增加代码可读性,尽可能的保持主机与从机风格统一性。
- 更友好支持tcp功能及其它传输类型扩展。
3. 功能
- wMODBUS协议栈 是针对通用的Modbus协议栈在嵌入式系统中应用的一个实现。
- wMODBUS协议栈 在硬件许可的情况下可以挂载任意多个主机与从机。支持多个主机与多个从机同时独立运行。
- wMODBUS协议栈 支持RTU/ASCII模式,支持串串口/网络模式。
- wMODBUS协议栈 支持如下功能码。
读输入寄存器 (0x04)
读保持寄存器 (0x03)
写单个寄存器 (0x06)
写多个寄存器 (0x10)
读/写多个寄存器 (0x17)
读取线圈状态 (0x01)
写单个线圈 (0x05)
写多个线圈 (0x0F)
读输入状态 (0x02) - wMODBUS协议栈 支持实时操作系统及裸机移植。
- wMODBUS协议栈 提供hook回调函数功能。
- wMODBUS协议栈 提供通信统计功能。
- wMODBUS协议栈 主机功能可支持与任意非连续地址的从机里进行通信。
- wMODBUS协议栈 主机功能为应用提供多种请求模式,用户可以选择阻塞还是非阻塞模式,自定义超时时间等,方便应用层灵活调用。
4. 文件结构
- mbconfig.h是wModbus的配置文件,可以对wModbus的功能进行裁减。
- mbevent.c 这个文件是与嵌入式操作系统相关的代码,针对不同的操作系统,代码需要进行相应的改写,主要是需要实现事件等待函数,事件发送函数等。从而使得中断函数可以对侦听主程序的数据传送功能。
- mb.c mb.h mbtype.h这两个文件是主机和从机共用的代码,这些函数已经写好,与嵌入式操作系统以及CPU都无关,用户无需再进行任何修改。主要是实现的了协议栈的创建,使能,接收拆包,发送打包等功能。
- smb.c smbbuf.c smbbuf.h 这五个文件是从机需使用的代码,这些函数已经写好,与嵌入式操作系统以及CPU都无关,用户无需再进行任何修改。主要是实现了从机的侦听与数据处理功能。
- mmb.c 这个文件是主机需使用的代码,这些函数已经写好,与嵌入式操作系统以及CPU都无关,用户无需再进行任何修改。主要是实现了主机的侦听与数据处理功能。
5. 使用方法
如果需要其它实现方法及商业合作,请与专利人邮件联系240697738@qq.com
发送回调函数
UCHAR PortTransmit (void *Parent, UCHAR *pData, USHORT Size,ULONG lTimeOut)
{
依照lTimeOut时间进行阻塞发送 取0时为永久阻塞,直到发送完成。
……
return MBTRUE;成功发送返回MBTRUE,否则返回MBFALSE
}
接收回调函数
SHORT PortReceive (void *Parent, UCHAR *pData, USHORT Size,ULONG lTimeOut)
{
依照lTimeOut时间进行阻塞接收 取0时为永久阻塞,直到接收完成。
……
Return 接收数据的实际长度,如果未接收到数据返回0,如果接收错误,返回-1。
}
从机任务函数
uint8_t buf[256];//定义操作数据内存
static OS_MUTEX mutex;
void Task(void *p_arg)
{
wMB mb;//定义wModbus协议栈
int Id;//端口号
//初使化传输路径 - 串口/网口 (依据Id)
//初使化wModbus协议栈
MB_Init(&mb,MB_MODE_RTU,1,0,&mutex); //站号为1的从机
//设置回调函数
MB_PortSet(&mb,PortTransmit,PortReceive);
while(1)
{//轮询接收并处理数据
if(MB_Poll(&mb, buf,0) <=0)
{
printf("MB Port failed!\n");
}
}
}
主机任务函数
uint8_t buf[256];//定义操作数据内存
static OS_MUTEX mutex;
void Task(void *p_arg)
{
wMB mb;//定义wModbus协议栈
int Id;//端口号
//初使化传输路径 - 串口/网口 (依据Id)
//初使化wModbus协议栈
MB_Init( & mb,MB_MODE_RTU,0,&mutex); //站号为0则为主机
//设置回调函数
MB_PortSet(&mb,PortTransmit,PortReceive);
//直接操作功能函数 – 阻塞等待数据返回
mMB_FN01_Read_CoilsRegister()
mMB_FN02_Read_DiscreteRegister()
……
}
6. 程序源码
mbconfig.h文件:
/*
********************************************************************************************************
* wModbus
* The Embedded Modbus Stack
*
* Copyright: Wu HaiMeng. All rights reserved.Protected by international copyright laws.
*
* Programmer : Wu YuanFu
* Version : V2.50
* LICENSING TERMS:
* ---------------
* wModbus is provided in source form for FREE short-term evaluation, for educational use or
* for peaceful research. If you plan or intend to use wModbus in a commercial application/
* product then, you need to contact Wu YuanFu<240697738@qq.com> to properly license wModbus
* for its use in your application/product. The fact that the source is provided does NOT
* mean that you can use it commercially without paying a licensing fee.
*
* Knowledge of the source code may NOT be used to develop a similar product.
*
********************************************************************************************************
*/
/* Filename : mbconfig.h*/
#ifndef _MB_CONFIG_H
#define _MB_CONFIG_H
#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif
#define MBDISABLED ( 0 )
#define MBENABLED ( 1 )
#define MB_ADDRESS_BROADCAST ( 0 )
#define MB_ADDRESS_MIN ( 1 )
#define MB_ADDRESS_MAX ( 247)
#define MB_MASTER_ENABLED MBENABLED
#define MB_SLAVE_ENABLED MBENABLED
#define MB_TCP_ENABLED MBENABLED
#define MB_RTU_ENABLED MBENABLED
#define MB_ASCII_ENABLED MBENABLED
#define MB_FN01_READ_COILS_ENABLED MBENABLED
#define MB_FN02_READ_DISCRETE_ENABLED MBENABLED
#define MB_FN03_READ_HOLDING_ENABLED MBENABLED
#define MB_FN04_READ_INPUT_ENABLED MBENABLED
#define MB_FN05_WRITE_COIL_ENABLED MBENABLED
#define MB_FN06_WRITE_HOLDING_ENABLED MBENABLED
#define MB_FN15_WRITE_COILS_ENABLED MBENABLED
#define MB_FN16_WRITE_HOLDING_ENABLED MBENABLED
#define MB_FN17_OTHER_REP_SLAVEID_ENABLED MBENABLED
#define MB_FN23_READWRITE_HOLDING_ENABLED MBENABLED
#define MB_STAT_ENABLED MBENABLED
#define MB_BROADCASTRESPOND_ENABLED MBDISABLED
#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#endif
mbevent.c文件 - 以ucos系统为例
/*
********************************************************************************************************
* wModbus
* The Embedded Modbus Stack Software
*
* Copyright: Wu YuanFu. All rights reserved.Protected by international copyright laws.
*
* Programmer : Wu YuanFu
* Version : V2.50
* LICENSING TERMS:
* ---------------
* wModbus is provided in source form for FREE short-term evaluation, for educational use or
* for peaceful research. If you plan or intend to use wModbus in a commercial application/
* product then, you need to contact Wu YuanFu<240697738@qq.com> to properly license wModbus
* for its use in your application/product. The fact that the source is provided does NOT
* mean that you can use it commercially without paying a licensing fee.
*
* Knowledge of the source code may NOT be used to develop a similar product.
*
********************************************************************************************************
*/
/* Filename : mbevent.c*/
#include "mb.h"
#include "oS.h"
/*
********************************************************************************************************
* Init A Mutex RunRes
*
* Description: 此函数用于初使化RunRes互斥资源
* Arguments : p_mb 指向1个wModbus的指针
* Returns : UCHAR 返回处理结果
* MBTRUE 处理
* MBFALSE 出错
* Note(s) : 1 MB_MutexInit() 在MASTER Modbus中使用
********************************************************************************************************
*/
UCHAR MB_MutexInit( wMB *p_mb , void* mutex)
{
//根据操作系统不一致会有所区别,此处仅以uCos-III 为例。
OS_ERR OsErr;
p_mb->Mutex = mutex;
if( p_mb->Mutex == 0 )
{
return MBTRUE;
}
OSMutexCreate(p_mb->Mutex, "Master Run Res Sem",&OsErr );
if( OsErr == OS_ERR_NONE) return MBTRUE; else return MBFALSE;
}
/*
********************************************************************************************************
* Close A Mutex RunRes
*
* Description: 此函数用于删掉RunRes互斥资源
* Arguments : p_mb 指向1个wModbus的指针
* Returns : UCHAR 返回处理结果
* MBTRUE 处理
* MBFALSE 出错
* Note(s) : 1) MB_MutexClose()
********************************************************************************************************
*/
UCHAR MB_MutexClose( wMB *p_mb )
{
//根据操作系统不一致会有所区别,此处仅以uCos-III 为例。
OS_ERR OsErr;
if( p_mb->Mutex == 0 )
{
return MBTRUE;
}
OSMutexDel(p_mb->Mutex,OS_OPT_DEL_ALWAYS,&OsErr );
return MBTRUE;
}
/*
********************************************************************************************************
* Post A Mutex RunRes
*
* Description: 此函数用于发送RunRes互斥资源
* Arguments : p_mb 指向1个wModbus的指针
* Returns : UCHAR 返回处理结果
* MBTRUE 处理
* MBFALSE 出错
* Note(s) : 1) MB_MutexPost() 在MASTER Modbus中使用
********************************************************************************************************
*/
UCHAR MB_MutexPost( wMB *p_mb )
{
//根据操作系统不一致会有所区别,此处仅以uCos-III 为例。
OS_ERR OsErr;
if( p_mb->Mutex == 0 )
{
return MBTRUE;
}
OSMutexPost(p_mb->Mutex,OS_OPT_POST_NONE, &OsErr);
return MBTRUE;
}
/*
********************************************************************************************************
* Pend A Mutex RunRes
*
* Description: 此函数用于请求RunRes互斥资源
* Arguments : p_mb 指向1个wModbus的指针
* Returns : UCHAR 返回处理结果
* MBTRUE 处理
* MBFALSE 出错
* Note(s) : 1) MB_MutexPend() 在MASTER Modbus中使用
********************************************************************************************************
*/
UCHAR MB_MutexPend( wMB *p_mb)
{
//根据操作系统不一致会有所区别,此处仅以uCos-III 为例。
OS_ERR OsErr;
if( p_mb->Mutex == 0 )
{
return MBTRUE;
}
OSMutexPend(p_mb->Mutex, 0, OS_OPT_PEND_BLOCKING, 0, &OsErr);
if(OsErr == OS_ERR_NONE)return MBTRUE;else return MBFALSE;
}
mb.c文件
/*
********************************************************************************************************
* wModbus
* The Embedded Modbus Stack Software
*
* Copyright: Wu YuanFu. All rights reserved.Protected by international copyright laws.
*
* Programmer : Wu YuanFu
* Version : V2.50
* LICENSING TERMS:
* ---------------
* wModbus is provided in source form for FREE short-term evaluation, for educational use or
* for peaceful research. If you plan or intend to use wModbus in a commercial application/
* product then, you need to contact Wu YuanFu<240697738@qq.com> to properly license wModbus
* for its use in your application/product. The fact that the source is provided does NOT
* mean that you can use it commercially without paying a licensing fee.
*
* Knowledge of the source code may NOT be used to develop a similar product.
*
********************************************************************************************************
*/
/* Filename : mb.c*/
#include "mb.h"
#if ( MB_MASTER_ENABLED == MBENABLED || MB_SLAVE_ENABLED== MBENABLED )
/*
********************************************************************************************************
* LRC
*
* Description: 此函数用于ASCII模式下的LRC校验
* Arguments : pDataBuf 指向需要校验DataBuf的指针
* iLen DataBuf的长度
* Returns : UCHAR LRC校验的结果
* Note(s) : 1) MB_LRC()
********************************************************************************************************
*/
#if ( MB_ASCII_ENABLED == MBENABLED )
static UCHAR MB_LRC( UCHAR* pDataBuf, USHORT iLen)
{
UCHAR mLRC = 0x00;
while( iLen-- ){mLRC += *pDataBuf++;}
return ( - mLRC );
}
#endif
/*
********************************************************************************************************
* CRC
*
* Description: 此函数用于RTU模式下的CRC校验
* Arguments : pDataBuf 指向需要校验DataBuf的指针
* iLen DataBuf的长度
* Returns : USHORT CRC校验的结果
* Note(s) : 1) MB_CRC()
********************************************************************************************************
*/
#if ( MB_RTU_ENABLED == MBENABLED )
const USHORT MBCRC_table[256] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
static USHORT MB_CRC( UCHAR * pDataBuf, USHORT iLen )
{
USHORT mCRC = 0xffff;
while (iLen-- > 0)
mCRC = MBCRC_table[(mCRC ^ *pDataBuf++) & 0x00ff] ^ (mCRC >> 8) ;
return mCRC;
}
#endif
/*
********************************************************************************************************
* Init A wModbus
*
* Description: 此函数用于创建一个wModbus协议栈
* Arguments : p_mb 指向1个wModbus的指针
* Mode 传输模式
* Address 地址
* Parent 传输硬件句柄
* Returns : MBTRUE 创建成功
* MBFALSE 创建失败
* Note(s) : 1) MB_Init()
********************************************************************************************************
*/
UCHAR MB_Init( wMB *p_mb,MB_ModeType Mode,UCHAR Address,void *Parent,void* mutex)
{
if(p_mb != MBNULL)
{
if( Address == MB_ADDRESS_BROADCAST ){p_mb->MasterSlave = MBMASTER;}
else if(( Address >= MB_ADDRESS_MIN ) && ( Address <= MB_ADDRESS_MAX ))
{
p_mb->MasterSlave = MBSLAVE;
p_mb->NodeAddr = Address;
}
else {return MBFALSE;}
p_mb->Mode = Mode;
p_mb->Parent = Parent;
p_mb->ComCnt = 0;
#if (MB_STAT_ENABLED == MBENABLED)
p_mb->StatSendCtr = 0;
p_mb->StatReceiveErrCtr = 0;
p_mb->StatHandlersErrCtr = 0;
p_mb->StatOKCtr = 0;
#endif
return MB_MutexInit(p_mb,mutex);
}
return MBFALSE;
}
/*
********************************************************************************************************
* Close A wModbus
*
* Description: 此函数用于关闭一个wModbus协议栈
* Arguments : p_mb 指向1个wModbus的指针
* Returns : MBTRUE 创建成功
* MBFALSE 创建失败
* Note(s) : 1) MB_Close()
********************************************************************************************************
*/
UCHAR MB_Close( wMB *p_mb)
{
p_mb->Parent = 0;
p_mb->ComCnt = 0;
#if (MB_STAT_ENABLED == MBENABLED)
p_mb->StatSendCtr = 0;
p_mb->StatReceiveErrCtr = 0;
p_mb->StatHandlersErrCtr = 0;
p_mb->StatOKCtr = 0;
#endif
p_mb->TxCpltPtr = 0;
p_mb->RxCpltPtr = 0;
return MB_MutexClose(p_mb);
}
/*
********************************************************************************************************
* MB Port Set
*
* Description: 此函数用于初使化硬件端口参数
* Arguments : p_mb 指向1个wModbus的指针
* TxCpltPtr 数据发送回调函数
* RxCpltPtr 数据接收回调函数
* Returns : No
********************************************************************************************************
*/
void MB_PortSet(wMB *p_mb,MBPortTransmit TxCpltPtr,MBPortReceive RxCpltPtr)
{
if(p_mb != (wMB *)MBNULL)
{
p_mb->TxCpltPtr = TxCpltPtr;
p_mb->RxCpltPtr = RxCpltPtr;
}
}
#if ( MB_ASCII_ENABLED == MBENABLED )
const UCHAR MBChar_table[256] ={
'0' ,'1' ,'2' ,'3' ,'4' ,'5' ,'6' ,'7' ,'8' ,'9' ,'A' ,'B' ,'C' ,'D' ,'E' ,'F' ,
'G' ,'H' ,'I' ,'J' ,'K' ,'L' ,'M' ,'N' ,'O' ,'P' ,'Q' ,'R' ,'S' ,'T' ,'U' ,'V' ,
'W' ,'X' ,'Y' ,'Z' ,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
0x40,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x5b,0x5c,0x5d,0x5e,0x5f,
0x60,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x7b,0x7c,0x7d,0x7e,0x7f,
'0' ,'1' ,'2' ,'3' ,'4' ,'5' ,'6' ,'7' ,'8' ,'9' ,'A' ,'B' ,'C' ,'D' ,'E' ,'F' ,
'G' ,'H' ,'I' ,'J' ,'K' ,'L' ,'M' ,'N' ,'O' ,'P' ,'Q' ,'R' ,'S' ,'T' ,'U' ,'V' ,
'W' ,'X' ,'Y' ,'Z' ,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
0x40,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x5b,0x5c,0x5d,0x5e,0x5f,
0x60,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x7b,0x7c,0x7d,0x7e,0x7f
};
#endif
/*
********************************************************************************************************
* wModbus Receive manage
*
* Description: 此函数用于把一个wModbus协议栈接收到的数据进行接收处理。
* Arguments : p_mb 指向1个wModbus的指针
* Returns : UCHAR 返回处理结果
* MBTRUE 正确处理
* MBFALSE 数据出错
* Note(s) : 1) MB_Receive()
********************************************************************************************************
*/
UCHAR MB_Receive( wMB *p_mb,UCHAR* pRevBuf,USHORT RecvCnt )
{
UCHAR Status= MBFALSE;
volatile SHORT mi;
switch(p_mb->Mode)
{
#if ( MB_RTU_ENABLED == MBENABLED )
case MB_MODE_RTU:
if( MB_CRC( pRevBuf, RecvCnt ) == 0 )
{
p_mb->RecvAddr = pRevBuf[0];
p_mb->BufCnt = RecvCnt - 3 ;
Status = MBTRUE;
}
break;
#endif
#if ( MB_ASCII_ENABLED == MBENABLED )
case MB_MODE_ASCII:
if(pRevBuf[0] == 0x3A )
{
p_mb->BufCnt = (RecvCnt - 3) >> 1 ;
for(mi=0;mi<p_mb->BufCnt;mi++)
{
pRevBuf[ mi ] = ( MBChar_table[(pRevBuf[2 * mi + 1])] << 4)
| ( MBChar_table[(pRevBuf[2 * mi + 2])]);
}
if(MB_LRC(pRevBuf,p_mb->BufCnt) == 0)
{
p_mb->RecvAddr = pRevBuf[0];
p_mb->BufCnt = p_mb->BufCnt - 2 ;
Status = MBTRUE;
}
}
break;
#endif
#if ( MB_TCP_ENABLED == MBENABLED )
case MB_MODE_TCP:
p_mb->RecvAddr = pRevBuf[6];
p_mb->BufCnt = RecvCnt - MB_PDU_TCP_OFF ;
Status = MBTRUE;
break;
#endif
default:break;
}
return Status;
}
/*
********************************************************************************************************
* wModbus Send manage
*
* Description: 此函数用于把一个wModbus协议栈的数据进行发送处理。
* Arguments : p_mb 指向1个wModbus的指针
* Note(s) : 1) MB_Send()
********************************************************************************************************
*/
USHORT MB_Send( wMB *p_mb ,UCHAR* pSndBuf)
{
volatile USHORT usCRC16;
volatile SHORT mi;
volatile USHORT SendCnt;
if((p_mb->MasterSlave == MBMASTER) ||
(MB_BROADCASTRESPOND_ENABLED == MBENABLED)||
(p_mb->RecvAddr != MB_ADDRESS_BROADCAST))
{
SendCnt = p_mb->BufCnt;
switch(p_mb->Mode)
{
#if ( MB_RTU_ENABLED == MBENABLED )
case MB_MODE_RTU:
pSndBuf[0] = p_mb->NodeAddr;
SendCnt ++;
usCRC16 = MB_CRC( pSndBuf, SendCnt );
pSndBuf[SendCnt ++] = ( UCHAR )( usCRC16 & 0xFF );
pSndBuf[SendCnt ++] = ( UCHAR )( usCRC16 >> 8 );
break;
#endif
#if ( MB_ASCII_ENABLED == MBENABLED )
case MB_MODE_ASCII:
pSndBuf[0] = p_mb->NodeAddr;
SendCnt ++;
pSndBuf[SendCnt] = MB_LRC( pSndBuf, SendCnt );
for(mi=SendCnt;mi>=0;mi--)
{
pSndBuf[2 * mi + 2] = MBChar_table[( pSndBuf[ mi ] & 0x0F )];
pSndBuf[2 * mi + 1] = MBChar_table[( pSndBuf[ mi ] >> 4 )];
}
pSndBuf[0] = 0x3A;
pSndBuf[SendCnt * 2 + 3] = 0x0D;
pSndBuf[SendCnt * 2 + 4] = 0x0A;
SendCnt = SendCnt * 2 + 5;
break;
#endif
#if ( MB_TCP_ENABLED == MBENABLED )
case MB_MODE_TCP:
pSndBuf[6] = p_mb->NodeAddr;
SendCnt ++;
pSndBuf[4] = 0;
pSndBuf[5] = ( UCHAR )( SendCnt );
SendCnt += 6;
break;
#endif
default:break;
}
#if (MB_STAT_ENABLED == MBENABLED)
p_mb->StatSendCtr++;
#endif
p_mb->BufCnt = SendCnt;
return SendCnt;
}
return 0;
}
/*
********************************************************************************************************
* MB Poll
*
* Description: 此函数用于端口接收数据
* Arguments : p_mb 指向1个wModbus的指针
* Note(s) : 1) MB_Poll()
********************************************************************************************************
*/
MB_Exception MB_Poll(wMB *p_mb,UCHAR* pBuf,LONG lTimeOut)
{
#if (MB_MASTER_ENABLED == MBENABLED)
if(p_mb->MasterSlave == MBMASTER)
{
if((p_mb->TxCpltPtr != MBNULL) && (p_mb->BufCnt > 0))
{
p_mb->TxCpltPtr(p_mb->Parent,pBuf,p_mb->BufCnt,0);
}
}
#endif
if(p_mb->RxCpltPtr != MBNULL)
{
SHORT length = p_mb->RxCpltPtr(p_mb->Parent,pBuf,MB_PDU_SIZE_MAX,lTimeOut);
if(length >= MB_PDU_SIZE_MIN)
{
if(p_mb->MasterSlave == MBMASTER)
{
#if (MB_MASTER_ENABLED == MBENABLED)
return mMB_Deal( p_mb,pBuf,length);
#endif
}
else
{
#if (MB_SLAVE_ENABLED == MBENABLED)
USHORT Cnt = sMB_Deal( p_mb,pBuf,length);
if((p_mb->TxCpltPtr != MBNULL) && (Cnt > 0))
{
p_mb->TxCpltPtr(p_mb->Parent,pBuf,Cnt,0);
}
#endif
}
}
}
return MB_EX_NONE;
}
/*
********************************************************************************************************
* STAT Get
*
* Description: 此函数用于向获取统计信息
* Arguments : p_mb 指向1个wModbus的指针
* StatType 需要获取的数据类型
* Note(s) : 1) MB_STATGet()
********************************************************************************************************
*/
#if (MB_STAT_ENABLED == MBENABLED)
ULONG MB_STATGet( wMB *p_mb ,MB_StatType StatType)
{
ULONG Res = 0;
switch(StatType)
{
case MB_STAT_SEND:
Res = p_mb->StatSendCtr;break;
case MB_STAT_RECEIVEERR:
Res = p_mb->StatReceiveErrCtr;break;
case MB_STAT_HANDLERSERR:
Res = p_mb->StatHandlersErrCtr;break;
case MB_STAT_OK:
Res = p_mb->StatOKCtr;break;
}
return Res;
}
#endif
/*
********************************************************************************************************
* Set Bits To WordBuf
*
* Description: 此函数用于向WordBuf的数据表内设置NBits个Bits
* Arguments : pWordBuf 指向WordBuf的数据指针
* BitOffset 偏移地址
* NBits 需要设定的bit个数
* SetValue 需要设定的值
* Note(s) : 1) MB_UtilSetBits() 用于Discrete 或是 coils的数据转化
* 2) NBits<=16
********************************************************************************************************
*/
void MB_UtilSetBits( USHORT *pWordBuf, USHORT BitOffset, UCHAR NBits,USHORT SetValue )
{
ULONG *pDoubleWordBuf;
ULONG Mask,WordOffset,NPreBits;
ULONG Value = SetValue;
WordOffset = ( ULONG )( ( BitOffset ) / MB_BITS );
NPreBits = ( ULONG )( BitOffset - WordOffset * MB_BITS );
Mask = ( ULONG )( ( ( ULONG ) 1 << NBits ) - 1 ) << NPreBits;
pDoubleWordBuf = (ULONG *)&pWordBuf[WordOffset];
*pDoubleWordBuf = (ULONG)(( *pDoubleWordBuf & ( ~ Mask )) | ((Value << NPreBits) & Mask ));
}
/*
********************************************************************************************************
* Get Bits From WordBuf
*
* Description: 此函数用于从WordBuf的数据表内获取NBits个Bits
* Arguments : pWordBuf 指向WordBuf的数据指针
* BitOffset 偏移地址
* NBits 需要设定的bit个数
* Returns : USHORT 获取到的数据值
* Note(s) : 1) MB_UtilGetBits() 用于Discrete 或是 coils的数据转化
* 2) NBits<=16
********************************************************************************************************
*/
USHORT MB_UtilGetBits( USHORT *pWordBuf, USHORT BitOffset, UCHAR NBits )
{
ULONG *pDoubleWordBuf;
ULONG Mask,WordOffset,NPreBits;
WordOffset = ( ULONG )( ( BitOffset ) / MB_BITS );
NPreBits = ( ULONG )( BitOffset - WordOffset * MB_BITS );
Mask = ( ULONG )( ( ( ULONG ) 1 << NBits ) - 1 );
pDoubleWordBuf = (ULONG *)&pWordBuf[WordOffset];
return ((USHORT )((*pDoubleWordBuf >> NPreBits ) & Mask));
}
#endif
mb.h文件
/*
********************************************************************************************************
* wModbus
* The Embedded Modbus Stack Software
*
* Copyright: Wu YuanFu. All rights reserved.Protected by international copyright laws.
*
* Programmer : Wu YuanFu
* Version : V2.50
* LICENSING TERMS:
* ---------------
* wModbus is provided in source form for FREE short-term evaluation, for educational use or
* for peaceful research. If you plan or intend to use wModbus in a commercial application/
* product then, you need to contact Wu YuanFu<240697738@qq.com> to properly license wModbus
* for its use in your application/product. The fact that the source is provided does NOT
* mean that you can use it commercially without paying a licensing fee.
*
* Knowledge of the source code may NOT be used to develop a similar product.
*
********************************************************************************************************
*/
/* Filename : mb.h*/
#include "mbtype.h"
#if ( MB_SLAVE_ENABLED == MBENABLED)
#include "smbbuf.h"
#endif
#ifndef _MB_H
#define _MB_H
#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif
#if ( MB_MASTER_ENABLED == MBENABLED || MB_SLAVE_ENABLED== MBENABLED )
void MB_UtilSetBits( USHORT * pWordBuf, USHORT BitOffset,UCHAR NBits, USHORT SetValue );
USHORT MB_UtilGetBits( USHORT * pWordBuf, USHORT BitOffset,UCHAR NBits );
UCHAR MB_Receive(wMB *p_mb,UCHAR* pRevBuf,USHORT RecvCnt);
USHORT MB_Send(wMB *p_mb,UCHAR* pSndBuf);
UCHAR MB_MutexInit( wMB *p_mb , void* mutex);
UCHAR MB_MutexClose( wMB *p_mb );
UCHAR MB_MutexPend( wMB *p_mb);
UCHAR MB_MutexPost( wMB *p_mb );
//
UCHAR MB_Init(wMB *p_mb,MB_ModeType Mode,UCHAR Address,void *Parent,void* mutex);
void MB_PortSet(wMB *p_mb,MBPortTransmit TxCpltPtr,MBPortReceive RxCpltPtr);
UCHAR MB_Close( wMB *p_mb);
MB_Exception MB_Poll(wMB *p_mb,UCHAR* pBuf,LONG lTimeOut);
#if (MB_STAT_ENABLED == MBENABLED)
ULONG MB_STATGet(wMB *p_mb,MB_StatType StatType);
#endif
#if ( MB_SLAVE_ENABLED == MBENABLED)
USHORT sMB_Deal(wMB *p_mb,UCHAR* pBuf,USHORT length);
USHORT* sMB_GetpBuf(USHORT addr,USHORT num);
void sMB_RegHoldingWriteCallback(USHORT addr,USHORT value);
void sMB_RegCoilsWriteCallback( USHORT addr,UCHAR NBits,USHORT value);
#endif
#if (MB_MASTER_ENABLED == MBENABLED)
MB_Exception mMB_Deal(wMB *p_mb,UCHAR* pBuf,USHORT length);
#if MB_FN01_READ_COILS_ENABLED == MBENABLED
MB_Exception mMB_FN01_Read_CoilsRegister(wMB *p_mb,UCHAR SlaveAddr,USHORT RegAddr,USHORT RegCnt,USHORT *pRegBuffer,USHORT ReadBitOffset,LONG lTimeOut);
#endif
#if MB_FN02_READ_DISCRETE_ENABLED == MBENABLED
MB_Exception mMB_FN02_Read_DiscreteRegister(wMB *p_mb,UCHAR SlaveAddr,USHORT RegAddr,USHORT RegCnt,USHORT *pRegBuffer,USHORT ReadBitOffset,LONG lTimeOut);
#endif
#if MB_FN03_READ_HOLDING_ENABLED == MBENABLED
MB_Exception mMB_FN03_Read_HoldingRegister(wMB *p_mb,UCHAR SlaveAddr, USHORT RegAddr,USHORT RegCnt, USHORT *pRegBuffer,LONG lTimeOut);
#endif
#if MB_FN04_READ_INPUT_ENABLED == MBENABLED
MB_Exception mMB_FN04_Read_InputRegister(wMB *p_mb,UCHAR SlaveAddr,USHORT RegAddr,USHORT RegCnt,USHORT *pRegBuffer,LONG lTimeOut);
#endif
#if MB_FN05_WRITE_COIL_ENABLED == MBENABLED
MB_Exception mMB_FN05_Write_CoilsRegister(wMB *p_mb,UCHAR SlaveAddr, USHORT RegAddr,USHORT WriteData,LONG lTimeOut);
#endif
#if MB_FN06_WRITE_HOLDING_ENABLED == MBENABLED
MB_Exception mMB_FN06_Write_HoldingRegister(wMB *p_mb,UCHAR SlaveAddr,USHORT RegAddr,USHORT WriteData,LONG lTimeOut);
#endif
#if MB_FN15_WRITE_COILS_ENABLED == MBENABLED
MB_Exception mMB_FN15_Write_CoilsRegister(wMB *p_mb,UCHAR SlaveAddr,USHORT RegAddr,USHORT RegCnt,USHORT *pRegBuffer,USHORT WriteBitOffset,LONG lTimeOut);
#endif
#if MB_FN16_WRITE_HOLDING_ENABLED == MBENABLED
MB_Exception mMB_FN16_Write_HoldingRegister(wMB *p_mb,UCHAR SlaveAddr,USHORT RegAddr,USHORT RegCnt,USHORT *pRegBuffer,LONG lTimeOut );
#endif
#if MB_FN23_READWRITE_HOLDING_ENABLED == MBENABLED
MB_Exception mMB_FN23_ReadWrite_HoldingRegister(wMB *p_mb,UCHAR SlaveAddr,USHORT ReadRegAddr,USHORT ReadRegCnt,USHORT *pReadRegBuffer,USHORT WriteRegAddr,USHORT WriteRegCnt,USHORT *pWriteRegBuffer,LONG lTimeOut);
#endif
#endif
#endif
#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#endif
mbtype.h文件
/*
********************************************************************************************************
* wModbus
* The Embedded Modbus Stack Software
*
* Copyright: Wu YuanFu. All rights reserved.Protected by international copyright laws.
*
* Programmer : Wu YuanFu
* Version : V2.50
* LICENSING TERMS:
* ---------------
* wModbus is provided in source form for FREE short-term evaluation, for educational use or
* for peaceful research. If you plan or intend to use wModbus in a commercial application/
* product then, you need to contact Wu YuanFu<240697738@qq.com> to properly license wModbus
* for its use in your application/product. The fact that the source is provided does NOT
* mean that you can use it commercially without paying a licensing fee.
*
* Knowledge of the source code may NOT be used to develop a similar product.
*
********************************************************************************************************
*/
/* Filename : mbtype.h*/
#include "mbconfig.h"
#ifndef _MB_TYPE_H
#define _MB_TYPE_H
#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif
#define MBNULL ( 0 )
#define MBFALSE ( 0 )
#define MBTRUE ( 1 )
#define MBSLAVE ( 1 )
#define MBMASTER ( 0 )
#define MBREAD ( 0 )
#define MBWRITE ( 1 )
#define MB_FUNC_NONE ( 0x00 )
#define MB_FN01_READ_COILS ( 0x01 )
#define MB_FN02_READ_DISCRETE_INPUTS ( 0x02 )
#define MB_FN03_READ_HOLDING_REGISTER ( 0x03 )
#define MB_FN04_READ_INPUT_REGISTER ( 0x04 )
#define MB_FN05_WRITE_SINGLE_COIL ( 0x05 )
#define MB_FN06_WRITE_REGISTER ( 0x06 )
#define MB_FN11_DIAG_GET_COM_EVENT_CNT ( 0x0B )
#define MB_FN12_DIAG_GET_COM_EVENT_LOG ( 0x0C )
#define MB_FN15_WRITE_MULTIPLE_COILS ( 0x0F )
#define MB_FN16_WRITE_MULTIPLE_REGISTERS ( 0x10 )
#define MB_FN17_OTHER_REPORT_SLAVEID ( 0x11 )
#define MB_FN23_READWRITE_MULTIPLE_REGISTERS ( 0x17 )
#define MB_FUNC_ERROR ( 128 )
#define MB_PDU_FN01_READCOUNT_MAX ( 0x07D0 )
#define MB_PDU_FN02_READCOUNT_MAX ( 0x07D0 )
#define MB_PDU_FN03_READCOUNT_MAX ( 0x007D )
#define MB_PDU_FN04_READCOUNT_MAX ( 0x007D )
#define MB_PDU_FN15_WRITECOUNT_MAX ( 0x07B0 )
#define MB_PDU_FN16_WRITECOUNT_MAX ( 0x007B )
#define MB_PDU_FN23_READCOUNT_MAX ( 0x007D )
#define MB_PDU_FN23_WRITECOUNT_MAX ( 0x0079 )
#define MB_PDU_FNxx_COUNT_MIN ( 0x0001 )
#define MB_BITS ( 16 )
#define MB_PDU_SIZE_MIN ( 4 )
#define MB_PDU_SIZE_MAX ( 256)
#define MB_PDU_RTU_OFF ( 1 )
#define MB_PDU_TCP_OFF ( 7 )
#define MB_PDU_FUNC_OFF ( 0 )
#define MB_PDU_REQ_ADDR_OFF ( 1 )
#define MB_PDU_REQ_CNT_OFF ( 3 )
#define MB_PDU_REQ_2ndADDR_OFF ( 5 )
#define MB_PDU_REQ_2ndCNT_OFF ( 7 )
#define MB_PDU_FN01_BYTECNT_OFF ( 1 )
#define MB_PDU_FN01_VALUE_OFF ( 2 )
#define MB_PDU_FN02_BYTECNT_OFF ( 1 )
#define MB_PDU_FN02_VALUE_OFF ( 2 )
#define MB_PDU_FN03_BYTECNT_OFF ( 1 )
#define MB_PDU_FN03_VALUE_OFF ( 2 )
#define MB_PDU_FN04_BYTECNT_OFF ( 1 )
#define MB_PDU_FN04_VALUE_OFF ( 2 )
#define MB_PDU_FN05_VALUE_OFF ( 3 )
#define MB_PDU_FN06_VALUE_OFF ( 3 )
#define MB_PDU_FN15_BYTECNT_OFF ( 5 )
#define MB_PDU_FN15_VALUE_OFF ( 6 )
#define MB_PDU_FN16_BYTECNT_OFF ( 5 )
#define MB_PDU_FN16_VALUE_OFF ( 6 )
#define MB_PDU_FN23_WRITEBYTECNT_OFF ( 9 )
#define MB_PDU_FN23_WRITEVALUE_OFF ( 10 )
#define MB_PDU_FN23_READBYTECNT_OFF ( 1 )
#define MB_PDU_FN23_READVALUE_OFF ( 2 )
typedef unsigned char UCHAR;
typedef signed char CHAR;
typedef unsigned short int USHORT;
typedef signed short int SHORT;
typedef unsigned int ULONG;
typedef signed int LONG;
typedef enum
{
MB_MODE_RTU =1,
MB_MODE_ASCII =2,
MB_MODE_TCP =3,
} MB_ModeType;
typedef enum
{
MB_STAT_SEND =1,
MB_STAT_RECEIVEERR =2,
MB_STAT_HANDLERSERR =3,
MB_STAT_OK =4,
} MB_StatType;
typedef enum
{
MB_EX_NONE = 0x00, /**/
MB_EX_ILLEGAL_FUNCTION = 0x01, /*不合法的功能代码*/
MB_EX_ILLEGAL_DATA_ADDRESS = 0x02, /*不合法数据地址*/
MB_EX_ILLEGAL_DATA_VALUE = 0x03, /*不合法数据*/
MB_EX_SLAVE_DEVICE_FAILURE = 0x04, /*从机设备故障*/
MB_EX_ACKNOWLEDGE = 0x05, /*确认*/
MB_EX_SLAVE_BUSY = 0x06, /*从机设备忙*/
MB_EX_NEGATIVE = 0x07, /*否定*/
MB_EX_MEMORY_PARITY_ERROR = 0x08, /*内存奇偶校验错误*/
MB_EX_GATEWAY_PATH_FAILED = 0x0A, /**/
MB_EX_GATEWAY_TGT_FAILED = 0x0B, /**/
MB_EX_NO_MEMORY = 0x11, //无可用内存
MB_EX_REVDATAERR = 0x12, //数据校验出错
} MB_Exception;
typedef UCHAR(*MBPortTransmit )(void *Parent, UCHAR *pData, USHORT Size,ULONG lTimeOut);//发送回调函数
typedef SHORT(*MBPortReceive )(void *Parent, UCHAR *pData, USHORT Size,ULONG lTimeOut);//接收回调函数
typedef struct wmb wMB;
struct wmb{
UCHAR NodeAddr; /*node 地址*/
UCHAR MasterSlave; /*主从类型*/
MB_ModeType Mode; /*传输模式*/
UCHAR ReadWrite; /*读写类型*/
UCHAR Value_off;
UCHAR RecvAddr;
UCHAR BufCnt;
USHORT RegCnt;
USHORT RegAddress;
USHORT ComCnt;
void *Parent; /*参数*/
void *Mutex;
MBPortReceive RxCpltPtr; /*接收回调函数*/
MBPortTransmit TxCpltPtr; /*发送回调函数*/
#if (MB_MASTER_ENABLED == MBENABLED)
USHORT BitOffset;
USHORT *RegDataPtr;
#endif
#if (MB_STAT_ENABLED == MBENABLED)
ULONG StatSendCtr; /*发送量统计*/
ULONG StatReceiveErrCtr; /*接收错误量统计*/
ULONG StatHandlersErrCtr; /*处理错误量统计*/
ULONG StatOKCtr; /*正确量统计*/
#endif
};
#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#endif
smb.c文件
/*
********************************************************************************************************
* wModbus
* The Embedded Modbus Stack Software
*
* Copyright: Wu YuanFu. All rights reserved.Protected by international copyright laws.
*
* Programmer : Wu YuanFu
* Version : V2.50
* LICENSING TERMS:
* ---------------
* wModbus is provided in source form for FREE short-term evaluation, for educational use or
* for peaceful research. If you plan or intend to use wModbus in a commercial application/
* product then, you need to contact Wu YuanFu<240697738@qq.com> to properly license wModbus
* for its use in your application/product. The fact that the source is provided does NOT
* mean that you can use it commercially without paying a licensing fee.
*
* Knowledge of the source code may NOT be used to develop a similar product.
*
********************************************************************************************************
*/
/* Filename : smb.c*/
#include "mb.h"
#define sMB_PDU_FN01_RcvLen_Min ( 5 )
#define sMB_PDU_FN02_RcvLen_Min ( 5 )
#define sMB_PDU_FN03_RcvLen_Min ( 5 )
#define sMB_PDU_FN04_RcvLen_Min ( 5 )
#define sMB_PDU_FN05_RcvLen_Min ( 5 )
#define sMB_PDU_FN06_RcvLen_Min ( 5 )
#define sMB_PDU_FN15_RcvLen_Min ( 7 )
#define sMB_PDU_FN16_RcvLen_Min ( 8 )
#define sMB_PDU_FN23_RcvLen_Min ( 12 )
#define sMB_GetRegValue( x ) ( USHORT )(( FramePtr[x] << 8 ) | FramePtr[x+ 1])
#if ( MB_SLAVE_ENABLED == MBENABLED)
/*
********************************************************************************************************
* sMB RegInputCB
*
* Description: 此函数用于从机 RegInput 的数据处理函数
* Arguments : p_mb 指向1个wModbus的指针
* Returns :
* Note(s) : 1) 用于FN04 命令
********************************************************************************************************
*/
static MB_Exception sMB_RegInputCB( wMB *p_mb ,UCHAR* pBuf)
{
UCHAR *pRegFrame;
USHORT *sMBpBuf = sMB_GetpBuf(p_mb->RegAddress,p_mb->RegCnt);
if(sMBpBuf != MBNULL)
{
if(p_mb->Mode == MB_MODE_TCP)
{
pRegFrame= &pBuf[MB_PDU_TCP_OFF + p_mb->Value_off];
}else
{pRegFrame = &pBuf[MB_PDU_RTU_OFF + p_mb->Value_off];}
for(USHORT i = 0;i < p_mb->RegCnt;i++)
{
*pRegFrame++ = *sMBpBuf >> 8;
*pRegFrame++ = *sMBpBuf++ ;
}
}
else{return MB_EX_ILLEGAL_DATA_ADDRESS;}
return MB_EX_NONE;
}
/*
********************************************************************************************************
* sMB RegHolding
*
* Description: 此函数用于从机 RegHolding 的数据处理函数
* Arguments : p_mb 指向1个wModbus的指针
* Returns :
* Note(s) : 1) 用于FN03 FN06 FN16 FN23 命令
********************************************************************************************************
*/
static MB_Exception sMB_RegHoldingCB( wMB *p_mb ,UCHAR* pBuf)
{
UCHAR *pRegFrame;
USHORT *sMBpBuf = sMB_GetpBuf(p_mb->RegAddress,p_mb->RegCnt);
if(sMBpBuf != MBNULL)
{
if(p_mb->Mode == MB_MODE_TCP)
{
pRegFrame= &pBuf[MB_PDU_TCP_OFF + p_mb->Value_off];
}else
{pRegFrame = &pBuf[MB_PDU_RTU_OFF + p_mb->Value_off];}
switch ( p_mb->ReadWrite )
{
case MBREAD:
for(USHORT i = 0;i < p_mb->RegCnt;i++)
{
*pRegFrame++ = *sMBpBuf >> 8;
*pRegFrame++ = *sMBpBuf++ ;
}
break;
case MBWRITE:
for(USHORT i = 0;i < p_mb->RegCnt;i++)
{
*sMBpBuf = *pRegFrame++ << 8;
*sMBpBuf |= *pRegFrame++;
sMB_RegHoldingWriteCallback(p_mb->RegAddress + i,*sMBpBuf++);
}
break;
}
}
else{return MB_EX_ILLEGAL_DATA_ADDRESS; }
return MB_EX_NONE;
}
/*
********************************************************************************************************
* sMB RegCoilsCB
*
* Description: 此函数用于从机 RegCoilsCB 的数据处理函数
* Arguments : p_mb 指向1个wModbus的指针
* Returns :
* Note(s) : 1) 用于FN01 FN05 FN15命令
********************************************************************************************************
*/
static MB_Exception sMB_RegCoilsCB( wMB *p_mb ,UCHAR* pBuf)
{
USHORT *pRegFrame;
USHORT *sMBpBuf = sMB_GetpBuf(p_mb->RegAddress,p_mb->RegCnt);
if(sMBpBuf != MBNULL)
{
if(p_mb->Mode == MB_MODE_TCP)
{
pRegFrame = (USHORT *)&pBuf[MB_PDU_TCP_OFF + p_mb->Value_off];
}else
{pRegFrame = (USHORT *)&pBuf[MB_PDU_RTU_OFF + p_mb->Value_off];}
USHORT Index = ( p_mb->RegAddress - sMB_COILS_START );
SHORT RegCnt = ( SHORT )p_mb->RegCnt;
switch ( p_mb->ReadWrite )
{
case MBREAD:
while( RegCnt > 0 )
{
UCHAR NBits = ( UCHAR )( RegCnt > MB_BITS ? MB_BITS : RegCnt );
*pRegFrame++ = MB_UtilGetBits( sMBpBuf, Index,NBits);
RegCnt -= MB_BITS;
Index += MB_BITS;
}
break;
case MBWRITE:
while( RegCnt > 0 )
{
UCHAR NBits = ( UCHAR )( RegCnt > MB_BITS ? MB_BITS : RegCnt );
MB_UtilSetBits(sMBpBuf, Index,NBits,*pRegFrame);
sMB_RegCoilsWriteCallback(Index + sMB_COILS_START,NBits,*pRegFrame);
RegCnt -= MB_BITS;
Index += MB_BITS;
pRegFrame++;
}
break;
}
}
else{return MB_EX_ILLEGAL_DATA_ADDRESS;}
return MB_EX_NONE;
}
/*
********************************************************************************************************
* sMB RegDiscreteCB
*
* Description: 此函数用于从机 RegDiscreteCB 的数据处理函数
* Arguments : p_mb 指向1个wModbus的指针
* Returns :
* Note(s) : 1) 用于FN02 命令
********************************************************************************************************
*/
static MB_Exception sMB_RegDiscreteCB(wMB *p_mb,UCHAR* pBuf)
{
USHORT *pRegFrame;
USHORT *sMBpBuf = sMB_GetpBuf(p_mb->RegAddress,p_mb->RegCnt);
if(sMBpBuf != MBNULL)
{
if(p_mb->Mode == MB_MODE_TCP)
{
pRegFrame = (USHORT *)&pBuf[MB_PDU_TCP_OFF + p_mb->Value_off];
}else
{pRegFrame = (USHORT *)&pBuf[MB_PDU_RTU_OFF + p_mb->Value_off];}
USHORT Index = ( p_mb->RegAddress - sMB_DISCRETE_START );
SHORT RegCnt = ( SHORT )p_mb->RegCnt;
while( RegCnt > 0 )
{
UCHAR NBits = ( UCHAR )( RegCnt > MB_BITS ? MB_BITS : RegCnt );
*pRegFrame++ = MB_UtilGetBits( sMBpBuf, Index,NBits );
RegCnt -= MB_BITS;
Index += MB_BITS;
}
}
else{return MB_EX_ILLEGAL_DATA_ADDRESS;}
return MB_EX_NONE;
}
/*
********************************************************************************************************
* sMB FN01 Handler
*
* Description: 此函数用于从机 FN01 号命令的处理函数
* Arguments : p_mb 指向1个wModbus的指针
* Returns :
* Note(s) : 1)
********************************************************************************************************
*/
#if MB_FN01_READ_COILS_ENABLED == MBENABLED
static MB_Exception sMB_FN01_Read_CoilsHandler( wMB *p_mb ,UCHAR* pBuf)
{
UCHAR *FramePtr;
UCHAR ucNBytes;
MB_Exception eStatus = MB_EX_NONE;
if( p_mb->BufCnt == sMB_PDU_FN01_RcvLen_Min )
{
if(p_mb->Mode == MB_MODE_TCP)
{
FramePtr = &pBuf[MB_PDU_TCP_OFF];
}else
{FramePtr = &pBuf[MB_PDU_RTU_OFF];}
p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
p_mb->RegCnt = sMB_GetRegValue( MB_PDU_REQ_CNT_OFF );
if((p_mb->RegCnt >= MB_PDU_FNxx_COUNT_MIN ) && (p_mb->RegCnt< MB_PDU_FN01_READCOUNT_MAX))
{
if( ( p_mb->RegCnt & 0x0007 ) != 0 )
{
ucNBytes = ( UCHAR )( p_mb->RegCnt / 8 + 1 );
}
else
{
ucNBytes = ( UCHAR )( p_mb->RegCnt / 8 );
}
FramePtr[MB_PDU_FN01_BYTECNT_OFF] = ucNBytes;
p_mb->BufCnt = 2 + ucNBytes;
p_mb->Value_off = MB_PDU_FN01_VALUE_OFF;
p_mb->ReadWrite = MBREAD;
eStatus = sMB_RegCoilsCB( p_mb,pBuf);
}
else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
}
else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
return eStatus;
}
#endif
/*
********************************************************************************************************
* sMB FN02 Handler
*
* Description: 此函数用于从机 FN02 号命令的处理函数
* Arguments : p_mb 指向1个wModbus的指针
* Returns :
* Note(s) : 1)
********************************************************************************************************
*/
#if MB_FN02_READ_DISCRETE_ENABLED == MBENABLED
static MB_Exception sMB_FN02_Read_DiscreteHandler( wMB *p_mb,UCHAR* pBuf)
{
UCHAR *FramePtr;
UCHAR ucNBytes;
MB_Exception eStatus = MB_EX_NONE;
if( p_mb->BufCnt == sMB_PDU_FN02_RcvLen_Min )
{
if(p_mb->Mode == MB_MODE_TCP)
{
FramePtr = &pBuf[MB_PDU_TCP_OFF];
}else
{FramePtr = &pBuf[MB_PDU_RTU_OFF];}
p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
p_mb->RegCnt = sMB_GetRegValue( MB_PDU_REQ_CNT_OFF );
if((p_mb->RegCnt >= MB_PDU_FNxx_COUNT_MIN) && (p_mb->RegCnt<MB_PDU_FN02_READCOUNT_MAX))
{
if( ( p_mb->RegCnt & 0x0007 ) != 0 )
{
ucNBytes = ( UCHAR ) ( p_mb->RegCnt / 8 + 1 );
}
else
{
ucNBytes = ( UCHAR ) ( p_mb->RegCnt / 8 );
}
FramePtr[MB_PDU_FN02_BYTECNT_OFF] = ucNBytes;
p_mb->BufCnt = 2 + ucNBytes;
p_mb->Value_off = MB_PDU_FN02_VALUE_OFF ;
eStatus = sMB_RegDiscreteCB( p_mb,pBuf);
}
else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
}
else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
return eStatus;
}
#endif
/*
********************************************************************************************************
* sMB FN03 Handler
*
* Description: 此函数用于从机 FN03 号命令的处理函数
* Arguments : p_mb 指向1个wModbus的指针
* Returns :
* Note(s) : 1)
********************************************************************************************************
*/
#if MB_FN03_READ_HOLDING_ENABLED == MBENABLED
static MB_Exception sMB_FN03_Read_HoldingRegister( wMB *p_mb,UCHAR* pBuf)
{
UCHAR *FramePtr;
MB_Exception eStatus = MB_EX_NONE;
if( p_mb->BufCnt == sMB_PDU_FN03_RcvLen_Min )
{
if(p_mb->Mode == MB_MODE_TCP)
{
FramePtr = &pBuf[MB_PDU_TCP_OFF];
}else
{FramePtr = &pBuf[MB_PDU_RTU_OFF];}
p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
p_mb->RegCnt = sMB_GetRegValue( MB_PDU_REQ_CNT_OFF );
if((p_mb->RegCnt>=MB_PDU_FNxx_COUNT_MIN) && (p_mb->RegCnt<= MB_PDU_FN03_READCOUNT_MAX))
{
FramePtr[MB_PDU_FN03_BYTECNT_OFF] = p_mb->RegCnt * 2;
p_mb->BufCnt = 2 + p_mb->RegCnt * 2;
p_mb->Value_off = MB_PDU_FN03_VALUE_OFF ;
p_mb->ReadWrite = MBREAD;
eStatus = sMB_RegHoldingCB( p_mb,pBuf);
}
else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
}
else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
return eStatus;
}
#endif
/*
********************************************************************************************************
* sMB FN04 Handler
*
* Description: 此函数用于从机 FN04 号命令的处理函数
* Arguments : p_mb 指向1个wModbus的指针
* Returns :
* Note(s) : 1)
********************************************************************************************************
*/
#if MB_FN04_READ_INPUT_ENABLED == MBENABLED
static MB_Exception sMB_FN04_Read_InputHandler( wMB *p_mb,UCHAR* pBuf)
{
UCHAR *FramePtr;
MB_Exception eStatus = MB_EX_NONE;
if( p_mb->BufCnt == sMB_PDU_FN04_RcvLen_Min )
{
if(p_mb->Mode == MB_MODE_TCP)
{
FramePtr = &pBuf[MB_PDU_TCP_OFF];
}else
{FramePtr = &pBuf[MB_PDU_RTU_OFF];}
p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
p_mb->RegCnt = sMB_GetRegValue( MB_PDU_REQ_CNT_OFF );
if( ( p_mb->RegCnt >= MB_PDU_FNxx_COUNT_MIN) && (p_mb->RegCnt<MB_PDU_FN04_READCOUNT_MAX))
{
FramePtr[MB_PDU_FN04_BYTECNT_OFF] = p_mb->RegCnt * 2 ;
p_mb->BufCnt = 2 + p_mb->RegCnt * 2;
p_mb->Value_off = MB_PDU_FN04_VALUE_OFF ;
eStatus = sMB_RegInputCB( p_mb,pBuf);
}
else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
}
else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
return eStatus;
}
#endif
/*
********************************************************************************************************
* sMB FN05 Handler
*
* Description: 此函数用于从机 FN05 号命令的处理函数
* Arguments : p_mb 指向1个wModbus的指针
* Returns :
* Note(s) : 1)
********************************************************************************************************
*/
#if MB_FN05_WRITE_COIL_ENABLED == MBENABLED
static MB_Exception sMB_FN05_Write_CoilsHandler( wMB *p_mb ,UCHAR* pBuf)
{
UCHAR *FramePtr;
MB_Exception eStatus = MB_EX_NONE;
if( p_mb->BufCnt == sMB_PDU_FN05_RcvLen_Min )
{
if(p_mb->Mode == MB_MODE_TCP)
{
FramePtr = &pBuf[MB_PDU_TCP_OFF];
}else
{FramePtr = &pBuf[MB_PDU_RTU_OFF];}
p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
p_mb->RegCnt = 1;
if((FramePtr[MB_PDU_FN05_VALUE_OFF + 1] == 0x00 )
&& ((FramePtr[MB_PDU_FN05_VALUE_OFF] == 0xFF )
|| (FramePtr[MB_PDU_FN05_VALUE_OFF] == 0 )))
{
if( FramePtr[MB_PDU_FN05_VALUE_OFF] == 0xFF )
{
FramePtr[MB_PDU_FN05_VALUE_OFF] = 1;
}
p_mb->Value_off = MB_PDU_FN05_VALUE_OFF ;
p_mb->ReadWrite = MBWRITE;
eStatus = sMB_RegCoilsCB( p_mb,pBuf);
if(FramePtr[MB_PDU_FN05_VALUE_OFF] == 1)
{
FramePtr[MB_PDU_FN05_VALUE_OFF] = 0xFF;
}
}
else {eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
}
else {eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
return eStatus;
}
#endif
/*
********************************************************************************************************
* sMB FN06 Handler
*
* Description: 此函数用于从机 FN06 号命令的处理函数
* Arguments : p_mb 指向1个wModbus的指针
* Returns :
* Note(s) : 1)
********************************************************************************************************
*/
#if MB_FN06_WRITE_HOLDING_ENABLED == MBENABLED
static MB_Exception sMB_FN06_Write_HoldingHandler( wMB *p_mb ,UCHAR* pBuf)
{
UCHAR *FramePtr;
MB_Exception eStatus = MB_EX_NONE;
if( p_mb->BufCnt == sMB_PDU_FN06_RcvLen_Min )
{
if(p_mb->Mode == MB_MODE_TCP)
{
FramePtr = &pBuf[MB_PDU_TCP_OFF];
}else
{FramePtr = &pBuf[MB_PDU_RTU_OFF];}
p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
p_mb->RegCnt = 1;
p_mb->Value_off = MB_PDU_FN06_VALUE_OFF ;
p_mb->ReadWrite = MBWRITE;
eStatus = sMB_RegHoldingCB( p_mb,pBuf);
}
else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
return eStatus;
}
#endif
/*
********************************************************************************************************
* sMB FN15 Handler
*
* Description: 此函数用于从机 FN15 号命令的处理函数
* Arguments : p_mb 指向1个wModbus的指针
* Returns :
* Note(s) : 1)
********************************************************************************************************
*/
#if MB_FN15_WRITE_COILS_ENABLED == MBENABLED
static MB_Exception sMB_FN15_Write_CoilsHandler( wMB *p_mb ,UCHAR* pBuf)
{
UCHAR *FramePtr;
UCHAR ucNBytes;
MB_Exception eStatus = MB_EX_NONE;
if( p_mb->BufCnt >= sMB_PDU_FN15_RcvLen_Min )
{
if(p_mb->Mode == MB_MODE_TCP)
{
FramePtr = &pBuf[MB_PDU_TCP_OFF];
}else
{FramePtr = &pBuf[MB_PDU_RTU_OFF];}
p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
p_mb->RegCnt = sMB_GetRegValue( MB_PDU_REQ_CNT_OFF );
if( ( p_mb->RegCnt & 0x0007 ) != 0 )
{
ucNBytes = ( UCHAR )( p_mb->RegCnt / 8 + 1 );
}
else
{
ucNBytes = ( UCHAR )( p_mb->RegCnt / 8 );
}
if((p_mb->RegCnt>=MB_PDU_FNxx_COUNT_MIN) && (p_mb->RegCnt<=MB_PDU_FN15_WRITECOUNT_MAX)
&& ( ucNBytes == FramePtr[MB_PDU_FN15_BYTECNT_OFF] ))
{
p_mb->BufCnt = MB_PDU_FN15_BYTECNT_OFF;
p_mb->Value_off = MB_PDU_FN15_VALUE_OFF ;
p_mb->ReadWrite = MBWRITE;
eStatus = sMB_RegCoilsCB( p_mb,pBuf);
}
else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
}
else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
return eStatus;
}
#endif
/*
********************************************************************************************************
* sMB FN16 Handler
*
* Description: 此函数用于从机 FN16 号命令的处理函数
* Arguments : p_mb 指向1个wModbus的指针
* Returns :
* Note(s) : 1)
********************************************************************************************************
*/
#if MB_FN16_WRITE_HOLDING_ENABLED == MBENABLED
static MB_Exception sMB_FN16_Write_HoldingHandler( wMB *p_mb ,UCHAR* pBuf)
{
UCHAR *FramePtr;
MB_Exception eStatus = MB_EX_NONE;
if( p_mb->BufCnt >= sMB_PDU_FN16_RcvLen_Min )
{
if(p_mb->Mode == MB_MODE_TCP)
{
FramePtr = &pBuf[MB_PDU_TCP_OFF];
}else
{FramePtr = &pBuf[MB_PDU_RTU_OFF];}
p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
p_mb->RegCnt = sMB_GetRegValue( MB_PDU_REQ_CNT_OFF );
if((p_mb->RegCnt>=MB_PDU_FNxx_COUNT_MIN) &&(p_mb->RegCnt <=MB_PDU_FN16_WRITECOUNT_MAX)
&& ( FramePtr[MB_PDU_FN16_BYTECNT_OFF] == ( 2 * p_mb->RegCnt )))
{
p_mb->BufCnt = MB_PDU_FN16_BYTECNT_OFF;
p_mb->Value_off = MB_PDU_FN16_VALUE_OFF ;
p_mb->ReadWrite = MBWRITE;
eStatus = sMB_RegHoldingCB( p_mb,pBuf);
}
else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
}
else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
return eStatus;
}
#endif
/*
********************************************************************************************************
* sMB FN23 Handler
*
* Description: 此函数用于从机 FN23 号命令的处理函数
* Arguments : p_mb 指向1个wModbus的指针
* Returns :
* Note(s) : 1)
********************************************************************************************************
*/
#if MB_FN23_READWRITE_HOLDING_ENABLED == MBENABLED
static MB_Exception sMB_FN23_ReadWrite_HoldingHandler( wMB *p_mb,UCHAR* pBuf)
{
UCHAR *FramePtr;
MB_Exception eStatus = MB_EX_NONE;
if( p_mb->BufCnt >= sMB_PDU_FN23_RcvLen_Min )
{
if(p_mb->Mode == MB_MODE_TCP)
{
FramePtr = &pBuf[MB_PDU_TCP_OFF];
}else
{FramePtr = &pBuf[MB_PDU_RTU_OFF];}
p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_2ndADDR_OFF );
p_mb->RegCnt = sMB_GetRegValue( MB_PDU_REQ_2ndCNT_OFF );
if((p_mb->RegCnt>=MB_PDU_FNxx_COUNT_MIN) && (p_mb->RegCnt <=MB_PDU_FN23_WRITECOUNT_MAX)
&&(( 2 * p_mb->RegCnt ) == FramePtr[MB_PDU_FN23_WRITEBYTECNT_OFF] ))
{
p_mb->Value_off = MB_PDU_FN23_WRITEVALUE_OFF ;
p_mb->ReadWrite = MBWRITE;
eStatus = sMB_RegHoldingCB( p_mb,pBuf);
p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
p_mb->RegCnt = sMB_GetRegValue( MB_PDU_REQ_CNT_OFF );
if((eStatus == MB_EX_NONE ) &&( p_mb->RegCnt >= 1 )
&& ( p_mb->RegCnt <= MB_PDU_FN23_READCOUNT_MAX ))
{
FramePtr[MB_PDU_FN23_READBYTECNT_OFF] = p_mb->RegCnt * 2 ;
p_mb->BufCnt = 2 + 2 * p_mb->RegCnt;
p_mb->Value_off = MB_PDU_FN23_READVALUE_OFF ;
p_mb->ReadWrite = MBREAD;
eStatus =sMB_RegHoldingCB( p_mb,pBuf);
}
}
else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
}
return eStatus;
}
#endif
/*
********************************************************************************************************
* Function Handlers
*
* Description: 此函数用于从机wModbus协议栈的功能函数库调用。
* Arguments : p_mb 指向1个wModbus的指针
* Note(s) : 1) sMB_FuncHandlers() 自动被 sMB_Poll()调用
********************************************************************************************************
*/
static MB_Exception sMB_FuncHandlers(wMB *p_mb,UCHAR* pBuf)
{
UCHAR *FramePtr;
MB_Exception Exception;
if(p_mb->Mode == MB_MODE_TCP)
{
FramePtr = &pBuf[MB_PDU_TCP_OFF];
}else
{FramePtr = &pBuf[MB_PDU_RTU_OFF];}
switch (FramePtr[MB_PDU_FUNC_OFF])
{
#if MB_FN01_READ_COILS_ENABLED == MBENABLED
case MB_FN01_READ_COILS:
#if (MB_BROADCASTRESPOND_ENABLED != MBENABLED)
if(p_mb->RecvAddr != MB_ADDRESS_BROADCAST )
#endif
{Exception = sMB_FN01_Read_CoilsHandler(p_mb,pBuf);}break;
#endif
#if MB_FN02_READ_DISCRETE_ENABLED == MBENABLED
case MB_FN02_READ_DISCRETE_INPUTS:
#if (MB_BROADCASTRESPOND_ENABLED != MBENABLED)
if(p_mb->RecvAddr != MB_ADDRESS_BROADCAST )
#endif
{Exception = sMB_FN02_Read_DiscreteHandler(p_mb,pBuf);}break;
#endif
#if MB_FN03_READ_HOLDING_ENABLED == MBENABLED
case MB_FN03_READ_HOLDING_REGISTER:
#if (MB_BROADCASTRESPOND_ENABLED != MBENABLED)
if(p_mb->RecvAddr != MB_ADDRESS_BROADCAST )
#endif
{Exception = sMB_FN03_Read_HoldingRegister(p_mb,pBuf);}break;
#endif
#if MB_FN04_READ_INPUT_ENABLED == MBENABLED
case MB_FN04_READ_INPUT_REGISTER:
#if (MB_BROADCASTRESPOND_ENABLED != MBENABLED)
if(p_mb->RecvAddr != MB_ADDRESS_BROADCAST )
#endif
{Exception = sMB_FN04_Read_InputHandler(p_mb,pBuf);}break;
#endif
#if MB_FN05_WRITE_COIL_ENABLED == MBENABLED
case MB_FN05_WRITE_SINGLE_COIL:
{Exception = sMB_FN05_Write_CoilsHandler(p_mb,pBuf);}break;
#endif
#if MB_FN06_WRITE_HOLDING_ENABLED == MBENABLED
case MB_FN06_WRITE_REGISTER:
{Exception = sMB_FN06_Write_HoldingHandler(p_mb,pBuf);}break;
#endif
#if MB_FN15_WRITE_COILS_ENABLED == MBENABLED
case MB_FN15_WRITE_MULTIPLE_COILS:
{Exception = sMB_FN15_Write_CoilsHandler(p_mb,pBuf);}break;
#endif
#if MB_FN16_WRITE_HOLDING_ENABLED == MBENABLED
case MB_FN16_WRITE_MULTIPLE_REGISTERS:
{Exception = sMB_FN16_Write_HoldingHandler(p_mb,pBuf);}break;
#endif
#if MB_FN23_READWRITE_HOLDING_ENABLED == MBENABLED
case MB_FN23_READWRITE_MULTIPLE_REGISTERS:
{Exception = sMB_FN23_ReadWrite_HoldingHandler(p_mb,pBuf);}break;
#endif
default:
{Exception = MB_EX_ILLEGAL_FUNCTION;}break;
}
return Exception;
}
/*
********************************************************************************************************
* Deal A wModbus
*
* Description: 此函数用于从机wModbus协议栈Poll函数,需循环调用。
* Arguments : p_mb 指向1个wModbus的指针
* Returns : MB_Exception 返回错误代码。
* Note(s) : 1) sMB_Deal() 应当创建一个wModbus协议栈并使能后使用
********************************************************************************************************
*/
USHORT sMB_Deal( wMB *p_mb,UCHAR* pBuf,USHORT length )
{
UCHAR *FramePtr;
MB_Exception eStatus;
USHORT slen = 0;
if ( MB_MutexPend( p_mb ) != MBFALSE )
{
if(MB_Receive( p_mb,pBuf,length) != MBTRUE)
{
#if (MB_STAT_ENABLED == MBENABLED)
p_mb->StatReceiveErrCtr++;
#endif
}
else
{
if(( p_mb->RecvAddr == p_mb->NodeAddr ) || ( p_mb->RecvAddr == MB_ADDRESS_BROADCAST ))
{
eStatus = sMB_FuncHandlers(p_mb,pBuf);
if( eStatus != MB_EX_NONE )
{
p_mb->BufCnt = 0;
if(p_mb->Mode == MB_MODE_TCP)
{
FramePtr= &pBuf[MB_PDU_TCP_OFF];
}else
{
FramePtr = &pBuf[MB_PDU_RTU_OFF];
}
FramePtr[p_mb->BufCnt ++] = FramePtr[MB_PDU_FUNC_OFF] | MB_FUNC_ERROR ;
FramePtr[p_mb->BufCnt ++] = eStatus;
#if (MB_STAT_ENABLED == MBENABLED)
p_mb->StatHandlersErrCtr++;
#endif
}
#if (MB_STAT_ENABLED == MBENABLED)
else
{
p_mb->StatOKCtr++;
}
#endif
slen = MB_Send(p_mb,pBuf);
}
}
MB_MutexPost(p_mb);
}
return slen;
}
#endif
smbbuf.c文件
/*
********************************************************************************************************
* wModbus
* The Embedded Modbus Stack Software
*
* Copyright: Wu YuanFu. All rights reserved.Protected by international copyright laws.
*
* Programmer : Wu YuanFu
* Version : V2.50
* LICENSING TERMS:
* ---------------
* wModbus is provided in source form for FREE short-term evaluation, for educational use or
* for peaceful research. If you plan or intend to use wModbus in a commercial application/
* product then, you need to contact Wu YuanFu<240697738@qq.com> to properly license wModbus
* for its use in your application/product. The fact that the source is provided does NOT
* mean that you can use it commercially without paying a licensing fee.
*
* Knowledge of the source code may NOT be used to develop a similar product.
*
********************************************************************************************************
*/
/* Filename : mbbuf.c*/
#include "smbbuf.h"
#if ( MB_SLAVE_ENABLED== MBENABLED )
#define sMB_HoldingBuf_Addr 0 //数量为 sMB_HOLDING_NREGS
#define sMB_InputBuf_Addr (sMB_HoldingBuf_Addr + sMB_HOLDING_NREGS) //数量为 sMB_INPUT_NREGS
#define sMB_CoilsBuf_Addr (sMB_InputBuf_Addr + sMB_INPUT_NREGS) //数量为 sMB_COILS_NREGS/MB_BITS + 1
#define sMB_DiscreteBuf_Addr (sMB_CoilsBuf_Addr + sMB_COILS_NREGS/MB_BITS +1) //数量为 sMB_DISCRETE_NREGS/MB_BITS + 1
#define sMB_BUF_SIZE (sMB_DiscreteBuf_Addr + sMB_DISCRETE_NREGS/MB_BITS + 1) //数量为 sMB_DISCRETE_NREGS/MB_BITS + 1
static USHORT MBBuf[sMB_BUF_SIZE];
/*
********************************************************************************************************
* sMB RegHoldingWrite Callback
*
* Description: 此函数用于RegHoldingWrite回调函数
* Arguments : addr RegHolding地址
* : value RegHolding地址上的值
* Note(s) : 1) sMB_RegHoldingCBCallback() 可作为用户hook函数。
********************************************************************************************************
*/
__weak void sMB_RegHoldingWriteCallback(USHORT addr,USHORT value)
{
}
/*
********************************************************************************************************
* sMB RegCoilsWrite Callback
*
* Description: 此函数用于RegCoilsWrite回调函数
* Arguments : addr RegCoils地址
* : NBits 写入的位数 <=16
* : value RegCoils地址上的值
* Note(s) : 1) sMB_RegCoilsCBCallback() 可作为用户hook函数。
********************************************************************************************************
*/
__weak void sMB_RegCoilsWriteCallback( USHORT addr,UCHAR NBits,USHORT value)
{
}
USHORT* sMB_GetpBuf(USHORT addr,USHORT num)
{
USHORT* pBuf;
if((addr >= sMB_HOLDING_START ) && ((addr + num) <= (sMB_HOLDING_START+ sMB_HOLDING_NREGS)))
{
pBuf = &MBBuf[addr - sMB_HOLDING_START + sMB_HoldingBuf_Addr];
}
else if((addr >= sMB_INPUT_START ) && ((addr + num) <= (sMB_INPUT_START+ sMB_INPUT_NREGS)))
{
pBuf = &MBBuf[addr - sMB_INPUT_START + sMB_InputBuf_Addr];
}
else if((addr >= sMB_COILS_START ) && ((addr + num) <= (sMB_COILS_START+ sMB_COILS_NREGS)))
{
pBuf = &MBBuf[sMB_CoilsBuf_Addr];
}
else if((addr >= sMB_DISCRETE_START ) && ((addr + num) <= (sMB_DISCRETE_START+ sMB_DISCRETE_NREGS)))
{
pBuf = &MBBuf[sMB_DiscreteBuf_Addr];
}
else{return MBNULL;}
return pBuf;
}
/*
********************************************************************************************************
* Set Buf
*
* Description: 此函数用于设置数据
* Arguments : addr buf数据偏移地址
* dst 目标数据地址
* num 数据个数
* Returns : MBTRUE 成功
* MBFALSE 失败
* Note(s) : 1) MB_GetBuf()
********************************************************************************************************
*/
MB_Exception MB_SetBufs(USHORT addr,USHORT* dst,USHORT num)
{
USHORT i;
USHORT* src;
src = sMB_GetpBuf(addr,num);
if(src != MBNULL)
{
for(i=0;i<num;i++)
{
src[i] = dst[i];
}
return MB_EX_NONE;
}
return MB_EX_ILLEGAL_DATA_ADDRESS;
}
MB_Exception MB_SetBuf(USHORT addr,USHORT dst)
{
USHORT* src;
src = sMB_GetpBuf(addr,1);
if(src != MBNULL)
{
*src = dst;
return MB_EX_NONE;
}
return MB_EX_ILLEGAL_DATA_ADDRESS;
}
/*
********************************************************************************************************
* Get Buf
*
* Description: 此函数用于获取数据
* Arguments : addr buf数据偏移地址
* dst 目标数据地址
* num 数据个数
* Returns : MBTRUE 成功
* MBFALSE 失败
* Note(s) : 1) MB_GetBuf()
********************************************************************************************************
*/
MB_Exception MB_GetBufs(USHORT addr,USHORT* dst,USHORT num)
{
USHORT i;
USHORT* src;
src = sMB_GetpBuf(addr,num);
if(src != MBNULL)
{
for(i=0;i<num;i++)
{
dst[i] = src[i];
}
return MB_EX_NONE;
}
return MB_EX_ILLEGAL_DATA_ADDRESS;
}
USHORT MB_GetBuf(USHORT addr)
{
USHORT* src;
src = sMB_GetpBuf(addr,1);
if(src != MBNULL)
{
return *src;
}
return MBNULL;
}
#endif
smbbuf.h文件
/*
********************************************************************************************************
* wModbus
* The Embedded Modbus Stack Software
*
* Copyright: Wu YuanFu. All rights reserved.Protected by international copyright laws.
*
* Programmer : Wu YuanFu
* Version : V2.50
* LICENSING TERMS:
* ---------------
* wModbus is provided in source form for FREE short-term evaluation, for educational use or
* for peaceful research. If you plan or intend to use wModbus in a commercial application/
* product then, you need to contact Wu YuanFu<240697738@qq.com> to properly license wModbus
* for its use in your application/product. The fact that the source is provided does NOT
* mean that you can use it commercially without paying a licensing fee.
*
* Knowledge of the source code may NOT be used to develop a similar product.
*
********************************************************************************************************
*/
/* Filename : mbbuf.h*/
#include "mbtype.h"
#ifndef _MB_BUF_H
#define _MB_BUF_H
#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif
#if ( MB_SLAVE_ENABLED== MBENABLED )
MB_Exception MB_SetBufs(USHORT addr,USHORT* dst,USHORT num);
MB_Exception MB_GetBufs(USHORT addr,USHORT* dst,USHORT num);
MB_Exception MB_SetBuf(USHORT addr,USHORT dst);
USHORT MB_GetBuf(USHORT addr);
#define sMB_HOLDING_START 0x1000 //HOLDING起始地址
#define sMB_HOLDING_NREGS 512
#define sMB_INPUT_START 0x9000 //INPUT起始地址
#define sMB_INPUT_NREGS 16
#define sMB_COILS_START 0x0500 //COILS起始地址
#define sMB_COILS_NREGS 64
#define sMB_DISCRETE_START 0x0400 //DISCRETE起始地址
#define sMB_DISCRETE_NREGS 64
#endif
#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#endif
mmb.c文件
暂不提供