提交 e984da7f 编写于 作者: B Bernard Xiong

Merge remote-tracking branch 'upstream/master'

......@@ -14,7 +14,11 @@
#include <rtthread.h>
#include <board.h>
#ifdef RT_USING_FINSH
#include <shell.h>
#include <finsh.h>
#endif
#ifdef RT_USING_COMPONENTS_INIT
#include <components.h>
#endif
......@@ -25,12 +29,8 @@ void rt_init_thread_entry(void *parameter)
/* Initialization RT-Thread Components */
#ifdef RT_USING_COMPONENTS_INIT
rt_components_init();
#endif
#ifdef RT_USING_FINSH
/* initialize finsh */
#elif defined(RT_USING_FINSH)
finsh_system_init();
finsh_set_device(FINSH_DEVICE_NAME);
#endif
}
......
......@@ -50,6 +50,14 @@
#define WIN32_DIRDISK_ROOT "." /* "F:\\Project\\svn\\rtt\\trunk\\bsp\\simulator_test" */
typedef struct {
HANDLE handle;
char *start;
char *end;
char *curr;
struct _finddata_t finddata;
} WINDIR;
/* There are so many error codes in windows, you'd better google for details.
* google "System Error Codes (Windows)"
* http://msdn.microsoft.com/ZH-CN/library/windows/desktop/ms681381(v=vs.85).aspx
......@@ -166,8 +174,8 @@ static int dfs_win32_open(struct dfs_fd *file)
oflag = file->flags;
if (oflag & DFS_O_DIRECTORY) /* operations about dir */
{
struct _finddata_t dir;
int handle;
WINDIR *wdirp;
HANDLE handle;
int len;
file_path = winpath_dirdup(WIN32_DIRDISK_ROOT, file->path);
......@@ -191,14 +199,24 @@ static int dfs_win32_open(struct dfs_fd *file)
strcat(file_path, "*.*");
/* _findfirst will get '.' */
if ((handle = _findfirst(file_path, &dir)) == -1)
/* save this pointer,will used by dfs_win32_getdents*/
wdirp = rt_malloc(sizeof(WINDIR));
RT_ASSERT(wdirp != NULL);
if ((handle = _findfirst(file_path, &wdirp->finddata)) == -1)
{
rt_free(wdirp);
rt_free(file_path);
goto __err;
}
/* save this pointer,will used by dfs_win32_getdents*/
file->data = (void *)handle;
len = strlen(wdirp->finddata.name) + 1;
wdirp->handle = handle;
//wdirp->nfiles = 1;
wdirp->start = malloc(len); //not rt_malloc!
wdirp->end = wdirp->curr = wdirp->start;
wdirp->end += len;
strncpy(wdirp->curr, wdirp->finddata.name, len);
file->data = (void *)wdirp;
rt_free(file_path);
return DFS_STATUS_OK;
}
......@@ -243,25 +261,22 @@ __err:
static int dfs_win32_close(struct dfs_fd *file)
{
int oflag;
oflag = file->flags;
if (oflag & DFS_O_DIRECTORY)
if (file->flags & DFS_O_DIRECTORY)
{
/* operations about dir */
if (_findclose((intptr_t)file->data) < 0)
goto __err;
return 0;
WINDIR *wdirp = (WINDIR*)(file->data);
RT_ASSERT(wdirp != RT_NULL);
if (_findclose((intptr_t)wdirp->handle) == 0) {
free(wdirp->start); //NOTE: here we don't use rt_free!
rt_free(wdirp);
return 0;
}
}
else /* regular file operations */
{
if (_close((int)(file->data)) == 0)
return 0;
}
/* regular file operations */
if (_close((int)(file->data)) < 0)
goto __err;
return 0;
__err:
return win32_result_to_dfs(GetLastError());
}
......@@ -316,16 +331,19 @@ static int dfs_win32_seek(struct dfs_fd *file,
/* set offset as current offset */
if (file->type == FT_DIRECTORY)
{
return -DFS_STATUS_ENOSYS;
WINDIR* wdirp = (WINDIR*)(file->data);
RT_ASSERT(wdirp != RT_NULL);
wdirp->curr = wdirp->start + offset;
return offset;
}
else if (file->type == FT_REGULAR)
else //file->type == FT_REGULAR)
{
result = _lseek((int)(file->data), offset, SEEK_SET);
if (result >= 0)
return offset;
else
return win32_result_to_dfs(GetLastError());
}
return win32_result_to_dfs(GetLastError());
}
/* return the size of struct dirent*/
......@@ -334,53 +352,52 @@ static int dfs_win32_getdents(
struct dirent *dirp,
rt_uint32_t count)
{
rt_uint32_t index;
struct dirent *d;
struct _finddata_t fileinfo;
int handle;
WINDIR *wdirp;
struct dirent *d = dirp;
int result;
handle = (int)(file->data);
RT_ASSERT(handle != RT_NULL);
/* make integer count */
if (count / sizeof(struct dirent) != 1)
return -DFS_STATUS_EINVAL;
/* round count, count is always 1 */
count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
if (count == 0) return -DFS_STATUS_EINVAL;
wdirp = (WINDIR*)(file->data);
RT_ASSERT(wdirp != RT_NULL);
if (wdirp->curr == NULL) //no more entries in this directory
return 0;
index = 0;
/* usually, the while loop should only be looped only once! */
while (1)
/* get the current entry */
if (wdirp->finddata.attrib & _A_SUBDIR)
d->d_type = DFS_DT_DIR;
else
d->d_type = DFS_DT_REG;
d->d_namlen = strlen(wdirp->curr);
strncpy(d->d_name, wdirp->curr, DFS_PATH_MAX);
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
wdirp->curr += (strlen(wdirp->curr) + 1);
file->pos = wdirp->curr - wdirp->start + sizeof(struct dirent);//NOTE!
/* now set up for the next call to readdir */
if (wdirp->curr >= wdirp->end)
{
d = dirp + index;
if (_findnext(handle, &fileinfo) != 0) //-1 failed
goto __err;
if (fileinfo.attrib & _A_SUBDIR)
d->d_type = DFS_DT_DIR; /* directory */
if (_findnext(wdirp->handle, &wdirp->finddata) == 0)
{
char* old_start = wdirp->start;
long name_len = strlen(wdirp->finddata.name) + 1;
wdirp->start = realloc(wdirp->start, wdirp->end - wdirp->start + name_len);
wdirp->curr = wdirp->start + (wdirp->curr - old_start);
wdirp->end = wdirp->curr + name_len;
strcpy(wdirp->curr, wdirp->finddata.name);
}
else
d->d_type = DFS_DT_REG;
/* write the rest arguments of struct dirent* dirp */
d->d_namlen = strlen(fileinfo.name);
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
strcpy(d->d_name, fileinfo.name);
index ++;
if (index * sizeof(struct dirent) >= count)
break;
{
if ((result = GetLastError()) == ERROR_NO_MORE_FILES)
wdirp->curr = NULL;
else
return win32_result_to_dfs(result);
}
}
if (index == 0)
return 0;
file->pos += index * sizeof(struct dirent);
return index * sizeof(struct dirent);
__err:
if ((result = GetLastError()) == ERROR_NO_MORE_FILES)
return 0;
else
return win32_result_to_dfs(result);
return sizeof(struct dirent);
}
static int dfs_win32_unlink(struct dfs_filesystem *fs, const char *path)
......
/*
* FreeModbus Libary: STM32 Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: porttimer_m.c,v 1.60 2013/08/13 15:07:05 Armink add Master Functions$
*/
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbport.h"
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED
/* ----------------------- Variables ----------------------------------------*/
static USHORT usT35TimeOut50us;
static USHORT usPrescalerValue = 0;
/* ----------------------- static functions ---------------------------------*/
static void prvvTIMERExpiredISR(void);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us)
{
NVIC_InitTypeDef NVIC_InitStructure;
//====================================时钟初始化===========================
//使能定时器2时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
//====================================定时器初始化===========================
//定时器时间基配置说明
//HCLK为72MHz,APB1经过2分频为36MHz
//TIM2的时钟倍频后为72MHz(硬件自动倍频,达到最大)
//TIM2的分频系数为3599,时间基频率为72 / (1 + Prescaler) = 20KHz,基准为50us
//TIM最大计数值为usTim1Timerout50u
usPrescalerValue = (uint16_t) (SystemCoreClock / 20000) - 1;
//保存T35定时器计数值
usT35TimeOut50us = usTimeOut50us;
//预装载使能
TIM_ARRPreloadConfig(TIM2, ENABLE);
//====================================中断初始化===========================
//设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//清除溢出中断标志位
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
//定时器3溢出中断关闭
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
//定时器3禁能
TIM_Cmd(TIM2, DISABLE);
return TRUE;
}
void vMBMasterPortTimersT35Enable()
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Set current timer mode,don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_T35);
TIM_TimeBaseStructure.TIM_Prescaler = usPrescalerValue;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = (uint16_t) usT35TimeOut50us;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_SetCounter(TIM2, 0);
TIM_Cmd(TIM2, ENABLE);
}
void vMBMasterPortTimersConvertDelayEnable()
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Set current timer mode,don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_CONVERT_DELAY);
TIM_TimeBaseStructure.TIM_Prescaler = usPrescalerValue;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = (uint16_t)(MB_MASTER_DELAY_MS_CONVERT * 1000 / 50);
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_SetCounter(TIM2, 0);
TIM_Cmd(TIM2, ENABLE);
}
void vMBMasterPortTimersRespondTimeoutEnable()
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Set current timer mode,don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_RESPOND_TIMEOUT);
TIM_TimeBaseStructure.TIM_Prescaler = usPrescalerValue;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = (uint16_t)(MB_MASTER_TIMEOUT_MS_RESPOND * 1000 / 50);
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_SetCounter(TIM2, 0);
TIM_Cmd(TIM2, ENABLE);
}
void vMBMasterPortTimersDisable()
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
TIM_SetCounter(TIM2, 0);
TIM_Cmd(TIM2, DISABLE);
}
void prvvTIMERExpiredISR(void)
{
(void) pxMBMasterPortCBTimerExpired();
}
void TIM2_IRQHandler(void)
{
rt_interrupt_enter();
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清中断标记
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除定时器TIM2溢出中断标志位
prvvTIMERExpiredISR();
}
rt_interrupt_leave();
}
#endif
#include "user_mb_app.h"
/*------------------------Slave mode use these variables----------------------*/
//Slave mode:DiscreteInputs variables
USHORT usSDiscInStart = S_DISCRETE_INPUT_START;
#if S_DISCRETE_INPUT_NDISCRETES%8
UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8+1];
#else
UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8] ;
#endif
//Slave mode:Coils variables
USHORT usSCoilStart = S_COIL_START;
#if S_COIL_NCOILS%8
UCHAR ucSCoilBuf[S_COIL_NCOILS/8+1] ;
#else
UCHAR ucSCoilBuf[S_COIL_NCOILS/8] ;
#endif
//Slave mode:InputRegister variables
USHORT usSRegInStart = S_REG_INPUT_START;
USHORT usSRegInBuf[S_REG_INPUT_NREGS] ;
//Slave mode:HoldingRegister variables
USHORT usSRegHoldStart = S_REG_HOLDING_START;
USHORT usSRegHoldBuf[S_REG_HOLDING_NREGS] ;
/*-----------------------Master mode use these variables----------------------*/
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
//Master mode:DiscreteInputs variables
USHORT usMDiscInStart = M_DISCRETE_INPUT_START;
#if M_DISCRETE_INPUT_NDISCRETES%8
UCHAR ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES/8+1];
#else
UCHAR ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES/8];
#endif
//Master mode:Coils variables
USHORT usMCoilStart = M_COIL_START;
#if M_COIL_NCOILS%8
UCHAR ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS/8+1];
#else
UCHAR ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS/8];
#endif
//Master mode:InputRegister variables
USHORT usMRegInStart = M_REG_INPUT_START;
USHORT usMRegInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_INPUT_NREGS];
//Master mode:HoldingRegister variables
USHORT usMRegHoldStart = M_REG_HOLDING_START;
USHORT usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS];
#endif
//******************************输入寄存器回调函数**********************************
//函数定义: eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
//描 述:输入寄存器相关的功能(读、连续读)
//入口参数:pucRegBuffer : 回调函数将Modbus寄存器的当前值写入的缓冲区
// usAddress : 寄存器的起始地址,输入寄存器的地址范围是1-65535。
// usNRegs : 寄存器数量
//出口参数:eMBErrorCode : 这个函数将返回的错误码
//备 注:Editor:Armink 2010-10-31 Company: BXXJS
//**********************************************************************************
eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex;
USHORT * pusRegInputBuf;
UCHAR REG_INPUT_START;
UCHAR REG_INPUT_NREGS;
UCHAR usRegInStart;
//Determine the master or slave
if (xMBMasterGetCBRunInMasterMode())
{
pusRegInputBuf = usMRegInBuf[ucMBMasterGetDestAddress()];
REG_INPUT_START = M_REG_INPUT_START;
REG_INPUT_NREGS = M_REG_INPUT_NREGS;
usRegInStart = usMRegInStart;
}
else
{
pusRegInputBuf = usSRegInBuf;
REG_INPUT_START = S_REG_INPUT_START;
REG_INPUT_NREGS = S_REG_INPUT_NREGS;
usRegInStart = usSRegInStart;
}
if( ( usAddress >= REG_INPUT_START )
&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
{
iRegIndex = ( int )( usAddress - usRegInStart );
while( usNRegs > 0 )
{
//Determine the master or slave
if (xMBMasterGetCBRunInMasterMode())
{
pusRegInputBuf[iRegIndex] = *pucRegBuffer++ << 8;
pusRegInputBuf[iRegIndex] |= *pucRegBuffer++;
}
else
{
*pucRegBuffer++ = ( unsigned char )( pusRegInputBuf[iRegIndex] >> 8 );
*pucRegBuffer++ = ( unsigned char )( pusRegInputBuf[iRegIndex] & 0xFF );
}
iRegIndex++;
usNRegs--;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
//******************************保持寄存器回调函数**********************************
//函数定义: eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
//描 述:保持寄存器相关的功能(读、连续读、写、连续写)
//入口参数:pucRegBuffer : 如果需要更新用户寄存器数值,这个缓冲区必须指向新的寄存器数值。
// 如果协议栈想知道当前的数值,回调函数必须将当前值写入这个缓冲区
// usAddress : 寄存器的起始地址。
// usNRegs : 寄存器数量
// eMode : 如果该参数为eMBRegisterMode::MB_REG_WRITE,用户的应用数值将从pucRegBuffer中得到更新。
// 如果该参数为eMBRegisterMode::MB_REG_READ,用户需要将当前的应用数据存储在pucRegBuffer中
//出口参数:eMBErrorCode : 这个函数将返回的错误码
//备 注:Editor:Armink 2010-10-31 Company: BXXJS
//**********************************************************************************
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex;
USHORT * pusRegHoldingBuf;
UCHAR REG_HOLDING_START;
UCHAR REG_HOLDING_NREGS;
UCHAR usRegHoldStart;
//Determine the master or slave
if (xMBMasterGetCBRunInMasterMode())
{
pusRegHoldingBuf = usMRegHoldBuf[ucMBMasterGetDestAddress()];
REG_HOLDING_START = M_REG_HOLDING_START;
REG_HOLDING_NREGS = M_REG_HOLDING_NREGS;
usRegHoldStart = usMRegHoldStart;
//If mode is read,the master will wirte the received date to bufffer.
eMode = MB_REG_WRITE;
}
else
{
pusRegHoldingBuf = usSRegHoldBuf;
REG_HOLDING_START = S_REG_HOLDING_START;
REG_HOLDING_NREGS = S_REG_HOLDING_NREGS;
usRegHoldStart = usSRegHoldStart;
}
if( ( usAddress >= REG_HOLDING_START ) &&
( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
{
iRegIndex = ( int )( usAddress - usRegHoldStart );
switch ( eMode )
{
/* Pass current register values to the protocol stack. */
case MB_REG_READ:
while( usNRegs > 0 )
{
*pucRegBuffer++ = ( unsigned char )( pusRegHoldingBuf[iRegIndex] >> 8 );
*pucRegBuffer++ = ( unsigned char )( pusRegHoldingBuf[iRegIndex] & 0xFF );
iRegIndex++;
usNRegs--;
}
break;
/* Update current register values with new values from the
* protocol stack. */
case MB_REG_WRITE:
while( usNRegs > 0 )
{
pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
iRegIndex++;
usNRegs--;
}
break;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
//****************************线圈状态寄存器回调函数********************************
//函数定义: eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
//描 述:线圈状态寄存器相关的功能(读、连续读、写、连续写)
//入口参数:pucRegBuffer : 位组成一个字节,起始寄存器对应的位处于该字节pucRegBuffer的最低位LSB。
// 如果回调函数要写这个缓冲区,没有用到的线圈(例如不是8个一组的线圈状态)对应的位的数值必须设置位0。
// usAddress : 第一个线圈地址。
// usNCoils : 请求的线圈个数
// eMode ;如果该参数为eMBRegisterMode::MB_REG_WRITE,用户的应用数值将从pucRegBuffer中得到更新。
// 如果该参数为eMBRegisterMode::MB_REG_READ,用户需要将当前的应用数据存储在pucRegBuffer中
//出口参数:eMBErrorCode : 这个函数将返回的错误码
//备 注:Editor:Armink 2010-10-31 Company: BXXJS
//**********************************************************************************
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex , iRegBitIndex , iNReg;
UCHAR * pucCoilBuf;
UCHAR COIL_START;
UCHAR COIL_NCOILS;
UCHAR usCoilStart;
iNReg = usNCoils / 8 + 1; //占用寄存器数量
//Determine the master or slave
if (xMBMasterGetCBRunInMasterMode())
{
pucCoilBuf = ucMCoilBuf[ucMBMasterGetDestAddress()];
COIL_START = M_COIL_START;
COIL_NCOILS = M_COIL_NCOILS;
usCoilStart = usMCoilStart;
//If mode is read,the master will wirte the received date to bufffer.
eMode = MB_REG_WRITE;
}
else
{
pucCoilBuf = ucSCoilBuf;
COIL_START = S_COIL_START;
COIL_NCOILS = S_COIL_NCOILS;
usCoilStart = usSCoilStart;
}
if( ( usAddress >= COIL_START ) &&
( usAddress + usNCoils <= COIL_START + COIL_NCOILS ) )
{
iRegIndex = ( int )( usAddress - usCoilStart ) / 8 ; //每个寄存器存8个
iRegBitIndex = ( int )( usAddress - usCoilStart ) % 8 ; //相对于寄存器内部的位地址
switch ( eMode )
{
/* Pass current coil values to the protocol stack. */
case MB_REG_READ:
while( iNReg > 0 )
{
*pucRegBuffer++ = xMBUtilGetBits(&pucCoilBuf[iRegIndex++] , iRegBitIndex , 8);
iNReg --;
}
pucRegBuffer --;
usNCoils = usNCoils % 8; //余下的线圈数
*pucRegBuffer = *pucRegBuffer <<(8 - usNCoils); //高位补零
*pucRegBuffer = *pucRegBuffer >>(8 - usNCoils);
break;
/* Update current coil values with new values from the
* protocol stack. */
case MB_REG_WRITE:
while(iNReg > 1) //最后面余下来的数单独算
{
xMBUtilSetBits(&pucCoilBuf[iRegIndex++] , iRegBitIndex , 8 , *pucRegBuffer++);
iNReg--;
}
usNCoils = usNCoils % 8; //余下的线圈数
if (usNCoils != 0) //xMBUtilSetBits方法 在操作位数量为0时存在bug
{
xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, usNCoils,
*pucRegBuffer++);
}
break;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
//****************************离散输入寄存器回调函数********************************
//函数定义: eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
//描 述:离散输入寄存器相关的功能(读、连续读)
//入口参数:pucRegBuffer : 用当前的线圈数据更新这个寄存器,起始寄存器对应的位处于该字节pucRegBuffer的最低位LSB。
// 如果回调函数要写这个缓冲区,没有用到的线圈(例如不是8个一组的线圈状态)对应的位的数值必须设置为0。
// usAddress : 离散输入的起始地址
// usNDiscrete : 离散输入点数量
//出口参数:eMBErrorCode : 这个函数将返回的错误码
//备 注:Editor:Armink 2010-10-31 Company: BXXJS
//**********************************************************************************
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex , iRegBitIndex , iNReg;
UCHAR * pucDiscreteInputBuf;
UCHAR DISCRETE_INPUT_START;
UCHAR DISCRETE_INPUT_NDISCRETES;
UCHAR usDiscreteInputStart;
iNReg = usNDiscrete / 8 + 1; //占用寄存器数量
//Determine the master or slave
if (xMBMasterGetCBRunInMasterMode())
{
pucDiscreteInputBuf = ucMDiscInBuf[ucMBMasterGetDestAddress()];
DISCRETE_INPUT_START = M_DISCRETE_INPUT_START;
DISCRETE_INPUT_NDISCRETES = M_DISCRETE_INPUT_NDISCRETES;
usDiscreteInputStart = usMDiscInStart;
}
else
{
pucDiscreteInputBuf = ucSDiscInBuf;
DISCRETE_INPUT_START = S_DISCRETE_INPUT_START;
DISCRETE_INPUT_NDISCRETES = S_DISCRETE_INPUT_NDISCRETES;
usDiscreteInputStart = usSDiscInStart;
}
if( ( usAddress >= DISCRETE_INPUT_START )
&& ( usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES ) )
{
iRegIndex = ( int )( usAddress - usDiscreteInputStart ) / 8 ; //每个寄存器存8个
iRegBitIndex = ( int )( usAddress - usDiscreteInputStart ) % 8 ; //相对于寄存器内部的位地址
//Determine the master or slave
if (xMBMasterGetCBRunInMasterMode())
{
/* Update current coil values with new values from the
* protocol stack. */
while(iNReg > 1) //最后面余下来的数单独算
{
xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++] , iRegBitIndex , 8 , *pucRegBuffer++);
iNReg--;
}
usNDiscrete = usNDiscrete % 8; //余下的线圈数
if (usNDiscrete != 0) //xMBUtilSetBits方法 在操作位数量为0时存在bug
{
xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex,
usNDiscrete, *pucRegBuffer++);
}
}
else
{
while( iNReg > 0 )
{
*pucRegBuffer++ = xMBUtilGetBits(&pucDiscreteInputBuf[iRegIndex++] , iRegBitIndex , 8);
iNReg --;
}
pucRegBuffer --;
usNDiscrete = usNDiscrete % 8; //余下的线圈数
*pucRegBuffer = *pucRegBuffer <<(8 - usNDiscrete); //高位补零
*pucRegBuffer = *pucRegBuffer >>(8 - usNDiscrete);
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
......@@ -7,7 +7,6 @@ modbus/functions/mbutils.c
modbus/functions/mbfuncother.c
modbus/rtu/mbcrc.c
port/port.c
port/user_mb_app.c
""")
master_rtu_src = Split("""
......@@ -20,6 +19,7 @@ modbus/mb_m.c
port/portevent_m.c
port/portserial_m.c
port/porttimer_m.c
port/user_mb_app_m.c
""")
slave_rtu_src = Split("""
......@@ -32,6 +32,7 @@ modbus/mb.c
port/portevent.c
port/portserial.c
port/porttimer.c
port/user_mb_app.c
""")
master_slave_rtu_src = Split("""
......@@ -53,6 +54,8 @@ port/portserial.c
port/portserial_m.c
port/porttimer.c
port/porttimer_m.c
port/user_mb_app.c
port/user_mb_app_m.c
""")
# The set of source files associated with this SConscript file.
......
......@@ -74,14 +74,24 @@ eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#if MB_FUNC_READ_COILS_ENABLED > 0
/**
* This function will request read coil.
*
* @param ucSndAddr salve address
* @param usCoilAddr coil start address
* @param usNCoils coil total number
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*/
eMBMasterReqErrCode
eMBMasterReqReadCoils( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usNCoils )
eMBMasterReqReadCoils( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usNCoils ,LONG lTimeOut )
{
UCHAR *ucMBFrame;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( xMBMasterGetIsBusy() ) eErrStatus = MB_MRE_MASTER_BUSY;
else if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
......@@ -93,6 +103,8 @@ eMBMasterReqReadCoils( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usNCoils )
ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF + 1] = usNCoils;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
......@@ -108,7 +120,12 @@ eMBMasterFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
/* If this request is broadcast, and it's read mode. This request don't need execute. */
if ( xMBMasterRequestIsBroadcast() )
{
eStatus = MB_EX_NONE;
}
else if ( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 );
......@@ -136,7 +153,7 @@ eMBMasterFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
( ucByteCount == pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF] ) )
{
/* Make callback to fill the buffer. */
eRegStatus = eMBRegCoilsCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usCoilCount, MB_REG_READ );
eRegStatus = eMBMasterRegCoilsCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usCoilCount, MB_REG_READ );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
......@@ -161,15 +178,27 @@ eMBMasterFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
#if MB_FUNC_WRITE_COIL_ENABLED > 0
/**
* This function will request write one coil.
*
* @param ucSndAddr salve address
* @param usCoilAddr coil start address
* @param usCoilData data to be written
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*
* @see eMBMasterReqWriteMultipleCoils
*/
eMBMasterReqErrCode
eMBMasterReqWriteCoil( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usCoilData )
eMBMasterReqWriteCoil( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usCoilData, LONG lTimeOut )
{
UCHAR *ucMBFrame;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( xMBMasterGetIsBusy() ) eErrStatus = MB_MRE_MASTER_BUSY;
else if ( usCoilAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
if ( usCoilAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( ( usCoilData != 0xFF00 ) && ( usCoilData != 0x0000 ) ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
......@@ -181,6 +210,7 @@ eMBMasterReqWriteCoil( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usCoilData )
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF + 1] = usCoilData;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
......@@ -214,7 +244,7 @@ eMBMasterFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen )
ucBuf[0] = 0;
}
eRegStatus =
eMBRegCoilsCB( &ucBuf[0], usRegAddress, 1, MB_REG_WRITE );
eMBMasterRegCoilsCB( &ucBuf[0], usRegAddress, 1, MB_REG_WRITE );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
......@@ -240,18 +270,31 @@ eMBMasterFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen )
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
/**
* This function will request write multiple coils.
*
* @param ucSndAddr salve address
* @param usCoilAddr coil start address
* @param usNCoils coil total number
* @param usCoilData data to be written
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*
* @see eMBMasterReqWriteCoil
*/
eMBMasterReqErrCode
eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
USHORT usCoilAddr, USHORT usNCoils, UCHAR * pucDataBuffer )
USHORT usCoilAddr, USHORT usNCoils, UCHAR * pucDataBuffer, LONG lTimeOut)
{
UCHAR *ucMBFrame;
USHORT usRegIndex = 0;
UCHAR ucByteCount;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( xMBMasterGetIsBusy() ) eErrStatus = MB_MRE_MASTER_BUSY;
else if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( usNCoils > MB_PDU_REQ_WRITE_MUL_COILCNT_MAX ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
......@@ -277,6 +320,7 @@ eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
}
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + ucByteCount );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
......@@ -293,7 +337,8 @@ eMBMasterFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen == MB_PDU_FUNC_WRITE_MUL_SIZE )
/* If this request is broadcast, the *usLen is not need check. */
if( ( *usLen == MB_PDU_FUNC_WRITE_MUL_SIZE ) || xMBMasterRequestIsBroadcast() )
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
......@@ -318,7 +363,7 @@ eMBMasterFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
if( ( usCoilCnt >= 1 ) && ( ucByteCountVerify == ucByteCount ) )
{
eRegStatus =
eMBRegCoilsCB( &ucMBFrame[MB_PDU_REQ_WRITE_MUL_VALUES_OFF],
eMBMasterRegCoilsCB( &ucMBFrame[MB_PDU_REQ_WRITE_MUL_VALUES_OFF],
usRegAddress, usCoilCnt, MB_REG_WRITE );
/* If an error occured convert it into a Modbus exception. */
......
......@@ -57,16 +57,26 @@ eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
/* ----------------------- Start implementation -----------------------------*/
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#if MB_FUNC_READ_COILS_ENABLED > 0
#if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
/**
* This function will request read discrete inputs.
*
* @param ucSndAddr salve address
* @param usDiscreteAddr discrete start address
* @param usNDiscreteIn discrete total number
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*/
eMBMasterReqErrCode
eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr, USHORT usDiscreteAddr, USHORT usNDiscreteIn )
eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr, USHORT usDiscreteAddr, USHORT usNDiscreteIn, LONG lTimeOut )
{
UCHAR *ucMBFrame;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( xMBMasterGetIsBusy() ) eErrStatus = MB_MRE_MASTER_BUSY;
else if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
......@@ -78,6 +88,7 @@ eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr, USHORT usDiscreteAddr, USHORT u
ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF + 1] = usNDiscreteIn;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
......@@ -93,7 +104,12 @@ eMBMasterFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen )
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
/* If this request is broadcast, and it's read mode. This request don't need execute. */
if ( xMBMasterRequestIsBroadcast() )
{
eStatus = MB_EX_NONE;
}
else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 );
......@@ -120,7 +136,7 @@ eMBMasterFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen )
if ((usDiscreteCnt >= 1) && ucNBytes == pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF])
{
/* Make callback to fill the buffer. */
eRegStatus = eMBRegDiscreteCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usDiscreteCnt );
eRegStatus = eMBMasterRegDiscreteCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usDiscreteCnt );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
......
......@@ -86,14 +86,24 @@ eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
/**
* This function will request write holding register.
*
* @param ucSndAddr salve address
* @param usRegAddr register start address
* @param usRegData register data to be written
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*/
eMBMasterReqErrCode
eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRegData )
eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRegData, LONG lTimeOut )
{
UCHAR *ucMBFrame;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( xMBMasterGetIsBusy() ) eErrStatus = MB_MRE_MASTER_BUSY;
else if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
......@@ -105,6 +115,7 @@ eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRe
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF + 1] = usRegData ;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
......@@ -123,7 +134,7 @@ eMBMasterFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
usRegAddress++;
/* Make callback to update the value. */
eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF],
eRegStatus = eMBMasterRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF],
usRegAddress, 1, MB_REG_WRITE );
/* If an error occured convert it into a Modbus exception. */
......@@ -143,16 +154,27 @@ eMBMasterFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
/**
* This function will request write multiple holding register.
*
* @param ucSndAddr salve address
* @param usRegAddr register start address
* @param usNRegs register total number
* @param pusDataBuffer data to be written
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*/
eMBMasterReqErrCode
eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr,
USHORT usRegAddr, USHORT usNRegs, USHORT * pusDataBuffer )
USHORT usRegAddr, USHORT usNRegs, USHORT * pusDataBuffer, LONG lTimeOut )
{
UCHAR *ucMBFrame;
USHORT usRegIndex = 0;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( xMBMasterGetIsBusy() ) eErrStatus = MB_MRE_MASTER_BUSY;
else if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
......@@ -171,6 +193,7 @@ eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr,
}
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + 2*usNRegs );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
......@@ -186,7 +209,8 @@ eMBMasterFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen == MB_PDU_SIZE_MIN + MB_PDU_FUNC_WRITE_MUL_SIZE )
/* If this request is broadcast, the *usLen is not need check. */
if( ( *usLen == MB_PDU_SIZE_MIN + MB_PDU_FUNC_WRITE_MUL_SIZE ) || xMBMasterRequestIsBroadcast() )
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] << 8 );
......@@ -202,7 +226,7 @@ eMBMasterFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
{
/* Make callback to update the register values. */
eRegStatus =
eMBRegHoldingCB( &ucMBFrame[MB_PDU_REQ_WRITE_MUL_VALUES_OFF],
eMBMasterRegHoldingCB( &ucMBFrame[MB_PDU_REQ_WRITE_MUL_VALUES_OFF],
usRegAddress, usRegCount, MB_REG_WRITE );
/* If an error occured convert it into a Modbus exception. */
......@@ -227,14 +251,24 @@ eMBMasterFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
#if MB_FUNC_READ_HOLDING_ENABLED > 0
/**
* This function will request read holding register.
*
* @param ucSndAddr salve address
* @param usRegAddr register start address
* @param usNRegs register total number
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*/
eMBMasterReqErrCode
eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs )
eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut )
{
UCHAR *ucMBFrame;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( xMBMasterGetIsBusy() ) eErrStatus = MB_MRE_MASTER_BUSY;
else if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
......@@ -246,6 +280,7 @@ eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRe
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
......@@ -260,7 +295,12 @@ eMBMasterFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
/* If this request is broadcast, and it's read mode. This request don't need execute. */
if ( xMBMasterRequestIsBroadcast() )
{
eStatus = MB_EX_NONE;
}
else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 );
......@@ -268,7 +308,7 @@ eMBMasterFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
usRegAddress++;
usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] << 8 );
usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] );
usRegCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] );
/* Check if the number of registers to read is valid. If not
* return Modbus illegal data value exception.
......@@ -276,7 +316,7 @@ eMBMasterFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
if( ( usRegCount >= 1 ) && ( 2 * usRegCount == pucFrame[MB_PDU_FUNC_READ_BYTECNT_OFF] ) )
{
/* Make callback to fill the buffer. */
eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usRegCount, MB_REG_READ );
eRegStatus = eMBMasterRegHoldingCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usRegCount, MB_REG_READ );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
......@@ -300,17 +340,30 @@ eMBMasterFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
/**
* This function will request read and write holding register.
*
* @param ucSndAddr salve address
* @param usReadRegAddr read register start address
* @param usNReadRegs read register total number
* @param pusDataBuffer data to be written
* @param usWriteRegAddr write register start address
* @param usNWriteRegs write register total number
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*/
eMBMasterReqErrCode
eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
USHORT usReadRegAddr, USHORT usNReadRegs, USHORT * pusDataBuffer,
USHORT usWriteRegAddr, USHORT usNWriteRegs )
USHORT usWriteRegAddr, USHORT usNWriteRegs, LONG lTimeOut )
{
UCHAR *ucMBFrame;
USHORT usRegIndex = 0;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( xMBMasterGetIsBusy() ) eErrStatus = MB_MRE_MASTER_BUSY;
else if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
......@@ -333,6 +386,7 @@ eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
}
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READWRITE_SIZE_MIN + 2*usNWriteRegs );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
......@@ -349,7 +403,12 @@ eMBMasterFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READWRITE_SIZE_MIN)
/* If this request is broadcast, and it's read mode. This request don't need execute. */
if ( xMBMasterRequestIsBroadcast() )
{
eStatus = MB_EX_NONE;
}
else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READWRITE_SIZE_MIN )
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
usRegReadAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF] << 8U );
......@@ -369,13 +428,13 @@ eMBMasterFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen
if( ( 2 * usRegReadCount ) == pucFrame[MB_PDU_FUNC_READWRITE_READ_BYTECNT_OFF] )
{
/* Make callback to update the register values. */
eRegStatus = eMBRegHoldingCB( &ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF],
eRegStatus = eMBMasterRegHoldingCB( &ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF],
usRegWriteAddress, usRegWriteCount, MB_REG_WRITE );
if( eRegStatus == MB_ENOERR )
{
/* Make the read callback. */
eRegStatus = eMBRegHoldingCB(&pucFrame[MB_PDU_FUNC_READWRITE_READ_VALUES_OFF],
eRegStatus = eMBMasterRegHoldingCB(&pucFrame[MB_PDU_FUNC_READWRITE_READ_VALUES_OFF],
usRegReadAddress, usRegReadCount, MB_REG_READ);
}
if( eRegStatus != MB_ENOERR )
......
......@@ -59,14 +59,24 @@ eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#if MB_FUNC_READ_INPUT_ENABLED > 0
/**
* This function will request read input register.
*
* @param ucSndAddr salve address
* @param usRegAddr register start address
* @param usNRegs register total number
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*/
eMBMasterReqErrCode
eMBMasterReqReadInputRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs )
eMBMasterReqReadInputRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut )
{
UCHAR *ucMBFrame;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( xMBMasterGetIsBusy() ) eErrStatus = MB_MRE_MASTER_BUSY;
else if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
......@@ -78,6 +88,7 @@ eMBMasterReqReadInputRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
......@@ -92,7 +103,12 @@ eMBMasterFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen )
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN)
/* If this request is broadcast, and it's read mode. This request don't need execute. */
if ( xMBMasterRequestIsBroadcast() )
{
eStatus = MB_EX_NONE;
}
else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 );
......@@ -100,7 +116,7 @@ eMBMasterFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen )
usRegAddress++;
usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] << 8 );
usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] );
usRegCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] );
/* Check if the number of registers to read is valid. If not
* return Modbus illegal data value exception.
......@@ -108,7 +124,7 @@ eMBMasterFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen )
if( ( usRegCount >= 1 ) && ( 2 * usRegCount == pucFrame[MB_PDU_FUNC_READ_BYTECNT_OFF] ) )
{
/* Make callback to fill the buffer. */
eRegStatus = eMBRegInputCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usRegCount );
eRegStatus = eMBMasterRegInputCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usRegCount );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
......
......@@ -77,13 +77,10 @@ typedef enum
MB_MRE_NO_ERR, /*!< no error. */
MB_MRE_NO_REG, /*!< illegal register address. */
MB_MRE_ILL_ARG, /*!< illegal argument. */
MB_MRE_PORT_ERR, /*!< porting layer error. */
MB_MRE_NO_RES, /*!< insufficient resources. */
MB_MRE_IO, /*!< I/O error. */
MB_MRE_ILL_STATE, /*!< protocol stack in illegal state. */
MB_MRE_REV_DATA, /*!< receive data error. */
MB_MRE_TIMEDOUT, /*!< timeout error occurred. */
MB_MRE_MASTER_BUSY, /*!< master is busy now. */
MB_MRE_SLAVE_EXCE /*!< slave has exception. */
MB_MRE_EXE_FUN /*!< execute function error. */
} eMBMasterReqErrCode;
/*! \ingroup modbus
* \brief TimerMode is Master 3 kind of Timer modes.
......@@ -189,31 +186,176 @@ eMBErrorCode eMBMasterDisable( void );
*/
eMBErrorCode eMBMasterPoll( void );
/*! \ingroup modbus
* \brief Registers a callback handler for a given function code.
*
* This function registers a new callback handler for a given function code.
* The callback handler supplied is responsible for interpreting the Modbus PDU and
* the creation of an appropriate response. In case of an error it should return
* one of the possible Modbus exceptions which results in a Modbus exception frame
* sent by the protocol stack.
*
* \param ucFunctionCode The Modbus function code for which this handler should
* be registers. Valid function codes are in the range 1 to 127.
* \param pxHandler The function handler which should be called in case
* such a frame is received. If \c NULL a previously registered function handler
* for this function code is removed.
*
* \return eMBErrorCode::MB_ENOERR if the handler has been installed. If no
* more resources are available it returns eMBErrorCode::MB_ENORES. In this
* case the values in mbconfig.h should be adjusted. If the argument was not
* valid it returns eMBErrorCode::MB_EINVAL.
*/
eMBErrorCode eMBMasterRegisterCB( UCHAR ucFunctionCode,
pxMBFunctionHandler pxHandler );
/* ----------------------- Callback -----------------------------------------*/
/*! \defgroup modbus_master registers Modbus Registers
* \code #include "mb_m.h" \endcode
* The protocol stack does not internally allocate any memory for the
* registers. This makes the protocol stack very small and also usable on
* low end targets. In addition the values don't have to be in the memory
* and could for example be stored in a flash.<br>
* Whenever the protocol stack requires a value it calls one of the callback
* function with the register address and the number of registers to read
* as an argument. The application should then read the actual register values
* (for example the ADC voltage) and should store the result in the supplied
* buffer.<br>
* If the protocol stack wants to update a register value because a write
* register function was received a buffer with the new register values is
* passed to the callback function. The function should then use these values
* to update the application register values.
*/
/*! \ingroup modbus_registers
* \brief Callback function used if the value of a <em>Input Register</em>
* is required by the protocol stack. The starting register address is given
* by \c usAddress and the last register is given by <tt>usAddress +
* usNRegs - 1</tt>.
*
* \param pucRegBuffer A buffer where the callback function should write
* the current value of the modbus registers to.
* \param usAddress The starting address of the register. Input registers
* are in the range 1 - 65535.
* \param usNRegs Number of registers the callback function must supply.
*
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application does not map an coils
* within the requested address range. In this case a
* <b>ILLEGAL DATA ADDRESS</b> is sent as a response.
*/
eMBErrorCode eMBMasterRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNRegs );
/*! \ingroup modbus_registers
* \brief Callback function used if a <em>Holding Register</em> value is
* read or written by the protocol stack. The starting register address
* is given by \c usAddress and the last register is given by
* <tt>usAddress + usNRegs - 1</tt>.
*
* \param pucRegBuffer If the application registers values should be updated the
* buffer points to the new registers values. If the protocol stack needs
* to now the current values the callback function should write them into
* this buffer.
* \param usAddress The starting address of the register.
* \param usNRegs Number of registers to read or write.
* \param eMode If eMBRegisterMode::MB_REG_WRITE the application register
* values should be updated from the values in the buffer. For example
* this would be the case when the Modbus master has issued an
* <b>WRITE SINGLE REGISTER</b> command.
* If the value eMBRegisterMode::MB_REG_READ the application should copy
* the current values into the buffer \c pucRegBuffer.
*
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application does not map an coils
* within the requested address range. In this case a
* <b>ILLEGAL DATA ADDRESS</b> is sent as a response.
*/
eMBErrorCode eMBMasterRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNRegs, eMBRegisterMode eMode );
/*! \ingroup modbus_registers
* \brief Callback function used if a <em>Coil Register</em> value is
* read or written by the protocol stack. If you are going to use
* this function you might use the functions xMBUtilSetBits( ) and
* xMBUtilGetBits( ) for working with bitfields.
*
* \param pucRegBuffer The bits are packed in bytes where the first coil
* starting at address \c usAddress is stored in the LSB of the
* first byte in the buffer <code>pucRegBuffer</code>.
* If the buffer should be written by the callback function unused
* coil values (I.e. if not a multiple of eight coils is used) should be set
* to zero.
* \param usAddress The first coil number.
* \param usNCoils Number of coil values requested.
* \param eMode If eMBRegisterMode::MB_REG_WRITE the application values should
* be updated from the values supplied in the buffer \c pucRegBuffer.
* If eMBRegisterMode::MB_REG_READ the application should store the current
* values in the buffer \c pucRegBuffer.
*
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application does not map an coils
* within the requested address range. In this case a
* <b>ILLEGAL DATA ADDRESS</b> is sent as a response.
*/
eMBErrorCode eMBMasterRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNCoils, eMBRegisterMode eMode );
/*! \ingroup modbus_registers
* \brief Callback function used if a <em>Input Discrete Register</em> value is
* read by the protocol stack.
*
* If you are going to use his function you might use the functions
* xMBUtilSetBits( ) and xMBUtilGetBits( ) for working with bitfields.
*
* \param pucRegBuffer The buffer should be updated with the current
* coil values. The first discrete input starting at \c usAddress must be
* stored at the LSB of the first byte in the buffer. If the requested number
* is not a multiple of eight the remaining bits should be set to zero.
* \param usAddress The starting address of the first discrete input.
* \param usNDiscrete Number of discrete input values.
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application does not map an coils
* within the requested address range. In this case a
* <b>ILLEGAL DATA ADDRESS</b> is sent as a response.
*/
eMBErrorCode eMBMasterRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNDiscrete );
/*! \ingroup modbus
*\brief These Modbus functions are called for user when Modbus run in Master Mode.
*/
eMBMasterReqErrCode
eMBMasterReqReadInputRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs );
eMBMasterReqReadInputRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRegData );
eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRegData, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, USHORT * pusDataBuffer );
eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr,
USHORT usNRegs, USHORT * pusDataBuffer, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs );
eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
USHORT usReadRegAddr, USHORT usNReadRegs, USHORT * pusDataBuffer,
USHORT usWriteRegAddr, USHORT usNWriteRegs );
USHORT usWriteRegAddr, USHORT usNWriteRegs, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqReadCoils( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usNCoils );
eMBMasterReqReadCoils( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usNCoils, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqWriteCoil( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usCoilData );
eMBMasterReqWriteCoil( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usCoilData, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
USHORT usCoilAddr, USHORT usNCoils, UCHAR * pucDataBuffer );
USHORT usCoilAddr, USHORT usNCoils, UCHAR * pucDataBuffer, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr, USHORT usDiscreteAddr, USHORT usNDiscreteIn );
eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr, USHORT usDiscreteAddr, USHORT usNDiscreteIn, LONG lTimeOut );
eMBException
eMBMasterFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen );
......@@ -239,16 +381,18 @@ eMBMasterFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen
/*£¡ \ingroup modbus
*\brief These functions are interface for Modbus Master
*/
BOOL xMBMasterGetIsBusy( void );
void vMBMasterGetPDUSndBuf( UCHAR ** pucFrame );
UCHAR ucMBMasterGetDestAddress( void );
void vMBMasterSetDestAddress( UCHAR Address );
void vMBMasterSetIsBusy( BOOL IsBusy );
BOOL xMBMasterGetCBRunInMasterMode( void );
void vMBMasterSetCBRunInMasterMode( BOOL IsMasterMode );
UCHAR ucMBMasterGetPDUSndLength( void );
void vMBMasterSetPDUSndLength( UCHAR SendPDULength );
USHORT usMBMasterGetPDUSndLength( void );
void vMBMasterSetPDUSndLength( USHORT SendPDULength );
void vMBMasterSetCurTimerMode( eMBMasterTimerMode eMBTimerMode );
BOOL xMBMasterRequestIsBroadcast( void );
eMBMasterErrorEventType eMBMasterGetErrorType( void );
void vMBMasterSetErrorType( eMBMasterErrorEventType errorType );
eMBMasterReqErrCode eMBMasterWaitRequestFinish( void );
/* ----------------------- Callback -----------------------------------------*/
......
......@@ -115,9 +115,9 @@ PR_BEGIN_EXTERN_C
/*! \brief If master send a frame which is not broadcast,the master will wait sometime for slave.
* And if slave is not respond in this time,the master will process this timeout error.
* Then master can send other frame */
#define MB_MASTER_TIMEOUT_MS_RESPOND (2000)
/*! \brief The total slaves in Modbus Master system.Default 16.
* Note : The slave ID must be continuous from 0.*/
#define MB_MASTER_TIMEOUT_MS_RESPOND (100 )
/*! \brief The total slaves in Modbus Master system. Default 16.
* \note : The slave ID must be continuous from 1.*/
#define MB_MASTER_TOTAL_SLAVE_NUM ( 16 )
#endif
......
......@@ -36,25 +36,38 @@
PR_BEGIN_EXTERN_C
#endif
/* ----------------------- Defines ------------------------------------------*/
/* ----------------------- Type definitions ---------------------------------*/
typedef enum
{
EV_READY, /*!< Startup finished. */
EV_FRAME_RECEIVED, /*!< Frame received. */
EV_EXECUTE, /*!< Execute function. */
EV_FRAME_SENT /*!< Frame sent. */
EV_READY = 1<<0, /*!< Startup finished. */
EV_FRAME_RECEIVED = 1<<1, /*!< Frame received. */
EV_EXECUTE = 1<<2, /*!< Execute function. */
EV_FRAME_SENT = 1<<3 /*!< Frame sent. */
} eMBEventType;
typedef enum
{
EV_MASTER_READY, /*!< Startup finished. */
EV_MASTER_FRAME_RECEIVED, /*!< Frame received. */
EV_MASTER_EXECUTE, /*!< Execute function. */
EV_MASTER_FRAME_SENT, /*!< Frame sent. */
EV_MASTER_ERROR_PROCESS /*!< Frame error process*/
EV_MASTER_READY = 1<<0, /*!< Startup finished. */
EV_MASTER_FRAME_RECEIVED = 1<<1, /*!< Frame received. */
EV_MASTER_EXECUTE = 1<<2, /*!< Execute function. */
EV_MASTER_FRAME_SENT = 1<<3, /*!< Frame sent. */
EV_MASTER_ERROR_PROCESS = 1<<4, /*!< Frame error process. */
EV_MASTER_PROCESS_SUCESS = 1<<5, /*!< Request process success. */
EV_MASTER_ERROR_RESPOND_TIMEOUT = 1<<6, /*!< Request respond timeout. */
EV_MASTER_ERROR_RECEIVE_DATA = 1<<7, /*!< Request receive data error. */
EV_MASTER_ERROR_EXECUTE_FUNCTION = 1<<8, /*!< Request execute function error. */
} eMBMasterEventType;
typedef enum
{
EV_ERROR_RESPOND_TIMEOUT, /*!< Slave respond timeout. */
EV_ERROR_RECEIVE_DATA, /*!< Receive frame data erroe. */
EV_ERROR_EXECUTE_FUNCTION, /*!< Execute function error. */
} eMBMasterErrorEventType;
/*! \ingroup modbus
* \brief Parity used for characters in serial mode.
*
......@@ -82,6 +95,12 @@ BOOL xMBMasterPortEventPost( eMBMasterEventType eEvent );
BOOL xMBMasterPortEventGet( /*@out@ */ eMBMasterEventType * eEvent );
void vMBMasterOsResInit( void );
BOOL xMBMasterRunResTake( int32_t time );
void vMBMasterRunResRelease( void );
/* ----------------------- Serial port functions ----------------------------*/
BOOL xMBPortSerialInit( UCHAR ucPort, ULONG ulBaudRate,
......@@ -97,7 +116,6 @@ INLINE BOOL xMBPortSerialGetByte( CHAR * pucByte );
INLINE BOOL xMBPortSerialPutByte( CHAR ucByte );
BOOL xMBMasterPortSerialInit( UCHAR ucPort, ULONG ulBaudRate,
UCHAR ucDataBits, eMBParity eParity );
......@@ -132,6 +150,18 @@ INLINE void vMBMasterPortTimersRespondTimeoutEnable( void );
INLINE void vMBMasterPortTimersDisable( void );
/* ----------------- Callback for the master error process ------------------*/
void vMBMasterErrorCBRespondTimeout( UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength );
void vMBMasterErrorCBReceiveData( UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength );
void vMBMasterErrorCBExecuteFunction( UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength );
void vMBMasterCBRequestScuuess( void );
/* ----------------------- Callback for the protocol stack ------------------*/
/*!
......
......@@ -65,7 +65,7 @@
static UCHAR ucMBMasterDestAddress;
static BOOL xMBRunInMasterMode = FALSE;
static BOOL xMasterIsBusy = FALSE;
static eMBMasterErrorEventType eMBMasterCurErrorType;
static enum
{
......@@ -185,6 +185,8 @@ eMBMasterInit( eMBMode eMode, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity
{
eMBState = STATE_DISABLED;
}
/* initialize the OS resource for modbus master. */
vMBMasterOsResInit();
}
return eStatus;
}
......@@ -257,9 +259,10 @@ eMBMasterPoll( void )
static USHORT usLength;
static eMBException eException;
int i;
int i , j;
eMBErrorCode eStatus = MB_ENOERR;
eMBMasterEventType eEvent;
eMBMasterErrorEventType errorType;
/* Check if the protocol stack is ready. */
if( eMBState != STATE_ENABLED )
......@@ -285,6 +288,7 @@ eMBMasterPoll( void )
}
else
{
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
}
break;
......@@ -292,52 +296,80 @@ eMBMasterPoll( void )
case EV_MASTER_EXECUTE:
ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
eException = MB_EX_ILLEGAL_FUNCTION;
for( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
{
/* No more function handlers registered. Abort. */
if( xMasterFuncHandlers[i].ucFunctionCode == 0 )
{
break;
}
else if( xMasterFuncHandlers[i].ucFunctionCode == ucFunctionCode )
{
vMBMasterSetCBRunInMasterMode(TRUE);
eException = xMasterFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
vMBMasterSetCBRunInMasterMode(FALSE);
break;
}
}
/* If receive frame has exception .The receive function code highest bit is 1.*/
if(ucFunctionCode >> 7) eException = (eMBException)ucMBFrame[MB_PDU_DATA_OFF];
if(ucFunctionCode >> 7) {
eException = (eMBException)ucMBFrame[MB_PDU_DATA_OFF];
}
else
{
for (i = 0; i < MB_FUNC_HANDLERS_MAX; i++)
{
/* No more function handlers registered. Abort. */
if (xMasterFuncHandlers[i].ucFunctionCode == 0) {
break;
}
else if (xMasterFuncHandlers[i].ucFunctionCode == ucFunctionCode) {
vMBMasterSetCBRunInMasterMode(TRUE);
/* If master request is broadcast,
* the master need execute function for all slave.
*/
if ( xMBMasterRequestIsBroadcast() ) {
usLength = usMBMasterGetPDUSndLength();
for(j = 1; j <= MB_MASTER_TOTAL_SLAVE_NUM; j++){
vMBMasterSetDestAddress(j);
eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
}
}
else {
eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
}
vMBMasterSetCBRunInMasterMode(FALSE);
break;
}
}
}
/* If master has exception ,Master will send error process.Otherwise the Master is idle.*/
if (eException != MB_EX_NONE) ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
else vMBMasterSetIsBusy( FALSE );
if (eException != MB_EX_NONE) {
vMBMasterSetErrorType(EV_ERROR_EXECUTE_FUNCTION);
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
}
else {
vMBMasterCBRequestScuuess( );
vMBMasterRunResRelease( );
}
break;
case EV_MASTER_FRAME_SENT:
/* Master is busy now. */
vMBMasterSetIsBusy( TRUE );
vMBMasterGetPDUSndBuf( &ucMBFrame );
eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBFrame, ucMBMasterGetPDUSndLength() );
eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBFrame, usMBMasterGetPDUSndLength() );
break;
case EV_MASTER_ERROR_PROCESS:
vMBMasterSetIsBusy( FALSE );
/* Execute specified error process callback function. */
errorType = eMBMasterGetErrorType();
vMBMasterGetPDUSndBuf( &ucMBFrame );
switch (errorType) {
case EV_ERROR_RESPOND_TIMEOUT:
vMBMasterErrorCBRespondTimeout(ucMBMasterGetDestAddress(),
ucMBFrame, usMBMasterGetPDUSndLength());
break;
case EV_ERROR_RECEIVE_DATA:
vMBMasterErrorCBReceiveData(ucMBMasterGetDestAddress(),
ucMBFrame, usMBMasterGetPDUSndLength());
break;
case EV_ERROR_EXECUTE_FUNCTION:
vMBMasterErrorCBExecuteFunction(ucMBMasterGetDestAddress(),
ucMBFrame, usMBMasterGetPDUSndLength());
break;
}
vMBMasterRunResRelease();
break;
}
}
return MB_ENOERR;
}
/* Get whether the Modbus Master is busy.*/
BOOL xMBMasterGetIsBusy( void )
{
return xMasterIsBusy;
}
/* Set whether the Modbus Master is busy.*/
void vMBMasterSetIsBusy( BOOL IsBusy )
{
xMasterIsBusy = IsBusy;
}
/* Get whether the Modbus Master is run in master mode.*/
BOOL xMBMasterGetCBRunInMasterMode( void )
{
......@@ -348,15 +380,27 @@ void vMBMasterSetCBRunInMasterMode( BOOL IsMasterMode )
{
xMBRunInMasterMode = IsMasterMode;
}
/* Get Modbus Master send destination address*/
/* Get Modbus Master send destination address. */
UCHAR ucMBMasterGetDestAddress( void )
{
return ucMBMasterDestAddress;
}
/* Set Modbus Master send destination address*/
/* Set Modbus Master send destination address. */
void vMBMasterSetDestAddress( UCHAR Address )
{
ucMBMasterDestAddress = Address;
}
/* Get Modbus Master current error event type. */
eMBMasterErrorEventType eMBMasterGetErrorType( void )
{
return eMBMasterCurErrorType;
}
/* Set Modbus Master current error event type. */
void vMBMasterSetErrorType( eMBMasterErrorEventType errorType )
{
eMBMasterCurErrorType = errorType;
}
#endif
......@@ -74,7 +74,7 @@ static volatile eMBMasterRcvState eRcvState;
static volatile UCHAR ucMasterRTUSndBuf[MB_PDU_SIZE_MAX];
static volatile UCHAR ucMasterRTURcvBuf[MB_SER_PDU_SIZE_MAX];
static volatile UCHAR ucMasterSendPDULength;
static volatile USHORT usMasterSendPDULength;
static volatile UCHAR *pucMasterSndBufferCur;
static volatile USHORT usMasterSndBufferCount;
......@@ -235,7 +235,7 @@ xMBMasterRTUReceiveFSM( void )
BOOL xTaskNeedSwitch = FALSE;
UCHAR ucByte;
assert_param( eSndState == STATE_M_TX_IDLE );
assert_param(( eSndState == STATE_M_TX_IDLE ) || ( eSndState == STATE_M_TX_XFWR ));
/* Always read the character. */
( void )xMBMasterPortSerialGetByte( ( CHAR * ) & ucByte );
......@@ -364,12 +364,15 @@ xMBMasterRTUTimerExpired(void)
/* An error occured while receiving the frame. */
case STATE_M_RX_ERROR:
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
xNeedPoll = xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
break;
/* Function called in an illegal state. */
default:
assert_param(
( eRcvState == STATE_M_RX_INIT ) || ( eRcvState == STATE_M_RX_RCV ) || ( eRcvState == STATE_M_RX_ERROR ));
( eRcvState == STATE_M_RX_INIT ) || ( eRcvState == STATE_M_RX_RCV ) ||
( eRcvState == STATE_M_RX_ERROR ) || ( eRcvState == STATE_M_RX_IDLE ));
break;
}
eRcvState = STATE_M_RX_IDLE;
......@@ -380,18 +383,24 @@ xMBMasterRTUTimerExpired(void)
* If the frame is broadcast,The master will idle,and if the frame is not
* broadcast.Notify the listener process error.*/
case STATE_M_TX_XFWR:
if ( xFrameIsBroadcast == FALSE ) xNeedPoll = xMBMasterPortEventPost(EV_MASTER_ERROR_PROCESS);
if ( xFrameIsBroadcast == FALSE ) {
vMBMasterSetErrorType(EV_ERROR_RESPOND_TIMEOUT);
xNeedPoll = xMBMasterPortEventPost(EV_MASTER_ERROR_PROCESS);
}
break;
/* Function called in an illegal state. */
default:
assert_param( eSndState == STATE_M_TX_XFWR );
assert_param(
( eSndState == STATE_M_TX_XFWR ) || ( eSndState == STATE_M_TX_IDLE ));
break;
}
eSndState = STATE_M_TX_IDLE;
vMBMasterPortTimersDisable( );
/* If timer mode is convert delay ,then Master is idel now. */
if (eMasterCurTimerMode == MB_TMODE_CONVERT_DELAY) vMBMasterSetIsBusy( FALSE );
/* If timer mode is convert delay, the master event then turns EV_MASTER_EXECUTE status. */
if (eMasterCurTimerMode == MB_TMODE_CONVERT_DELAY) {
xNeedPoll = xMBMasterPortEventPost( EV_MASTER_EXECUTE );
}
return xNeedPoll;
}
......@@ -409,15 +418,15 @@ void vMBMasterGetPDUSndBuf( UCHAR ** pucFrame )
}
/* Set Modbus Master send PDU's buffer length.*/
void vMBMasterSetPDUSndLength( UCHAR SendPDULength )
void vMBMasterSetPDUSndLength( USHORT SendPDULength )
{
ucMasterSendPDULength = SendPDULength;
usMasterSendPDULength = SendPDULength;
}
/* Get Modbus Master send PDU's buffer length.*/
UCHAR ucMBMasterGetPDUSndLength( void )
USHORT usMBMasterGetPDUSndLength( void )
{
return ucMasterSendPDULength;
return usMasterSendPDULength;
}
/* Set Modbus Master current timer mode.*/
......@@ -425,5 +434,10 @@ void vMBMasterSetCurTimerMode( eMBMasterTimerMode eMBTimerMode )
{
eMasterCurTimerMode = eMBTimerMode;
}
/* The master request is broadcast? */
BOOL xMBMasterRequestIsBroadcast( void ){
return xFrameIsBroadcast;
}
#endif
/*
* FreeModbus Libary: LPC214X Port
* Copyright (C) 2007 Tiago Prado Lone <tiago@maxwellbohr.com.br>
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -16,7 +16,7 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: port.c,v 1.1 2007/04/24 23:15:18 wolti Exp $
* File: $Id: port.c,v 1.60 2015/02/01 9:18:05 Armink $
*/
/* ----------------------- System includes --------------------------------*/
......@@ -24,16 +24,15 @@
/* ----------------------- Modbus includes ----------------------------------*/
#include "port.h"
/* ----------------------- Variables ----------------------------------------*/
static rt_base_t level;
/* ----------------------- Start implementation -----------------------------*/
void EnterCriticalSection(void)
{
//关闭全局中断
__disable_irq();
level = rt_hw_interrupt_disable();
}
void ExitCriticalSection(void)
{
//开启全局中断
__enable_irq();
rt_hw_interrupt_enable(level);
}
/*
* FreeModbus Libary: BARE Port
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -30,22 +30,13 @@
#include <assert.h>
#include <inttypes.h>
#define INLINE
#define INLINE
#define PR_BEGIN_EXTERN_C extern "C" {
#define PR_END_EXTERN_C }
#define PR_END_EXTERN_C }
//TODO 暂时先写B13引脚,等组网测试时再确认
#define SLAVE_RS485_SEND_MODE GPIO_SetBits(GPIOB,GPIO_Pin_13)
#define SLAVE_RS485_RECEIVE_MODE GPIO_ResetBits(GPIOB,GPIO_Pin_13)
#define MASTER_RS485_SEND_MODE GPIO_SetBits(GPIOB,GPIO_Pin_13)
#define MASTER_RS485_RECEIVE_MODE GPIO_ResetBits(GPIOB,GPIO_Pin_13)
#define ENTER_CRITICAL_SECTION() EnterCriticalSection()
#define ENTER_CRITICAL_SECTION() EnterCriticalSection()
#define EXIT_CRITICAL_SECTION() ExitCriticalSection()
void EnterCriticalSection(void);
void ExitCriticalSection(void);
typedef uint8_t BOOL;
typedef unsigned char UCHAR;
......@@ -65,4 +56,7 @@ typedef int32_t LONG;
#define FALSE 0
#endif
void EnterCriticalSection(void);
void ExitCriticalSection(void);
#endif
/*
* FreeModbus Libary: STM32 Port
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
......@@ -24,35 +24,45 @@
#include "mbport.h"
/* ----------------------- Variables ----------------------------------------*/
static eMBEventType eQueuedEvent;
static BOOL xEventInQueue;
static struct rt_event xSlaveOsEvent;
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortEventInit( void )
{
xEventInQueue = FALSE;
rt_event_init(&xSlaveOsEvent,"slave event",RT_IPC_FLAG_PRIO);
return TRUE;
}
BOOL
xMBPortEventPost( eMBEventType eEvent )
{
xEventInQueue = TRUE;
eQueuedEvent = eEvent;
rt_event_send(&xSlaveOsEvent, eEvent);
return TRUE;
}
BOOL
xMBPortEventGet( eMBEventType * eEvent )
{
BOOL xEventHappened = FALSE;
if( xEventInQueue )
rt_uint32_t recvedEvent;
/* waiting forever OS event */
rt_event_recv(&xSlaveOsEvent,
EV_READY | EV_FRAME_RECEIVED | EV_EXECUTE | EV_FRAME_SENT,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER,
&recvedEvent);
switch (recvedEvent)
{
*eEvent = eQueuedEvent;
xEventInQueue = FALSE;
xEventHappened = TRUE;
case EV_READY:
*eEvent = EV_READY;
break;
case EV_FRAME_RECEIVED:
*eEvent = EV_FRAME_RECEIVED;
break;
case EV_EXECUTE:
*eEvent = EV_EXECUTE;
break;
case EV_FRAME_SENT:
*eEvent = EV_FRAME_SENT;
break;
}
return xEventHappened;
return TRUE;
}
/*
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: portevent_m.c v 1.60 2013/08/13 15:07:05 Armink add Master Functions$
*/
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbport.h"
#include "port.h"
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
/* ----------------------- Defines ------------------------------------------*/
/* ----------------------- Variables ----------------------------------------*/
static struct rt_semaphore xMasterRunRes;
static struct rt_event xMasterOsEvent;
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBMasterPortEventInit( void )
{
rt_event_init(&xMasterOsEvent,"master event",RT_IPC_FLAG_PRIO);
return TRUE;
}
BOOL
xMBMasterPortEventPost( eMBMasterEventType eEvent )
{
rt_event_send(&xMasterOsEvent, eEvent);
return TRUE;
}
BOOL
xMBMasterPortEventGet( eMBMasterEventType * eEvent )
{
rt_uint32_t recvedEvent;
/* waiting forever OS event */
rt_event_recv(&xMasterOsEvent,
EV_MASTER_READY | EV_MASTER_FRAME_RECEIVED | EV_MASTER_EXECUTE |
EV_MASTER_FRAME_SENT | EV_MASTER_ERROR_PROCESS,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER,
&recvedEvent);
/* the enum type couldn't convert to int type */
switch (recvedEvent)
{
case EV_MASTER_READY:
*eEvent = EV_MASTER_READY;
break;
case EV_MASTER_FRAME_RECEIVED:
*eEvent = EV_MASTER_FRAME_RECEIVED;
break;
case EV_MASTER_EXECUTE:
*eEvent = EV_MASTER_EXECUTE;
break;
case EV_MASTER_FRAME_SENT:
*eEvent = EV_MASTER_FRAME_SENT;
break;
case EV_MASTER_ERROR_PROCESS:
*eEvent = EV_MASTER_ERROR_PROCESS;
break;
}
return TRUE;
}
/**
* This function is initialize the OS resource for modbus master.
* Note:The resource is define by OS.If you not use OS this function can be empty.
*
*/
void vMBMasterOsResInit( void )
{
rt_sem_init(&xMasterRunRes, "master res", 0x01 , RT_IPC_FLAG_PRIO);
}
/**
* This function is take Mobus Master running resource.
* Note:The resource is define by Operating System.If you not use OS this function can be just return TRUE.
*
* @param lTimeOut the waiting time.
*
* @return resource taked result
*/
BOOL xMBMasterRunResTake( LONG lTimeOut )
{
/*If waiting time is -1 .It will wait forever */
return rt_sem_take(&xMasterRunRes, lTimeOut) ? FALSE : TRUE ;
}
/**
* This function is release Mobus Master running resource.
* Note:The resource is define by Operating System.If you not use OS this function can be empty.
*
*/
void vMBMasterRunResRelease( void )
{
/* release resource */
rt_sem_release(&xMasterRunRes);
}
/**
* This is modbus master respond timeout error process callback function.
* @note There functions will block modbus master poll while execute OS waiting.
* So,for real-time of system.Do not execute too much waiting process.
*
* @param ucDestAddress destination salve address
* @param pucPDUData PDU buffer data
* @param ucPDULength PDU buffer length
*
*/
void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength) {
/**
* @note This code is use OS's event mechanism for modbus master protocol stack.
* If you don't use OS, you can change it.
*/
rt_event_send(&xMasterOsEvent, EV_MASTER_ERROR_RESPOND_TIMEOUT);
/* You can add your code under here. */
}
/**
* This is modbus master receive data error process callback function.
* @note There functions will block modbus master poll while execute OS waiting.
* So,for real-time of system.Do not execute too much waiting process.
*
* @param ucDestAddress destination salve address
* @param pucPDUData PDU buffer data
* @param ucPDULength PDU buffer length
*
*/
void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength) {
/**
* @note This code is use OS's event mechanism for modbus master protocol stack.
* If you don't use OS, you can change it.
*/
rt_event_send(&xMasterOsEvent, EV_MASTER_ERROR_RECEIVE_DATA);
/* You can add your code under here. */
}
/**
* This is modbus master execute function error process callback function.
* @note There functions will block modbus master poll while execute OS waiting.
* So,for real-time of system.Do not execute too much waiting process.
*
* @param ucDestAddress destination salve address
* @param pucPDUData PDU buffer data
* @param ucPDULength PDU buffer length
*
*/
void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength) {
/**
* @note This code is use OS's event mechanism for modbus master protocol stack.
* If you don't use OS, you can change it.
*/
rt_event_send(&xMasterOsEvent, EV_MASTER_ERROR_EXECUTE_FUNCTION);
/* You can add your code under here. */
}
/**
* This is modbus master request process success callback function.
* @note There functions will block modbus master poll while execute OS waiting.
* So,for real-time of system.Do not execute too much waiting process.
*
*/
void vMBMasterCBRequestScuuess( void ) {
/**
* @note This code is use OS's event mechanism for modbus master protocol stack.
* If you don't use OS, you can change it.
*/
rt_event_send(&xMasterOsEvent, EV_MASTER_PROCESS_SUCESS);
/* You can add your code under here. */
}
/**
* This function is wait for modbus master request finish and return result.
* Waiting result include request process success, request respond timeout,
* receive data error and execute function error.You can use the above callback function.
* @note If you are use OS, you can use OS's event mechanism. Otherwise you have to run
* much user custom delay for waiting.
*
* @return request error code
*/
eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) {
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
rt_uint32_t recvedEvent;
/* waiting for OS event */
rt_event_recv(&xMasterOsEvent,
EV_MASTER_PROCESS_SUCESS | EV_MASTER_ERROR_RESPOND_TIMEOUT
| EV_MASTER_ERROR_RECEIVE_DATA
| EV_MASTER_ERROR_EXECUTE_FUNCTION,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER,
&recvedEvent);
switch (recvedEvent)
{
case EV_MASTER_PROCESS_SUCESS:
break;
case EV_MASTER_ERROR_RESPOND_TIMEOUT:
{
eErrStatus = MB_MRE_TIMEDOUT;
break;
}
case EV_MASTER_ERROR_RECEIVE_DATA:
{
eErrStatus = MB_MRE_REV_DATA;
break;
}
case EV_MASTER_ERROR_EXECUTE_FUNCTION:
{
eErrStatus = MB_MRE_EXE_FUN;
break;
}
}
return eErrStatus;
}
#endif
/*
* FreeModbus Libary: STM32 Port
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
......@@ -24,122 +24,148 @@
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#include "rtdevice.h"
#include "board.h"
/* ----------------------- Static variables ---------------------------------*/
ALIGN(RT_ALIGN_SIZE)
/* software simulation serial transmit IRQ handler thread stack */
static rt_uint8_t serial_soft_trans_irq_stack[512];
/* software simulation serial transmit IRQ handler thread */
static struct rt_thread thread_serial_soft_trans_irq;
/* serial event */
static struct rt_event event_serial;
/* modbus slave serial device */
static rt_serial_t *serial;
/* ----------------------- Defines ------------------------------------------*/
/* serial transmit event */
#define EVENT_SERIAL_TRANS_START (1<<0)
/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR(void);
static void prvvUARTRxISR(void);
static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size);
static void serial_soft_trans_irq(void* parameter);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
eMBParity eParity)
{
/**
* set 485 mode receive and transmit control IO
* @note MODBUS_SLAVE_RT_CONTROL_PIN_INDEX need be defined by user
*/
rt_pin_mode(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_MODE_OUTPUT);
/* set serial name */
if (ucPORT == 1) {
#if defined(RT_USING_UART1) || defined(RT_USING_REMAP_UART1)
extern struct rt_serial_device serial1;
serial = &serial1;
#endif
} else if (ucPORT == 2) {
#if defined(RT_USING_UART2)
extern struct rt_serial_device serial2;
serial = &serial2;
#endif
} else if (ucPORT == 3) {
#if defined(RT_USING_UART3)
extern struct rt_serial_device serial3;
serial = &serial3;
#endif
}
/* set serial configure parameter */
serial->config.baud_rate = ulBaudRate;
serial->config.stop_bits = STOP_BITS_1;
switch(eParity){
case MB_PAR_NONE: {
serial->config.data_bits = DATA_BITS_8;
serial->config.parity = PARITY_NONE;
break;
}
case MB_PAR_ODD: {
serial->config.data_bits = DATA_BITS_9;
serial->config.parity = PARITY_ODD;
break;
}
case MB_PAR_EVEN: {
serial->config.data_bits = DATA_BITS_9;
serial->config.parity = PARITY_EVEN;
break;
}
}
/* set serial configure */
serial->ops->configure(serial, &(serial->config));
/* open serial device */
if (!serial->parent.open(&serial->parent,
RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX )) {
serial->parent.rx_indicate = serial_rx_ind;
} else {
return FALSE;
}
/* software initialize */
rt_thread_init(&thread_serial_soft_trans_irq,
"slave trans",
serial_soft_trans_irq,
RT_NULL,
serial_soft_trans_irq_stack,
sizeof(serial_soft_trans_irq_stack),
10, 5);
rt_thread_startup(&thread_serial_soft_trans_irq);
rt_event_init(&event_serial, "slave event", RT_IPC_FLAG_PRIO);
return TRUE;
}
void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{
if (xRxEnable)
{
SLAVE_RS485_RECEIVE_MODE;
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
}
else
{
SLAVE_RS485_SEND_MODE;
USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
}
if (xTxEnable)
{
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
}
else
{
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
}
rt_uint32_t recved_event;
if (xRxEnable)
{
/* enable RX interrupt */
serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
/* switch 485 to receive mode */
rt_pin_write(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_LOW);
}
else
{
/* switch 485 to transmit mode */
rt_pin_write(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_HIGH);
/* disable RX interrupt */
serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX);
}
if (xTxEnable)
{
/* start serial transmit */
rt_event_send(&event_serial, EVENT_SERIAL_TRANS_START);
}
else
{
/* stop serial transmit */
rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 0,
&recved_event);
}
}
void vMBPortClose(void)
{
USART_ITConfig(USART1, USART_IT_TXE | USART_IT_RXNE, DISABLE);
USART_Cmd(USART1, DISABLE);
}
//默认一个从机 串口1 波特率可设置 奇偶检验可设置
BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
eMBParity eParity)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//======================时钟初始化=======================================
RCC_APB2PeriphClockCmd(
RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_USART1,
ENABLE);
//======================IO初始化=======================================
//USART1_TX
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART1_RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置485发送和接收模式
// TODO 暂时先写B13 等之后组网测试时再修改
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//======================串口初始化=======================================
USART_InitStructure.USART_BaudRate = ulBaudRate;
//设置校验模式
switch (eParity)
{
case MB_PAR_NONE: //无校验
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
break;
case MB_PAR_ODD: //奇校验
USART_InitStructure.USART_Parity = USART_Parity_Odd;
USART_InitStructure.USART_WordLength = USART_WordLength_9b;
break;
case MB_PAR_EVEN: //偶校验
USART_InitStructure.USART_Parity = USART_Parity_Even;
USART_InitStructure.USART_WordLength = USART_WordLength_9b;
break;
default:
return FALSE;
}
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
if (ucPORT != 1)
return FALSE;
ENTER_CRITICAL_SECTION(); //关全局中断
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);
//=====================中断初始化======================================
//设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
EXIT_CRITICAL_SECTION(); //开全局中断
return TRUE;
serial->parent.close(&(serial->parent));
}
BOOL xMBPortSerialPutByte(CHAR ucByte)
{
USART_SendData(USART1, ucByte);
return TRUE;
serial->parent.write(&(serial->parent), 0, &ucByte, 1);
return TRUE;
}
BOOL xMBPortSerialGetByte(CHAR * pucByte)
{
*pucByte = USART_ReceiveData(USART1);
return TRUE;
serial->parent.read(&(serial->parent), 0, pucByte, 1);
return TRUE;
}
/*
......@@ -151,7 +177,7 @@ BOOL xMBPortSerialGetByte(CHAR * pucByte)
*/
void prvvUARTTxReadyISR(void)
{
pxMBFrameCBTransmitterEmpty();
pxMBFrameCBTransmitterEmpty();
}
/*
......@@ -162,28 +188,35 @@ void prvvUARTTxReadyISR(void)
*/
void prvvUARTRxISR(void)
{
pxMBFrameCBByteReceived();
pxMBFrameCBByteReceived();
}
/*******************************************************************************
* Function Name : USART1_IRQHandler
* Description : This function handles USART1 global interrupt request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void USART1_IRQHandler(void)
{
rt_interrupt_enter();
//接收中断
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
prvvUARTRxISR();
}
//发送中断
if (USART_GetITStatus(USART1, USART_IT_TXE) == SET)
{
prvvUARTTxReadyISR();
}
rt_interrupt_leave();
/**
* Software simulation serial transmit IRQ handler.
*
* @param parameter parameter
*/
static void serial_soft_trans_irq(void* parameter) {
rt_uint32_t recved_event;
while (1)
{
/* waiting for serial transmit start */
rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START, RT_EVENT_FLAG_OR,
RT_WAITING_FOREVER, &recved_event);
/* execute modbus callback */
prvvUARTTxReadyISR();
}
}
/**
* This function is serial receive callback function
*
* @param dev the device of serial
* @param size the data size that receive
*
* @return return RT_EOK
*/
static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size) {
prvvUARTRxISR();
return RT_EOK;
}
/*
* FreeModbus Libary: STM32 Port
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
......@@ -24,123 +24,149 @@
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#include "rtdevice.h"
#include "board.h"
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
/* ----------------------- Static variables ---------------------------------*/
ALIGN(RT_ALIGN_SIZE)
/* software simulation serial transmit IRQ handler thread stack */
static rt_uint8_t serial_soft_trans_irq_stack[512];
/* software simulation serial transmit IRQ handler thread */
static struct rt_thread thread_serial_soft_trans_irq;
/* serial event */
static struct rt_event event_serial;
/* modbus slave serial device */
static rt_serial_t *serial;
/* ----------------------- Defines ------------------------------------------*/
/* serial transmit event */
#define EVENT_SERIAL_TRANS_START (1<<0)
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED
/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR(void);
static void prvvUARTRxISR(void);
static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size);
static void serial_soft_trans_irq(void* parameter);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
eMBParity eParity)
{
/**
* set 485 mode receive and transmit control IO
* @note MODBUS_MASTER_RT_CONTROL_PIN_INDEX need be defined by user
*/
rt_pin_mode(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_MODE_OUTPUT);
/* set serial name */
if (ucPORT == 1) {
#if defined(RT_USING_UART1) || defined(RT_USING_REMAP_UART1)
extern struct rt_serial_device serial1;
serial = &serial1;
#endif
} else if (ucPORT == 2) {
#if defined(RT_USING_UART2)
extern struct rt_serial_device serial2;
serial = &serial2;
#endif
} else if (ucPORT == 3) {
#if defined(RT_USING_UART3)
extern struct rt_serial_device serial3;
serial = &serial3;
#endif
}
/* set serial configure parameter */
serial->config.baud_rate = ulBaudRate;
serial->config.stop_bits = STOP_BITS_1;
switch(eParity){
case MB_PAR_NONE: {
serial->config.data_bits = DATA_BITS_8;
serial->config.parity = PARITY_NONE;
break;
}
case MB_PAR_ODD: {
serial->config.data_bits = DATA_BITS_9;
serial->config.parity = PARITY_ODD;
break;
}
case MB_PAR_EVEN: {
serial->config.data_bits = DATA_BITS_9;
serial->config.parity = PARITY_EVEN;
break;
}
}
/* set serial configure */
serial->ops->configure(serial, &(serial->config));
/* open serial device */
if (!serial->parent.open(&serial->parent,
RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX )) {
serial->parent.rx_indicate = serial_rx_ind;
} else {
return FALSE;
}
/* software initialize */
rt_thread_init(&thread_serial_soft_trans_irq,
"slave trans",
serial_soft_trans_irq,
RT_NULL,
serial_soft_trans_irq_stack,
sizeof(serial_soft_trans_irq_stack),
10, 5);
rt_thread_startup(&thread_serial_soft_trans_irq);
rt_event_init(&event_serial, "slave event", RT_IPC_FLAG_PRIO);
return TRUE;
}
void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{
if (xRxEnable)
{
MASTER_RS485_RECEIVE_MODE;
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
}
else
{
MASTER_RS485_SEND_MODE;
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
}
if (xTxEnable)
{
USART_ITConfig(USART2, USART_IT_TXE, ENABLE);
}
else
{
USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
}
rt_uint32_t recved_event;
if (xRxEnable)
{
/* enable RX interrupt */
serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
/* switch 485 to receive mode */
rt_pin_write(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_LOW);
}
else
{
/* switch 485 to transmit mode */
rt_pin_write(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_HIGH);
/* disable RX interrupt */
serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX);
}
if (xTxEnable)
{
/* start serial transmit */
rt_event_send(&event_serial, EVENT_SERIAL_TRANS_START);
}
else
{
/* stop serial transmit */
rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 0,
&recved_event);
}
}
void vMBMasterPortClose(void)
{
USART_ITConfig(USART2, USART_IT_TXE | USART_IT_RXNE, DISABLE);
USART_Cmd(USART2, DISABLE);
}
//默认一个主机 串口2 波特率可设置 奇偶检验可设置
BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
eMBParity eParity)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//======================时钟初始化=======================================
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
//======================IO初始化=======================================
//USART2_TX
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART2_RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置485发送和接收模式
// TODO 暂时先写B13 等之后组网测试时再修改
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//======================串口初始化=======================================
USART_InitStructure.USART_BaudRate = ulBaudRate;
//设置校验模式
switch (eParity)
{
case MB_PAR_NONE: //无校验
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
break;
case MB_PAR_ODD: //奇校验
USART_InitStructure.USART_Parity = USART_Parity_Odd;
USART_InitStructure.USART_WordLength = USART_WordLength_9b;
break;
case MB_PAR_EVEN: //偶校验
USART_InitStructure.USART_Parity = USART_Parity_Even;
USART_InitStructure.USART_WordLength = USART_WordLength_9b;
break;
default:
return FALSE;
}
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
if (ucPORT != 2)
return FALSE;
ENTER_CRITICAL_SECTION(); //关全局中断
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_Cmd(USART2, ENABLE);
//=====================中断初始化======================================
//设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
EXIT_CRITICAL_SECTION(); //开全局中断
return TRUE;
serial->parent.close(&(serial->parent));
}
BOOL xMBMasterPortSerialPutByte(CHAR ucByte)
{
USART_SendData(USART2, ucByte);
return TRUE;
serial->parent.write(&(serial->parent), 0, &ucByte, 1);
return TRUE;
}
BOOL xMBMasterPortSerialGetByte(CHAR * pucByte)
{
*pucByte = USART_ReceiveData(USART2);
return TRUE;
serial->parent.read(&(serial->parent), 0, pucByte, 1);
return TRUE;
}
/*
......@@ -152,7 +178,7 @@ BOOL xMBMasterPortSerialGetByte(CHAR * pucByte)
*/
void prvvUARTTxReadyISR(void)
{
pxMBMasterFrameCBTransmitterEmpty();
pxMBMasterFrameCBTransmitterEmpty();
}
/*
......@@ -163,30 +189,37 @@ void prvvUARTTxReadyISR(void)
*/
void prvvUARTRxISR(void)
{
pxMBMasterFrameCBByteReceived();
pxMBMasterFrameCBByteReceived();
}
/*******************************************************************************
* Function Name : USART2_IRQHandler
* Description : This function handles USART2 global interrupt request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void USART2_IRQHandler(void)
{
rt_interrupt_enter();
//接收中断
if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
{
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
prvvUARTRxISR();
}
//发送中断
if (USART_GetITStatus(USART2, USART_IT_TXE) == SET)
{
prvvUARTTxReadyISR();
}
rt_interrupt_leave();
/**
* Software simulation serial transmit IRQ handler.
*
* @param parameter parameter
*/
static void serial_soft_trans_irq(void* parameter) {
rt_uint32_t recved_event;
while (1)
{
/* waiting for serial transmit start */
rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START, RT_EVENT_FLAG_OR,
RT_WAITING_FOREVER, &recved_event);
/* execute modbus callback */
prvvUARTTxReadyISR();
}
}
/**
* This function is serial receive callback function
*
* @param dev the device of serial
* @param size the data size that receive
*
* @return return RT_EOK
*/
static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size) {
prvvUARTRxISR();
return RT_EOK;
}
#endif
/*
* FreeModbus Libary: STM32 Port
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
......@@ -16,46 +16,48 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: portevent_m.c v 1.60 2013/08/13 15:07:05 Armink add Master Functions$
* File: $Id: porttimer.c,v 1.60 2013/08/13 15:07:05 Armink $
*/
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED
/* ----------------------- Variables ----------------------------------------*/
static eMBMasterEventType eMasterQueuedEvent;
static BOOL xMasterEventInQueue;
/* ----------------------- static functions ---------------------------------*/
static struct rt_timer timer;
static void prvvTIMERExpiredISR(void);
static void timer_timeout_ind(void* parameter);
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBMasterPortEventInit( void )
BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
{
xMasterEventInQueue = FALSE;
rt_timer_init(&timer, "slave timer",
timer_timeout_ind, /* bind timeout callback function */
RT_NULL,
(50*usTim1Timerout50us)/(1000*1000/RT_TICK_PER_SECOND),
RT_TIMER_FLAG_ONE_SHOT); /* one shot */
return TRUE;
}
BOOL
xMBMasterPortEventPost( eMBMasterEventType eEvent )
void vMBPortTimersEnable()
{
xMasterEventInQueue = TRUE;
eMasterQueuedEvent = eEvent;
return TRUE;
rt_timer_start(&timer);
}
BOOL
xMBMasterPortEventGet( eMBMasterEventType * eEvent )
void vMBPortTimersDisable()
{
BOOL xEventHappened = FALSE;
if( xMasterEventInQueue )
{
*eEvent = eMasterQueuedEvent;
xMasterEventInQueue = FALSE;
xEventHappened = TRUE;
}
return xEventHappened;
rt_timer_stop(&timer);
}
#endif
void prvvTIMERExpiredISR(void)
{
(void) pxMBPortCBTimerExpired();
}
static void timer_timeout_ind(void* parameter)
{
prvvTIMERExpiredISR();
}
/*
* FreeModbus Libary: STM32 Port
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
......@@ -16,7 +16,7 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: porttimer.c,v 1.60 2013/08/13 15:07:05 Armink $
* File: $Id: porttimer_m.c,v 1.60 2013/08/13 15:07:05 Armink add Master Functions$
*/
/* ----------------------- Platform includes --------------------------------*/
......@@ -24,84 +24,84 @@
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbport.h"
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
/* ----------------------- Variables ----------------------------------------*/
static USHORT usT35TimeOut50us;
static struct rt_timer timer;
static void prvvTIMERExpiredISR(void);
static void timer_timeout_ind(void* parameter);
/* ----------------------- static functions ---------------------------------*/
static void prvvTIMERExpiredISR(void);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us)
{
/* backup T35 ticks */
usT35TimeOut50us = usTimeOut50us;
rt_timer_init(&timer, "master timer",
timer_timeout_ind, /* bind timeout callback function */
RT_NULL,
(50 * usT35TimeOut50us) / (1000 * 1000 / RT_TICK_PER_SECOND),
RT_TIMER_FLAG_ONE_SHOT); /* one shot */
uint16_t PrescalerValue = 0;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//====================================时钟初始化===========================
//使能定时器3时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
//====================================定时器初始化===========================
//定时器时间基配置说明
//HCLK为72MHz,APB1经过2分频为36MHz
//TIM3的时钟倍频后为72MHz(硬件自动倍频,达到最大)
//TIM3的分频系数为3599,时间基频率为72 / (1 + Prescaler) = 20KHz,基准为50us
//TIM最大计数值为usTim1Timerout50u
PrescalerValue = (uint16_t) (SystemCoreClock / 20000) - 1;
//定时器1初始化
TIM_TimeBaseStructure.TIM_Period = (uint16_t) usTim1Timerout50us;
TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
//预装载使能
TIM_ARRPreloadConfig(TIM3, ENABLE);
//====================================中断初始化===========================
//设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//清除溢出中断标志位
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
//定时器3溢出中断关闭
TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE);
//定时器3禁能
TIM_Cmd(TIM3, DISABLE);
return TRUE;
return TRUE;
}
void vMBPortTimersEnable()
void vMBMasterPortTimersT35Enable()
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_SetCounter(TIM3, 0);
TIM_Cmd(TIM3, ENABLE);
rt_tick_t timer_tick = (50 * usT35TimeOut50us)
/ (1000 * 1000 / RT_TICK_PER_SECOND);
/* Set current timer mode, don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_T35);
rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick);
rt_timer_start(&timer);
}
void vMBPortTimersDisable()
void vMBMasterPortTimersConvertDelayEnable()
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE);
TIM_SetCounter(TIM3, 0);
TIM_Cmd(TIM3, DISABLE);
rt_tick_t timer_tick = MB_MASTER_DELAY_MS_CONVERT * RT_TICK_PER_SECOND / 1000;
/* Set current timer mode, don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_CONVERT_DELAY);
rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick);
rt_timer_start(&timer);
}
void vMBMasterPortTimersRespondTimeoutEnable()
{
rt_tick_t timer_tick = MB_MASTER_TIMEOUT_MS_RESPOND * RT_TICK_PER_SECOND / 1000;
/* Set current timer mode, don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_RESPOND_TIMEOUT);
rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick);
rt_timer_start(&timer);
}
void vMBMasterPortTimersDisable()
{
rt_timer_stop(&timer);
}
void prvvTIMERExpiredISR(void)
{
(void) pxMBPortCBTimerExpired();
(void) pxMBMasterPortCBTimerExpired();
}
void TIM3_IRQHandler(void)
static void timer_timeout_ind(void* parameter)
{
rt_interrupt_enter();
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearFlag(TIM3, TIM_FLAG_Update); //清中断标记
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除定时器T3溢出中断标志位
prvvTIMERExpiredISR();
}
rt_interrupt_leave();
prvvTIMERExpiredISR();
}
#endif
/*
* FreeModbus Libary: user callback functions and buffer define in slave mode
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: user_mb_app.c,v 1.60 2013/11/23 11:49:05 Armink $
*/
#include "user_mb_app.h"
/*------------------------Slave mode use these variables----------------------*/
//Slave mode:DiscreteInputs variables
USHORT usSDiscInStart = S_DISCRETE_INPUT_START;
#if S_DISCRETE_INPUT_NDISCRETES%8
UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8+1];
#else
UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8] ;
#endif
//Slave mode:Coils variables
USHORT usSCoilStart = S_COIL_START;
#if S_COIL_NCOILS%8
UCHAR ucSCoilBuf[S_COIL_NCOILS/8+1] ;
#else
UCHAR ucSCoilBuf[S_COIL_NCOILS/8] ;
#endif
//Slave mode:InputRegister variables
USHORT usSRegInStart = S_REG_INPUT_START;
USHORT usSRegInBuf[S_REG_INPUT_NREGS] ;
//Slave mode:HoldingRegister variables
USHORT usSRegHoldStart = S_REG_HOLDING_START;
USHORT usSRegHoldBuf[S_REG_HOLDING_NREGS] ;
/**
* Modbus slave input register callback function.
*
* @param pucRegBuffer input register buffer
* @param usAddress input register address
* @param usNRegs input register number
*
* @return result
*/
eMBErrorCode eMBRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex;
USHORT * pusRegInputBuf;
USHORT REG_INPUT_START;
USHORT REG_INPUT_NREGS;
USHORT usRegInStart;
pusRegInputBuf = usSRegInBuf;
REG_INPUT_START = S_REG_INPUT_START;
REG_INPUT_NREGS = S_REG_INPUT_NREGS;
usRegInStart = usSRegInStart;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= REG_INPUT_START)
&& (usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS))
{
iRegIndex = usAddress - usRegInStart;
while (usNRegs > 0)
{
*pucRegBuffer++ = (UCHAR) (pusRegInputBuf[iRegIndex] >> 8);
*pucRegBuffer++ = (UCHAR) (pusRegInputBuf[iRegIndex] & 0xFF);
iRegIndex++;
usNRegs--;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
/**
* Modbus slave holding register callback function.
*
* @param pucRegBuffer holding register buffer
* @param usAddress holding register address
* @param usNRegs holding register number
* @param eMode read or write
*
* @return result
*/
eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNRegs, eMBRegisterMode eMode)
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex;
USHORT * pusRegHoldingBuf;
USHORT REG_HOLDING_START;
USHORT REG_HOLDING_NREGS;
USHORT usRegHoldStart;
pusRegHoldingBuf = usSRegHoldBuf;
REG_HOLDING_START = S_REG_HOLDING_START;
REG_HOLDING_NREGS = S_REG_HOLDING_NREGS;
usRegHoldStart = usSRegHoldStart;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= REG_HOLDING_START)
&& (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS))
{
iRegIndex = usAddress - usRegHoldStart;
switch (eMode)
{
/* read current register values from the protocol stack. */
case MB_REG_READ:
while (usNRegs > 0)
{
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] >> 8);
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] & 0xFF);
iRegIndex++;
usNRegs--;
}
break;
/* write current register values with new values from the protocol stack. */
case MB_REG_WRITE:
while (usNRegs > 0)
{
pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
iRegIndex++;
usNRegs--;
}
break;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
/**
* Modbus slave coils callback function.
*
* @param pucRegBuffer coils buffer
* @param usAddress coils address
* @param usNCoils coils number
* @param eMode read or write
*
* @return result
*/
eMBErrorCode eMBRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNCoils, eMBRegisterMode eMode)
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex , iRegBitIndex , iNReg;
UCHAR * pucCoilBuf;
USHORT COIL_START;
USHORT COIL_NCOILS;
USHORT usCoilStart;
iNReg = usNCoils / 8 + 1;
pucCoilBuf = ucSCoilBuf;
COIL_START = S_COIL_START;
COIL_NCOILS = S_COIL_NCOILS;
usCoilStart = usSCoilStart;
/* it already plus one in modbus function method. */
usAddress--;
if( ( usAddress >= COIL_START ) &&
( usAddress + usNCoils <= COIL_START + COIL_NCOILS ) )
{
iRegIndex = (USHORT) (usAddress - usCoilStart) / 8;
iRegBitIndex = (USHORT) (usAddress - usCoilStart) % 8;
switch ( eMode )
{
/* read current coil values from the protocol stack. */
case MB_REG_READ:
while (iNReg > 0)
{
*pucRegBuffer++ = xMBUtilGetBits(&pucCoilBuf[iRegIndex++],
iRegBitIndex, 8);
iNReg--;
}
pucRegBuffer--;
/* last coils */
usNCoils = usNCoils % 8;
/* filling zero to high bit */
*pucRegBuffer = *pucRegBuffer << (8 - usNCoils);
*pucRegBuffer = *pucRegBuffer >> (8 - usNCoils);
break;
/* write current coil values with new values from the protocol stack. */
case MB_REG_WRITE:
while (iNReg > 1)
{
xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, 8,
*pucRegBuffer++);
iNReg--;
}
/* last coils */
usNCoils = usNCoils % 8;
/* xMBUtilSetBits has bug when ucNBits is zero */
if (usNCoils != 0)
{
xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, usNCoils,
*pucRegBuffer++);
}
break;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
/**
* Modbus slave discrete callback function.
*
* @param pucRegBuffer discrete buffer
* @param usAddress discrete address
* @param usNDiscrete discrete number
*
* @return result
*/
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex , iRegBitIndex , iNReg;
UCHAR * pucDiscreteInputBuf;
USHORT DISCRETE_INPUT_START;
USHORT DISCRETE_INPUT_NDISCRETES;
USHORT usDiscreteInputStart;
iNReg = usNDiscrete / 8 + 1;
pucDiscreteInputBuf = ucSDiscInBuf;
DISCRETE_INPUT_START = S_DISCRETE_INPUT_START;
DISCRETE_INPUT_NDISCRETES = S_DISCRETE_INPUT_NDISCRETES;
usDiscreteInputStart = usSDiscInStart;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= DISCRETE_INPUT_START)
&& (usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES))
{
iRegIndex = (USHORT) (usAddress - usDiscreteInputStart) / 8;
iRegBitIndex = (USHORT) (usAddress - usDiscreteInputStart) % 8;
while (iNReg > 0)
{
*pucRegBuffer++ = xMBUtilGetBits(&pucDiscreteInputBuf[iRegIndex++],
iRegBitIndex, 8);
iNReg--;
}
pucRegBuffer--;
/* last discrete */
usNDiscrete = usNDiscrete % 8;
/* filling zero to high bit */
*pucRegBuffer = *pucRegBuffer << (8 - usNDiscrete);
*pucRegBuffer = *pucRegBuffer >> (8 - usNDiscrete);
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
#ifndef USER_APP
#ifndef USER_APP
#define USER_APP
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
......@@ -8,47 +8,39 @@
#include "mbutils.h"
/* -----------------------Slave Defines -------------------------------------*/
#define S_DISCRETE_INPUT_START 1
#define S_DISCRETE_INPUT_START 0
#define S_DISCRETE_INPUT_NDISCRETES 16
#define S_COIL_START 1
#define S_COIL_START 0
#define S_COIL_NCOILS 64
#define S_REG_INPUT_START 1
#define S_REG_INPUT_START 0
#define S_REG_INPUT_NREGS 100
#define S_REG_HOLDING_START 1
#define S_REG_HOLDING_START 0
#define S_REG_HOLDING_NREGS 100
//从机模式:在保持寄存器中,各个地址对应的功能定义
#define S_HD_RESERVE 0 //保留
#define S_HD_CPU_USAGE_MAJOR 1 //当前CPU利用率的整数位
#define S_HD_CPU_USAGE_MINOR 2 //当前CPU利用率的小数位
//从机模式:在输入寄存器中,各个地址对应的功能定义
#define S_IN_RESERVE 0 //保留
//从机模式:在线圈中,各个地址对应的功能定义
#define S_CO_RESERVE 2 //保留
//从机模式:在离散输入中,各个地址对应的功能定义
#define S_DI_RESERVE 1 //保留
/* salve mode: holding register's all address */
#define S_HD_RESERVE 0
/* salve mode: input register's all address */
#define S_IN_RESERVE 0
/* salve mode: coil's all address */
#define S_CO_RESERVE 0
/* salve mode: discrete's all address */
#define S_DI_RESERVE 0
/* -----------------------Master Defines -------------------------------------*/
#define M_DISCRETE_INPUT_START 1
#define M_DISCRETE_INPUT_START 0
#define M_DISCRETE_INPUT_NDISCRETES 16
#define M_COIL_START 1
#define M_COIL_START 0
#define M_COIL_NCOILS 64
#define M_REG_INPUT_START 1
#define M_REG_INPUT_START 0
#define M_REG_INPUT_NREGS 100
#define M_REG_HOLDING_START 1
#define M_REG_HOLDING_START 0
#define M_REG_HOLDING_NREGS 100
//主机模式:在保持寄存器中,各个地址对应的功能定义
#define M_HD_RESERVE 0 //保留
//主机模式:在输入寄存器中,各个地址对应的功能定义
#define M_IN_RESERVE 0 //保留
//主机模式:在线圈中,各个地址对应的功能定义
#define M_CO_RESERVE 2 //保留
//主机模式:在离散输入中,各个地址对应的功能定义
#define M_DI_RESERVE 1 //保留
/* master mode: holding register's all address */
#define M_HD_RESERVE 0
/* master mode: input register's all address */
#define M_IN_RESERVE 0
/* master mode: coil's all address */
#define M_CO_RESERVE 0
/* master mode: discrete's all address */
#define M_DI_RESERVE 0
#endif
/*
* FreeModbus Libary: user callback functions and buffer define in master mode
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: user_mb_app_m.c,v 1.60 2013/11/23 11:49:05 Armink $
*/
#include "user_mb_app.h"
/*-----------------------Master mode use these variables----------------------*/
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
//Master mode:DiscreteInputs variables
USHORT usMDiscInStart = M_DISCRETE_INPUT_START;
#if M_DISCRETE_INPUT_NDISCRETES%8
UCHAR ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES/8+1];
#else
UCHAR ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES/8];
#endif
//Master mode:Coils variables
USHORT usMCoilStart = M_COIL_START;
#if M_COIL_NCOILS%8
UCHAR ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS/8+1];
#else
UCHAR ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS/8];
#endif
//Master mode:InputRegister variables
USHORT usMRegInStart = M_REG_INPUT_START;
USHORT usMRegInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_INPUT_NREGS];
//Master mode:HoldingRegister variables
USHORT usMRegHoldStart = M_REG_HOLDING_START;
USHORT usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS];
/**
* Modbus master input register callback function.
*
* @param pucRegBuffer input register buffer
* @param usAddress input register address
* @param usNRegs input register number
*
* @return result
*/
eMBErrorCode eMBMasterRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex;
USHORT * pusRegInputBuf;
USHORT REG_INPUT_START;
USHORT REG_INPUT_NREGS;
USHORT usRegInStart;
pusRegInputBuf = usMRegInBuf[ucMBMasterGetDestAddress() - 1];
REG_INPUT_START = M_REG_INPUT_START;
REG_INPUT_NREGS = M_REG_INPUT_NREGS;
usRegInStart = usMRegInStart;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= REG_INPUT_START)
&& (usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS))
{
iRegIndex = usAddress - usRegInStart;
while (usNRegs > 0)
{
pusRegInputBuf[iRegIndex] = *pucRegBuffer++ << 8;
pusRegInputBuf[iRegIndex] |= *pucRegBuffer++;
iRegIndex++;
usNRegs--;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
/**
* Modbus master holding register callback function.
*
* @param pucRegBuffer holding register buffer
* @param usAddress holding register address
* @param usNRegs holding register number
* @param eMode read or write
*
* @return result
*/
eMBErrorCode eMBMasterRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNRegs, eMBRegisterMode eMode)
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex;
USHORT * pusRegHoldingBuf;
USHORT REG_HOLDING_START;
USHORT REG_HOLDING_NREGS;
USHORT usRegHoldStart;
pusRegHoldingBuf = usMRegHoldBuf[ucMBMasterGetDestAddress() - 1];
REG_HOLDING_START = M_REG_HOLDING_START;
REG_HOLDING_NREGS = M_REG_HOLDING_NREGS;
usRegHoldStart = usMRegHoldStart;
/* if mode is read, the master will write the received date to buffer. */
eMode = MB_REG_WRITE;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= REG_HOLDING_START)
&& (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS))
{
iRegIndex = usAddress - usRegHoldStart;
switch (eMode)
{
/* read current register values from the protocol stack. */
case MB_REG_READ:
while (usNRegs > 0)
{
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] >> 8);
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] & 0xFF);
iRegIndex++;
usNRegs--;
}
break;
/* write current register values with new values from the protocol stack. */
case MB_REG_WRITE:
while (usNRegs > 0)
{
pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
iRegIndex++;
usNRegs--;
}
break;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
/**
* Modbus master coils callback function.
*
* @param pucRegBuffer coils buffer
* @param usAddress coils address
* @param usNCoils coils number
* @param eMode read or write
*
* @return result
*/
eMBErrorCode eMBMasterRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNCoils, eMBRegisterMode eMode)
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex , iRegBitIndex , iNReg;
UCHAR * pucCoilBuf;
USHORT COIL_START;
USHORT COIL_NCOILS;
USHORT usCoilStart;
iNReg = usNCoils / 8 + 1;
pucCoilBuf = ucMCoilBuf[ucMBMasterGetDestAddress() - 1];
COIL_START = M_COIL_START;
COIL_NCOILS = M_COIL_NCOILS;
usCoilStart = usMCoilStart;
/* if mode is read,the master will write the received date to buffer. */
eMode = MB_REG_WRITE;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= COIL_START)
&& (usAddress + usNCoils <= COIL_START + COIL_NCOILS))
{
iRegIndex = (USHORT) (usAddress - usCoilStart) / 8;
iRegBitIndex = (USHORT) (usAddress - usCoilStart) % 8;
switch (eMode)
{
/* read current coil values from the protocol stack. */
case MB_REG_READ:
while (iNReg > 0)
{
*pucRegBuffer++ = xMBUtilGetBits(&pucCoilBuf[iRegIndex++],
iRegBitIndex, 8);
iNReg--;
}
pucRegBuffer--;
/* last coils */
usNCoils = usNCoils % 8;
/* filling zero to high bit */
*pucRegBuffer = *pucRegBuffer << (8 - usNCoils);
*pucRegBuffer = *pucRegBuffer >> (8 - usNCoils);
break;
/* write current coil values with new values from the protocol stack. */
case MB_REG_WRITE:
while (iNReg > 1)
{
xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, 8,
*pucRegBuffer++);
iNReg--;
}
/* last coils */
usNCoils = usNCoils % 8;
/* xMBUtilSetBits has bug when ucNBits is zero */
if (usNCoils != 0)
{
xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, usNCoils,
*pucRegBuffer++);
}
break;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
/**
* Modbus master discrete callback function.
*
* @param pucRegBuffer discrete buffer
* @param usAddress discrete address
* @param usNDiscrete discrete number
*
* @return result
*/
eMBErrorCode eMBMasterRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex , iRegBitIndex , iNReg;
UCHAR * pucDiscreteInputBuf;
USHORT DISCRETE_INPUT_START;
USHORT DISCRETE_INPUT_NDISCRETES;
USHORT usDiscreteInputStart;
iNReg = usNDiscrete / 8 + 1;
pucDiscreteInputBuf = ucMDiscInBuf[ucMBMasterGetDestAddress() - 1];
DISCRETE_INPUT_START = M_DISCRETE_INPUT_START;
DISCRETE_INPUT_NDISCRETES = M_DISCRETE_INPUT_NDISCRETES;
usDiscreteInputStart = usMDiscInStart;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= DISCRETE_INPUT_START)
&& (usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES))
{
iRegIndex = (USHORT) (usAddress - usDiscreteInputStart) / 8;
iRegBitIndex = (USHORT) (usAddress - usDiscreteInputStart) % 8;
/* write current discrete values with new values from the protocol stack. */
while (iNReg > 1)
{
xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex, 8,
*pucRegBuffer++);
iNReg--;
}
/* last discrete */
usNDiscrete = usNDiscrete % 8;
/* xMBUtilSetBits has bug when ucNBits is zero */
if (usNDiscrete != 0)
{
xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex,
usNDiscrete, *pucRegBuffer++);
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
#endif
# The Roadmap of RT-Thread v2.1.0 version #
Thank all of the developers and contributors, the final version of RT-Thread v2.0.0 has been released. The next version should be a small version, not always similar to the last version, which is a big version:-) The version number should be v2.1.0. There are lot of people ask me what's the features of next version. In fact, I would say, RT-Thread is an open source community, which the development of RT-Thread RTOS is depended by community, belonging to each community participants. If you want to let RT-Thread has some features, please implement it! Then share them to the community. If those part meet the RT-Thread rule (such as no license conflict), there is no reason that not to put them into the upstream of RT-Thread.
So more representatives mentioned below are my (Bernard) personal point of view:
1. CloudIDE, which is hosted on http://lab.rt-thread.org/cloudide, is an online IDE, ah, similar to mbed;-) But hope there are some own characteristics, and at least, it's faster in China. (When it's ready, we maybe setup a local IDE version.) It's in alpha phase right now, which introduces multi-tab edit mode; adding the Wi-Fi startkit hardware to update its firmware in fly; sharing snippets and components between developers; integrating help documentation and other information. The intention is to create a convenient way for newcomer, but not troubled by the development environment. Developers only need a web browser and the corresponding hardware, such as Wi-Fi startkit (which also is called as ART-wifi).
2. In embedded system salon which is held in Shanghai China, December of last year, developer Weety mentioned POSIX compatibility issue, which leading to not easy to port some Linux software to RT-Thread. The main problem here is that the BSD socket interface is entirely in lwIP protocol stack, while the file system interface of RT-Thread is another one. Therefore, RT-Thread has no unified select/read/write/poll function on socket/file descriptor/device; Another implicit problem is, POSIX implementation is not completed standard. There may be some pits inside. This issue is a big problem, since we chose the open source system, then he/she must also take into account the open source ecosystem as well. There are many open source resources you can use or re-use. Therefore, RT-Thread also need to be more open attitude to solve this problem so that it can be more open, to enhance the affinity of the POSIX standard itself. Similarly, it should be better supported for some of the C ++ standard. RT-Thread will be more POSIX, more open. RT-Thread is there, and how to create a better application, it's up to the user's innovation.
3. Some rich feature SoC, such as the number of new pop package ARM9 (With built-in SDRAM/DDR), Cortex-A7/8/9, MIPS32/64, or even x86, these SoC will be certainly and gradually evolved into the RT-Thread target hardware platform, but the work should be heavier. If the above No.2 POSIX issue resolved, it's possible to support them. The primary working is the driver implementation, and then integrated with POSIX interface, it will be easier to port other components.
From my side of the energy can put into it, I should be focusing my working on the building up the platform, so that RT-Thread can be more POSIX, more standardized, more open and easy to use. The current planning point is to release RT-Thread v2.1.0 alpha version on the end of Q1 2015. This version should include dfs_lwIP file system interface, and then make sure the branch direction.
The others, the following list are some thought but no obligation feature list, please interested guys come to claim, thanks:
* CloudIDE related
- Improve the NAT function, turns ART-wifi board into a Wi-Fi repeater (routing).
- Look forward to sharing MQTT/CoAP components on CloudIDE;
- Look forward to adding Wi-Fi/6LoWPAN gateway in the ART-wifi startkit.
- Look forward to adding Wi-Fi/nRF51822 BLE gateway in the ART-wifi startkit.
- Look forward to turning the ART-wifi startkit as a multi-axis flight control, and porting some algorighms in PX4 project;
- Look forward to sharing Lewei50/Yeelink access component on CloudIDE;
- Look forward to sharing SSL component on CloudIDE;
- Look forward to sharing components on CloudIDE to access Ali cloud, Baidu cloud, Tencent cloud etc;
- Add more sensors driver, e.g., barometer, thermometer, illumination, 9-axis sensor etc;
- Look forward to integrating RealBoard LPC4088 APP development environment on CloudIDE;
- Look forward to integrating UI design feature on CloudIDE;
- Look forward to turnning CloudIDE become a local desktop application;
* POSIX-related
- Implement dfs_lwIP file system interface for DFS fd/lwIP socket interface. To implement select/poll interface before DFS;
- More better integration between DFS and device file system interface(devfs).
- Add more POSIX interfaces, including but not limited to aio, signal and other functions etc;
- Improve DeviceDriver framework for device interfaces (rt_device_*). Application layer uses rt_device_* and devfs interface, firmware/driver developer uses device driver framework interface.
* Others
- Porting TCP/IP protocol stack and POSIX environmemnt in OpenBSD;
- CanOpen component;
- ARM Cortex-A8/A9 + M4/M3 hardware platform;
- Some other hardware porting;
Bernard Xiong
2015.2.26
/*
* File : rtdef.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
* COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -29,6 +29,7 @@
* RT_USING_MEMHEAP condition.
* 2012-12-30 Bernard add more control command for graphic.
* 2013-01-09 Bernard change version number.
* 2015-02-01 Bernard change version number to v2.1.0
*/
#ifndef __RT_DEF_H__
......@@ -49,7 +50,7 @@ extern "C" {
/* RT-Thread version information */
#define RT_VERSION 2L /**< major version number */
#define RT_SUBVERSION 0L /**< minor version number */
#define RT_SUBVERSION 1L /**< minor version number */
#define RT_REVISION 0L /**< revise version number */
/* RT-Thread version */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册