add i2c led
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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: port.c,v 1.60 2015/02/01 9:18:05 Armink $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes --------------------------------*/
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "port.h"
|
||||
/* ----------------------- Variables ----------------------------------------*/
|
||||
static struct rt_semaphore lock;
|
||||
static int is_inited = 0;
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
void EnterCriticalSection(void)
|
||||
{
|
||||
rt_err_t err;
|
||||
if(!is_inited)
|
||||
{
|
||||
err = rt_sem_init(&lock, "fmb_lock", 1, RT_IPC_FLAG_PRIO);
|
||||
if(err != RT_EOK)
|
||||
{
|
||||
rt_kprintf("Freemodbus Critical init failed!\n");
|
||||
}
|
||||
is_inited = 1;
|
||||
}
|
||||
rt_sem_take(&lock, RT_WAITING_FOREVER);
|
||||
}
|
||||
|
||||
void ExitCriticalSection(void)
|
||||
{
|
||||
rt_sem_release(&lock);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* FreeModbus Libary: BARE 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: port.h ,v 1.60 2013/08/13 15:07:05 Armink add Master Functions $
|
||||
*/
|
||||
|
||||
#ifndef _PORT_H
|
||||
#define _PORT_H
|
||||
|
||||
#include "mbconfig.h"
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define INLINE
|
||||
#define PR_BEGIN_EXTERN_C extern "C" {
|
||||
#define PR_END_EXTERN_C }
|
||||
|
||||
#define ENTER_CRITICAL_SECTION() EnterCriticalSection()
|
||||
#define EXIT_CRITICAL_SECTION() ExitCriticalSection()
|
||||
|
||||
typedef uint8_t BOOL;
|
||||
|
||||
typedef unsigned char UCHAR;
|
||||
typedef char CHAR;
|
||||
|
||||
typedef uint16_t USHORT;
|
||||
typedef int16_t SHORT;
|
||||
|
||||
typedef uint32_t ULONG;
|
||||
typedef int32_t LONG;
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
void EnterCriticalSection(void);
|
||||
void ExitCriticalSection(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.c,v 1.60 2013/08/13 15:07:05 Armink $
|
||||
*/
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbport.h"
|
||||
|
||||
/* ----------------------- Variables ----------------------------------------*/
|
||||
static struct rt_event xSlaveOsEvent;
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
BOOL
|
||||
xMBPortEventInit( void )
|
||||
{
|
||||
rt_event_init(&xSlaveOsEvent,"slave event",RT_IPC_FLAG_PRIO);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBPortEventPost( eMBEventType eEvent )
|
||||
{
|
||||
rt_event_send(&xSlaveOsEvent, eEvent);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBPortEventGet( eMBEventType * eEvent )
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 TRUE;
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* 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;
|
||||
default:
|
||||
*eEvent = EV_MASTER_FRAME_RECEIVED;
|
||||
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
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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: portserial.c,v 1.60 2013/08/13 15:07:05 Armink $
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbport.h"
|
||||
#include "rtdevice.h"
|
||||
#include "board.h"
|
||||
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
/* software simulation serial transmit IRQ handler thread stack */
|
||||
#ifdef rt_align
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
#else
|
||||
ALIGN(RT_ALIGN_SIZE)
|
||||
#endif
|
||||
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 struct rt_serial_device *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)
|
||||
{
|
||||
rt_device_t dev = RT_NULL;
|
||||
char uart_name[20];
|
||||
/**
|
||||
* set 485 mode receive and transmit control IO
|
||||
* @note MODBUS_SLAVE_RT_CONTROL_PIN_INDEX need be defined by user
|
||||
*/
|
||||
#if defined(RT_MODBUS_SLAVE_USE_CONTROL_PIN)
|
||||
rt_pin_mode(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_MODE_OUTPUT);
|
||||
#endif
|
||||
/* set serial name */
|
||||
rt_snprintf(uart_name,sizeof(uart_name), "uart%d", ucPORT);
|
||||
|
||||
dev = rt_device_find(uart_name);
|
||||
if(dev == RT_NULL)
|
||||
{
|
||||
/* can not find uart */
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
serial = (struct rt_serial_device*)dev;
|
||||
}
|
||||
|
||||
/* 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 (!rt_device_open(&serial->parent, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX)) {
|
||||
rt_device_set_rx_indicate(&serial->parent, serial_rx_ind);
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* software initialize */
|
||||
rt_event_init(&event_serial, "slave event", RT_IPC_FLAG_PRIO);
|
||||
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);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
|
||||
{
|
||||
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 */
|
||||
#if defined(RT_MODBUS_SLAVE_USE_CONTROL_PIN)
|
||||
rt_pin_write(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_LOW);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* switch 485 to transmit mode */
|
||||
#if defined(RT_MODBUS_SLAVE_USE_CONTROL_PIN)
|
||||
rt_pin_write(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_HIGH);
|
||||
#endif
|
||||
/* 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)
|
||||
{
|
||||
serial->parent.close(&(serial->parent));
|
||||
}
|
||||
|
||||
BOOL xMBPortSerialPutByte(CHAR ucByte)
|
||||
{
|
||||
serial->parent.write(&(serial->parent), 0, &ucByte, 1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL xMBPortSerialGetByte(CHAR * pucByte)
|
||||
{
|
||||
serial->parent.read(&(serial->parent), 0, pucByte, 1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an interrupt handler for the transmit buffer empty interrupt
|
||||
* (or an equivalent) for your target processor. This function should then
|
||||
* call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
|
||||
* a new character can be sent. The protocol stack will then call
|
||||
* xMBPortSerialPutByte( ) to send the character.
|
||||
*/
|
||||
void prvvUARTTxReadyISR(void)
|
||||
{
|
||||
pxMBFrameCBTransmitterEmpty();
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an interrupt handler for the receive interrupt for your target
|
||||
* processor. This function should then call pxMBFrameCBByteReceived( ). The
|
||||
* protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
|
||||
* character.
|
||||
*/
|
||||
void prvvUARTRxISR(void)
|
||||
{
|
||||
pxMBFrameCBByteReceived();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
while(size--)
|
||||
prvvUARTRxISR();
|
||||
return RT_EOK;
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 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: portserial_m.c,v 1.60 2013/08/13 15:07:05 Armink add Master Functions $
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- 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 ---------------------------------*/
|
||||
/* software simulation serial transmit IRQ handler thread stack */
|
||||
#ifdef rt_align
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
#else
|
||||
ALIGN(RT_ALIGN_SIZE)
|
||||
#endif
|
||||
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 master serial device */
|
||||
static struct rt_serial_device *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 xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
|
||||
eMBParity eParity)
|
||||
{
|
||||
rt_device_t dev = RT_NULL;
|
||||
char uart_name[20];
|
||||
|
||||
/**
|
||||
* set 485 mode receive and transmit control IO
|
||||
* @note MODBUS_MASTER_RT_CONTROL_PIN_INDEX need be defined by user
|
||||
*/
|
||||
#if defined(RT_MODBUS_MASTER_USE_CONTROL_PIN)
|
||||
rt_pin_mode(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_MODE_OUTPUT);
|
||||
#endif
|
||||
/* set serial name */
|
||||
rt_snprintf(uart_name,sizeof(uart_name), "uart%d", ucPORT);
|
||||
|
||||
dev = rt_device_find(uart_name);
|
||||
if(dev == RT_NULL)
|
||||
{
|
||||
/* can not find uart */
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
serial = (struct rt_serial_device*)dev;
|
||||
}
|
||||
|
||||
/* 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 (!rt_device_open(&serial->parent, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX)) {
|
||||
rt_device_set_rx_indicate(&serial->parent, serial_rx_ind);
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* software initialize */
|
||||
rt_event_init(&event_serial, "master event", RT_IPC_FLAG_PRIO);
|
||||
rt_thread_init(&thread_serial_soft_trans_irq,
|
||||
"master 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);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
|
||||
{
|
||||
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 */
|
||||
#if defined(RT_MODBUS_MASTER_USE_CONTROL_PIN)
|
||||
rt_pin_write(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_LOW);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* switch 485 to transmit mode */
|
||||
#if defined(RT_MODBUS_MASTER_USE_CONTROL_PIN)
|
||||
rt_pin_write(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_HIGH);
|
||||
#endif
|
||||
/* 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)
|
||||
{
|
||||
serial->parent.close(&(serial->parent));
|
||||
}
|
||||
|
||||
BOOL xMBMasterPortSerialPutByte(CHAR ucByte)
|
||||
{
|
||||
serial->parent.write(&(serial->parent), 0, &ucByte, 1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL xMBMasterPortSerialGetByte(CHAR * pucByte)
|
||||
{
|
||||
serial->parent.read(&(serial->parent), 0, pucByte, 1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an interrupt handler for the transmit buffer empty interrupt
|
||||
* (or an equivalent) for your target processor. This function should then
|
||||
* call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
|
||||
* a new character can be sent. The protocol stack will then call
|
||||
* xMBPortSerialPutByte( ) to send the character.
|
||||
*/
|
||||
void prvvUARTTxReadyISR(void)
|
||||
{
|
||||
pxMBMasterFrameCBTransmitterEmpty();
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an interrupt handler for the receive interrupt for your target
|
||||
* processor. This function should then call pxMBFrameCBByteReceived( ). The
|
||||
* protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
|
||||
* character.
|
||||
*/
|
||||
void prvvUARTRxISR(void)
|
||||
{
|
||||
pxMBMasterFrameCBByteReceived();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* FreeModbus Libary: RT-Thread Port
|
||||
* Copyright (C) 2019 flybreak <guozhanxin@rt-thread.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: portserial.c,v 1.60 2019/07/11 17:04:32 flybreak $
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
|
||||
#ifdef PKG_MODBUS_SLAVE_TCP
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbport.h"
|
||||
#include "tcpserver.h"
|
||||
|
||||
/* ----------------------- Defines -----------------------------------------*/
|
||||
#define MB_TCP_DEFAULT_PORT 502
|
||||
#define MB_TCP_BUF_SIZE ( 256 + 7 )
|
||||
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
static tcpclient_t mb_client;
|
||||
static UCHAR prvvTCPBuf[MB_TCP_BUF_SIZE];
|
||||
static USHORT prvvTCPLength;
|
||||
|
||||
static void tcpserver_event_notify(tcpclient_t client, rt_uint8_t event)
|
||||
{
|
||||
static rt_tick_t recv_tick = 0;
|
||||
switch (event)
|
||||
{
|
||||
case TCPSERVER_EVENT_CONNECT:
|
||||
if (mb_client == RT_NULL)
|
||||
{
|
||||
mb_client = client;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(rt_tick_get() - recv_tick > 30 * RT_TICK_PER_SECOND) /* set timeout as 30s */
|
||||
{
|
||||
tcpserver_close(mb_client);
|
||||
mb_client = client;
|
||||
recv_tick = rt_tick_get();
|
||||
}
|
||||
else
|
||||
{
|
||||
tcpserver_close(client);
|
||||
rt_kprintf("Multi-host is not supported, please disconnect the current host first!\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TCPSERVER_EVENT_RECV:
|
||||
if( mb_client == client)
|
||||
{
|
||||
recv_tick = rt_tick_get();
|
||||
prvvTCPLength = tcpserver_recv(mb_client, &prvvTCPBuf, MB_TCP_BUF_SIZE, 100);
|
||||
if (prvvTCPLength)
|
||||
{
|
||||
xMBPortEventPost(EV_FRAME_RECEIVED);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TCPSERVER_EVENT_DISCONNECT:
|
||||
if (mb_client == client)
|
||||
mb_client = RT_NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBTCPPortInit(USHORT usTCPPort)
|
||||
{
|
||||
struct tcpserver *serv;
|
||||
|
||||
if (usTCPPort == 0)
|
||||
usTCPPort = MB_TCP_DEFAULT_PORT;
|
||||
|
||||
serv = tcpserver_create(0, usTCPPort);
|
||||
|
||||
tcpserver_set_notify_callback(serv, tcpserver_event_notify);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
vMBTCPPortClose(void)
|
||||
{
|
||||
tcpserver_destroy(mb_client->server);
|
||||
}
|
||||
|
||||
void
|
||||
vMBTCPPortDisable(void)
|
||||
{
|
||||
tcpserver_close(mb_client);
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBTCPPortGetRequest(UCHAR **ppucMBTCPFrame, USHORT *usTCPLength)
|
||||
{
|
||||
*ppucMBTCPFrame = &prvvTCPBuf[0];
|
||||
*usTCPLength = prvvTCPLength;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBTCPPortSendResponse(const UCHAR *pucMBTCPFrame, USHORT usTCPLength)
|
||||
{
|
||||
rt_int16_t ret;
|
||||
BOOL bFrameSent = FALSE;
|
||||
|
||||
if (mb_client)
|
||||
{
|
||||
ret = tcpserver_send(mb_client, (void *)pucMBTCPFrame, usTCPLength, 0);
|
||||
if (ret == usTCPLength)
|
||||
bFrameSent = TRUE;
|
||||
}
|
||||
return bFrameSent;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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: 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"
|
||||
|
||||
/* ----------------------- static functions ---------------------------------*/
|
||||
static struct rt_timer timer;
|
||||
static void prvvTIMERExpiredISR(void);
|
||||
static void timer_timeout_ind(void* parameter);
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
|
||||
{
|
||||
rt_timer_init(&timer, "slave timer",
|
||||
timer_timeout_ind, /* bind timeout callback function */
|
||||
RT_NULL,
|
||||
(50 * usTim1Timerout50us) / (1000 * 1000 / RT_TICK_PER_SECOND) + 1,
|
||||
RT_TIMER_FLAG_ONE_SHOT); /* one shot */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void vMBPortTimersEnable()
|
||||
{
|
||||
rt_timer_start(&timer);
|
||||
}
|
||||
|
||||
void vMBPortTimersDisable()
|
||||
{
|
||||
rt_timer_stop(&timer);
|
||||
}
|
||||
|
||||
void prvvTIMERExpiredISR(void)
|
||||
{
|
||||
(void) pxMBPortCBTimerExpired();
|
||||
}
|
||||
|
||||
static void timer_timeout_ind(void* parameter)
|
||||
{
|
||||
prvvTIMERExpiredISR();
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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: 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 > 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 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) + 1,
|
||||
RT_TIMER_FLAG_ONE_SHOT); /* one shot */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void vMBMasterPortTimersT35Enable()
|
||||
{
|
||||
rt_tick_t timer_tick = (50 * usT35TimeOut50us)
|
||||
/ (1000 * 1000 / RT_TICK_PER_SECOND) + 1;
|
||||
|
||||
/* 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 vMBMasterPortTimersConvertDelayEnable()
|
||||
{
|
||||
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) pxMBMasterPortCBTimerExpired();
|
||||
}
|
||||
|
||||
static void timer_timeout_ind(void* parameter)
|
||||
{
|
||||
prvvTIMERExpiredISR();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef USER_APP
|
||||
#define USER_APP
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbconfig.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbutils.h"
|
||||
|
||||
/* -----------------------Slave Defines -------------------------------------*/
|
||||
#define S_DISCRETE_INPUT_START RT_S_DISCRETE_INPUT_START
|
||||
#define S_DISCRETE_INPUT_NDISCRETES RT_S_DISCRETE_INPUT_NDISCRETES
|
||||
#define S_COIL_START RT_S_COIL_START
|
||||
#define S_COIL_NCOILS RT_S_COIL_NCOILS
|
||||
#define S_REG_INPUT_START RT_S_REG_INPUT_START
|
||||
#define S_REG_INPUT_NREGS RT_S_REG_INPUT_NREGS
|
||||
#define S_REG_HOLDING_START RT_S_REG_HOLDING_START
|
||||
#define S_REG_HOLDING_NREGS RT_S_REG_HOLDING_NREGS
|
||||
/* salve mode: holding register's all address */
|
||||
#define S_HD_RESERVE RT_S_HD_RESERVE
|
||||
/* salve mode: input register's all address */
|
||||
#define S_IN_RESERVE RT_S_IN_RESERVE
|
||||
/* salve mode: coil's all address */
|
||||
#define S_CO_RESERVE RT_S_CO_RESERVE
|
||||
/* salve mode: discrete's all address */
|
||||
#define S_DI_RESERVE RT_S_DI_RESERVE
|
||||
|
||||
/* -----------------------Master Defines -------------------------------------*/
|
||||
#define M_DISCRETE_INPUT_START RT_M_DISCRETE_INPUT_START
|
||||
#define M_DISCRETE_INPUT_NDISCRETES RT_M_DISCRETE_INPUT_NDISCRETES
|
||||
#define M_COIL_START RT_M_COIL_START
|
||||
#define M_COIL_NCOILS RT_M_COIL_NCOILS
|
||||
#define M_REG_INPUT_START RT_M_REG_INPUT_START
|
||||
#define M_REG_INPUT_NREGS RT_M_REG_INPUT_NREGS
|
||||
#define M_REG_HOLDING_START RT_M_REG_HOLDING_START
|
||||
#define M_REG_HOLDING_NREGS RT_M_REG_HOLDING_NREGS
|
||||
/* master mode: holding register's all address */
|
||||
#define M_HD_RESERVE RT_M_HD_RESERVE
|
||||
/* master mode: input register's all address */
|
||||
#define M_IN_RESERVE RT_M_IN_RESERVE
|
||||
/* master mode: coil's all address */
|
||||
#define M_CO_RESERVE RT_M_CO_RESERVE
|
||||
/* master mode: discrete's all address */
|
||||
#define M_DI_RESERVE RT_M_DI_RESERVE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* 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
|
||||
Reference in New Issue
Block a user