forked from xuos/xiuos
Merge branch 'prepare_for_master' of https://gitlink.org.cn/xuos/xiuos into control
This commit is contained in:
commit
93614746fe
|
@ -22,9 +22,6 @@
|
|||
[submodule "Ubiquitous/RT-Thread_Fusion_XiUOS/aiit_board/xidatong-riscv64/kendryte-sdk/kendryte-sdk-source"]
|
||||
path = Ubiquitous/RT-Thread_Fusion_XiUOS/aiit_board/xidatong-riscv64/kendryte-sdk/kendryte-sdk-source
|
||||
url = https://www.gitlink.org.cn/chunyexixiaoyu/kendryte-sdk-source.git
|
||||
[submodule "APP_Framework/lib/lorawan/lora_radio_driver"]
|
||||
path = APP_Framework/lib/lorawan/lora_radio_driver
|
||||
url = https://gitlink.org.cn/xuos/lora_radio_driver
|
||||
[submodule "APP_Framework/lib/lorawan/lorawan_devicenode"]
|
||||
path = APP_Framework/lib/lorawan/lorawan_devicenode
|
||||
url = https://gitlink.org.cn/xuos/lorawan_devicenode.git
|
||||
|
|
|
@ -20,4 +20,5 @@ menu "Applications"
|
|||
source "$APP_DIR/Applications/sensor_app/Kconfig"
|
||||
source "$APP_DIR/Applications/embedded_database_app/Kconfig"
|
||||
source "$APP_DIR/Applications/webnet/Kconfig"
|
||||
source "$APP_DIR/Applications/webserver/Kconfig"
|
||||
endmenu
|
||||
|
|
|
@ -39,6 +39,10 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
|
|||
ifeq ($(CONFIG_APP_USING_WEBNET),y)
|
||||
SRC_DIR += webnet
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_APPLICATION_WEBSERVER),y)
|
||||
SRC_DIR += webserver
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
endif
|
|
@ -281,6 +281,7 @@ menu "test app"
|
|||
menuconfig USER_TEST_MQTTCLIENT
|
||||
bool "Config test mqtt client"
|
||||
default n
|
||||
select LIB_USING_CJSON
|
||||
|
||||
menuconfig USER_TEST_FTPCLIENT
|
||||
bool "Config test ftp client"
|
||||
|
|
|
@ -150,7 +150,9 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
|
|||
endif
|
||||
|
||||
ifeq ($(CONFIG_USER_TEST_FTPCLIENT_RISCV),y)
|
||||
SRC_FILES += test_ftpclient_riscv/test_ftpclient_riscv.c
|
||||
ifeq ($(CONFIG_BSP_USING_W5500),y)
|
||||
SRC_FILES += test_ftpclient_riscv/test_ftpclient_riscv.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_USER_TEST_LORA_P2P),y)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
* @date: 2023/2/17
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <transform.h>
|
||||
#ifdef ADD_XIZI_FEATURES
|
||||
|
@ -54,28 +55,34 @@ void TestCAN(void)
|
|||
}
|
||||
printf("CAN configure successful!\n");
|
||||
|
||||
uint8_t data_buff[64u] = {1,2,3,4,4,3,2,1};
|
||||
uint8_t data_buff[64u] = "12344321";
|
||||
struct CanSendConfigure frame_send;
|
||||
frame_send.ide=0;
|
||||
frame_send.stdid = 0x55;
|
||||
frame_send.rtr=0;
|
||||
frame_send.data_lenth=8;
|
||||
frame_send.data = data_buff;
|
||||
|
||||
struct CanSendConfigure frame_recv;
|
||||
uint8_t recv_buff[65U] = {0};
|
||||
uint8_t recv_buff[64u] = {};
|
||||
frame_recv.data = recv_buff;
|
||||
|
||||
// CAN write
|
||||
while (1)
|
||||
{
|
||||
PrivTaskDelay(500);
|
||||
PrivWrite(can_fd, &frame_send, NONE);
|
||||
PrivTaskDelay(500);
|
||||
// PrivTaskDelay(500);
|
||||
// PrivWrite(can_fd, &frame_send, NONE);
|
||||
// PrivTaskDelay(500);
|
||||
PrivRead(can_fd, &frame_recv, NONE);
|
||||
// if any data has received,Then printf message
|
||||
if(frame_recv.data_lenth > 0){
|
||||
printf("ID %08x:%s\n",frame_recv.exdid,frame_recv.data);
|
||||
printf("ID %08x : \n",frame_recv.exdid);
|
||||
for(int i = 0; i < frame_recv.data_lenth; i ++) {
|
||||
printf("0x%x ", frame_recv.data[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
frame_send.data = recv_buff;
|
||||
PrivWrite(can_fd, &frame_send, NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <transform.h>
|
||||
#ifdef ADD_XIZI_FEATURES
|
||||
|
||||
#ifdef BSP_USING_W5500
|
||||
#include <socket.h>
|
||||
|
||||
#define BUFF_SIZE 128
|
||||
|
@ -189,6 +190,6 @@ PRIV_SHELL_CMD_FUNCTION(TestSocketAsClient, a w5500 client-ip-port-msg test samp
|
|||
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -22,7 +22,7 @@
|
|||
#include <transform.h>
|
||||
#ifdef ADD_XIZI_FEATURES
|
||||
|
||||
#define BSP_LED_PIN 29
|
||||
#define BSP_LED_PIN 134
|
||||
#define NULL_PARAMETER 0
|
||||
|
||||
static uint16_t pin_fd=0;
|
||||
|
@ -30,6 +30,7 @@ static struct PinStat pin_led;
|
|||
|
||||
void LedFlip(void *parameter)
|
||||
{
|
||||
printf("%s val %d time %d\n", __func__, pin_led.val, PrivGetTickTime());
|
||||
pin_led.pin = BSP_LED_PIN;
|
||||
pin_led.val = !pin_led.val;
|
||||
PrivWrite(pin_fd, &pin_led, NULL_PARAMETER);
|
||||
|
@ -37,7 +38,7 @@ void LedFlip(void *parameter)
|
|||
|
||||
void TestHwTimer(void)
|
||||
{
|
||||
x_ticks_t period = 1;
|
||||
uint32_t period_ms = 500;
|
||||
|
||||
pin_fd = PrivOpen(HWTIMER_PIN_DEV_DRIVER, O_RDWR);
|
||||
if(pin_fd<0) {
|
||||
|
@ -75,7 +76,7 @@ void TestHwTimer(void)
|
|||
return;
|
||||
}
|
||||
|
||||
ioctl_cfg.args = (void *).
|
||||
ioctl_cfg.args = (void *)&period_ms;
|
||||
if (0 != PrivIoctl(timer_fd, OPE_CFG, &ioctl_cfg)) {
|
||||
printf("timer pin fd error %d\n", pin_fd);
|
||||
PrivClose(pin_fd);
|
||||
|
|
|
@ -98,6 +98,7 @@ void TestLora(int argc, char *argv[])
|
|||
uart_cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
|
||||
uart_cfg.serial_timeout = 1000;
|
||||
uart_cfg.is_ext_uart = 0;
|
||||
uart_cfg.dev_recv_callback = NULL;
|
||||
|
||||
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
|
||||
ioctl_cfg.args = (void *)&uart_cfg;
|
||||
|
|
|
@ -62,6 +62,7 @@ static struct SerialDataCfg serial_cfg =
|
|||
.serial_buffer_size = SERIAL_RB_BUFSZ,
|
||||
.serial_timeout = E220_DAFAULT_SERIAL_TIMEOUT, // 串口超时配置
|
||||
.is_ext_uart = 0,
|
||||
.dev_recv_callback = NULL,
|
||||
};
|
||||
|
||||
enum LoraMode current_mode = -1; // 当前模块处于什么模式
|
||||
|
|
|
@ -138,6 +138,7 @@ void Test485(void)
|
|||
uart_cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
|
||||
uart_cfg.serial_timeout = -1;
|
||||
uart_cfg.is_ext_uart = 0;
|
||||
uart_cfg.dev_recv_callback = NULL;
|
||||
|
||||
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
|
||||
ioctl_cfg.args = (void *)&uart_cfg;
|
||||
|
|
|
@ -70,6 +70,7 @@ void Test485(void)
|
|||
uart_cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
|
||||
uart_cfg.serial_timeout = 1000;
|
||||
uart_cfg.is_ext_uart = 0;
|
||||
uart_cfg.dev_recv_callback = NULL;
|
||||
|
||||
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
|
||||
ioctl_cfg.args = (void *)&uart_cfg;
|
||||
|
|
|
@ -76,10 +76,12 @@ struct IperfParam {
|
|||
static void* TestIperfServer(void* param)
|
||||
{
|
||||
struct IperfParam* iperf_param = (struct IperfParam*)param;
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 6);
|
||||
if (sock < 0) {
|
||||
printf("[%s] Err: Can't create socker.\n", __func__);
|
||||
return NULL;
|
||||
} else {
|
||||
printf("[%s] Info Create server socket %d\n", __func__, sock);
|
||||
}
|
||||
|
||||
uint8_t* recv_data = (uint8_t*)malloc(IPERF_BUFSZ);
|
||||
|
@ -121,8 +123,9 @@ static void* TestIperfServer(void* param)
|
|||
socklen_t sin_size = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_in client_addr;
|
||||
int connection = accept(sock, (struct sockaddr*)&client_addr, &sin_size);
|
||||
printf("[%s] Info: New client connected from (%s, %d)\n", __func__,
|
||||
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
|
||||
printf("[%s] Info: New client connected from (%s, %d), connect: %d\n", __func__,
|
||||
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port),
|
||||
connection);
|
||||
|
||||
int flag = 1;
|
||||
setsockopt(connection,
|
||||
|
@ -141,8 +144,8 @@ static void* TestIperfServer(void* param)
|
|||
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
|
||||
break;
|
||||
} else if (bytes_received < 0) {
|
||||
KPrintf("recv error, client: (%s, %d)\n",
|
||||
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
|
||||
KPrintf("recv error: %d, client: (%s, %d)\n",
|
||||
bytes_received, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -258,8 +261,6 @@ enum IperfParamEnum {
|
|||
|
||||
void TestSocket(int argc, char* argv[])
|
||||
{
|
||||
lwip_config_tcp(0, lwip_ipaddr, lwip_netmask, lwip_gwaddr);
|
||||
|
||||
static char usage_info[] = "Run either a iperf server or iperf client.";
|
||||
static char program_info[] = "Lwip socket test task, a simple iperf.";
|
||||
static const char* const usages[] = {
|
||||
|
|
|
@ -23,12 +23,13 @@
|
|||
void TimerFunction(union sigval sig_val)
|
||||
{
|
||||
static int cnt = 0;
|
||||
printf("%s cnt %d\n", __func__, cnt++);
|
||||
printf("%s cnt %d ms %d\n", __func__, cnt++, PrivGetTickTime());
|
||||
}
|
||||
|
||||
void TestTimer(void)
|
||||
{
|
||||
int ret = 0;
|
||||
static int count = 0;
|
||||
int timer_flags;
|
||||
timer_t timer_id;
|
||||
struct sigevent evp;
|
||||
|
@ -40,7 +41,9 @@ void TestTimer(void)
|
|||
evp.sigev_notify_function = TimerFunction;
|
||||
evp.sigev_notify_attributes = &timer_flags;
|
||||
|
||||
ret = timer_create(CLOCK_REALTIME, &evp, &timer_id);
|
||||
count++;
|
||||
|
||||
ret = PrivTimerCreate(count, &evp, &timer_id);
|
||||
if (ret < 0) {
|
||||
printf("%s create timer failed ret %d\n", __func__, ret);
|
||||
return;
|
||||
|
@ -48,14 +51,14 @@ void TestTimer(void)
|
|||
|
||||
struct itimerspec value;
|
||||
//active time interval
|
||||
value.it_interval.tv_sec = 2;
|
||||
value.it_interval.tv_nsec = 0;
|
||||
value.it_interval.tv_sec = 0;
|
||||
value.it_interval.tv_nsec = 1000000 * 10;
|
||||
|
||||
//first timer set time
|
||||
value.it_value.tv_sec = 2;
|
||||
value.it_value.tv_nsec = 0;
|
||||
|
||||
ret = timer_settime(timer_id, 1, &value, NULL);
|
||||
ret = PrivTimerModify(timer_id, 1, &value, NULL);
|
||||
if (ret < 0) {
|
||||
printf("%s set timer time failed ret %d\n", __func__, ret);
|
||||
return;
|
||||
|
|
|
@ -68,6 +68,7 @@ void TestUart(int argc, char* argv[])
|
|||
uart_cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
|
||||
uart_cfg.serial_timeout = -1;
|
||||
uart_cfg.is_ext_uart = 0;
|
||||
uart_cfg.dev_recv_callback = NULL;
|
||||
|
||||
struct PrivIoctlCfg ioctl_cfg;
|
||||
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
|
||||
|
|
|
@ -15,6 +15,10 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
|
|||
SRC_DIR += socket_demo
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_CONNECTION_ADAPTER_FREEMODBUSTCP),y)
|
||||
SRC_DIR += freemodbus_tcp_slave
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
endif
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
SRC_FILES := tcpserver_sample.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* FreeModbus Libary: Win32 Demo Application
|
||||
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
|
||||
*
|
||||
* 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$
|
||||
*/
|
||||
|
||||
/**********************************************************
|
||||
* Linux TCP support.
|
||||
* Based on Walter's project.
|
||||
* Modified by Steven Guo <gotop167@163.com>
|
||||
***********************************************************/
|
||||
|
||||
/* ----------------------- Standard C Libs includes --------------------------*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <transform.h>
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbport.h"
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define PROG "freemodbus"
|
||||
|
||||
#define REG_INPUT_START 1000
|
||||
#define REG_INPUT_NREGS 4
|
||||
#define REG_HOLDING_START 2000
|
||||
#define REG_HOLDING_NREGS 10
|
||||
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
static USHORT usRegInputStart = REG_INPUT_START;
|
||||
static USHORT usRegInputBuf[REG_INPUT_NREGS];
|
||||
static USHORT usRegHoldingStart = REG_HOLDING_START;
|
||||
static USHORT usRegHoldingBuf[REG_HOLDING_NREGS];
|
||||
static pthread_mutex_t xLock;
|
||||
static enum ThreadState
|
||||
{
|
||||
STOPPED,
|
||||
RUNNING,
|
||||
SHUTDOWN
|
||||
} ePollThreadState;
|
||||
|
||||
/* ----------------------- Static functions ---------------------------------*/
|
||||
static BOOL bCreatePollingThread( void );
|
||||
static enum ThreadState eGetPollingThreadState( void );
|
||||
static void eSetPollingThreadState( enum ThreadState eNewState );
|
||||
static void* pvPollingThread( void *pvParameter );
|
||||
int LWIPConnectSocket(uint16_t port);
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
int MBSlave()
|
||||
{
|
||||
int iExitCode;
|
||||
CHAR cCh;
|
||||
BOOL bDoExit;
|
||||
usRegHoldingBuf[5] = 123;
|
||||
usRegHoldingBuf[7] = 234;
|
||||
|
||||
printf("%s ip %d.%d.%d.%d mask %d.%d.%d.%d gw %d.%d.%d.%d\n", __func__,
|
||||
192, 168, 250, 233,
|
||||
255, 255, 255, 255,
|
||||
192, 168, 250, 1);
|
||||
uint8_t local_ip[4] = {192,168,250,233};
|
||||
uint8_t gateway[4] = {192,168,250,1};
|
||||
uint8_t netmask[4] = {255,255,255,0};
|
||||
lwip_config_tcp(0, local_ip, netmask, gateway);
|
||||
printf("%s LWIPInit done\n", __func__);
|
||||
|
||||
if( eMBTCPInit( MB_TCP_PORT_USE_DEFAULT ) != MB_ENOERR )
|
||||
{
|
||||
fprintf( stderr, "%s: can't initialize modbus stack!\r\n", PROG );
|
||||
iExitCode = EXIT_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
eSetPollingThreadState( STOPPED );
|
||||
/* CLI interface. */
|
||||
if( bCreatePollingThread( ) != TRUE )
|
||||
{
|
||||
printf( "Can't start protocol stack! Already running?\r\n" );
|
||||
}
|
||||
}
|
||||
printf("%d %d %s\n",sizeof(usRegHoldingBuf),__LINE__,__func__);
|
||||
|
||||
while(1)
|
||||
{
|
||||
for(int i =0; i<sizeof(usRegHoldingBuf)/2;i++)
|
||||
{
|
||||
printf("poll recv is %3d\n", usRegHoldingBuf[i]);
|
||||
MdelayKTask(100);
|
||||
}
|
||||
}
|
||||
return iExitCode;
|
||||
}
|
||||
|
||||
PRIV_SHELL_CMD_FUNCTION(MBSlave, a Mtcp server Demo, PRIV_SHELL_CMD_MAIN_ATTR);
|
||||
|
||||
|
||||
BOOL bCreatePollingThread( void )
|
||||
{
|
||||
BOOL bResult;
|
||||
pthread_t xThread;
|
||||
if( eGetPollingThreadState( ) == STOPPED )
|
||||
{
|
||||
if( pthread_create( &xThread, NULL, pvPollingThread, NULL ) != 0 )
|
||||
{
|
||||
/* Can't create the polling thread. */
|
||||
bResult = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
bResult = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bResult = FALSE;
|
||||
}
|
||||
return bResult;
|
||||
}
|
||||
|
||||
|
||||
void* pvPollingThread( void *pvParameter )
|
||||
{
|
||||
eSetPollingThreadState( RUNNING );
|
||||
|
||||
if( eMBEnable( ) == MB_ENOERR )
|
||||
{
|
||||
do
|
||||
{
|
||||
if( eMBPoll( ) != MB_ENOERR )
|
||||
break;
|
||||
}
|
||||
while( eGetPollingThreadState( ) != SHUTDOWN );
|
||||
}
|
||||
|
||||
( void )eMBDisable( );
|
||||
|
||||
eSetPollingThreadState( STOPPED );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum ThreadState eGetPollingThreadState( )
|
||||
{
|
||||
enum ThreadState eCurState;
|
||||
|
||||
( void )pthread_mutex_lock( &xLock );
|
||||
eCurState = ePollThreadState;
|
||||
( void )pthread_mutex_unlock( &xLock );
|
||||
|
||||
return eCurState;
|
||||
}
|
||||
|
||||
void eSetPollingThreadState( enum ThreadState eNewState )
|
||||
{
|
||||
( void )pthread_mutex_lock( &xLock );
|
||||
ePollThreadState = eNewState;
|
||||
( void )pthread_mutex_unlock( &xLock );
|
||||
}
|
||||
|
||||
eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
int iRegIndex;
|
||||
|
||||
if( ( usAddress >= REG_INPUT_START )
|
||||
&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
|
||||
{
|
||||
iRegIndex = ( int )( usAddress - usRegInputStart );
|
||||
while( usNRegs > 0 )
|
||||
{
|
||||
*pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
|
||||
*pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
|
||||
iRegIndex++;
|
||||
usNRegs--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_ENOREG;
|
||||
}
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
int iRegIndex;
|
||||
|
||||
if( ( usAddress >= REG_HOLDING_START ) &&
|
||||
( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
|
||||
{
|
||||
iRegIndex = ( int )( usAddress - usRegHoldingStart );
|
||||
switch ( eMode )
|
||||
{
|
||||
/* Pass current register values to the protocol stack. */
|
||||
case MB_REG_READ:
|
||||
while( usNRegs > 0 )
|
||||
{
|
||||
*pucRegBuffer++ = ( UCHAR ) ( usRegHoldingBuf[iRegIndex] >> 8 );
|
||||
*pucRegBuffer++ = ( UCHAR ) ( usRegHoldingBuf[iRegIndex] & 0xFF );
|
||||
iRegIndex++;
|
||||
usNRegs--;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Update current register values with new values from the
|
||||
* protocol stack. */
|
||||
case MB_REG_WRITE:
|
||||
while( usNRegs > 0 )
|
||||
{
|
||||
usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
|
||||
usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
|
||||
iRegIndex++;
|
||||
usNRegs--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_ENOREG;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
|
||||
eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
|
||||
{
|
||||
return MB_ENOREG;
|
||||
}
|
||||
|
||||
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
|
||||
{
|
||||
return MB_ENOREG;
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
SRC_DIR := advantech beckhoff br delta mitsubishi omron schneider siemens ge xinje inovance keyence panasonic fatek
|
||||
SRC_DIR := advantech beckhoff br delta mitsubishi omron schneider siemens ge xinje inovance keyence panasonic fatek ab abb
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
SRC_FILES := ab_l30erm.c ab_micro850.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,91 @@
|
|||
# AB_850通信测试
|
||||
|
||||
[TOC]
|
||||
|
||||
## 通信接线及参数设置
|
||||
|
||||
* 网口
|
||||
|
||||
*Mosbus TCP协议,IP:192.168.250.56,Port:502
|
||||
|
||||
## 存储区
|
||||
|
||||
- 存储区D区
|
||||
|
||||
## JSON配方设计
|
||||
|
||||
* AB_850类型PLC需要配置控制器映射
|
||||
|
||||

|
||||
|
||||
* 共测试Word和real共2种类型数据,real型数据有2个Word组成,以下为JSON文件解释。
|
||||
|
||||
- ```json
|
||||
{
|
||||
"device_id": 1, //设备ID默认是1,此参数无效
|
||||
"device_name": "AB_850", //设备名称,自定义
|
||||
"communication_type": 0, //通讯协议类型 0是以太网,1是串口
|
||||
"socket_config": { //以太网配置
|
||||
"plc_ip": "192.168.250.56", //PLC的IP地址
|
||||
"local_ip": "192.168.250.233", //矽达通IP地址设定
|
||||
"gateway": "192.168.250.1", //矽达通的网关地址设定
|
||||
"netmask": "255.255.255.0", //矽达通子网掩码设定
|
||||
"port":502 //端口号设定
|
||||
},
|
||||
"protocol_type": 2, //通讯协议,2代表modbus-tcp协议
|
||||
"read_period": 100, //交互周期ms
|
||||
"read_item_list": [
|
||||
{
|
||||
"value_name": "CON_DATA[0]", //变量名称,自定义
|
||||
"value_type": 1, //变量类型,BOOL = 1,INT8 = 2,INT16,INT32,UINT8,UINT16,UINT32,DOUBLE,FLOAT = 9
|
||||
"function_code": 1, //功能码。1是读线圈
|
||||
"start_address": 0, //起始地址
|
||||
"data_length": 1 //默认是1,代表读取1个数据类型长度
|
||||
},
|
||||
{
|
||||
"value_name": "CON_DATA[1]", //变量名称,自定义
|
||||
"value_type": 1, //变量类型,BOOL = 1,INT8 = 2,INT16,INT32,UINT8,UINT16,UINT32,DOUBLE,FLOAT = 9
|
||||
"function_code": 1, //功能码。1是读
|
||||
"start_address": 1, //起始地址偏移1位106*8+1=849
|
||||
"data_length": 1 //默认是1,代表读取1个数据类型长度
|
||||
},
|
||||
{
|
||||
"value_name": "CON_INT", //变量名称,自定义
|
||||
"value_type": 3, //变量类型,BOOL = 1,INT8 = 2,INT16,INT32,UINT8,UINT16,UINT32,DOUBLE,FLOAT = 9
|
||||
"function_code": 3, //功能码。3是读
|
||||
"start_address": 2, //起始地址偏移2位
|
||||
"data_length": 1 //默认是1,代表读取1个数据类型长度
|
||||
},
|
||||
{
|
||||
"value_name": "CON_ARRAY[0]_1", //变量名称,自定义
|
||||
"value_type": 3, //变量类型,BOOL = 1,INT8 = 2,INT16,INT32,UINT8,UINT16,UINT32,DOUBLE,FLOAT = 9
|
||||
"function_code": 3, //功能码。3是读
|
||||
"start_address": 3, //起始地址偏移3位
|
||||
"data_length": 1 //默认是1,代表读取1个数据类型长度
|
||||
},
|
||||
{
|
||||
"value_name": "CON_ARRAY[0]_2", //变量名称,自定义,CON_ARRAY[0]_1和CON_ARRAY[0]_2组成real型数据
|
||||
"value_type": 3, //变量类型,BOOL = 1,INT8 = 2,INT16,INT32,UINT8,UINT16,UINT32,DOUBLE,FLOAT = 9
|
||||
"function_code": 3, //功能码。3是读
|
||||
"start_address": 4, //起始地址偏移4位
|
||||
"data_length": 1 //默认是1,代表读取1个数据类型长度
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 通信测试
|
||||
|
||||
(1) 新增1个通信demo,命名为ab_micro850.c;
|
||||
|
||||
(2) 复制modbus_tcp样例代码程序到ab_micro850.c文件中;
|
||||
|
||||
(3) void **ControlAB850Test**(void) 更改函数名;
|
||||
|
||||
(4) PRIV_SHELL_CMD_FUNCTION(**ControlAB850Test**, AB Plc micro850 Demo**, PRIV_SHELL_CMD_MAIN_ATTR);更改测试指令;
|
||||
|
||||
(5) 剪裁配置完成后,用过烧写器下载至矽数通中,重启后完成测试。
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
# AB_L30ERM通信测试
|
||||
|
||||
[TOC]
|
||||
|
||||
## 通信接线及参数设置
|
||||
|
||||
* 网口
|
||||
|
||||
*Ethernet/ip协议,IP:192.168.250.57,Port:44818
|
||||
|
||||
## 存储区
|
||||
|
||||
- Ethernet/ip协议是根据变量名称搜索寄存器地址
|
||||
|
||||
## JSON配方设计
|
||||
|
||||
* 本实例共测试Word和real共2种类型数据,以下为JSON文件解释。
|
||||
|
||||
- ```json
|
||||
{
|
||||
"device_id": “ab_l30”, //
|
||||
"device_name": "robot", //设备名称,自定义
|
||||
"communication_type": 0, //通讯协议类型 0是以太网,1是串口
|
||||
"socket_config": { //以太网配置
|
||||
"plc_ip": "192.168.250.37", //PLC的IP地址
|
||||
"local_ip": "192.168.250.123", //矽达通IP地址设定
|
||||
"gateway": "192.168.250.1", //矽达通的网关地址设定
|
||||
"netmask": "255.255.255.0", //矽达通子网掩码设定
|
||||
"port":502 //端口号设定
|
||||
},
|
||||
"protocol_type": 12, //通讯协议,12代表ethernet/ip协议
|
||||
"read_period": 100, //交互周期ms
|
||||
"read_item_list": [
|
||||
{
|
||||
"value_name": "L30_SPEED", //变量名称,自定义
|
||||
"value_type": 3, //变量类型,BOOL = 1,INT8 = 2,INT16,INT32,UINT8,UINT16,UINT32,DOUBLE,FLOAT = 9
|
||||
"wordlen": "WORD", //以WORD方式传输
|
||||
"amount": 1 //默认是1,代表读取1个数据类型长度
|
||||
},
|
||||
{
|
||||
"value_name": "L30_TORQUE", //变量名称,自定义
|
||||
"value_type": 9, //变量类型,BOOL = 1,INT8 = 2,INT16,INT32,UINT8,UINT16,UINT32,DOUBLE,FLOAT = 9
|
||||
"wordlen": 2, //以WORD方式传输
|
||||
"amount": 1 //默认是1,代表读取1个数据类型长度
|
||||
},
|
||||
{
|
||||
"value_name": "D", //变量名称,自定义
|
||||
"value_type": 3, //变量类型,BOOL = 1,INT8 = 2,INT16,INT32,UINT8,UINT16,UINT32,DOUBLE,FLOAT = 9
|
||||
"wordlen": 3, //以WORD方式传输
|
||||
"amount": 1 //默认是1,代表读取1个数据类型长度
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 通信测试
|
||||
|
||||
(1) 新增1个通信demo,命名为ab_l30erm.c;
|
||||
|
||||
(2) 复制modbus_tcp样例代码程序到ab_l30erm.c文件中;
|
||||
|
||||
(3) void **ControlABL30Test**(void) 更改函数名;
|
||||
|
||||
(4) PRIV_SHELL_CMD_FUNCTION(**ControlABL30Test**, AB Plc l30ermDemo**, PRIV_SHELL_CMD_MAIN_ATTR);更改测试指令;
|
||||
|
||||
(5) 剪裁配置完成后,用过烧写器下载至矽数通中,重启后完成测试。
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2022 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ab_l30.c
|
||||
* @brief PLC ABB L30 app
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.8.27
|
||||
*/
|
||||
|
||||
#include <control.h>
|
||||
|
||||
void ControlABL30Test(void)
|
||||
{
|
||||
int i = 0;
|
||||
uint16_t read_data_length = 0;
|
||||
uint8_t read_data[1024] = {0};
|
||||
ControlProtocolType CIP_protocol = ControlProtocolFind();
|
||||
if (NULL == CIP_protocol) {
|
||||
printf("%s get CIP protocol %p failed\n", __func__, CIP_protocol);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("%s get CIP protocol %p successfull\n", __func__, CIP_protocol);
|
||||
if (CONTROL_REGISTERED == CIP_protocol->protocol_status) {
|
||||
ControlProtocolOpen(CIP_protocol);
|
||||
|
||||
for (;;) {
|
||||
read_data_length = ControlProtocolRead(CIP_protocol, read_data, sizeof(read_data));
|
||||
printf("%s read [%d] CIP data %d using receipe file\n", __func__, i, read_data_length);
|
||||
i++;
|
||||
PrivTaskDelay(1000);
|
||||
}
|
||||
|
||||
//ControlProtocolClose(CIP_protocol);
|
||||
}
|
||||
}
|
||||
PRIV_SHELL_CMD_FUNCTION(ControlABL30Test, Ab Plc CIP Demo, PRIV_SHELL_CMD_MAIN_ATTR);
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2022 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ab_micro850.c
|
||||
* @brief PLC AB MICRO850 app
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.10.5
|
||||
*/
|
||||
|
||||
#include <control.h>
|
||||
|
||||
void ControlAB850Test(void)
|
||||
{
|
||||
int i, j = 0;
|
||||
int read_data_length = 0;
|
||||
uint8_t read_data[128] = {0};
|
||||
ControlProtocolType modbus_tcp_protocol = ControlProtocolFind();
|
||||
if (NULL == modbus_tcp_protocol) {
|
||||
printf("%s get modbus tcp protocol %p failed\n", __func__, modbus_tcp_protocol);
|
||||
return;
|
||||
}
|
||||
printf("%s get modbus tcp protocol %p successfull\n", __func__, modbus_tcp_protocol);
|
||||
|
||||
if (CONTROL_REGISTERED == modbus_tcp_protocol->protocol_status) {
|
||||
ControlProtocolOpen(modbus_tcp_protocol);
|
||||
for (;;) {
|
||||
read_data_length = ControlProtocolRead(modbus_tcp_protocol, read_data, sizeof(read_data));
|
||||
printf("%s read [%d] modbus tcp data %d using receipe file\n", __func__, i, read_data_length);
|
||||
if (read_data_length) {
|
||||
for (j = 0; j < read_data_length; j ++) {
|
||||
printf("j %d data 0x%x\n", j, read_data[j]);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
memset(read_data, 0, sizeof(read_data));
|
||||
PrivTaskDelay(10000);
|
||||
}
|
||||
//ControlProtocolClose(modbus_tcp_protocol);
|
||||
}
|
||||
}
|
||||
PRIV_SHELL_CMD_FUNCTION(ControlAB850Test, AB Plc MICRO850 Demo, PRIV_SHELL_CMD_MAIN_ATTR);
|
Binary file not shown.
After Width: | Height: | Size: 2.3 MiB |
Binary file not shown.
After Width: | Height: | Size: 2.6 MiB |
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"device_id": "ab_l30",
|
||||
"device_name": "robot",
|
||||
"communication_type": 0,
|
||||
"socket_config": {
|
||||
"plc_ip": "192.168.250.57",
|
||||
"local_ip": "192.168.250.123",
|
||||
"gateway": "192.168.250.1",
|
||||
"netmask": "255.255.255.0",
|
||||
"port": 44818
|
||||
},
|
||||
"protocol_type": 12,
|
||||
"read_period": 100,
|
||||
"read_item_list": [
|
||||
{
|
||||
"value_name": "L30_SPEED",
|
||||
"value_type": 3,
|
||||
"wordlen": "WORD",
|
||||
"amount": 1
|
||||
},
|
||||
{
|
||||
"value_name": "L30_TORQUE",
|
||||
"value_type": 9,
|
||||
"wordlen": "WORD",
|
||||
"amount": 1
|
||||
},
|
||||
{
|
||||
"value_name": "D",
|
||||
"value_type": 3,
|
||||
"wordlen": "WORD",
|
||||
"amount": 1
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"device_id": 1,
|
||||
"device_name": "AB_850",
|
||||
"communication_type": 0,
|
||||
"socket_config": {
|
||||
"plc_ip": "192.168.250.32",
|
||||
"local_ip": "192.168.250.56",
|
||||
"gateway": "192.168.250.1",
|
||||
"netmask": "255.255.255.0",
|
||||
"port": 502
|
||||
},
|
||||
"protocol_type": 2,
|
||||
"read_period": 100,
|
||||
"read_item_list": [
|
||||
{
|
||||
"value_name": "D106.0",
|
||||
"value_type": 1,
|
||||
"function_code": 1,
|
||||
"start_address": 848,
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"value_name": "D106.1",
|
||||
"value_type": 1,
|
||||
"function_code": 1,
|
||||
"start_address":849,
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"value_name": "D100",
|
||||
"value_type": 3,
|
||||
"function_code": 3,
|
||||
"start_address": 100,
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"value_name": "D102",
|
||||
"value_type": 3,
|
||||
"function_code": 3,
|
||||
"start_address": 102,
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"value_name": "D103",
|
||||
"value_type": 3,
|
||||
"function_code": 3,
|
||||
"start_address": 103,
|
||||
"quantity": 1
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
SRC_FILES := abb_pm5630.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,87 @@
|
|||
# ABB通信测试
|
||||
|
||||
[TOC]
|
||||
|
||||
## 通信接线及参数设置
|
||||
|
||||
* 网口
|
||||
|
||||
*Mosbus TCP协议,IP:192.168.250.58,Port:502
|
||||
|
||||
## 存储区
|
||||
|
||||
- 存储区MW区
|
||||
|
||||
## JSON配方设计
|
||||
|
||||
* 共测试Word和real共2种类型数据,real型数据有2个Word组成,以下为JSON文件解释。
|
||||
|
||||
- ```json
|
||||
{
|
||||
"device_id": 1, //设备ID默认是1,此参数无效
|
||||
"device_name": "ABB_PM5630", //设备名称,自定义
|
||||
"communication_type": 0, //通讯协议类型 0是以太网,1是串口
|
||||
"socket_config": { //以太网配置
|
||||
"plc_ip": "192.168.250.58", //PLC的IP地址
|
||||
"local_ip": "192.168.250.233", //矽达通IP地址设定
|
||||
"gateway": "192.168.250.1", //矽达通的网关地址设定
|
||||
"netmask": "255.255.255.0", //矽达通子网掩码设定
|
||||
"port":502 //端口号设定
|
||||
},
|
||||
"protocol_type": 2, //通讯协议,2代表modbus-tcp协议
|
||||
"read_period": 100, //交互周期ms
|
||||
"read_item_list": [
|
||||
{
|
||||
"value_name": "MW0", //变量名称,自定义
|
||||
"value_type": 3, //变量类型,BOOL = 1,INT8 = 2,INT16,INT32,UINT8,UINT16,UINT32,DOUBLE,FLOAT = 9
|
||||
"function_code": 3, //功能码。3是读
|
||||
"start_address": 0, //起始地址
|
||||
"data_length": 1 //默认是1,代表读取1个数据类型长度
|
||||
},
|
||||
{
|
||||
"value_name": "MW1", //变量名称,自定义
|
||||
"value_type": 3, //变量类型,BOOL = 1,INT8 = 2,INT16,INT32,UINT8,UINT16,UINT32,DOUBLE,FLOAT = 9
|
||||
"function_code": 3, //功能码。3是读
|
||||
"start_address": 1, //起始地址偏移1位
|
||||
"data_length": 1 //默认是1,代表读取1个数据类型长度
|
||||
},
|
||||
{
|
||||
"value_name": "MW10", //变量名称,自定义
|
||||
"value_type": 3, //变量类型,BOOL = 1,INT8 = 2,INT16,INT32,UINT8,UINT16,UINT32,DOUBLE,FLOAT = 9
|
||||
"function_code": 3, //功能码。3是读
|
||||
"start_address": 10, //起始地址偏移10位
|
||||
"data_length": 1 //默认是1,代表读取1个数据类型长度
|
||||
},
|
||||
{
|
||||
"value_name": "MD20_1", //变量名称,自定义
|
||||
"value_type": 3, //变量类型,BOOL = 1,INT8 = 2,INT16,INT32,UINT8,UINT16,UINT32,DOUBLE,FLOAT = 9
|
||||
"function_code": 3, //功能码。3是读
|
||||
"start_address": 20, //起始地址偏移20位
|
||||
"data_length": 1 //默认是1,代表读取1个数据类型长度
|
||||
},
|
||||
{
|
||||
"value_name": "MD20_2", //变量名称,自定义,MD20_1和MD20_2组成real型数据
|
||||
"value_type": 3, //变量类型,BOOL = 1,INT8 = 2,INT16,INT32,UINT8,UINT16,UINT32,DOUBLE,FLOAT = 9
|
||||
"function_code": 3, //功能码。3是读
|
||||
"start_address": 21, //起始地址偏移21位
|
||||
"data_length": 1 //默认是1,代表读取1个数据类型长度
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 通信测试
|
||||
|
||||
(1) 新增1个通信demo,命名为abb_pm5630.c;
|
||||
|
||||
(2) 复制modbus_tcp样例代码程序到abb_pm5630.c文件中;
|
||||
|
||||
(3) void **ControlABBPM5630Test**(void) 更改函数名;
|
||||
|
||||
(4) PRIV_SHELL_CMD_FUNCTION(**ControlABBPM5630Test**, ABB Plc PM5630 Demo**, PRIV_SHELL_CMD_MAIN_ATTR);更改测试指令;
|
||||
|
||||
(5) 剪裁配置完成后,用过烧写器下载至矽数通中,重启后完成测试。
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2022 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file abb_pm5630.c
|
||||
* @brief PLC ABB pm5630 app
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.10.20
|
||||
*/
|
||||
|
||||
#include <control.h>
|
||||
|
||||
void ControlABBPM5630Test(void)
|
||||
{
|
||||
int i, j = 0;
|
||||
int read_data_length = 0;
|
||||
uint8_t read_data[128] = {0};
|
||||
ControlProtocolType modbus_tcp_protocol = ControlProtocolFind();
|
||||
if (NULL == modbus_tcp_protocol) {
|
||||
printf("%s get modbus tcp protocol %p failed\n", __func__, modbus_tcp_protocol);
|
||||
return;
|
||||
}
|
||||
printf("%s get modbus tcp protocol %p successfull\n", __func__, modbus_tcp_protocol);
|
||||
|
||||
if (CONTROL_REGISTERED == modbus_tcp_protocol->protocol_status) {
|
||||
ControlProtocolOpen(modbus_tcp_protocol);
|
||||
for (;;) {
|
||||
read_data_length = ControlProtocolRead(modbus_tcp_protocol, read_data, sizeof(read_data));
|
||||
printf("%s read [%d] modbus tcp data %d using receipe file\n", __func__, i, read_data_length);
|
||||
if (read_data_length) {
|
||||
for (j = 0; j < read_data_length; j ++) {
|
||||
printf("j %d data 0x%x\n", j, read_data[j]);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
memset(read_data, 0, sizeof(read_data));
|
||||
PrivTaskDelay(10000);
|
||||
}
|
||||
//ControlProtocolClose(modbus_tcp_protocol);
|
||||
}
|
||||
}
|
||||
PRIV_SHELL_CMD_FUNCTION(ControlABBPM5630Test, ABB Plc PM5630 Demo, PRIV_SHELL_CMD_MAIN_ATTR);
|
Binary file not shown.
After Width: | Height: | Size: 2.7 MiB |
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"device_id": 1,
|
||||
"device_name": "ABB_PM5630",
|
||||
"communication_type": 0,
|
||||
"socket_config": {
|
||||
"plc_ip": "192.168.250.32",
|
||||
"local_ip": "192.168.250.58",
|
||||
"gateway": "192.168.250.1",
|
||||
"netmask": "255.255.255.0",
|
||||
"port": 502
|
||||
},
|
||||
"protocol_type": 2,
|
||||
"read_period": 100,
|
||||
"read_item_list": [
|
||||
{
|
||||
"value_name": "MW0",
|
||||
"value_type": 3,
|
||||
"function_code": 3,
|
||||
"start_address": 0,
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"value_name": "MW1",
|
||||
"value_type": 3,
|
||||
"function_code": 3,
|
||||
"start_address":1,
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"value_name": "MW10",
|
||||
"value_type": 3,
|
||||
"function_code": 3,
|
||||
"start_address": 10,
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"value_name": "MD20_1",
|
||||
"value_type": 3,
|
||||
"function_code": 3,
|
||||
"start_address":20,
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"value_name": "MD20_2",
|
||||
"value_type": 3,
|
||||
"function_code": 3,
|
||||
"start_address":21,
|
||||
"quantity": 1
|
||||
}
|
||||
]
|
||||
}
|
|
@ -22,9 +22,13 @@ extern void ApplicationOtaTaskInit(void);
|
|||
extern int OtaTask(void);
|
||||
#endif
|
||||
|
||||
#ifdef APPLICATION_WEBSERVER
|
||||
extern int webserver(void);
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("Hello, world! \n");
|
||||
printf("\nHello, world!\n");
|
||||
FrameworkInit();
|
||||
#ifdef APPLICATION_OTA
|
||||
ApplicationOtaTaskInit();
|
||||
|
@ -33,6 +37,11 @@ int main(void)
|
|||
#ifdef OTA_BY_PLATFORM
|
||||
OtaTask();
|
||||
#endif
|
||||
|
||||
#ifdef APPLICATION_WEBSERVER
|
||||
webserver();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
// int cppmain(void);
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
menuconfig APPLICATION_WEBSERVER
|
||||
bool "Application webserver using mongoose"
|
||||
default n
|
||||
|
||||
if APPLICATION_WEBSERVER
|
||||
choice
|
||||
prompt "choose board for webserver"
|
||||
default APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
|
||||
config APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
bool "board select xishutong-4g, support dual ethernet port and 4G"
|
||||
select BSP_USING_SDIO
|
||||
select BSP_USING_W5500
|
||||
select BSP_USING_ETHERNET
|
||||
select SUPPORT_CONNECTION_FRAMEWORK
|
||||
select CONNECTION_ADAPTER_4G
|
||||
select ADAPTER_EC200A
|
||||
select LIB_USING_LORAWAN
|
||||
select LIB_USING_LORA_RADIO
|
||||
|
||||
config APPLICATION_WEBSERVER_XISHUTONG
|
||||
bool "board select xishutong, support single ethernet port"
|
||||
select BSP_USING_SDIO
|
||||
select BSP_USING_LWIP
|
||||
select LIB_USING_LORAWAN
|
||||
select LIB_USING_LORA_RADIO
|
||||
endchoice
|
||||
endif
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
SRC_FILES += webserver_project.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1 @@
|
|||
mongoose.a基于工具链arm-none-eabi-gcc (15:6.3.1+svn253039-1build1) 6.3.1 20170620编译而来,若使用的arm工具链版本存在差异或使用的是RISC-V工具链,则需重新编译mongoose.a,避免遇到异常问题。
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,929 @@
|
|||
// Copyright (c) 2022 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// UI example
|
||||
// It implements the following endpoints:
|
||||
// /api/config/get - respond with current config
|
||||
// /api/config/set - POST a config change
|
||||
// any other URI serves static files from s_root_dir
|
||||
// Data and results are JSON strings
|
||||
|
||||
/**
|
||||
* @file webserver_project.c
|
||||
* @brief support webserver_project for XiUOS
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023-11-07
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: webserver_project.c
|
||||
Description: support webserver_project for XiUOS
|
||||
Others:
|
||||
History:
|
||||
1. Date: 2023-11-07
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1、support xishutong-arm32 board, using W5500 to support webserver.
|
||||
|
||||
2. Date: 2024-1-3
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1、support xishutong board(single ethernet port), using MAC to support webserver
|
||||
*************************************************/
|
||||
|
||||
|
||||
#include "ip_addr.h"
|
||||
#include "mongoose.h"
|
||||
#include "netdev.h"
|
||||
#include <sys_arch.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include "lwip/sys.h"
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
#include <adapter.h>
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Local variable definitions ('static')
|
||||
******************************************************************************/
|
||||
char index_path[] = "login.html";
|
||||
|
||||
static const char* s_http_addr = "http://192.168.131.88:8000"; // HTTP port
|
||||
static const char* s_root_dir = "webserver";
|
||||
static const char* s_enable_hexdump = "no";
|
||||
static const char* s_ssi_pattern = "#.html";
|
||||
static const char* web_version = "XiUOS WebServer 1.0";
|
||||
|
||||
static const char* net_carrier_china_mobile = "中国移动";
|
||||
static const char* net_carrier_china_unicom = "中国联通";
|
||||
static const char* net_carrier_china_telecom = "中国电信";
|
||||
|
||||
static struct netdev* p_netdev_webserver;
|
||||
static struct netdev* p_netdev_ethernet;
|
||||
static pthread_t tid;
|
||||
|
||||
#define WB_EVENT_TASK_STACK_SIZE 4096
|
||||
#define WB_EVENT_TASK_PRIO 20
|
||||
|
||||
#define WB_4G_CONNECT 0x0001
|
||||
#define WB_4G_DISCONNECT 0x0002
|
||||
#define WB_MQTT_CONNECT 0x0004
|
||||
#define WB_MQTT_DISCONNECT 0x0008
|
||||
#define WB_LORA_CONNECT 0x0010
|
||||
#define WB_LORA_DISCONNECT 0x0020
|
||||
#define WB_ETHERNET_CONNECT 0x0040
|
||||
#define WB_ETHERNET_DISCONNECT 0x0080
|
||||
#define WB_EVENT_ALL (WB_4G_CONNECT | WB_4G_DISCONNECT | \
|
||||
WB_MQTT_CONNECT | WB_MQTT_DISCONNECT | \
|
||||
WB_LORA_CONNECT | WB_LORA_DISCONNECT | \
|
||||
WB_ETHERNET_CONNECT | WB_ETHERNET_DISCONNECT)
|
||||
|
||||
static int wb_event;
|
||||
static unsigned int status = 0;
|
||||
static pthread_t wb_event_task;
|
||||
|
||||
enum ModulesType
|
||||
{
|
||||
MODULES_NULL = 0, // null
|
||||
MODULES_4G, // support 4G modules
|
||||
MODULES_LORA, // support LoRa modules
|
||||
MODULES_ALL, //all
|
||||
};
|
||||
|
||||
/*define device info*/
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
static const char* device_name = "矽数通4G";
|
||||
static const char* device_type = "xishutong-arm32";
|
||||
static const char* device_serial_num = "123456789";
|
||||
static int support_module = MODULES_ALL;
|
||||
#endif
|
||||
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG
|
||||
static const char* device_name = "矽数通";
|
||||
static const char* device_type = "xishutong-arm32";
|
||||
static const char* device_serial_num = "123456789";
|
||||
static int support_module = MODULES_LORA;
|
||||
#endif
|
||||
|
||||
/*define webserver info*/
|
||||
static struct webserver_config {
|
||||
char *ip, *mask, *gw, *dns;
|
||||
} webserver_config;
|
||||
|
||||
/*define interface info*/
|
||||
static struct rs485_config {
|
||||
int baud_rate;
|
||||
int data_bit;
|
||||
int stop_bit;
|
||||
int parity;
|
||||
} rs485_config;
|
||||
int rs485_uart_fd = -1;
|
||||
|
||||
#define RS485_DEVICE_PATH "/dev/usart4_dev4"
|
||||
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
/*define net 4G info*/
|
||||
static struct net_4g_info {
|
||||
char map_ip[20];
|
||||
char connect_ip[40];
|
||||
char operator[20];
|
||||
char signal_strength[20];
|
||||
char connect_port[20];
|
||||
|
||||
int net_4g_init_flag;
|
||||
int connect_status;
|
||||
} net_4g_info;
|
||||
|
||||
struct Adapter* adapter;
|
||||
|
||||
static struct net_4g_mqtt_info {
|
||||
char topic[40];
|
||||
char username[40];
|
||||
char password[40];
|
||||
char client_id[40];
|
||||
int connect_status;
|
||||
} net_4g_mqtt_info;
|
||||
#endif
|
||||
|
||||
/*define net LoRa info*/
|
||||
struct net_lora_info
|
||||
{
|
||||
uint32_t frequency; // frequency
|
||||
uint8_t sf; // spreadfactor
|
||||
uint8_t bw; // bandwidth
|
||||
|
||||
uint32_t connect_status; //connect status
|
||||
uint8_t lora_init_flag; //if 1 means already init
|
||||
} net_lora_info;
|
||||
|
||||
/*define net Ethernet info*/
|
||||
static struct net_ethernet_info {
|
||||
char ethernetIp[20];
|
||||
char ethernetNetmask[20];
|
||||
char ethernetGateway[20];
|
||||
char ethernetDNS[20];
|
||||
char targetIp[20];
|
||||
char targetPort[20];
|
||||
char targetGateway[20];
|
||||
char targetDNS[20];
|
||||
int connect_status;
|
||||
} net_ethernet_info;
|
||||
|
||||
static int socket_fd = -1;
|
||||
|
||||
static char tcp_ethernet_ipaddr[] = {192, 168, 130, 77};
|
||||
static char tcp_ethernet_netmask[] = {255, 255, 254, 0};
|
||||
static char tcp_ethernet_gwaddr[] = {192, 168, 130, 1};
|
||||
|
||||
static uint16_t tcp_socket_port = 8888;
|
||||
|
||||
/*define PLC info*/
|
||||
static char *plc_json;
|
||||
#define JSON_FILE_NAME "test_recipe.json"
|
||||
|
||||
/*******************************************************************************
|
||||
* Function implementation - judge using 4G modules or LoRa modules
|
||||
******************************************************************************/
|
||||
static int JudgeModulesType(void)
|
||||
{
|
||||
int ret;
|
||||
int retry = 5;
|
||||
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
extern int TestLoraRadio(int argc, char *argv[]);
|
||||
char* check_params[2] = {"TestLoraRadio", "check"};
|
||||
do {
|
||||
ret = TestLoraRadio(2, check_params);
|
||||
if (ret > 0) {
|
||||
retry = 0;
|
||||
support_module = MODULES_LORA;
|
||||
} else {
|
||||
retry--;
|
||||
}
|
||||
} while (retry > 0);
|
||||
#endif
|
||||
|
||||
return support_module;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Function implementation - define interface info
|
||||
******************************************************************************/
|
||||
static void Rs485InitConfigure(void)
|
||||
{
|
||||
rs485_uart_fd = PrivOpen(RS485_DEVICE_PATH, O_RDWR);
|
||||
if (rs485_uart_fd < 0) {
|
||||
printf("open rs485 %s fd error:%d\n", RS485_DEVICE_PATH, rs485_uart_fd);
|
||||
return;
|
||||
}
|
||||
printf("uart %s open success\n", RS485_DEVICE_PATH);
|
||||
|
||||
struct SerialDataCfg uart_cfg;
|
||||
memset(&uart_cfg, 0, sizeof(struct SerialDataCfg));
|
||||
|
||||
rs485_config.baud_rate = BAUD_RATE_115200;
|
||||
rs485_config.data_bit = DATA_BITS_8;
|
||||
rs485_config.stop_bit = STOP_BITS_1;
|
||||
rs485_config.parity = PARITY_NONE;
|
||||
|
||||
uart_cfg.serial_baud_rate = rs485_config.baud_rate;
|
||||
uart_cfg.serial_data_bits = rs485_config.data_bit;
|
||||
uart_cfg.serial_stop_bits = rs485_config.stop_bit;
|
||||
uart_cfg.serial_parity_mode = rs485_config.parity;
|
||||
uart_cfg.serial_bit_order = BIT_ORDER_LSB;
|
||||
uart_cfg.serial_invert_mode = NRZ_NORMAL;
|
||||
uart_cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
|
||||
uart_cfg.serial_timeout = -1;
|
||||
uart_cfg.is_ext_uart = 0;
|
||||
uart_cfg.dev_recv_callback = NULL;
|
||||
|
||||
struct PrivIoctlCfg ioctl_cfg;
|
||||
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
|
||||
ioctl_cfg.args = (void *)&uart_cfg;
|
||||
|
||||
if (0 != PrivIoctl(rs485_uart_fd, OPE_INT, &ioctl_cfg)) {
|
||||
printf("ioctl uart fd error %d\n", rs485_uart_fd);
|
||||
PrivClose(rs485_uart_fd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void Rs485Configure(int baud_rate, int data_bit, int stop_bit, int parity)
|
||||
{
|
||||
if (rs485_uart_fd < 0) {
|
||||
rs485_uart_fd = PrivOpen(RS485_DEVICE_PATH, O_RDWR);
|
||||
if (rs485_uart_fd < 0) {
|
||||
printf("open rs485 %s fd error:%d\n", RS485_DEVICE_PATH, rs485_uart_fd);
|
||||
return;
|
||||
}
|
||||
printf("uart %s open success\n", RS485_DEVICE_PATH);
|
||||
}
|
||||
|
||||
struct SerialDataCfg uart_cfg;
|
||||
memset(&uart_cfg, 0, sizeof(struct SerialDataCfg));
|
||||
|
||||
uart_cfg.serial_baud_rate = baud_rate;
|
||||
uart_cfg.serial_data_bits = data_bit;
|
||||
uart_cfg.serial_stop_bits = stop_bit;
|
||||
uart_cfg.serial_parity_mode = parity;
|
||||
uart_cfg.serial_bit_order = BIT_ORDER_LSB;
|
||||
uart_cfg.serial_invert_mode = NRZ_NORMAL;
|
||||
uart_cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
|
||||
uart_cfg.serial_timeout = -1;
|
||||
uart_cfg.is_ext_uart = 0;
|
||||
uart_cfg.dev_recv_callback = NULL;
|
||||
|
||||
struct PrivIoctlCfg ioctl_cfg;
|
||||
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
|
||||
ioctl_cfg.args = (void *)&uart_cfg;
|
||||
|
||||
if (0 != PrivIoctl(rs485_uart_fd, OPE_INT, &ioctl_cfg)) {
|
||||
printf("ioctl uart fd error %d\n", rs485_uart_fd);
|
||||
PrivClose(rs485_uart_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Board RS485 changed to [br: %d, data: %d, stop: %d, party: %d]\n",
|
||||
baud_rate, data_bit, stop_bit, parity);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Function implementation - define net 4G info
|
||||
******************************************************************************/
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
static void Net4gGetInfo(char *ip, char *operator, char *signal_strength)
|
||||
{
|
||||
if (net_4g_info.net_4g_init_flag) {
|
||||
strcpy(ip, adapter->network_info.ip_address);
|
||||
sprintf(signal_strength, "%d", adapter->network_info.signal_strength);
|
||||
|
||||
switch (adapter->network_info.carrier_type)
|
||||
{
|
||||
case CARRIER_CHINA_MOBILE:
|
||||
strcpy(operator, net_carrier_china_mobile);
|
||||
break;
|
||||
case CARRIER_CHINA_UNICOM:
|
||||
strcpy(operator, net_carrier_china_unicom);
|
||||
break;
|
||||
case CARRIER_CHINA_TELECOM:
|
||||
strcpy(operator, net_carrier_china_telecom);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Net4gConnect(void)
|
||||
{
|
||||
int ret = -1;
|
||||
int ec200a_baud_rate;
|
||||
const char *send_msg = "Adapter_4G Test";
|
||||
|
||||
if (0 == net_4g_info.net_4g_init_flag) {
|
||||
adapter->socket.socket_id = 0;
|
||||
ec200a_baud_rate = 115200;
|
||||
AdapterDeviceOpen(adapter);
|
||||
AdapterDeviceControl(adapter, OPE_INT, &ec200a_baud_rate);
|
||||
AdapterDeviceNetstat(adapter);
|
||||
net_4g_info.net_4g_init_flag = 1;
|
||||
}
|
||||
|
||||
if (1 == net_4g_mqtt_info.connect_status) {
|
||||
AdapterDeviceMqttDisconnect(adapter);
|
||||
net_4g_mqtt_info.connect_status = 0;
|
||||
}
|
||||
|
||||
if (0 == net_4g_info.connect_status) {
|
||||
ret = AdapterDeviceConnect(adapter, CLIENT, net_4g_info.connect_ip, net_4g_info.connect_port, IPV4);
|
||||
if (ret < 0) {
|
||||
net_4g_info.connect_status = 0;
|
||||
printf("webserver %s fail\n", __func__);
|
||||
} else {
|
||||
net_4g_info.connect_status = 1;
|
||||
AdapterDeviceSend(adapter, send_msg, strlen(send_msg));
|
||||
printf("webserver %s success\n", __func__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Net4gDisconnect(void)
|
||||
{
|
||||
if (1 == net_4g_info.connect_status) {
|
||||
uint8_t priv_net_group = IP_PROTOCOL;
|
||||
AdapterDeviceDisconnect(adapter, &priv_net_group);
|
||||
net_4g_info.connect_status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Function implementation - define net 4G MQTT info
|
||||
******************************************************************************/
|
||||
static void NetMqttConnect(void)
|
||||
{
|
||||
int ret = -1;
|
||||
int ec200a_baud_rate = 0;
|
||||
|
||||
//for test
|
||||
const char *send_msg = "Adapter_4G MQTT Test";
|
||||
char recv_msg[256] = {0};
|
||||
int send_cnt = 1;
|
||||
|
||||
if (0 == net_4g_info.net_4g_init_flag) {
|
||||
adapter->socket.socket_id = 0;
|
||||
ec200a_baud_rate = 115200;
|
||||
AdapterDeviceOpen(adapter);
|
||||
AdapterDeviceControl(adapter, OPE_INT, &ec200a_baud_rate);
|
||||
AdapterDeviceNetstat(adapter);
|
||||
net_4g_info.net_4g_init_flag = 1;
|
||||
}
|
||||
|
||||
if (1 == net_4g_info.connect_status) {
|
||||
uint8_t priv_net_group = IP_PROTOCOL;
|
||||
AdapterDeviceDisconnect(adapter, &priv_net_group);
|
||||
net_4g_info.connect_status = 0;
|
||||
}
|
||||
|
||||
if (0 == net_4g_mqtt_info.connect_status) {
|
||||
ret = AdapterDeviceMqttConnect(adapter, net_4g_info.connect_ip, net_4g_info.connect_port,
|
||||
net_4g_mqtt_info.client_id, net_4g_mqtt_info.username, net_4g_mqtt_info.password);
|
||||
if (ret < 0) {
|
||||
net_4g_mqtt_info.connect_status = 0;
|
||||
printf("webserver %s fail\n", __func__);
|
||||
} else {
|
||||
net_4g_mqtt_info.connect_status = 1;
|
||||
|
||||
//for test
|
||||
while (send_cnt < 11) {
|
||||
AdapterDeviceMqttSend(adapter, net_4g_mqtt_info.topic, send_msg, strlen(send_msg));
|
||||
AdapterDeviceMqttRecv(adapter, net_4g_mqtt_info.topic, recv_msg, sizeof(recv_msg));
|
||||
printf("[%d]4G mqtt test recv msg %s\n", send_cnt, recv_msg);
|
||||
send_cnt++;
|
||||
}
|
||||
|
||||
printf("webserver %s success\n", __func__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void NetMqttDisconnect(void)
|
||||
{
|
||||
if (1 == net_4g_mqtt_info.connect_status) {
|
||||
AdapterDeviceMqttDisconnect(adapter);
|
||||
net_4g_mqtt_info.connect_status = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Function implementation - define net LoRa info
|
||||
******************************************************************************/
|
||||
static void NetLoraConnect(void)
|
||||
{
|
||||
if (MODULES_LORA == support_module) {
|
||||
char* tx_params[5] = {"TestLoraRadio", "tx", "1", "2000", "2"};
|
||||
extern int TestLoraRadio(int argc, char *argv[]);
|
||||
|
||||
if (0 == net_lora_info.lora_init_flag) {
|
||||
net_lora_info.lora_init_flag = 1;
|
||||
}
|
||||
|
||||
TestLoraRadio(5, tx_params);
|
||||
net_lora_info.connect_status = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void NetLoraDisconnect(void)
|
||||
{
|
||||
if (MODULES_LORA == support_module) {
|
||||
net_lora_info.connect_status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Function implementation - define net Ethernet info
|
||||
******************************************************************************/
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
static void TcpClientConnect(void)
|
||||
{
|
||||
int cnt = 20;
|
||||
int ret;
|
||||
char send_msg[128];
|
||||
|
||||
sscanf(net_ethernet_info.targetPort, "%d", &tcp_socket_port);
|
||||
|
||||
memset(send_msg, 0, sizeof(send_msg));
|
||||
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (socket_fd < 0) {
|
||||
printf("Socket error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_in tcp_sock;
|
||||
tcp_sock.sin_family = AF_INET;
|
||||
tcp_sock.sin_port = htons(tcp_socket_port);
|
||||
tcp_sock.sin_addr.s_addr = inet_addr(net_ethernet_info.targetIp);
|
||||
|
||||
memset(&(tcp_sock.sin_zero), 0, sizeof(tcp_sock.sin_zero));
|
||||
|
||||
int keepalive = 1;
|
||||
int keepidle = 30;
|
||||
int keepinterval = 5;
|
||||
int keepcount = 5;
|
||||
setsockopt(socket_fd,
|
||||
IPPROTO_TCP, /* set option at TCP level */
|
||||
TCP_KEEPALIVE, /* name of option */
|
||||
(void*)&keepalive, /* the cast is historical cruft */
|
||||
sizeof(keepalive)); /* length of option value */
|
||||
|
||||
setsockopt(socket_fd,
|
||||
IPPROTO_TCP, /* set option at TCP level */
|
||||
TCP_KEEPIDLE, /* name of option */
|
||||
(void*)&keepidle, /* the cast is historical cruft */
|
||||
sizeof(keepidle)); /* length of option value */
|
||||
|
||||
setsockopt(socket_fd,
|
||||
IPPROTO_TCP, /* set option at TCP level */
|
||||
TCP_KEEPINTVL, /* name of option */
|
||||
(void*)&keepinterval, /* the cast is historical cruft */
|
||||
sizeof(keepinterval)); /* length of option value */
|
||||
|
||||
setsockopt(socket_fd,
|
||||
IPPROTO_TCP, /* set option at TCP level */
|
||||
TCP_KEEPCNT, /* name of option */
|
||||
(void*)&keepcount, /* the cast is historical cruft */
|
||||
sizeof(keepcount)); /* length of option value */
|
||||
|
||||
ret = connect(socket_fd, (struct sockaddr *)&tcp_sock, sizeof(struct sockaddr));
|
||||
if (ret < 0) {
|
||||
printf("Unable to connect %s:%d = %d\n", net_ethernet_info.targetIp, tcp_socket_port, ret);
|
||||
closesocket(socket_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("TCP connect %s:%d success, start to send.\n", net_ethernet_info.targetIp, tcp_socket_port);
|
||||
net_ethernet_info.connect_status = 1;
|
||||
|
||||
while (cnt --) {
|
||||
printf("Lwip client is running.\n");
|
||||
snprintf(send_msg, sizeof(send_msg), "TCP test package times %d\r\n", cnt);
|
||||
send(socket_fd, send_msg, strlen(send_msg), 0);
|
||||
printf("Send tcp msg: %s ", send_msg);
|
||||
PrivTaskDelay(1000);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void TcpClientDisconnect(void)
|
||||
{
|
||||
printf("TCP disconnect\n");
|
||||
closesocket(socket_fd);
|
||||
net_ethernet_info.connect_status = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Function implementation - define plc info
|
||||
******************************************************************************/
|
||||
static void PlcInfoWriteToSd(const char *json)
|
||||
{
|
||||
extern int GetSdMountStatus(void);
|
||||
if(GetSdMountStatus()) {
|
||||
KPrintf("------Start download json file !------\r\n");
|
||||
|
||||
FILE *fp = fopen(JSON_FILE_NAME, "w");
|
||||
if(fp == NULL) {
|
||||
printf("%s file create failed,please check!\r\n", JSON_FILE_NAME);
|
||||
} else {
|
||||
printf("%s file create success!\r\n", JSON_FILE_NAME);
|
||||
fprintf(fp, "%s", json);
|
||||
fclose(fp);
|
||||
}
|
||||
printf("------download %s file done!------\r\n", JSON_FILE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Function implementation - WebserverEventTask
|
||||
******************************************************************************/
|
||||
static void *WebserverEventTask(void *arg)
|
||||
{
|
||||
wb_event = PrivEventCreate(LINKLIST_FLAG_FIFO);
|
||||
while(1) {
|
||||
if (0 == PrivEventProcess(wb_event, WB_EVENT_ALL, EVENT_OR | EVENT_AUTOCLEAN, 0, &status)) {
|
||||
switch( status ) {
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
case WB_4G_CONNECT:
|
||||
Net4gConnect();
|
||||
break;
|
||||
case WB_4G_DISCONNECT:
|
||||
Net4gDisconnect();
|
||||
break;
|
||||
case WB_MQTT_CONNECT:
|
||||
NetMqttConnect();
|
||||
break;
|
||||
case WB_MQTT_DISCONNECT:
|
||||
NetMqttDisconnect();
|
||||
break;
|
||||
#endif
|
||||
case WB_LORA_CONNECT:
|
||||
NetLoraConnect();
|
||||
break;
|
||||
case WB_LORA_DISCONNECT:
|
||||
NetLoraDisconnect();
|
||||
break;
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
case WB_ETHERNET_CONNECT:
|
||||
TcpClientConnect();
|
||||
break;
|
||||
case WB_ETHERNET_DISCONNECT:
|
||||
TcpClientDisconnect();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void WbEventInit(void)
|
||||
{
|
||||
char task_name[] = "wb_event_task";
|
||||
pthread_args_t args;
|
||||
args.pthread_name = task_name;
|
||||
|
||||
pthread_attr_t attr;
|
||||
attr.schedparam.sched_priority = WB_EVENT_TASK_PRIO;
|
||||
attr.stacksize = WB_EVENT_TASK_STACK_SIZE;
|
||||
|
||||
PrivTaskCreate(&wb_event_task, &attr, &WebserverEventTask, (void *)&args);
|
||||
PrivTaskStartup(&wb_event_task);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Function implementation - webserver
|
||||
******************************************************************************/
|
||||
// Try to update a single configuration value
|
||||
static void update_config(struct mg_str json, const char* path, char** value)
|
||||
{
|
||||
char* jval;
|
||||
if ((jval = mg_json_get_str(json, path)) != NULL) {
|
||||
free(*value);
|
||||
*value = strdup(jval);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_config_array(struct mg_str json, const char* path, char* value)
|
||||
{
|
||||
char* jval;
|
||||
if ((jval = mg_json_get_str(json, path)) != NULL) {
|
||||
sprintf(value, "%s", jval);
|
||||
}
|
||||
}
|
||||
|
||||
static void fn(struct mg_connection* c, int ev, void* ev_data, void* fn_data)
|
||||
{
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message*)ev_data, tmp = { 0 };
|
||||
/*define modules info*/
|
||||
if (mg_http_match_uri(hm, "/net/getModulesInfo")) {
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n",
|
||||
"{%m:%d}\n",
|
||||
MG_ESC("modulesStatus"), JudgeModulesType());
|
||||
}
|
||||
/*define device info*/
|
||||
else if (mg_http_match_uri(hm, "/getSystemInfo")) {
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n",
|
||||
"{%m:%m, %m:%m, %m:%m, %m:%m, %m:%m, %m:%m}\n",
|
||||
MG_ESC("deviceName"), MG_ESC(device_name),
|
||||
MG_ESC("deviceType"), MG_ESC(device_type),
|
||||
MG_ESC("deviceNo"), MG_ESC(device_serial_num),
|
||||
MG_ESC("ip"), MG_ESC(webserver_config.ip),
|
||||
MG_ESC("netmask"), MG_ESC(webserver_config.mask),
|
||||
MG_ESC("gateway"), MG_ESC(webserver_config.gw));
|
||||
}
|
||||
/*define webserver info*/
|
||||
else if (mg_http_match_uri(hm, "/setNetInfo")) {
|
||||
struct mg_str json = hm->body;
|
||||
printf("json: %s\n", json.ptr);
|
||||
update_config(json, "$.ip", &webserver_config.ip);
|
||||
update_config(json, "$.netmask", &webserver_config.mask);
|
||||
update_config(json, "$.gateway", &webserver_config.gw);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
|
||||
ip_addr_t ipaddr, maskaddr, gwaddr;
|
||||
inet_aton(webserver_config.ip, &ipaddr);
|
||||
inet_aton(webserver_config.mask, &maskaddr);
|
||||
inet_aton(webserver_config.gw, &gwaddr);
|
||||
p_netdev_webserver->ops->set_addr_info(p_netdev_webserver, &ipaddr, &maskaddr, &gwaddr);
|
||||
|
||||
printf("Board Webserver Net changed to [IP: %s, Mask: %s, GW: %s]\n",
|
||||
webserver_config.ip,
|
||||
webserver_config.mask,
|
||||
webserver_config.gw);
|
||||
}
|
||||
/*define interface info*/
|
||||
else if (mg_http_match_uri(hm, "/interface/get485Info")) {
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n",
|
||||
"{%m:%d, %m:%d, %m:%d, %m:%d}\n",
|
||||
MG_ESC("baudRate"), rs485_config.baud_rate,
|
||||
MG_ESC("wordLength"), rs485_config.data_bit,
|
||||
MG_ESC("stopBits"), rs485_config.stop_bit,
|
||||
MG_ESC("parity"), rs485_config.parity);
|
||||
} else if (mg_http_match_uri(hm, "/interface/set485Info")) {
|
||||
struct mg_str json = hm->body;
|
||||
printf("json: %s\n", json.ptr);
|
||||
rs485_config.baud_rate = mg_json_get_long(json, "$.baudRate", 0);
|
||||
rs485_config.data_bit = mg_json_get_long(json, "$.wordLength", 0);
|
||||
rs485_config.stop_bit = mg_json_get_long(json, "$.stopBits", 0);
|
||||
rs485_config.parity = mg_json_get_long(json, "$.parity", 0);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
|
||||
Rs485Configure(rs485_config.baud_rate, rs485_config.data_bit, rs485_config.stop_bit, rs485_config.parity);
|
||||
}
|
||||
/*define net 4G info*/
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
else if (mg_http_match_uri(hm, "/net/get4gInfo")) {
|
||||
|
||||
Net4gGetInfo(net_4g_info.map_ip, net_4g_info.operator, net_4g_info.signal_strength);
|
||||
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n",
|
||||
"{%m:%m, %m:%m, %m:%m, %m:%m, %m:%m, %m:%d}\n",
|
||||
MG_ESC("mapIp"), MG_ESC(net_4g_info.map_ip),
|
||||
MG_ESC("operator"), MG_ESC(net_4g_info.operator),
|
||||
MG_ESC("signalIntensity"), MG_ESC(net_4g_info.signal_strength),
|
||||
MG_ESC("publicIp"), MG_ESC(net_4g_info.connect_ip),
|
||||
MG_ESC("publicPort"), MG_ESC(net_4g_info.connect_port),
|
||||
MG_ESC("status"), net_4g_info.connect_status);
|
||||
} else if (mg_http_match_uri(hm, "/net/set4gInfo")) {
|
||||
struct mg_str json = hm->body;
|
||||
printf("json: %s\n", json.ptr);
|
||||
update_config_array(json, "$.publicIp", net_4g_info.connect_ip);
|
||||
update_config_array(json, "$.publicPort", net_4g_info.connect_port);
|
||||
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
} else if (mg_http_match_uri(hm, "/net/connect4G")) {
|
||||
//enable 4G connect function
|
||||
PrivEvenTrigger(wb_event, WB_4G_CONNECT);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
} else if (mg_http_match_uri(hm, "/net/disconnect4G")) {
|
||||
//disable 4G connect function
|
||||
PrivEvenTrigger(wb_event, WB_4G_CONNECT);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
} else if (mg_http_match_uri(hm, "/net/getMQTTInfo")) {
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n",
|
||||
"{%m:%m, %m:%m, %m:%m, %m:%m, %m:%d}\n",
|
||||
MG_ESC("topic"), MG_ESC(net_4g_mqtt_info.topic),
|
||||
MG_ESC("username"), MG_ESC(net_4g_mqtt_info.username),
|
||||
MG_ESC("password"), MG_ESC(net_4g_mqtt_info.password),
|
||||
MG_ESC("clientId"), MG_ESC(net_4g_mqtt_info.client_id),
|
||||
MG_ESC("status"), net_4g_mqtt_info.connect_status);
|
||||
} else if (mg_http_match_uri(hm, "/net/setMQTTInfo")) {
|
||||
struct mg_str json = hm->body;
|
||||
printf("json: %s\n", json.ptr);
|
||||
update_config_array(json, "$.topic", net_4g_mqtt_info.topic);
|
||||
update_config_array(json, "$.username", net_4g_mqtt_info.username);
|
||||
update_config_array(json, "$.password", net_4g_mqtt_info.password);
|
||||
update_config_array(json, "$.clientId", net_4g_mqtt_info.client_id);
|
||||
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
} else if (mg_http_match_uri(hm, "/net/connectMQTT")) {
|
||||
//enable 4G MQTT connect function
|
||||
PrivEvenTrigger(wb_event, WB_MQTT_CONNECT);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
} else if (mg_http_match_uri(hm, "/net/disconnectMQTT")) {
|
||||
//disable 4G MQTT connect function
|
||||
PrivEvenTrigger(wb_event, WB_MQTT_DISCONNECT);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
}
|
||||
#endif
|
||||
/*define net LoRa info*/
|
||||
else if (mg_http_match_uri(hm, "/net/getLoraInfo")) {
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n",
|
||||
"{%m:%d, %m:%d, %m:%d, %m:%d}\n",
|
||||
MG_ESC("range"), net_lora_info.frequency,
|
||||
MG_ESC("bandwidth"), net_lora_info.bw,
|
||||
MG_ESC("factor"), net_lora_info.sf,
|
||||
MG_ESC("status"), net_lora_info.connect_status);
|
||||
}
|
||||
else if (mg_http_match_uri(hm, "/net/setLoraInfo")) {
|
||||
struct mg_str json = hm->body;
|
||||
printf("json: %s\n", json.ptr);
|
||||
net_lora_info.frequency = mg_json_get_long(json, "$.range", 0);
|
||||
net_lora_info.sf = mg_json_get_long(json, "$.factor", 0);
|
||||
net_lora_info.bw = mg_json_get_long(json, "$.bandwidth", 0);
|
||||
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
|
||||
extern void LoraRadioParamsUpdate(uint32_t frequency, uint8_t sf, uint8_t bw);
|
||||
LoraRadioParamsUpdate(net_lora_info.frequency, net_lora_info.sf, net_lora_info.bw);
|
||||
} else if (mg_http_match_uri(hm, "/net/ConnectLora")) {
|
||||
//enable LoRa connect function
|
||||
PrivEvenTrigger(wb_event, WB_LORA_CONNECT);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
} else if (mg_http_match_uri(hm, "/net/DisonnectLora")) {
|
||||
//disable LoRa connect function
|
||||
PrivEvenTrigger(wb_event, WB_LORA_DISCONNECT);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
}
|
||||
/*define net Ethernet info*/
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
else if (mg_http_match_uri(hm, "/net/getEthernetInfo")) {
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n",
|
||||
"{%m:%m, %m:%m, %m:%m, %m:%m, %m:%m, %m:%m, %m:%m, %m:%m, %m:%d}\n",
|
||||
MG_ESC("ethernetIp"), MG_ESC(net_ethernet_info.ethernetIp),
|
||||
MG_ESC("ethernetNetmask"), MG_ESC(net_ethernet_info.ethernetNetmask),
|
||||
MG_ESC("ethernetGateway"), MG_ESC(net_ethernet_info.ethernetGateway),
|
||||
MG_ESC("ethernetDNS"), MG_ESC(net_ethernet_info.ethernetDNS),
|
||||
MG_ESC("targetIp"), MG_ESC(net_ethernet_info.targetIp),
|
||||
MG_ESC("targetPort"), MG_ESC(net_ethernet_info.targetPort),
|
||||
MG_ESC("targetGateway"), MG_ESC(net_ethernet_info.targetGateway),
|
||||
MG_ESC("targetDNS"), MG_ESC(net_ethernet_info.targetDNS),
|
||||
MG_ESC("ethernetStatus"), net_ethernet_info.connect_status);
|
||||
} else if (mg_http_match_uri(hm, "/net/setEthernetInfo")) {
|
||||
struct mg_str json = hm->body;
|
||||
printf("json: %s\n", json.ptr);
|
||||
update_config_array(json, "$.ethernetIp", net_ethernet_info.ethernetIp);
|
||||
update_config_array(json, "$.ethernetNetmask", net_ethernet_info.ethernetNetmask);
|
||||
update_config_array(json, "$.ethernetGateway", net_ethernet_info.ethernetGateway);
|
||||
update_config_array(json, "$.ethernetDNS", net_ethernet_info.ethernetDNS);
|
||||
update_config_array(json, "$.targetIp", net_ethernet_info.targetIp);
|
||||
update_config_array(json, "$.targetPort", net_ethernet_info.targetPort);
|
||||
update_config_array(json, "$.targetGateway", net_ethernet_info.targetGateway);
|
||||
update_config_array(json, "$.targetDNS", net_ethernet_info.targetDNS);
|
||||
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
|
||||
p_netdev_ethernet = netdev_get_by_name("hd");
|
||||
if (p_netdev_ethernet) {
|
||||
ip_addr_t ipaddr, maskaddr, gwaddr;
|
||||
inet_aton(net_ethernet_info.ethernetIp, &ipaddr);
|
||||
inet_aton(net_ethernet_info.ethernetNetmask, &maskaddr);
|
||||
inet_aton(net_ethernet_info.ethernetGateway, &gwaddr);
|
||||
p_netdev_ethernet->ops->set_addr_info(p_netdev_ethernet, &ipaddr, &maskaddr, &gwaddr);
|
||||
|
||||
printf("Ethernet Configuration changed to [IP: %s, Mask: %s, GW: %s]\n",
|
||||
net_ethernet_info.ethernetIp, net_ethernet_info.ethernetNetmask,
|
||||
net_ethernet_info.ethernetGateway);
|
||||
}
|
||||
} else if (mg_http_match_uri(hm, "/net/connectEthernet")) {
|
||||
//enable Ethernet connect function
|
||||
PrivEvenTrigger(wb_event, WB_ETHERNET_CONNECT);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
} else if (mg_http_match_uri(hm, "/net/disconnectEthernet")) {
|
||||
//disable Ethernet connect function
|
||||
PrivEvenTrigger(wb_event, WB_ETHERNET_DISCONNECT);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
}
|
||||
#endif
|
||||
/*define plc info*/
|
||||
else if (mg_http_match_uri(hm, "/control/setPLCInfo")) {
|
||||
struct mg_str json = hm->body;
|
||||
printf("json: %s\n", json.ptr);
|
||||
PlcInfoWriteToSd(json.ptr);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"success\"}\r\n");
|
||||
} else {
|
||||
struct mg_str unknown = mg_str_n("?", 1), *cl;
|
||||
struct mg_http_serve_opts opts = { .root_dir = s_root_dir, .ssi_pattern = s_ssi_pattern };
|
||||
mg_http_serve_dir(c, hm, &opts);
|
||||
mg_http_parse((char*)c->send.buf, c->send.len, &tmp);
|
||||
cl = mg_http_get_header(&tmp, "Content-Length");
|
||||
if (cl == NULL)
|
||||
cl = &unknown;
|
||||
MG_INFO(("%.*s %.*s %.*s %.*s", (int)hm->method.len, hm->method.ptr,
|
||||
(int)hm->uri.len, hm->uri.ptr, (int)tmp.uri.len, tmp.uri.ptr,
|
||||
(int)cl->len, cl->ptr));
|
||||
}
|
||||
}
|
||||
(void)fn_data;
|
||||
}
|
||||
|
||||
static void* do_webserver(void* args)
|
||||
{
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
p_netdev_webserver = netdev_get_by_name("wz");
|
||||
if (p_netdev_webserver == NULL) {
|
||||
MG_INFO(("Did not find wz netdev, use default.\n"));
|
||||
p_netdev_webserver = NETDEV_DEFAULT;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG
|
||||
p_netdev_webserver = netdev_get_by_name("hd");
|
||||
if (p_netdev_webserver == NULL) {
|
||||
MG_INFO(("Did not find hd netdev, use default.\n"));
|
||||
p_netdev_webserver = NETDEV_DEFAULT;
|
||||
}
|
||||
#endif
|
||||
MG_INFO(("Webserver Use Netdev %s", p_netdev_webserver->name));
|
||||
webserver_config.ip = strdup(inet_ntoa(*p_netdev_webserver->ip_addr));
|
||||
webserver_config.mask = strdup(inet_ntoa(*p_netdev_webserver->netmask));
|
||||
webserver_config.gw = strdup(inet_ntoa(*p_netdev_webserver->gw));
|
||||
webserver_config.dns = strdup(inet_ntoa(p_netdev_webserver->dns_servers[0]));
|
||||
|
||||
|
||||
#ifdef BSP_USING_RS485
|
||||
Rs485InitConfigure();
|
||||
#endif
|
||||
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
adapter = AdapterDeviceFindByName(ADAPTER_4G_NAME);
|
||||
#endif
|
||||
|
||||
//4g init param
|
||||
net_4g_info.net_4g_init_flag = 0;
|
||||
net_4g_info.connect_status = 0;
|
||||
net_4g_mqtt_info.connect_status = 0;
|
||||
|
||||
//lora init param
|
||||
net_lora_info.bw = 2;//bw 0:125 kHz 1:250 kHz 2:500 kHz,
|
||||
net_lora_info.sf = 12;//sf12
|
||||
net_lora_info.lora_init_flag = 0;
|
||||
|
||||
WbEventInit();
|
||||
|
||||
struct mg_mgr mgr; // Event manager
|
||||
// mg_log_set(MG_LL_INFO); // Set to 3 to enable debug
|
||||
mg_log_set(MG_LL_ERROR); // Set to 3 to enable debug
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
mg_http_listen(&mgr, s_http_addr, fn, NULL); // Create HTTP listener
|
||||
for (;;)
|
||||
mg_mgr_poll(&mgr, 50); // Infinite event loop
|
||||
mg_mgr_free(&mgr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int webserver(void)
|
||||
{
|
||||
extern void LwipNetworkActive(int argc, char* argv[]);
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG_4G
|
||||
char* params[2] = {"LwipNetworkActive", "-a"};
|
||||
LwipNetworkActive(2, params);
|
||||
#endif
|
||||
|
||||
#ifdef APPLICATION_WEBSERVER_XISHUTONG
|
||||
char* params[3] = {"LwipNetworkActive", "-e", "0"};
|
||||
LwipNetworkActive(3, params);
|
||||
|
||||
extern void LwipSetNetwork(int argc, char* argv[]);
|
||||
char* ip_params[5] = {"LwipSetNetwork", "-d", "hd", "-i", "192.168.131.88"};
|
||||
LwipSetNetwork(5, ip_params);
|
||||
char* gw_params[5] = {"LwipSetNetwork", "-d", "hd", "-g", "192.168.131.1"};
|
||||
LwipSetNetwork(5, gw_params);
|
||||
#endif
|
||||
|
||||
pthread_attr_t attr;
|
||||
attr.schedparam.sched_priority = 30;
|
||||
attr.stacksize = 0x4000;
|
||||
|
||||
char task_name[] = "do_webserver";
|
||||
pthread_args_t args;
|
||||
args.pthread_name = task_name;
|
||||
|
||||
PrivTaskCreate(&tid, &attr, &do_webserver, (void *)&args);
|
||||
PrivTaskStartup(&tid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(5),
|
||||
Webserver, webserver, webserver for project);
|
|
@ -1,8 +1,15 @@
|
|||
config ADAPTER_EC200T
|
||||
bool "Using 4G adapter device EC200T"
|
||||
default y
|
||||
default n
|
||||
|
||||
if ADAPTER_EC200T
|
||||
source "$APP_DIR/Framework/connection/4g/ec200t/Kconfig"
|
||||
endif
|
||||
|
||||
|
||||
config ADAPTER_EC200A
|
||||
bool "Using 4G adapter device EC200A"
|
||||
default n
|
||||
|
||||
if ADAPTER_EC200A
|
||||
source "$APP_DIR/Framework/connection/4g/ec200a/Kconfig"
|
||||
endif
|
||||
|
|
|
@ -13,5 +13,9 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
|
|||
SRC_DIR += ec200t
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ADAPTER_EC200A),y)
|
||||
SRC_DIR += ec200a
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
endif
|
|
@ -24,6 +24,10 @@
|
|||
extern AdapterProductInfoType Ec200tAttach(struct Adapter *adapter);
|
||||
#endif
|
||||
|
||||
#ifdef ADAPTER_EC200A
|
||||
extern AdapterProductInfoType Ec200aAttach(struct Adapter *adapter);
|
||||
#endif
|
||||
|
||||
static int Adapter4GRegister(struct Adapter *adapter)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -74,6 +78,20 @@ int Adapter4GInit(void)
|
|||
adapter->info = product_info;
|
||||
adapter->done = product_info->model_done;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef ADAPTER_EC200A
|
||||
AdapterProductInfoType product_info = Ec200aAttach(adapter);
|
||||
if (!product_info) {
|
||||
printf("Adapter4GInit ec200a attach error\n");
|
||||
PrivFree(adapter);
|
||||
return -1;
|
||||
}
|
||||
|
||||
adapter->product_info_flag = 1;
|
||||
adapter->info = product_info;
|
||||
adapter->done = product_info->model_done;
|
||||
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
|
@ -86,7 +104,7 @@ int Adapter4GTest(void)
|
|||
char recv_msg[256] = {0};
|
||||
int baud_rate = BAUD_RATE_115200;
|
||||
|
||||
struct Adapter* adapter = AdapterDeviceFindByName(ADAPTER_4G_NAME);
|
||||
struct Adapter* adapter = AdapterDeviceFindByName(ADAPTER_4G_NAME);
|
||||
|
||||
#ifdef ADAPTER_EC200T
|
||||
/* Using Public TCP server to test 4G Socket connection */
|
||||
|
@ -108,6 +126,44 @@ int Adapter4GTest(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef ADAPTER_EC200A
|
||||
/* Using Public TCP server to test 4G Socket connection */
|
||||
uint8 server_addr[64] = "xyheqmx.e3.luyouxia.net";
|
||||
uint8 server_port[64] = "13333";
|
||||
uint8 client_id[64] = "quectel";
|
||||
uint8 username[64] = "test";
|
||||
uint8 password[64] = "test123456";
|
||||
uint8 topic_pub[64] = "/reply";
|
||||
uint8 topic_sub[64] = "/get";
|
||||
|
||||
adapter->socket.socket_id = 0;
|
||||
|
||||
AdapterDeviceOpen(adapter);
|
||||
AdapterDeviceControl(adapter, OPE_INT, &baud_rate);
|
||||
|
||||
AdapterDeviceNetstat(adapter);
|
||||
|
||||
/*4G TCP Connect Test*/
|
||||
// AdapterDeviceConnect(adapter, CLIENT, server_addr, server_port, IPV4);
|
||||
|
||||
// while (1) {
|
||||
// AdapterDeviceSend(adapter, send_msg, strlen(send_msg));
|
||||
// AdapterDeviceRecv(adapter, recv_msg, 256);
|
||||
// printf("4G recv msg %s\n", recv_msg);
|
||||
// memset(recv_msg, 0, 256);
|
||||
// }
|
||||
|
||||
/*4G MQTT Connect Test*/
|
||||
AdapterDeviceMqttConnect(adapter, server_addr, server_port, client_id, username, password);
|
||||
|
||||
while (1) {
|
||||
AdapterDeviceMqttSend(adapter, topic_pub, send_msg, strlen(send_msg));
|
||||
AdapterDeviceMqttRecv(adapter, topic_sub, recv_msg, 256);
|
||||
printf("4G mqtt recv msg %s\n", recv_msg);
|
||||
memset(recv_msg, 0, 256);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
PRIV_SHELL_CMD_FUNCTION(Adapter4GTest, a EC200T adpter sample, PRIV_SHELL_CMD_FUNC_ATTR);
|
||||
PRIV_SHELL_CMD_FUNCTION(Adapter4GTest, a EC200T or EC200A adapter sample, PRIV_SHELL_CMD_FUNC_ATTR);
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
config ADAPTER_4G_EC200A
|
||||
string "EC200A adapter name"
|
||||
default "ec200a"
|
||||
|
||||
if ADD_XIZI_FEATURES
|
||||
config ADAPTER_EC200A_USING_PWRKEY
|
||||
bool "EC200A using PWRKEY pin number"
|
||||
default n
|
||||
|
||||
if ADAPTER_EC200A_USING_PWRKEY
|
||||
config ADAPTER_EC200A_PWRKEY
|
||||
int "EC200A PWRKEY pin number"
|
||||
default "144"
|
||||
|
||||
config ADAPTER_EC200A_PIN_DRIVER
|
||||
string "EC200A device pin driver path"
|
||||
default "/dev/pin_dev"
|
||||
endif
|
||||
|
||||
config ADAPTER_EC200A_DRIVER_EXTUART
|
||||
bool "Using extra uart to support 4G"
|
||||
default n
|
||||
|
||||
config ADAPTER_EC200A_DRIVER
|
||||
string "EC200A device uart driver path"
|
||||
default "/dev/usart6_dev6"
|
||||
depends on !ADAPTER_EC200A_DRIVER_EXTUART
|
||||
|
||||
if ADAPTER_EC200A_DRIVER_EXTUART
|
||||
config ADAPTER_EC200A_DRIVER
|
||||
string "EC200A device extra uart driver path"
|
||||
default "/dev/extuart_dev5"
|
||||
|
||||
config ADAPTER_EC200A_DRIVER_EXT_PORT
|
||||
int "if EC200A device using extuart, choose port"
|
||||
default "5"
|
||||
endif
|
||||
endif
|
||||
|
||||
if ADD_NUTTX_FEATURES
|
||||
config ADAPTER_EC200A_USING_PWRKEY
|
||||
bool "EC200A using PWRKEY pin number"
|
||||
default n
|
||||
|
||||
if ADAPTER_EC200A_USING_PWRKEY
|
||||
config ADAPTER_EC200A_PWRKEY
|
||||
int "EC200A PWRKEY pin number"
|
||||
default "144"
|
||||
|
||||
config ADAPTER_EC200A_PIN_DRIVER
|
||||
string "EC200A device pin driver path"
|
||||
default "/dev/gpio3"
|
||||
endif
|
||||
|
||||
config ADAPTER_EC200A_DRIVER_EXTUART
|
||||
bool "Using extra uart to support 4G"
|
||||
default n
|
||||
|
||||
config ADAPTER_EC200A_DRIVER
|
||||
string "EC200A device uart driver path"
|
||||
default "/dev/ttyS8"
|
||||
depends on !ADAPTER_EC200A_DRIVER_EXTUART
|
||||
|
||||
if ADAPTER_EC200A_DRIVER_EXTUART
|
||||
config ADAPTER_EC200A_DRIVER
|
||||
string "EC200A device extra uart driver path"
|
||||
default "/dev/extuart_dev5"
|
||||
|
||||
config ADAPTER_EC200A_DRIVER_EXT_PORT
|
||||
int "if EC200A device using extuart, choose port"
|
||||
default "5"
|
||||
endif
|
||||
endif
|
||||
|
||||
if ADD_RTTHREAD_FEATURES
|
||||
config ADAPTER_EC200A_PWRKEY
|
||||
int "EC200A PWRKEY pin number"
|
||||
default "144"
|
||||
|
||||
config ADAPTER_EC200A_PIN_DRIVER
|
||||
string "EC200A device pin driver path"
|
||||
default "/dev/pin_dev"
|
||||
|
||||
config ADAPTER_EC200A_DRIVER_EXTUART
|
||||
bool "Using extra uart to support 4G"
|
||||
default n
|
||||
|
||||
config ADAPTER_EC200A_DRIVER
|
||||
string "EC200A device uart driver path"
|
||||
default "/dev/usart8"
|
||||
depends on !ADAPTER_EC200A_DRIVER_EXTUART
|
||||
|
||||
if ADAPTER_EC200A_DRIVER_EXTUART
|
||||
config ADAPTER_EC200A_DRIVER
|
||||
string "EC200A device extra uart driver path"
|
||||
default "/dev/extuart_dev5"
|
||||
|
||||
config ADAPTER_EC200A_DRIVER_EXT_PORT
|
||||
int "if EC200A device using extuart, choose port"
|
||||
default "5"
|
||||
endif
|
||||
|
||||
|
||||
endif
|
|
@ -0,0 +1,6 @@
|
|||
############################################################################
|
||||
# APP_Framework/Framework/connection/4g/ec200a/Make.defs
|
||||
############################################################################
|
||||
ifneq ($(CONFIG_ADAPTER_4G_EC200A),)
|
||||
CONFIGURED_APPS += $(APPDIR)/../../../APP_Framework/Framework/connection/4g/ec200a
|
||||
endif
|
|
@ -0,0 +1,14 @@
|
|||
include $(KERNEL_ROOT)/.config
|
||||
ifeq ($(CONFIG_ADD_NUTTX_FEATURES),y)
|
||||
include $(APPDIR)/Make.defs
|
||||
CSRCS += ec200a.c
|
||||
include $(APPDIR)/Application.mk
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
|
||||
SRC_FILES := ec200a.c ec200a_mqtt.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
endif
|
|
@ -0,0 +1,10 @@
|
|||
from building import *
|
||||
import os
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
if GetDepend(['ADAPTER_EC200A']):
|
||||
src += ['ec200a.c', 'ec200a_mqtt.c']
|
||||
group = DefineGroup('connection 4g ec200a', src, depend = [], CPPPATH = [cwd])
|
||||
|
||||
Return('group')
|
|
@ -0,0 +1,555 @@
|
|||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ec200a.c
|
||||
* @brief Implement the connection 4G adapter function, using EC200A device
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.12.22
|
||||
*/
|
||||
|
||||
#include <adapter.h>
|
||||
#include <at_agent.h>
|
||||
|
||||
#define EC200A_AT_MODE_CMD "+++"
|
||||
#define EC200A_GET_QCCID_CMD "AT+QCCID\r\n"
|
||||
#define EC200A_GET_CPIN_CMD "AT+CPIN?\r\n"
|
||||
#define EC200A_GET_CREG_CMD "AT+CREG?\r\n"
|
||||
#define EC200A_CFG_TCP_CMD "AT+QICSGP"
|
||||
#define EC200A_ACTIVE_PDP_CMD "AT+QIACT=1\r\n"
|
||||
#define EC200A_DEACTIVE_PDP_CMD "AT+QIDEACT=1\r\n"
|
||||
#define EC200A_OPEN_SOCKET_CMD "AT+QIOPEN=1,%u"
|
||||
#define EC200A_CLOSE_SOCKET_CMD "AT+QICLOSE=%u\r\n"
|
||||
#define EC200A_CLOSE "AT+QPOWD\r\n"
|
||||
#define EC200A_GET_COPS_CMD "AT+COPS?\r\n"
|
||||
#define EC200A_GET_CSQ_CMD "AT+CSQ\r\n"
|
||||
#define EC200A_GET_POP_IP "AT+CGPADDR=1\r\n"
|
||||
|
||||
#define EC200A_OK_REPLY "OK"
|
||||
#define EC200A_READY_REPLY "READY"
|
||||
#define EC200A_CREG_REPLY ",1"
|
||||
#define EC200A_CONNECT_REPLY "CONNECT"
|
||||
|
||||
#define TRY_TIMES 10
|
||||
|
||||
extern int Ec200aMqttConnect(struct Adapter *adapter, const char *ip, const char *port, const char *client_id, const char *username, const char *password);
|
||||
extern int Ec200aMqttDisconnect(struct Adapter *adapter);
|
||||
extern int Ec200aMqttSend(struct Adapter *adapter, const char *topic, const void *buf, size_t len);
|
||||
extern int Ec200aMqttRecv(struct Adapter *adapter, const char *topic, void *buf, size_t len);
|
||||
|
||||
static void Ec200aPowerSet(void)
|
||||
{
|
||||
#ifdef ADAPTER_EC200A_USING_PWRKEY
|
||||
int pin_fd;
|
||||
pin_fd = PrivOpen(ADAPTER_EC200A_PIN_DRIVER, O_RDWR);
|
||||
if (pin_fd < 0) {
|
||||
printf("open %s error\n", ADAPTER_EC200A_PIN_DRIVER);
|
||||
return;
|
||||
}
|
||||
|
||||
struct PinParam pin_param;
|
||||
pin_param.cmd = GPIO_CONFIG_MODE;
|
||||
pin_param.mode = GPIO_CFG_OUTPUT;
|
||||
pin_param.pin = ADAPTER_EC200A_PWRKEY;
|
||||
|
||||
struct PrivIoctlCfg ioctl_cfg;
|
||||
ioctl_cfg.ioctl_driver_type = PIN_TYPE;
|
||||
ioctl_cfg.args = &pin_param;
|
||||
PrivIoctl(pin_fd, OPE_CFG, &ioctl_cfg);
|
||||
|
||||
struct PinStat pin_stat;
|
||||
pin_stat.pin = ADAPTER_EC200A_PWRKEY;
|
||||
pin_stat.val = GPIO_LOW; //put power key at low-level state
|
||||
PrivWrite(pin_fd, &pin_stat, 1);
|
||||
|
||||
PrivTaskDelay(2500); //wait at least 2s
|
||||
|
||||
pin_stat.val = GPIO_HIGH; //put power key at high-level state
|
||||
PrivWrite(pin_fd, &pin_stat, 1);
|
||||
|
||||
PrivClose(pin_fd);
|
||||
|
||||
PrivTaskDelay(10000);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int Ec200aOpen(struct Adapter *adapter)
|
||||
{
|
||||
/*step1: open ec200a serial port*/
|
||||
adapter->fd = PrivOpen(ADAPTER_EC200A_DRIVER, O_RDWR);
|
||||
if (adapter->fd < 0) {
|
||||
printf("Ec200aOpen get serial %s fd error\n", ADAPTER_EC200A_DRIVER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*step2: init AT agent*/
|
||||
if (!adapter->agent) {
|
||||
char *agent_name = "4G_uart_client";
|
||||
if (0 != InitATAgent(agent_name, adapter->fd, 512)) {
|
||||
printf("at agent init failed !\n");
|
||||
return -1;
|
||||
}
|
||||
ATAgentType at_agent = GetATAgent(agent_name);
|
||||
|
||||
adapter->agent = at_agent;
|
||||
}
|
||||
|
||||
PrivTaskDelay(2500);
|
||||
|
||||
ADAPTER_DEBUG("Ec200a open done\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Ec200aClose(struct Adapter *adapter)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t ec200a_cmd[64];
|
||||
|
||||
if (!adapter->agent) {
|
||||
printf("Ec200aClose AT agent NULL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
AtSetReplyEndChar(adapter->agent, 0x4F, 0x4B); //'O', 'K'
|
||||
|
||||
/*step1: serial write "+++", quit transparent mode*/
|
||||
ATOrderSend(adapter->agent, REPLY_TIME_OUT, NULL, "+++");
|
||||
|
||||
/*step2: serial write "AT+QICLOSE", close socket connect before open socket*/
|
||||
memset(ec200a_cmd, 0, sizeof(ec200a_cmd));
|
||||
sprintf(ec200a_cmd, EC200A_CLOSE_SOCKET_CMD, adapter->socket.socket_id);
|
||||
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, ec200a_cmd, EC200A_OK_REPLY);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step3: serial write "AT+QIDEACT", close TCP net before open socket*/
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_DEACTIVE_PDP_CMD, EC200A_OK_REPLY);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
/*step4: power down ec200a*/
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_CLOSE, EC200A_OK_REPLY);
|
||||
PrivTaskDelay(12500); //wait at least 12s
|
||||
|
||||
/*step5: close ec200a serial port*/
|
||||
PrivClose(adapter->fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef ADD_RTTHREAD_FEATURES
|
||||
static int Ec200aIoctl(struct Adapter *adapter, int cmd, void *args){ return 0;}
|
||||
#else
|
||||
static int Ec200aIoctl(struct Adapter *adapter, int cmd, void *args)
|
||||
{
|
||||
if (OPE_INT != cmd) {
|
||||
printf("Ec200aIoctl only support OPE_INT, do not support %d\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t baud_rate = *((uint32_t *)args);
|
||||
|
||||
struct SerialDataCfg serial_cfg;
|
||||
memset(&serial_cfg, 0 ,sizeof(struct SerialDataCfg));
|
||||
serial_cfg.serial_baud_rate = baud_rate;
|
||||
serial_cfg.serial_data_bits = DATA_BITS_8;
|
||||
serial_cfg.serial_stop_bits = STOP_BITS_1;
|
||||
serial_cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
|
||||
serial_cfg.serial_parity_mode = PARITY_NONE;
|
||||
serial_cfg.serial_bit_order = STOP_BITS_1;
|
||||
serial_cfg.serial_invert_mode = NRZ_NORMAL;
|
||||
#ifdef TOOL_USING_OTA
|
||||
serial_cfg.serial_timeout = OTA_RX_TIMEOUT;
|
||||
#else
|
||||
//serial receive timeout 10s
|
||||
serial_cfg.serial_timeout = 100000;
|
||||
#endif
|
||||
serial_cfg.is_ext_uart = 0;
|
||||
#ifdef ADAPTER_EC200A_DRIVER_EXT_PORT
|
||||
serial_cfg.is_ext_uart = 1;
|
||||
serial_cfg.ext_uart_no = ADAPTER_EC200A_DRIVER_EXT_PORT;
|
||||
serial_cfg.port_configure = PORT_CFG_INIT;
|
||||
#endif
|
||||
|
||||
struct PrivIoctlCfg ioctl_cfg;
|
||||
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
|
||||
ioctl_cfg.args = &serial_cfg;
|
||||
PrivIoctl(adapter->fd, OPE_INT, &ioctl_cfg);
|
||||
|
||||
Ec200aPowerSet();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int Ec200aConnect(struct Adapter *adapter, enum NetRoleType net_role, const char *ip, const char *port, enum IpType ip_type)
|
||||
{
|
||||
int ret = 0;
|
||||
int try = 0;
|
||||
uint8_t ec200a_cmd[64];
|
||||
|
||||
AtSetReplyEndChar(adapter->agent, 0x4F, 0x4B);
|
||||
|
||||
/*step1: serial write "+++", quit transparent mode*/
|
||||
PrivTaskDelay(1500); //before +++ command, wait at least 1s
|
||||
ATOrderSend(adapter->agent, REPLY_TIME_OUT, NULL, "+++");
|
||||
PrivTaskDelay(1500); //after +++ command, wait at least 1s
|
||||
|
||||
/*step2: serial write "AT+CCID", get SIM ID*/
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_GET_QCCID_CMD, EC200A_OK_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step3: serial write "AT+CPIN?", check SIM status*/
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_GET_CPIN_CMD, EC200A_READY_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step4: serial write "AT+CREG?", check whether registered to GSM net*/
|
||||
PrivTaskDelay(1000); //before CREG command, wait 1s
|
||||
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_GET_CREG_CMD, EC200A_CREG_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step5: serial write "AT+QICSGP", connect to China Mobile using ipv4 or ipv6*/
|
||||
memset(ec200a_cmd, 0, sizeof(ec200a_cmd));
|
||||
|
||||
if (IPV4 == ip_type) {
|
||||
strcpy(ec200a_cmd, "AT+QICSGP=1,1,\"CMNET\",\"\",\"\",1\r\n");
|
||||
} else if (IPV6 == ip_type) {
|
||||
strcpy(ec200a_cmd, "AT+QICSGP=1,2,\"CMNET\",\"\",\"\",1\r\n");
|
||||
}
|
||||
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, ec200a_cmd, EC200A_OK_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step6: serial write "AT+QICLOSE", close socket connect before open socket*/
|
||||
memset(ec200a_cmd, 0, sizeof(ec200a_cmd));
|
||||
|
||||
sprintf(ec200a_cmd, EC200A_CLOSE_SOCKET_CMD, adapter->socket.socket_id);
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, ec200a_cmd, EC200A_OK_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step7: serial write "AT+QIDEACT", close TCP net before open socket*/
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_DEACTIVE_PDP_CMD, EC200A_OK_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step8: serial write "AT+QIACT", open TCP net*/
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_ACTIVE_PDP_CMD, EC200A_OK_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step9: serial write "AT+QIOPEN", connect socket using TCP*/
|
||||
memset(ec200a_cmd, 0, sizeof(ec200a_cmd));
|
||||
sprintf(ec200a_cmd, EC200A_OPEN_SOCKET_CMD, adapter->socket.socket_id);
|
||||
strcat(ec200a_cmd, ",\"TCP\",\"");
|
||||
strcat(ec200a_cmd, ip);
|
||||
strcat(ec200a_cmd, "\",");
|
||||
strcat(ec200a_cmd, port);
|
||||
strcat(ec200a_cmd, ",0,2\r\n");
|
||||
|
||||
AtSetReplyEndChar(adapter->agent, 0x43, 0x54);
|
||||
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, ec200a_cmd, EC200A_CONNECT_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ADAPTER_DEBUG("Ec200a connect TCP done\n");
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
ADAPTER_DEBUG("Ec200a connect TCP failed. Power down\n");
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_CLOSE, EC200A_OK_REPLY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int Ec200aSend(struct Adapter *adapter, const void *buf, size_t len)
|
||||
{
|
||||
if (adapter->agent) {
|
||||
EntmSend(adapter->agent, (const char *)buf, len);
|
||||
} else {
|
||||
printf("Ec200aSend can not find agent\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Ec200aRecv(struct Adapter *adapter, void *buf, size_t len)
|
||||
{
|
||||
if (adapter->agent) {
|
||||
return EntmRecv(adapter->agent, (char *)buf, len, 6);
|
||||
} else {
|
||||
printf("Ec200aRecv can not find agent\n");
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int Ec200aDisconnect(struct Adapter *adapter)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t ec200a_cmd[64];
|
||||
|
||||
AtSetReplyEndChar(adapter->agent, 0x4F, 0x4B);
|
||||
|
||||
/*step1: serial write "+++", quit transparent mode*/
|
||||
PrivTaskDelay(1500); //before +++ command, wait at least 1s
|
||||
ATOrderSend(adapter->agent, REPLY_TIME_OUT, NULL, "+++");
|
||||
PrivTaskDelay(1500); //after +++ command, wait at least 1s
|
||||
|
||||
/*step2: serial write "AT+QICLOSE", close socket connect before open socket*/
|
||||
memset(ec200a_cmd, 0, sizeof(ec200a_cmd));
|
||||
sprintf(ec200a_cmd, EC200A_CLOSE_SOCKET_CMD, adapter->socket.socket_id);
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, ec200a_cmd, EC200A_OK_REPLY);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ADAPTER_DEBUG("Ec200a disconnect TCP done\n");
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
ADAPTER_DEBUG("Ec200a disconnect TCP failed. Power down\n");
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_CLOSE, EC200A_OK_REPLY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void extractCarrierInfo(char *response, struct NetworkInfo *networkInfo)
|
||||
{
|
||||
const char *delimiter = "\"";
|
||||
const char *token;
|
||||
|
||||
token = strtok(response, delimiter);
|
||||
token = strtok(NULL, delimiter);
|
||||
|
||||
if (strcmp(token, "CHINA MOBILE") == 0) {
|
||||
networkInfo->carrier_type = CARRIER_CHINA_MOBILE;
|
||||
} else if (strcmp(token, "CHN-UNICOM") == 0) {
|
||||
networkInfo->carrier_type = CARRIER_CHINA_UNICOM;
|
||||
} else if (strcmp(token, "CHN-CT") == 0) {
|
||||
networkInfo->carrier_type = CARRIER_CHINA_TELECOM;
|
||||
} else {
|
||||
networkInfo->carrier_type = CARRIER_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static int Ec200aNetstat(struct Adapter *adapter) {
|
||||
char result[64] = {0};
|
||||
|
||||
struct NetworkInfo info = {
|
||||
.carrier_type = CARRIER_UNKNOWN,
|
||||
.signal_strength = 0,
|
||||
.ip_address = "192.168.1.1"
|
||||
};
|
||||
|
||||
int ret = 0;
|
||||
int try = 0;
|
||||
|
||||
AtSetReplyEndChar(adapter->agent, 0x4F, 0x4B);
|
||||
|
||||
/*step1: serial write "+++", quit transparent mode*/
|
||||
PrivTaskDelay(1500); //before +++ command, wait at least 1s
|
||||
ATOrderSend(adapter->agent, REPLY_TIME_OUT, NULL, "+++");
|
||||
PrivTaskDelay(1500); //after +++ command, wait at least 1s
|
||||
|
||||
/*step2: serial write "AT+CCID", get SIM ID*/
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_GET_QCCID_CMD, EC200A_OK_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step3: serial write "AT+CPIN?", check SIM status*/
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_GET_CPIN_CMD, EC200A_READY_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step4: serial write "AT+CREG?", check whether registered to GSM net*/
|
||||
PrivTaskDelay(1000); //before CREG command, wait 1s
|
||||
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_GET_CREG_CMD, EC200A_CREG_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step5: serial write "AT+COPS?", get carrier type*/
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtGetNetworkInfoReply(adapter->agent, EC200A_GET_COPS_CMD, result);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
extractCarrierInfo(result, &info);
|
||||
adapter->network_info.carrier_type = info.carrier_type;
|
||||
|
||||
/*step6: serial write "AT+CSQ", get carrier type*/
|
||||
memset(result, 0, sizeof(result));
|
||||
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtGetNetworkInfoReply(adapter->agent, EC200A_GET_CSQ_CMD, result);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
if (sscanf(result, "AT+CSQ\n+CSQ: %d", &info.signal_strength) == 1) {
|
||||
printf("Signal Strength: %d\n", info.signal_strength);
|
||||
adapter->network_info.signal_strength = info.signal_strength;
|
||||
} else {
|
||||
printf("Failed to parse signal strength\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step7: serial write "AT+CSQ", get carrier type*/
|
||||
memset(result, 0, sizeof(result));
|
||||
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtGetNetworkInfoReply(adapter->agent, EC200A_GET_POP_IP, result);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
if (sscanf(result, "AT+CGPADDR=1\n+CGPADDR: 1,\"%15[^\"]\"", info.ip_address) == 1) {
|
||||
printf("IP Address: %s\n", info.ip_address);
|
||||
strcpy(adapter->network_info.ip_address, info.ip_address);
|
||||
} else {
|
||||
printf("Failed to parse IP address\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
ADAPTER_DEBUG("Ec200a get netstat failed. Power down\n");
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_CLOSE, EC200A_OK_REPLY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const struct IpProtocolDone ec200a_done =
|
||||
{
|
||||
.open = Ec200aOpen,
|
||||
.close = Ec200aClose,
|
||||
.ioctl = Ec200aIoctl,
|
||||
.setup = NULL,
|
||||
.setdown = NULL,
|
||||
.setaddr = NULL,
|
||||
.setdns = NULL,
|
||||
.setdhcp = NULL,
|
||||
.ping = NULL,
|
||||
.netstat = Ec200aNetstat,
|
||||
.connect = Ec200aConnect,
|
||||
.send = Ec200aSend,
|
||||
.recv = Ec200aRecv,
|
||||
.disconnect = Ec200aDisconnect,
|
||||
.mqttconnect = Ec200aMqttConnect,
|
||||
.mqttdisconnect = Ec200aMqttDisconnect,
|
||||
.mqttsend = Ec200aMqttSend,
|
||||
.mqttrecv = Ec200aMqttRecv,
|
||||
};
|
||||
|
||||
AdapterProductInfoType Ec200aAttach(struct Adapter *adapter)
|
||||
{
|
||||
struct AdapterProductInfo *product_info = PrivMalloc(sizeof(struct AdapterProductInfo));
|
||||
if (!product_info) {
|
||||
printf("Ec200aAttach malloc product_info error\n");
|
||||
PrivFree(product_info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(product_info->model_name, ADAPTER_4G_EC200A);
|
||||
|
||||
product_info->model_done = (void *)&ec200a_done;
|
||||
|
||||
return product_info;
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ec200a.c
|
||||
* @brief Implement the connection 4G adapter function, using EC200A device
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.1.5
|
||||
*/
|
||||
#include <adapter.h>
|
||||
#include <at_agent.h>
|
||||
|
||||
#define EC200A_GET_QCCID_CMD "AT+QCCID\r\n"
|
||||
#define EC200A_GET_CPIN_CMD "AT+CPIN?\r\n"
|
||||
#define EC200A_GET_CREG_CMD "AT+CREG?\r\n"
|
||||
#define EC200A_CLOSE "AT+QPOWD\r\n"
|
||||
#define EC200A_SET_MQTT_MODE_CMD "AT+QMTCFG=\"recv/mode\",0,0,1\r\n"
|
||||
#define EC200A_SET_MQTT_SERVER_CMD "AT+QMTOPEN=0,"
|
||||
#define EC200A_SET_MQTT_CONNECT_CMD "AT+QMTCONN=0,"
|
||||
#define EC200A_SET_MQTT_DISCONN_CMD "AT+QMTDISC=0\r\n"
|
||||
#define EC200A_SET_MQTT_PUBEX_CMD "AT+QMTPUBEX=0,0,0,0,"
|
||||
#define EC200A_SET_MQTT_SUB_CMD "AT+QMTSUB=0,1,"
|
||||
|
||||
#define EC200A_OK_REPLY "OK"
|
||||
#define EC200A_READY_REPLY "READY"
|
||||
#define EC200A_CREG_REPLY ",1"
|
||||
#define EC200A_PUBEX_REPLY ">"
|
||||
|
||||
#define TRY_TIMES 10
|
||||
|
||||
int Ec200aMqttConnect(struct Adapter *adapter, const char *ip, const char *port, const char *client_id, const char *username, const char *password) {
|
||||
int ret = 0;
|
||||
int try = 0;
|
||||
uint8_t ec200a_cmd[64];
|
||||
|
||||
AtSetReplyEndChar(adapter->agent, 0x4F, 0x4B);
|
||||
|
||||
/*step1: serial write "+++", quit transparent mode*/
|
||||
PrivTaskDelay(1500); //before +++ command, wait at least 1s
|
||||
ATOrderSend(adapter->agent, REPLY_TIME_OUT, NULL, "+++");
|
||||
PrivTaskDelay(1500); //after +++ command, wait at least 1s
|
||||
|
||||
/*step2: serial write "AT+CCID", get SIM ID*/
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_GET_QCCID_CMD, EC200A_OK_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step3: serial write "AT+CPIN?", check SIM status*/
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_GET_CPIN_CMD, EC200A_READY_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step4: serial write "AT+CREG?", check whether registered to GSM net*/
|
||||
PrivTaskDelay(1000); //before CREG command, wait 1s
|
||||
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_GET_CREG_CMD, EC200A_CREG_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step5: serial write "AT+QMTCFG=", config mqtt params*/
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_SET_MQTT_MODE_CMD, EC200A_OK_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step6: serial write "AT+OPEN=", config mqtt ip and port*/
|
||||
memset(ec200a_cmd, 0, sizeof(ec200a_cmd));
|
||||
strcpy(ec200a_cmd, EC200A_SET_MQTT_SERVER_CMD);
|
||||
strcat(ec200a_cmd, "\"");
|
||||
strcat(ec200a_cmd, ip);
|
||||
strcat(ec200a_cmd, "\",");
|
||||
strcat(ec200a_cmd, port);
|
||||
strcat(ec200a_cmd, "\r\n");
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, ec200a_cmd, EC200A_OK_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*step7: serial write "AT+QMTCONN=", config mqtt connection*/
|
||||
PrivTaskDelay(1000); //before mqtt connect command, wait 1s
|
||||
|
||||
memset(ec200a_cmd, 0, sizeof(ec200a_cmd));
|
||||
strcpy(ec200a_cmd, EC200A_SET_MQTT_CONNECT_CMD);
|
||||
strcat(ec200a_cmd, "\"");
|
||||
strcat(ec200a_cmd, client_id);
|
||||
strcat(ec200a_cmd, "\",\"");
|
||||
strcat(ec200a_cmd, username);
|
||||
strcat(ec200a_cmd, "\",\"");
|
||||
strcat(ec200a_cmd, password);
|
||||
strcat(ec200a_cmd, "\"\r\n");
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, ec200a_cmd, EC200A_OK_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ADAPTER_DEBUG("Ec200a mqtt connect done\n");
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
ADAPTER_DEBUG("Ec200a mqtt connect failed. Power down\n");
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_CLOSE, EC200A_OK_REPLY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Ec200aMqttDisconnect(struct Adapter *adapter)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
AtSetReplyEndChar(adapter->agent, 0x4F, 0x4B);
|
||||
|
||||
/*step1: serial write "+++", quit transparent mode*/
|
||||
PrivTaskDelay(1500); //before +++ command, wait at least 1s
|
||||
ATOrderSend(adapter->agent, REPLY_TIME_OUT, NULL, "+++");
|
||||
PrivTaskDelay(1500); //after +++ command, wait at least 1s
|
||||
|
||||
/*step2: serial write "AT+QMTDISC", close mqtt connect*/
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_SET_MQTT_DISCONN_CMD, EC200A_OK_REPLY);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ADAPTER_DEBUG("Ec200a disconnect mqtt done\n");
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
ADAPTER_DEBUG("Ec200a disconnect mqtt failed. Power down\n");
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_CLOSE, EC200A_OK_REPLY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Ec200aMqttSend(struct Adapter *adapter, const char *topic, const void *buf, size_t len) {
|
||||
int ret = 0;
|
||||
int try = 0;
|
||||
uint8_t ec200a_cmd[64];
|
||||
|
||||
AtSetReplyEndChar(adapter->agent, 0x3E, 0x20);
|
||||
|
||||
char len_str[10];
|
||||
sprintf(len_str, "%u", len);
|
||||
memset(ec200a_cmd, 0, sizeof(ec200a_cmd));
|
||||
strcpy(ec200a_cmd, EC200A_SET_MQTT_PUBEX_CMD);
|
||||
strcat(ec200a_cmd, "\"");
|
||||
strcat(ec200a_cmd, topic);
|
||||
strcat(ec200a_cmd, "\",");
|
||||
strcat(ec200a_cmd, len_str);
|
||||
strcat(ec200a_cmd, "\r\n");
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, ec200a_cmd, EC200A_PUBEX_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
EntmSend(adapter->agent, buf, len);
|
||||
|
||||
ADAPTER_DEBUG("Ec200a mqtt send done\n");
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
ADAPTER_DEBUG("Ec200a mqtt send failed. Power down\n");
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_CLOSE, EC200A_OK_REPLY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Ec200aMqttRecv(struct Adapter *adapter, const char *topic, void *buf, size_t len) {
|
||||
int ret = 0;
|
||||
int try = 0;
|
||||
uint8_t ec200a_cmd[64];
|
||||
|
||||
AtSetReplyEndChar(adapter->agent, 0x4F, 0x4B);
|
||||
|
||||
memset(ec200a_cmd, 0, sizeof(ec200a_cmd));
|
||||
strcpy(ec200a_cmd, EC200A_SET_MQTT_SUB_CMD);
|
||||
strcat(ec200a_cmd, "\"");
|
||||
strcat(ec200a_cmd, topic);
|
||||
strcat(ec200a_cmd, "\",0\r\n");
|
||||
|
||||
PrivTaskDelay(1000); //before mqtt sub topic command, wait 1s
|
||||
for(try = 0; try < TRY_TIMES; try++){
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, ec200a_cmd, EC200A_OK_REPLY);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
EntmRecv(adapter->agent, buf, len, 30);
|
||||
|
||||
ADAPTER_DEBUG("Ec200a mqtt recv done\n");
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
ADAPTER_DEBUG("Ec200a mqtt recv failed. Power down\n");
|
||||
ret = AtCmdConfigAndCheck(adapter->agent, EC200A_CLOSE, EC200A_OK_REPLY);
|
||||
return -1;
|
||||
}
|
|
@ -167,7 +167,7 @@ static int Ec200tIoctl(struct Adapter *adapter, int cmd, void *args)
|
|||
serial_cfg.serial_timeout = OTA_RX_TIMEOUT;
|
||||
#else
|
||||
//serial receive timeout 10s
|
||||
serial_cfg.serial_timeout = 100000;
|
||||
serial_cfg.serial_timeout = 10000;
|
||||
#endif
|
||||
serial_cfg.is_ext_uart = 0;
|
||||
#ifdef ADAPTER_EC200T_DRIVER_EXT_PORT
|
||||
|
@ -175,6 +175,7 @@ static int Ec200tIoctl(struct Adapter *adapter, int cmd, void *args)
|
|||
serial_cfg.ext_uart_no = ADAPTER_EC200T_DRIVER_EXT_PORT;
|
||||
serial_cfg.port_configure = PORT_CFG_INIT;
|
||||
#endif
|
||||
serial_cfg.dev_recv_callback = NULL;
|
||||
|
||||
struct PrivIoctlCfg ioctl_cfg;
|
||||
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
|
||||
|
|
|
@ -902,3 +902,118 @@ int AdapterDeviceNetstat(struct Adapter *adapter)
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description: Connect to a certain mqtt server
|
||||
* @param adapter - adapter device pointer
|
||||
* @param ip - connect ip
|
||||
* @param port - connect port
|
||||
* @param client_id - client id
|
||||
* @param username - client username
|
||||
* @param password - client password
|
||||
* @return success: 0 , failure: other
|
||||
*/
|
||||
int AdapterDeviceMqttConnect(struct Adapter *adapter, const char *ip, const char *port, const char *client_id, const char *username, const char *password)
|
||||
{
|
||||
if (!adapter)
|
||||
return -1;
|
||||
|
||||
if (PRIVATE_PROTOCOL == adapter->net_protocol) {
|
||||
printf("AdapterDeviceMqttConnect not suuport private_protocol, please use join\n");
|
||||
return -1;
|
||||
} else if (IP_PROTOCOL == adapter->net_protocol) {
|
||||
struct IpProtocolDone *ip_done = (struct IpProtocolDone *)adapter->done;
|
||||
|
||||
if (NULL == ip_done->mqttconnect)
|
||||
return -1;
|
||||
|
||||
return ip_done->mqttconnect(adapter, ip, port, client_id, username, password);
|
||||
} else {
|
||||
printf("AdapterDeviceMqttConnect net_protocol %d not support\n", adapter->net_protocol);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Adapter disconnect from mqtt server
|
||||
* @param adapter - adapter device pointer
|
||||
* @return success: 0 , failure: other
|
||||
*/
|
||||
int AdapterDeviceMqttDisconnect(struct Adapter *adapter)
|
||||
{
|
||||
if (!adapter)
|
||||
return -1;
|
||||
|
||||
if (PRIVATE_PROTOCOL == adapter->net_protocol) {
|
||||
printf("AdapterDeviceMqttDisconnect not suuport private_protocol, please use join\n");
|
||||
return -1;
|
||||
} else if (IP_PROTOCOL == adapter->net_protocol) {
|
||||
struct IpProtocolDone *ip_done = (struct IpProtocolDone *)adapter->done;
|
||||
|
||||
if (NULL == ip_done->mqttdisconnect)
|
||||
return -1;
|
||||
|
||||
return ip_done->mqttdisconnect(adapter);
|
||||
} else {
|
||||
printf("AdapterDeviceMqttDisconnect net_protocol %d not support\n", adapter->net_protocol);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Send data to mqtt server
|
||||
* @param adapter - adapter device pointer
|
||||
* @param topic - publish topic
|
||||
* @param buf - data buffer
|
||||
* @param len - data length
|
||||
* @return length of data written
|
||||
*/
|
||||
ssize_t AdapterDeviceMqttSend(struct Adapter *adapter, const char *topic, const void *buf, size_t len)
|
||||
{
|
||||
if (!adapter)
|
||||
return -1;
|
||||
|
||||
if (PRIVATE_PROTOCOL == adapter->net_protocol) {
|
||||
printf("AdapterDeviceMqttSend not support private_protocol, please use join\n");
|
||||
return -1;
|
||||
} else if (IP_PROTOCOL == adapter->net_protocol) {
|
||||
struct IpProtocolDone *ip_done = (struct IpProtocolDone *)adapter->done;
|
||||
|
||||
if (NULL == ip_done->mqttsend)
|
||||
return -1;
|
||||
|
||||
return ip_done->mqttsend(adapter, topic, buf, len);
|
||||
} else {
|
||||
printf("AdapterDeviceMqttSend net_protocol %d not support\n", adapter->net_protocol);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Receice data from mqtt server
|
||||
* @param adapter - adapter device pointer
|
||||
* @param topic - subscribe topic
|
||||
* @param buf - buffer to save data
|
||||
* @param len - buffer length
|
||||
* @return gotten data length
|
||||
*/
|
||||
ssize_t AdapterDeviceMqttRecv(struct Adapter *adapter, const char *topic, void *buf, size_t len)
|
||||
{
|
||||
if (!adapter)
|
||||
return -1;
|
||||
|
||||
if (PRIVATE_PROTOCOL == adapter->net_protocol) {
|
||||
printf("AdapterDeviceMqttRecv not support private_protocol, please use join\n");
|
||||
return -1;;
|
||||
} else if (IP_PROTOCOL == adapter->net_protocol) {
|
||||
struct IpProtocolDone *ip_done = (struct IpProtocolDone *)adapter->done;
|
||||
|
||||
if (NULL == ip_done->mqttrecv)
|
||||
return -1;
|
||||
|
||||
return ip_done->mqttrecv(adapter, topic, buf, len);
|
||||
} else {
|
||||
printf("AdapterDeviceMqttRecv net_protocol %d not support\n", adapter->net_protocol);
|
||||
return -1;
|
||||
}
|
||||
}
|
|
@ -118,6 +118,19 @@ enum IpType
|
|||
IPV6,
|
||||
};
|
||||
|
||||
enum CarrierType {
|
||||
CARRIER_CHINA_MOBILE = 1,
|
||||
CARRIER_CHINA_UNICOM,
|
||||
CARRIER_CHINA_TELECOM,
|
||||
CARRIER_UNKNOWN,
|
||||
};
|
||||
|
||||
struct NetworkInfo {
|
||||
enum CarrierType carrier_type;
|
||||
int signal_strength;
|
||||
char ip_address[16];
|
||||
};
|
||||
|
||||
struct AdapterData
|
||||
{
|
||||
uint32 len;
|
||||
|
@ -150,6 +163,10 @@ struct IpProtocolDone
|
|||
int (*send)(struct Adapter *adapter, const void *buf, size_t len);
|
||||
int (*recv)(struct Adapter *adapter, void *buf, size_t len);
|
||||
int (*disconnect)(struct Adapter *adapter);
|
||||
int (*mqttconnect)(struct Adapter *adapter, const char *ip, const char *port, const char *client_id, const char *username, const char *password);
|
||||
int (*mqttdisconnect)(struct Adapter *adapter);
|
||||
int (*mqttsend)(struct Adapter *adapter, const char *topic, const void *buf, size_t len);
|
||||
int (*mqttrecv)(struct Adapter *adapter, const char *topic, void *buf, size_t len);
|
||||
};
|
||||
|
||||
struct PrivProtocolDone
|
||||
|
@ -186,6 +203,8 @@ struct Adapter
|
|||
enum NetRoleType net_role;
|
||||
enum AdapterStatus adapter_status;
|
||||
|
||||
struct NetworkInfo network_info;
|
||||
|
||||
char buffer[ADAPTER_BUFFSIZE];
|
||||
|
||||
void *done;
|
||||
|
@ -254,6 +273,18 @@ int AdapterDevicePing(struct Adapter *adapter, const char *destination);
|
|||
/*Show the net status*/
|
||||
int AdapterDeviceNetstat(struct Adapter *adapter);
|
||||
|
||||
/*Connect to a certain mqtt server*/
|
||||
int AdapterDeviceMqttConnect(struct Adapter *adapter, const char *ip, const char *port, const char *client_id, const char *username, const char *password);
|
||||
|
||||
/*Adapter disconnect from mqtt server*/
|
||||
int AdapterDeviceMqttDisconnect(struct Adapter *adapter);
|
||||
|
||||
/*Send data to mqtt server*/
|
||||
ssize_t AdapterDeviceMqttSend(struct Adapter *adapter, const char *topic, const void *buf, size_t len);
|
||||
|
||||
/*Receice data from mqtt server*/
|
||||
ssize_t AdapterDeviceMqttRecv(struct Adapter *adapter, const char *topic, void *buf, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -225,6 +225,43 @@ __exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int AtGetNetworkInfoReply(ATAgentType agent, char *cmd, char *result)
|
||||
{
|
||||
int ret = 0;
|
||||
if (NULL == agent || NULL == cmd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ATReplyType reply = CreateATReply(256);
|
||||
if (NULL == reply) {
|
||||
printf("%s %d at_create_resp failed!\n",__func__,__LINE__);
|
||||
ret = -1;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
ret = ATOrderSend(agent, REPLY_TIME_OUT, reply, cmd);
|
||||
if(ret < 0){
|
||||
printf("%s %d ATOrderSend failed.\n",__func__,__LINE__);
|
||||
ret = -1;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
const char *replyText = GetReplyText(reply);
|
||||
if (replyText == NULL || replyText[0] == '\0') {
|
||||
printf("%s %n get reply failed.\n",__func__,__LINE__);
|
||||
ret = -1;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
strncpy(result, replyText, 63);
|
||||
result[63] = '\0';
|
||||
printf("[reply result: %s]\n", result);
|
||||
|
||||
__exit:
|
||||
DeleteATReply(reply);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *GetReplyText(ATReplyType reply)
|
||||
{
|
||||
return reply->reply_buffer;
|
||||
|
@ -355,7 +392,7 @@ static int GetCompleteATReply(ATAgentType agent)
|
|||
PrivMutexObtain(&agent->lock);
|
||||
if (agent->receive_mode == ENTM_MODE) {
|
||||
if (agent->entm_recv_len < ENTM_RECV_MAX) {
|
||||
#ifdef TOOL_USING_MQTT
|
||||
#ifdef LIB_USING_MQTT
|
||||
if((res == 1) && (agent->entm_recv_len < agent->read_len))
|
||||
{
|
||||
agent->entm_recv_buf[agent->entm_recv_len] = ch;
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#define REPLY_TIME_OUT 10
|
||||
|
||||
#ifdef TOOL_USING_OTA
|
||||
#define ENTM_RECV_MAX OTA_RX_BUFFERSIZE
|
||||
#define ENTM_RECV_MAX (OTA_FRAME_SIZE + 1024)
|
||||
#else
|
||||
#define ENTM_RECV_MAX 256
|
||||
#endif
|
||||
|
@ -104,5 +104,6 @@ int ParseATReply(char* str, const char *format, ...);
|
|||
void DeleteATReply(ATReplyType reply);
|
||||
int ATOrderSend(ATAgentType agent, uint32_t timeout_s, ATReplyType reply, const char *cmd_expr, ...);
|
||||
int AtCmdConfigAndCheck(ATAgentType agent, char *cmd, char *check);
|
||||
int AtGetNetworkInfoReply(ATAgentType agent, char *cmd, char *result);
|
||||
|
||||
#endif
|
|
@ -268,6 +268,7 @@ static int Hc08Open(struct Adapter *adapter)
|
|||
serial_cfg.ext_uart_no = ADAPTER_HC08_DRIVER_EXT_PORT;
|
||||
serial_cfg.port_configure = PORT_CFG_INIT;
|
||||
#endif
|
||||
serial_cfg.dev_recv_callback = NULL;
|
||||
|
||||
struct PrivIoctlCfg ioctl_cfg;
|
||||
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
|
||||
|
@ -326,6 +327,7 @@ static int Hc08Ioctl(struct Adapter *adapter, int cmd, void *args)
|
|||
serial_cfg.ext_uart_no = ADAPTER_HC08_DRIVER_EXT_PORT;
|
||||
serial_cfg.port_configure = PORT_CFG_INIT;
|
||||
#endif
|
||||
serial_cfg.dev_recv_callback = NULL;
|
||||
|
||||
serial_cfg.serial_timeout = -1;
|
||||
|
||||
|
|
|
@ -407,6 +407,7 @@ static int Hfa21EthernetIoctl(struct Adapter *adapter, int cmd, void *args)
|
|||
serial_cfg.ext_uart_no = ADAPTER_HFA21_DRIVER_EXT_PORT;
|
||||
serial_cfg.port_configure = PORT_CFG_INIT;
|
||||
#endif
|
||||
serial_cfg.dev_recv_callback = NULL;
|
||||
|
||||
struct PrivIoctlCfg ioctl_cfg;
|
||||
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
config CONNECTION_MODBUS
|
||||
bool "Using industrial fieldbus ModBus"
|
||||
default n
|
||||
|
||||
if CONNECTION_MODBUS
|
||||
source "$APP_DIR/Framework/connection/industrial_fieldbus/modbus/Kconfig"
|
||||
endif
|
||||
|
||||
|
||||
|
|
@ -1,3 +1,7 @@
|
|||
SRC_DIR :=
|
||||
|
||||
ifeq ($(CONFIG_CONNECTION_MODBUS),y)
|
||||
SRC_DIR += modbus
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
* FreeModbus Libary: BARE Demo Application
|
||||
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* File: $Id$
|
||||
*/
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbport.h"
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define REG_INPUT_START 1000
|
||||
#define REG_INPUT_NREGS 4
|
||||
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
static USHORT usRegInputStart = REG_INPUT_START;
|
||||
static USHORT usRegInputBuf[REG_INPUT_NREGS];
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
int
|
||||
main( void )
|
||||
{
|
||||
eMBErrorCode eStatus;
|
||||
|
||||
eStatus = eMBInit( MB_RTU, 0x0A, 0, 38400, MB_PAR_EVEN );
|
||||
|
||||
/* Enable the Modbus Protocol Stack. */
|
||||
eStatus = eMBEnable( );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
( void )eMBPoll( );
|
||||
|
||||
/* Here we simply count the number of poll cycles. */
|
||||
usRegInputBuf[0]++;
|
||||
}
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
int iRegIndex;
|
||||
|
||||
if( ( usAddress >= REG_INPUT_START )
|
||||
&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
|
||||
{
|
||||
iRegIndex = ( int )( usAddress - usRegInputStart );
|
||||
while( usNRegs > 0 )
|
||||
{
|
||||
*pucRegBuffer++ =
|
||||
( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
|
||||
*pucRegBuffer++ =
|
||||
( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
|
||||
iRegIndex++;
|
||||
usNRegs--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_ENOREG;
|
||||
}
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
|
||||
eMBRegisterMode eMode )
|
||||
{
|
||||
return MB_ENOREG;
|
||||
}
|
||||
|
||||
|
||||
eMBErrorCode
|
||||
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
|
||||
eMBRegisterMode eMode )
|
||||
{
|
||||
return MB_ENOREG;
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
|
||||
{
|
||||
return MB_ENOREG;
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* FreeModbus Libary: BARE Port
|
||||
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
|
||||
*
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#ifndef _PORT_H
|
||||
#define _PORT_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define INLINE inline
|
||||
#define PR_BEGIN_EXTERN_C extern "C" {
|
||||
#define PR_END_EXTERN_C }
|
||||
|
||||
#define ENTER_CRITICAL_SECTION( )
|
||||
#define EXIT_CRITICAL_SECTION( )
|
||||
|
||||
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
|
||||
|
||||
#endif
|
|
@ -1,152 +0,0 @@
|
|||
/*
|
||||
* FreeModbus Libary: BARE Port
|
||||
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
|
||||
*
|
||||
* 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$
|
||||
*/
|
||||
|
||||
|
||||
#include <adapter.h>
|
||||
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbport.h"
|
||||
|
||||
/* ----------------------- static functions ---------------------------------*/
|
||||
static void prvvUARTTxReadyISR( void );
|
||||
static void prvvUARTRxISR( void );
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
void
|
||||
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
|
||||
{
|
||||
/* If xRXEnable enable serial receive interrupts. If xTxENable enable
|
||||
* transmitter empty interrupts.
|
||||
*/
|
||||
|
||||
if(xRxEnable && !xTxEnable)//接收数据
|
||||
{
|
||||
Set485Input();
|
||||
}
|
||||
if(!xRxEnable && xTxEnable)
|
||||
{
|
||||
Set485Output();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
|
||||
{
|
||||
struct SerialDataCfg serial_cfg;
|
||||
memset(&serial_cfg, 0 ,sizeof(struct SerialDataCfg));
|
||||
serial_cfg.serial_baud_rate = (uint32_t)ulBaudRate;
|
||||
serial_cfg.serial_data_bits = (uint8_t)ucDataBits;
|
||||
serial_cfg.serial_stop_bits = STOP_BITS_1;
|
||||
serial_cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
|
||||
serial_cfg.serial_parity_mode = (uint8_t)eParity;
|
||||
serial_cfg.serial_bit_order = STOP_BITS_1;
|
||||
serial_cfg.serial_invert_mode = NRZ_NORMAL;
|
||||
serial_cfg.is_ext_uart = 0;
|
||||
|
||||
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBPortSerialPutByte( CHAR ucByte )
|
||||
{
|
||||
/* Put a byte in the UARTs transmit buffer. This function is called
|
||||
* by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
|
||||
* called. */
|
||||
Set485Output();
|
||||
PrivTaskDelay(20);
|
||||
|
||||
PrivWrite(uart_fd, ucByte, 1);
|
||||
|
||||
PrivTaskDelay(15);
|
||||
Set485Input();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBPortSerialGetByte( CHAR * pucByte )
|
||||
{
|
||||
/* Return the byte in the UARTs receive buffer. This function is called
|
||||
* by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
PrivRead(uart_fd, pucByte, 1);//
|
||||
|
||||
//need to wait 30ms , make sure write cmd again and receive data successfully
|
||||
PrivTaskDelay(30);
|
||||
|
||||
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.
|
||||
*/
|
||||
static 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.
|
||||
*/
|
||||
static void prvvUARTRxISR( void )
|
||||
{
|
||||
pxMBFrameCBByteReceived( );
|
||||
}
|
||||
|
||||
static int pin_fd = 0;
|
||||
static int uart_fd = 0;
|
||||
|
||||
/**
|
||||
* @description: Set Uart 485 Input
|
||||
* @return
|
||||
*/
|
||||
static void Set485Input(void)
|
||||
{
|
||||
struct PinStat pin_stat;
|
||||
pin_stat.pin = 2;//CONTROL_FRAMEWORK_UART_485_DIR
|
||||
pin_stat.val = GPIO_LOW;
|
||||
PrivWrite(pin_fd, &pin_stat, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Set Uart 485 Output
|
||||
* @return
|
||||
*/
|
||||
static void Set485Output(void)
|
||||
{
|
||||
struct PinStat pin_stat;
|
||||
pin_stat.pin = 2;//CONTROL_FRAMEWORK_UART_485_DIR
|
||||
pin_stat.val = GPIO_HIGH;
|
||||
PrivWrite(pin_fd, &pin_stat, 1);
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
choice
|
||||
prompt "choose ModBus type"
|
||||
default CONNECTION_MODBUS_USING_RTU
|
||||
|
||||
config CONNECTION_MODBUS_USING_RTU
|
||||
bool "select ModBus_RTU function"
|
||||
|
||||
config CONNECTION_MODBUS_USING_TCP
|
||||
bool "select ModBus_TCP function"
|
||||
endchoice
|
||||
|
||||
if CONNECTION_MODBUS_USING_RTU
|
||||
choice
|
||||
prompt "choose ModBus_RTU work mode"
|
||||
default CONNECTION_MODBUS_USING_RTU_MASTER
|
||||
|
||||
config CONNECTION_MODBUS_USING_RTU_MASTER
|
||||
bool "select ModBus_RTU master mode"
|
||||
|
||||
config CONNECTION_MODBUS_USING_RTU_SLAVE
|
||||
bool "select ModBus_RTU slave mode"
|
||||
endchoice
|
||||
|
||||
if CONNECTION_MODBUS_USING_RTU_MASTER
|
||||
menu "ModBus_RTU Master Register Configure"
|
||||
config X_M_DISCRETE_INPUT_START
|
||||
int "master discrete input start address"
|
||||
default 0
|
||||
|
||||
config X_M_DISCRETE_INPUT_NDISCRETES
|
||||
int "master discrete input discretes numbers"
|
||||
default 16
|
||||
|
||||
config X_M_COIL_START
|
||||
int "master coil start address"
|
||||
default 0
|
||||
|
||||
config X_M_COIL_NCOILS
|
||||
int "master coil numbers"
|
||||
default 64
|
||||
|
||||
config X_M_REG_INPUT_START
|
||||
int "master input start address"
|
||||
default 0
|
||||
|
||||
config X_M_REG_INPUT_NREGS
|
||||
int "master input regs numbers"
|
||||
default 100
|
||||
|
||||
config X_M_REG_HOLDING_START
|
||||
int "master holding start address"
|
||||
default 0
|
||||
|
||||
config X_M_REG_HOLDING_NREGS
|
||||
int "master holding regs numbers"
|
||||
default 100
|
||||
|
||||
config X_M_HD_RESERVE
|
||||
int "master holding reserve numbers"
|
||||
default 0
|
||||
|
||||
config X_M_IN_RESERVE
|
||||
int "master input reserve numbers"
|
||||
default 0
|
||||
|
||||
config X_M_CO_RESERVE
|
||||
int "master coil reserve numbers"
|
||||
default 0
|
||||
|
||||
config X_M_DI_RESERVE
|
||||
int "master discrete reserve numbers"
|
||||
default 0
|
||||
endmenu
|
||||
endif
|
||||
|
||||
if CONNECTION_MODBUS_USING_RTU_SLAVE
|
||||
menu "ModBus_RTU Slave Register Configure"
|
||||
config X_S_DISCRETE_INPUT_START
|
||||
int "slave discrete input start address"
|
||||
default 0
|
||||
|
||||
config X_S_DISCRETE_INPUT_NDISCRETES
|
||||
int "slave discrete input discretes numbers"
|
||||
default 16
|
||||
|
||||
config X_S_COIL_START
|
||||
int "slave coil start address"
|
||||
default 0
|
||||
|
||||
config X_S_COIL_NCOILS
|
||||
int "slave coil numbers"
|
||||
default 64
|
||||
|
||||
config X_S_REG_INPUT_START
|
||||
int "slave input start address"
|
||||
default 0
|
||||
|
||||
config X_S_REG_INPUT_NREGS
|
||||
int "slave input regs numbers"
|
||||
default 100
|
||||
|
||||
config X_S_REG_HOLDING_START
|
||||
int "slave holding start address"
|
||||
default 0
|
||||
|
||||
config X_S_REG_HOLDING_NREGS
|
||||
int "slave holding regs numbers"
|
||||
default 100
|
||||
|
||||
config X_S_HD_RESERVE
|
||||
int "slave holding reserve numbers"
|
||||
default 0
|
||||
|
||||
config X_S_IN_RESERVE
|
||||
int "slave input reserve numbers"
|
||||
default 0
|
||||
|
||||
config X_S_CO_RESERVE
|
||||
int "slave coil reserve numbers"
|
||||
default 0
|
||||
|
||||
config X_S_DI_RESERVE
|
||||
int "slave discrete reserve numbers"
|
||||
default 0
|
||||
endmenu
|
||||
endif
|
||||
|
||||
config CONNECTION_MODBUS_RTU_UART_485_DIR
|
||||
int "serial 485 direction pin number"
|
||||
default "67"
|
||||
|
||||
config CONNECTION_MODBUS_RTU_PIN_DEV
|
||||
string "device pin dev path for serial 485 DIR"
|
||||
default "/dev/pin_dev"
|
||||
|
||||
config CONNECTION_MODBUS_RTU_EXTUART
|
||||
bool "Using extra uart to support serial 485"
|
||||
default n
|
||||
|
||||
config CONNECTION_MODBUS_RTU_UART_DEV
|
||||
string "device uart dev path for serial 485"
|
||||
default "/dev/usart4_dev4"
|
||||
depends on !CONTROL_FRAMEWORK_DRIVER_EXTUART
|
||||
|
||||
if CONTROL_FRAMEWORK_DRIVER_EXTUART
|
||||
config CONNECTION_MODBUS_RTU_UART_DEV
|
||||
string "device extra uart dev path for serial 485"
|
||||
default "/dev/extuart_dev0"
|
||||
|
||||
config CONNECTION_MODBUS_RTU_UART_DEV_EXT_PORT
|
||||
int "if device using extuart, choose port"
|
||||
default "0"
|
||||
endif
|
||||
endif
|
||||
|
||||
if CONNECTION_MODBUS_USING_TCP
|
||||
config CONNECTION_MODBUS_USING_TCP_SLAVE
|
||||
bool "select ModBus_TCP slave mode"
|
||||
default y
|
||||
|
||||
if CONNECTION_MODBUS_USING_TCP_SLAVE
|
||||
menu "ModBus_TCP Slave Register Configure"
|
||||
config X_S_DISCRETE_INPUT_START
|
||||
int "slave discrete input start address"
|
||||
default 0
|
||||
|
||||
config X_S_DISCRETE_INPUT_NDISCRETES
|
||||
int "slave discrete input discretes numbers"
|
||||
default 16
|
||||
|
||||
config X_S_COIL_START
|
||||
int "slave coil start address"
|
||||
default 0
|
||||
|
||||
config X_S_COIL_NCOILS
|
||||
int "slave coil numbers"
|
||||
default 64
|
||||
|
||||
config X_S_REG_INPUT_START
|
||||
int "slave input start address"
|
||||
default 0
|
||||
|
||||
config X_S_REG_INPUT_NREGS
|
||||
int "slave input regs numbers"
|
||||
default 100
|
||||
|
||||
config X_S_REG_HOLDING_START
|
||||
int "slave holding start address"
|
||||
default 0
|
||||
|
||||
config X_S_REG_HOLDING_NREGS
|
||||
int "slave holding regs numbers"
|
||||
default 100
|
||||
|
||||
config X_S_HD_RESERVE
|
||||
int "slave holding reserve numbers"
|
||||
default 0
|
||||
|
||||
config X_S_IN_RESERVE
|
||||
int "slave input reserve numbers"
|
||||
default 0
|
||||
|
||||
config X_S_CO_RESERVE
|
||||
int "slave coil reserve numbers"
|
||||
default 0
|
||||
|
||||
config X_S_DI_RESERVE
|
||||
int "slave discrete reserve numbers"
|
||||
default 0
|
||||
endmenu
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
@ -1,3 +1,11 @@
|
|||
SRC_DIR :=
|
||||
SRC_DIR := freemodbus-latest
|
||||
|
||||
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU),y)
|
||||
SRC_FILES :=
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_TCP),y)
|
||||
SRC_FILES :=
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file adapter_Modbus_rtu.c
|
||||
* @brief Implement the connection 4G adapter function
|
||||
* @version 1.1
|
||||
* @author AIIT XIUOS Lab
|
||||
* @date 2021.06.25
|
||||
*/
|
||||
|
||||
#include <adapter.h>
|
||||
|
||||
|
||||
|
||||
static int AdapterModbusRtuRegister(struct Adapter *adapter)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
strncpy(adapter->name, ADAPTER_MODBUS_RTU_NAME, NAME_NUM_MAX);
|
||||
|
||||
adapter->net_protocol = PROTOCOL_NONE;//IP层协议类型,串口没有此层
|
||||
adapter->net_role = SLAVE;
|
||||
adapter->adapter_status = UNREGISTERED;
|
||||
|
||||
ret = AdapterDeviceRegister(adapter);
|
||||
if (ret < 0) {
|
||||
printf("AdapterModbusRtu register error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AdapterModbusRtuInit(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct Adapter *adapter = PrivMalloc(sizeof(struct Adapter));
|
||||
if (!adapter) {
|
||||
PrivFree(adapter);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(adapter, 0, sizeof(struct Adapter));
|
||||
|
||||
ret = AdapterModbusRtuRegister(adapter);
|
||||
if (ret < 0) {
|
||||
printf("AdapterModbusRtuInit register ModbusRtu adapter error\n");
|
||||
PrivFree(adapter);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,329 @@
|
|||
2013-10-17 (REL_1_6_0) Armink <armink.ztl@gmail.com>
|
||||
Notes: Added modbus master.
|
||||
|
||||
2010-05-06 (REL_1_5_0) Christian Walter <cwalter@embedded-solutions.at>
|
||||
Notes: Added support for Atmel AT91SAM3S (Cortex M3) for IAR.
|
||||
|
||||
Detailed notes:
|
||||
- FEATURES (ATSAM3S) : Added new port.
|
||||
|
||||
2007-08-28 (REL_1_4_0) Christian Walter <wolti@sil.at>:
|
||||
Notes: Added support for HCS08. Fixed some small bugs in the documentation
|
||||
for the porting layer.
|
||||
|
||||
Detailed notes:
|
||||
- FEATURES (HCS08) : Added new port.
|
||||
- BUGS (ALL) : Fixed some small bugs in the porting guide.
|
||||
|
||||
2007-07-17 (REL_1_3_0) Christian Walter <wolti@sil.at>:
|
||||
Notes: Added ARM7/AT91SAM7X port. Added Linux/TCP port from Steven Guo.
|
||||
|
||||
Detailed notes:
|
||||
- FEATURES (ARM7): Added ARM7/AT91SAM7x port.
|
||||
- FEATURES (LINUX): Added Linux/TCP port from Steven Guo.
|
||||
- BUGS (ALL): Fixed bug in <eMBFuncReadInputRegister> where the high
|
||||
byte of the register count was ignored. This does not have a
|
||||
practical impact because the actual number of registers is always
|
||||
lower.
|
||||
|
||||
2007-07-17 (REL_1_3_0) Christian Walter <wolti@sil.at>:
|
||||
Notes: Added Linux/TCP port. Fixed bug in MSP430 port.
|
||||
Detailted notes:
|
||||
- FEATURE (LINUX): Added Linux/TCP port.
|
||||
- BUGS (MSP430): Fixed bug with calculating the timer value.
|
||||
|
||||
2007-04-25 (REL_1_2_0) Christian Walter <wolti@sil.at>:
|
||||
Notes: Added LPC214X ARM port with Keil compiler. Added Z8Encore port for
|
||||
Z8F6422 microcontroller.
|
||||
|
||||
Detailed notes:
|
||||
- FEATURE (ARM): Added LPC214X ARM port for Keil ARM 2.41.
|
||||
- FEATURE (Z8ENCORE): Added Z8F6422 for Z8Encore using the ZDS II - Z8
|
||||
Encore! development tools.
|
||||
|
||||
2007-02-18 (REL_1_1_2) Christian Walter <wolti@sil.at>:
|
||||
Notes: Fixed typo with the defined defining the supported Modbus
|
||||
functions. Fixed bug when illegal slave address was passed to eMBInit
|
||||
where the error was not detected. Fixed typo in the holding registers
|
||||
where the frame for write multiple registers was parsed with the wrong
|
||||
constants. The fix is not critical because the values matched. Fixed bug
|
||||
in discrete input registers implementation where the frame was not parsed
|
||||
correctly. Added new support for a CodeWarrior Coldfire port.
|
||||
|
||||
Detailed notes:
|
||||
- BUG (ALL): Modbus functions are compiled into the stack conditionally
|
||||
by changing the MB_FUNC_XXX defines to either true(1) or false(0).
|
||||
The defines for MB_FUNC_READ_HOLDING and MB_FUNC_WRITE_HOLDING
|
||||
were wrong.
|
||||
- BUG (ALL): eMBInit did not correctly check for addresses. Therefore
|
||||
is was possible to start the Modbus stack with an address of 0
|
||||
or one > 247.
|
||||
- BUG (ALL): eMBFuncWriteHoldingRegister should use
|
||||
MB_PDU_FUNC_WRITE_MUL_ADDR_OFF and not MB_PDU_FUNC_READ_ADDR_OFF.
|
||||
- BUG (ALL): eMBFuncReadDiscreteInputs calculated the number of discrete
|
||||
registers to read wrong.
|
||||
- FEATURE (ALL): Fixed some warnings in the code.
|
||||
|
||||
2006-11-19 (REL_1_1_1) Christian Walter <wolti@sil.at>:
|
||||
Notes: Fixed bug in Read/Write Multiple Registers function where
|
||||
the registers addresses where calculated wrong.
|
||||
Fixed bug in RTU and ASCII with the resource allocation in case of
|
||||
an error.
|
||||
Changed license to BSD style licsense.
|
||||
|
||||
Detailed notes:
|
||||
- OTHER (ALL): License is now BSD for protocol stack.
|
||||
- BUG (ALL): The registers address received in a Modbus frame
|
||||
must be converted to application addresses. The code for this
|
||||
conversion was missing and therefore has lead to error when
|
||||
this function was used (Registers of by one, Start at > 1).
|
||||
- BUG (ALL): If the serial initialization within the porting fails
|
||||
a timer is still allocated in eMBRTUInit and eMBASCIIInit. This
|
||||
can lead to a memory leak depending upon the implementation of the
|
||||
porting layer.
|
||||
- FEATURE (MCF5235): Added sample shell scripts for testing.
|
||||
- FEATURE (MSP430): Added sample shell script for testing and
|
||||
changed default values to match the other ports.
|
||||
|
||||
2006-10-30 (REL_1_1_0) Christian Walter <wolti@sil.at>:
|
||||
Notes: Added support for Read/Write Multiple Registers function
|
||||
(0x17). Added some tips to reduce memory requirements.
|
||||
Added MSP430 Port for GCC and Rowley Crossworks.
|
||||
|
||||
Detailed notes:
|
||||
- FEATURE (MSP430): Added new MSP430 port.
|
||||
- FEATURE (ALL): Added support for Read/Write Multiple Registers
|
||||
function (0x17). The implementation simply makes two callbacks
|
||||
to the eMBRegHoldingCB function where first the values are
|
||||
written and then the other register values are read.
|
||||
- FEATURE (ALL): Added some tips on reducing memory requirements
|
||||
with the protocol stack.
|
||||
|
||||
2006-10-30 (REL_1_0_5) Christian Walter <wolti@sil.at>:
|
||||
Notes: eMBDisable and eMBClose can now be called multiple times
|
||||
which makes shutdown of the protocol stack easier.
|
||||
Fixed bug in RTU state machine where we switched from the
|
||||
error state immediately to the idle state. Correct behaviour
|
||||
would be to wait till the end of frame.
|
||||
Added new STR71X GCC port which uses only freely available tools
|
||||
like GNU ARM, OpenOCD (Wiggler) and GDB.
|
||||
|
||||
Detailed notes:
|
||||
- FEATURE (STR71X): Added GCC standalone port which does not
|
||||
depend on the Rowley Crosswork tools.
|
||||
- FEATURE (ALL): eMBDisable can now be called multiple times
|
||||
and returns MB_ENOERR in case is was already disabled.
|
||||
eMBClose also supports beeing called multiple times in
|
||||
which pvMBFrameCloseCur( ) is called when the protocol stack
|
||||
is in state STATE_DISABLED.
|
||||
- BUG (RTU): Fixed bug in xMBRTUReceiveFSM where the error
|
||||
state is immediately left because of a missing break. Instead
|
||||
we should wait till the damaged frame is finished.
|
||||
|
||||
2006-10-11 (REL_1_0_4) Christian Walter <wolti@sil.at>:
|
||||
Notes: Fixed bug when more than 255 coils are requested. Fixed bug in
|
||||
Linux/Cygwin port when not all bytes could be written by the first
|
||||
call to write. Added support for removing previously registered
|
||||
function handlers.
|
||||
|
||||
Detailed notes:
|
||||
- BUG (ALL): mbfunccoils contained a bug which limited the amount
|
||||
of coils to read to 255.
|
||||
- BUG (LINUX): prvbMBPortSerialWrite contained a bug in the loop
|
||||
which writes the RTU/ASCII frame to the serial file descriptor.
|
||||
If not all bytes where written in the first call or write was
|
||||
interrupted the sent frame is corrupted.
|
||||
- FEATURE (ALL): eMBRegisterCB now supports NULL as handler
|
||||
argument in which case a previously registered function
|
||||
handler is deregistered from the protocol stack.
|
||||
|
||||
2006-09-27 (REL_1_0_3) Christian Walter <wolti@sil.at>:
|
||||
Notes: Added new functions to support registering of custom callback
|
||||
handlers. This makes it possible to implement new Modbus function
|
||||
codes without touching the protocol stack.
|
||||
New port for ATMega128 added. Thanks to Richard C Sandoz Jr. for
|
||||
the patches.
|
||||
|
||||
Detailed notes:
|
||||
- FEATURE (ALL): Added support for registering new functions handlers
|
||||
with eMBRegisterCB.
|
||||
- FEATURE (AVR): Added patches from Richard C Sandoz Jr. for ATMega128
|
||||
|
||||
2006-09-06 (REL_1_0_2) Christian Walter <wolti@sil.at>:
|
||||
Notes: Fixed bug in FreeRTOS porting layer for STR71X/lwIP target where
|
||||
memory is not freed in the sys_arch_thread_remove function.
|
||||
Synched MCF5235TCP port with the FreeRTOS/lwIP port for the STR71X.
|
||||
|
||||
Detailed notes:
|
||||
- BUG (STR71XTCP): Sys_arch_thread_remove did not free the memory from
|
||||
the TCB.
|
||||
- BUG (STR71XTCP): Unnecessary call to vTaskSuspendAll removed.
|
||||
- BUG (STR71XTCP): Bug with counting variable. The first to lwIP tasks
|
||||
got the same name (lwIP0).
|
||||
- FEATURE (MCF5235TCP): Enhanced functions from the STR71X/lwIP port
|
||||
merged into the Coldfire port.
|
||||
|
||||
2006-09-04 (REL_1_0_1) Christian Walter <wolti@sil.at>:
|
||||
Notes: Fixed bug in serial driver for STR71x target when the ring buffer
|
||||
overflows.
|
||||
|
||||
Detailed notes:
|
||||
- BUG (STR71XTCP): Under high load the ring buffer in the serial driver
|
||||
functions might overflow. There was an error with counting the number
|
||||
of received characters which corrupted received frames.
|
||||
Now receiver correctly recovers in case of dropped bytes.
|
||||
|
||||
2006-09-04 (REL_1_0) Christian Walter <wolti@sil.at>:
|
||||
Notes: Added support for ATmega8, ATmega16, ATmega32, ATmega169 and
|
||||
RS485 drivers in the AVR support. Special thanks to Tran Minh Hoang
|
||||
for his contribution.
|
||||
Added a new lwIP port for the STR71X target which uses one serial
|
||||
interface for a PPP connection. This can be used for remote Modbus/TCP
|
||||
devices in combination with a Modem (E.g. GPRS or Analog).
|
||||
|
||||
Detailed notes:
|
||||
- FEATURES (AVR): Integrated patches from Tran Minh Hoang to support the
|
||||
ATmega8, ATmega16, ATmega32, ATmega169 controllers.
|
||||
- FEATURES (AVR): Added support for RS485 drivers in the AVR code. The
|
||||
example supports the DS76176.
|
||||
- FEATURES (STR71XTCP): implemented function in STR71X/lwIP porting layer
|
||||
to remove running tasks.
|
||||
- FEATURES (STR71XTCP): added new thread creation function in STR71X/lwIP
|
||||
porting layer which allows specifing the stack size.
|
||||
- BUGS (STR71XTCP): pppOpen defined in ppp.c does not check the return
|
||||
value of sys_thread_new. If task creation fails the system crashes.
|
||||
- BUGS (STR71XTCP): pppMain must not return - Instead it should remove
|
||||
its task from the scheduler.
|
||||
|
||||
2006-08-30 (REL_9) Christian Walter <wolti@sil.at>:
|
||||
Notes: Added lwIP port for the MCF5235 target. The lwIP part is
|
||||
generic and therefore FreeModbus now works on any target with
|
||||
lwIP support.
|
||||
|
||||
Detailed notes:
|
||||
- FEATURES: Incoperated MCF5235 FreeRTOS/lwIP port done by the
|
||||
author in this project.
|
||||
- FEATURES: Added lwIP port for FreeModbus
|
||||
- FEATURES: Added demo application for FreeModbus and lwIP.
|
||||
|
||||
2006-08-22 (REL_0_82) Christian Walter <wolti@sil.at>
|
||||
Notes: Fixed bug with Modbus ASCII support
|
||||
|
||||
Detailed notes:
|
||||
- BUG: During the last upgrade an error was introduced in the
|
||||
initialization code of Modbus ASCII and therefore ASCII
|
||||
support was broken. The bug is fixed now and was tested with
|
||||
the Win32 port.
|
||||
|
||||
2006-08-22 (REL_0_81) Christian Walter <wolti@sil.at>
|
||||
Notes: Added porting guide
|
||||
|
||||
Detailed notes:
|
||||
- OTHER: Added a new porting guide to the documentation.
|
||||
- OTHER: Added a empty example for new ports to the project as a
|
||||
starting point.
|
||||
|
||||
2006-08-01 (REL_0_8) Christian Walter <wolti@sil.at>
|
||||
Notes: Added Linux RTU/ASCII port.
|
||||
|
||||
Detailed notes:
|
||||
- FEATURES: Added a new Linux RTU/ASCII port. The port should work
|
||||
on any Linux distribution and it should be possible to run it
|
||||
on uCLinux.
|
||||
|
||||
2006-06-26 (REL_0_7) Christian Walter <wolti@sil.at>
|
||||
Notes: Changed the WIN32 serial port to better fit into the design.
|
||||
|
||||
Detailed notes:
|
||||
- OTHER: Design of the WIN32 serial port changed. The polling function
|
||||
for the serial device are now called from the event loop.
|
||||
- OTHER: Debugging uses the same interface as the WIN32/TCP port.
|
||||
|
||||
2006-06-25 Christian Walter <wolti@sil.at>
|
||||
|
||||
Notes: Initial work on a Modbus/TCP port is available. The port includes
|
||||
an example for a Win32 port which uses the Winsock API.
|
||||
|
||||
Detailed notes:
|
||||
- FEATURES: added required functions to core protocol stack to support
|
||||
a Modbus/TCP implementation.
|
||||
- FEATURES: added a Win32 port for the Modbus/TCP core. The port is
|
||||
currently limited to one concurrent client.
|
||||
- OTHER: The implementation of eMBClose to shutdown the protocol stack
|
||||
was changed to unify it with the new Modbus/TCP code.
|
||||
-
|
||||
|
||||
2006-06-18 Christian Walter <wolti@sil.at>
|
||||
|
||||
Detailed notes:
|
||||
- OTHER: while working on the Win32 port some line feeds got
|
||||
wrong. Also some source files used tabs instead of spaces.
|
||||
- OTHER: prototypes for xMBUtilSetBits and xMBUtilGetBits fixed.
|
||||
usNBits should be ucNBits by convention.
|
||||
|
||||
2006-06-17 Christian Walter <wolti@sil.at>
|
||||
|
||||
Notes: Fixed various bugs with the Win32 port
|
||||
|
||||
Detailed notes:
|
||||
- FEATURES: implement shutdown functionality for protocol stack.
|
||||
- FEATURES: protocol stack can be enabled and disabled during runtime.
|
||||
- FEATURES: interface functions now do more error checking. For
|
||||
example if eMBPool is called in an uninitialized state.
|
||||
- FEATURES: extended Win32 demo application to use the new features.
|
||||
- BUG: fixed bug in Win32 demo for ASCII mode.
|
||||
|
||||
2006-06-16 Christian Walter <wolti@sil.at>
|
||||
Notes: The new version includes a new port for the
|
||||
Win32 platform
|
||||
|
||||
Detailed notes:
|
||||
- FEATURES: added Win32 platform
|
||||
|
||||
2006-05-14 Christian Walter <wolti@sil.at>
|
||||
Notes: The new version includes a new port for the
|
||||
Freescale MCF5235 processor.
|
||||
|
||||
Detailed notes:
|
||||
- FEATURES: added new MCF5235 port.
|
||||
- OTHER: fixed some missing code headers.
|
||||
|
||||
2006-05-01 Christian Walter <wolti@sil.at>
|
||||
Notes: This version removes the t1.5 timers from the Modbus RTU
|
||||
implementation because no one actually uses it and the CPU
|
||||
load is very high. T
|
||||
In addition some documentation cleanups has been done and the
|
||||
ARM demo has been updated.
|
||||
|
||||
Detailed notes:
|
||||
|
||||
- FEATURES: the t1.5 timeout has been removed. Therefore only
|
||||
one timer is required.
|
||||
- BUG: the ARM demo project missed some files in the project
|
||||
workspace and did not compile cleanly
|
||||
|
||||
2006-02-28 Christian Walter <wolti@sil.at>
|
||||
Notes: This version includes support for two new command
|
||||
(write multiple coils, read discrete input)
|
||||
|
||||
Detailed notes:
|
||||
- BUG: some function used the wrong data types
|
||||
- FEATURES: added support for write multiple coils function.
|
||||
- FEATURES: added support for read discrete input.
|
||||
- OTHER: some code cleanups with lint tool.
|
||||
|
||||
2006-02-28 Christian Walter <wolti@sil.at>
|
||||
|
||||
Notes: The new version 0.31 adds support for reading and writing the
|
||||
coil registers and add some bug fixes.
|
||||
|
||||
Detailed notes:
|
||||
- BUG: fixed bug with to small modbus requests being ignored.
|
||||
- FEATURES: added support for write single coil function.
|
||||
- FEATURES: added support for working with byte packed bit fields
|
||||
to support coils and discrete inputs better.
|
||||
- API: API for set slave id functions changed.
|
||||
|
||||
2006-02-26 Christian Walter <wolti@sil.at>
|
||||
|
||||
Notes: First public release which includes an ARM and AVR port.
|
|
@ -0,0 +1,26 @@
|
|||
Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||
Copyright (c) 2013-2019 Armink <armink.ztl@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
SRC_DIR := modbus port samples
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,307 @@
|
|||
# Freemodbus
|
||||
|
||||
[中文页](README_ZH.md) | English
|
||||
|
||||
## Introduction
|
||||
|
||||
This is the Freemodbus protocol stack ported by armink. Support the functions of the master and slave at the same time.
|
||||
|
||||
FreeModbus is an open source Modbus protocol stack, but only the slave is open source, and the host source code is **charged**. At the same time, no better open source Modbus host protocol stack was found on the Internet, so this FreeModbus protocol stack supporting host mode was developed. This version of FreeModbus has been changed to V1.6 and features are as follows:
|
||||
|
||||
- The newly added host source code is consistent with the style and interface of the original slave;
|
||||
- Support the host and slave to run in the same protocol stack;
|
||||
- Support real-time operating system and bare metal transplantation;
|
||||
- Provide a variety of request modes for applications, users can choose blocking or non-blocking mode, custom timeout time, etc., to facilitate flexible calls at the application layer;
|
||||
- Support all common Modbus methods.
|
||||
|
||||
### File structure
|
||||
|
||||
| Source File | Description |
|
||||
| --------------------------------------------- | ----------------------------------------------- |
|
||||
| FreeModbus\modbus\mb.c | Provides Modbus slave settings and polling related interfaces for the application layer |
|
||||
| FreeModbus\modbus\mb_m.c | Provides Modbus host settings and polling related interfaces for the application layer |
|
||||
| FreeModbus\modbus\ascii\mbascii.c | ASCII mode settings and state machine |
|
||||
| FreeModbus\modbus\functions\mbfunccoils.c | Slave coil related functions |
|
||||
| FreeModbus\modbus\functions\mbfunccoils_m.c | Host coil related functions |
|
||||
| FreeModbus\modbus\functions\mbfuncdisc.c | Slave Discrete Input Related Functions |
|
||||
| FreeModbus\modbus\functions\mbfuncdisc_m.c | Discrete input related functions of the host |
|
||||
| FreeModbus\modbus\functions\mbfuncholding.c | Slave holding register related functions |
|
||||
| FreeModbus\modbus\functions\mbfuncholding_m.c | Host holding register related functions |
|
||||
| FreeModbus\modbus\functions\mbfuncinput.c | Slave input register related functions |
|
||||
| FreeModbus\modbus\functions\mbfuncinput_m.c | Host input register related functions |
|
||||
| FreeModbus\modbus\functions\mbfuncother.c | Other Modbus functions |
|
||||
| FreeModbus\modbus\functions\mbutils.c | Some small tools that need to be used in the protocol stack |
|
||||
| FreeModbus\modbus\rtu\mbcrc.c | CRC check function |
|
||||
| FreeModbus\modbus\rtu\mbrtu.c | Slave RTU mode settings and state machine |
|
||||
| FreeModbus\modbus\rtu\mbrtu_m.c | Host RTU mode settings and state machine |
|
||||
| FreeModbus\modbus\tcp\mbtcp.c | TCP mode settings and state machine |
|
||||
| FreeModbus\port\port.c | Implement hardware porting part of the interface |
|
||||
| FreeModbus\port\portevent.c | Implement slave event porting interface |
|
||||
| FreeModbus\port\portevent_m.c | Implement host event and error handling porting interface |
|
||||
| FreeModbus\port\portserial.c | Slave port porting |
|
||||
| FreeModbus\port\portserial_m.c | Host serial port porting |
|
||||
| FreeModbus\port\porttimer.c | Slave timer porting |
|
||||
| FreeModbus\port\porttimer_m.c | Host timer porting |
|
||||
| FreeModbus\port\user_mb_app.c | Define slave data buffer, realize the callback interface of slave Modbus function |
|
||||
| FreeModbus\port\user_mb_app_m.c | Define host data buffer, realize the callback interface of host Modbus function |
|
||||
| FreeModbus\samples\sample_mb_master.c | Sample code for host use |
|
||||
| FreeModbus\samples\sample_mb_slave.c | Slave use sample code |
|
||||
| FreeModbus\samples\README.md | Sample code description document |
|
||||
|
||||
> Note: All files with the _m suffix are the files that must be used in the master mode. If the slave mode is used, these files are not required.
|
||||
|
||||
### License
|
||||
|
||||
The Freemodbus software package complies with the BSD license, see the `LICENSE` file for details.
|
||||
|
||||
### Dependence
|
||||
|
||||
- RT_Thread UART device
|
||||
|
||||
## method of obtaining
|
||||
|
||||
To use the Freemodbus software package, you need to select it in the RT-Thread package manager. The specific path is as follows:
|
||||
|
||||
```
|
||||
RT-Thread online packages
|
||||
IoT-internet of things --->
|
||||
[*] FreeModbus: Modbus master and slave stack --->
|
||||
[*] Master mode --->
|
||||
[*] Slave mode --->
|
||||
```
|
||||
|
||||
Finally, let RT-Thread's package manager automatically update, or use the `pkgs --update` command to update the package to the BSP.
|
||||
|
||||
## Instructions
|
||||
|
||||
### Data buffer
|
||||
|
||||
The location defined by the data buffer is at the top of the `FreeModbus\port\user_mb_app_m.c` file, with a total of **4** data types. By default, FreeModbus slaves use **one-dimensional array** as the data structure of the buffer area. The host can store the data of all slaves in the network, so the host uses **two-dimensional array** to store all slave node data. The column number of the two-dimensional array represents the register, coil and discrete address, and the row number represents the slave node ID, but it needs to be reduced by one. For example, `usMRegHoldBuf[2][1]` means the slave ID is 3, and the register address is maintained The slave data is 1.
|
||||
|
||||
### Modbus data processing callback interface
|
||||
|
||||
Modbus has 4 different data types in total, and all Modbus functions operate around these data types. Since different user data buffer structures may be different, the corresponding Modbus data processing methods are also different, so users need to customize the operations corresponding to each data type according to their own data buffer structure. All Modbus data processing callback interfaces are as follows:
|
||||
|
||||
| Interface | Function description |
|
||||
| ---------------------- | ------------------ |
|
||||
| eMBMasterRegInputCB | Input register callback interface |
|
||||
| eMBMasterRegHoldingCB | Holding register callback interface |
|
||||
| eMBMasterRegCoilsCB | Coil callback interface |
|
||||
| eMBMasterRegDiscreteCB | Discrete input callback interface |
|
||||
|
||||
> For the data buffer structure in the form of an array, the source code has already been transplanted and can be used directly.
|
||||
|
||||
### Initial configuration process
|
||||
|
||||
All configuration parameters of this protocol stack are located in `FreeModbus\modbus\include\mbconfig.h`, currently the protocol stack supports two modes of master and slave, and supports **both modes to be turned on at the same time**. The slave supports Modbus RTU, Modbus ASCII and Modbus TCP 3 modes, and the master now only supports the commonly used **Modbus RTU** mode. In the process of using the master, the user needs to configure the broadcast conversion delay time, command response timeout time and the number of slaves. It should be noted that the current protocol stack only supports continuous slave addresses, and the starting address starts from 1**.
|
||||
|
||||
### Normal use process
|
||||
|
||||
1. Call the `eMBMasterInit` method to initialize the Modbus host protocol stack, and some hardware related to the host is initialized at this time
|
||||
2. Call the `eMBMasterEnable` method to start the Modbus master
|
||||
3. By calling the `eMBMasterPoll` method in thread or timer polling, the polling cycle determines the response time of the command.
|
||||
4. Call the host to request the API method, set a certain request timeout period, and will not return until the method has a result. If the method is executed successfully and the command is a read command, you can obtain the latest slave data by viewing the data buffer of the Modbus master.
|
||||
|
||||
> For specific usage, please refer to the sample code in the `/samples` directory. Debugging the Modbus master-slave program can be debugged with Modbus Poll and Modbus slave software on the PC.
|
||||
|
||||
### Exception handling process
|
||||
|
||||
Exception handling mainly occurs during the normal use of the host. All the error codes of the host request API have been described at the beginning of Chapter 3. For these error codes, users need to complete different actions according to their own product features. It is recommended that users encapsulate and implement the retransmission mechanism of the host request method. This implementation is more flexible. Generally, retransmission is required when receiving frame data errors and command response timeout error codes. The number of retransmissions is automatically increased by one. If the set value is exceeded, the slave is considered to be offline, and all subsequent commands sent to this slave are intercepted in advance; if the second retransmission command response is successful, **automatically cleared** the slave retransmits frequency. All the above functions can be realized by using the host request method or using the callback interface in `FreeModbus\port\portevent_m.c`, and users can choose flexibly according to their needs.
|
||||
|
||||
## API detailed
|
||||
|
||||
The Modbus master is very different from the slave in the use process. The slave needs to passively wait for the request of the master, while the master actively sends out the request and receives and processes the response from the slave. When the host sends a broadcast request, the slave does not need to return a response, so the broadcast request is suitable for the master's write slave data command, not suitable for the read slave data command. The return value format of all methods in the host request API is the same, and the meaning of the return value is as follows.
|
||||
|
||||
| Return value | Description |
|
||||
| ------------------ | ------------------------------------------- |
|
||||
| MB_MRE_NO_ERR | Normal, no error |
|
||||
| MB_MRE_NO_REG | Register, coil or discrete input address error |
|
||||
| MB_MRE_ILL_ARG | Incorrect input parameter format |
|
||||
| MB_MRE_REV_DATA | Receive data error |
|
||||
| MB_MRE_TIMEDOUT | Response timed out. The host did not receive the response from the slave within the set time. |
|
||||
| MB_MRE_MASTER_BUSY | The host is busy. The request was not sent within the set time. |
|
||||
| MB_MRE_EXE_FUN | After the host receives the response, an error occurs when executing the Modbus method (function). |
|
||||
|
||||
> All host request methods are **thread safe** and **blocking mode**. During use, as long as the host resource is not obtained within the set timeout period, it will return that the host is busy; if the host resource is obtained within the set timeout period, it must wait for the request result before returning.
|
||||
|
||||
### Write a single holding register
|
||||
|
||||
Write data to a holding register of the slave
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr,
|
||||
USHORT usRegAddr,
|
||||
USHORT usRegData,
|
||||
LONG lTimeOut );
|
||||
```
|
||||
|
||||
| Parameters | Description |
|
||||
| --------- | ----------------------------------------------------------- |
|
||||
| ucSndAddr | Requested slave address, 0 means broadcast. |
|
||||
| usRegAddr | Write register address |
|
||||
| usRegData | Write register data |
|
||||
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
|
||||
|
||||
### Write multiple holding registers
|
||||
|
||||
Write data to multiple holding registers of the slave.
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr,
|
||||
USHORT usRegAddr,
|
||||
USHORT usNRegs,
|
||||
USHORT * pusDataBuffer,
|
||||
LONG lTimeOut)
|
||||
```
|
||||
|
||||
| Parameters | Description |
|
||||
| ------------- | ----------------------------------------------------------- |
|
||||
| ucSndAddr | Requested slave address, 0 means broadcast. |
|
||||
| usRegAddr | Start address of write register |
|
||||
| usNRegs | Total number of write registers |
|
||||
| pusDataBuffer | Write register data |
|
||||
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
|
||||
|
||||
### Read multiple holding registers
|
||||
|
||||
Read data in multiple holding registers
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr,
|
||||
USHORT usRegAddr,
|
||||
USHORT usNRegs,
|
||||
LONG lTimeOut );
|
||||
```
|
||||
|
||||
| Parameters | Description |
|
||||
| --------- | ----------------------------------------------------------- |
|
||||
| ucSndAddr | Requested slave address, 0 means broadcast. |
|
||||
| usRegAddr | Read register address |
|
||||
| usRegData | Number of read registers |
|
||||
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
|
||||
|
||||
### Read and write multiple holding registers
|
||||
|
||||
Read multiple registers first, and then write multiple registers.
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
|
||||
USHORT usReadRegAddr,
|
||||
USHORT usNReadRegs,
|
||||
USHORT * pusDataBuffer,
|
||||
USHORT usWriteRegAddr,
|
||||
USHORT usNWriteRegs,
|
||||
LONG lTimeOut)
|
||||
```
|
||||
|
||||
| Parameters | Description |
|
||||
| -------------- | ----------------------------------------------------------- |
|
||||
| ucSndAddr | Requested slave address, 0 means broadcast. |
|
||||
| usReadRegAddr | Read register address |
|
||||
| usNReadRegs | Number of read registers |
|
||||
| pusDataBuffer | Write register data |
|
||||
| usWriteRegAddr | Write register address |
|
||||
| usNWriteRegs | Number of write registers |
|
||||
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
|
||||
|
||||
### Read multiple input registers
|
||||
|
||||
Read data in multiple input registers
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqReadInputRegister( UCHAR ucSndAddr,
|
||||
USHORT usRegAddr,
|
||||
USHORT usNRegs,
|
||||
LONG lTimeOut );
|
||||
```
|
||||
|
||||
| Parameters | Description |
|
||||
| --------- | ----------------------------------------------------------- |
|
||||
| ucSndAddr | Requested slave address, 0 means broadcast. |
|
||||
| usRegAddr | Read register address |
|
||||
| usRegData | Number of read registers |
|
||||
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
|
||||
|
||||
### Write a single coil
|
||||
|
||||
Write data to a coil of the slave
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqWriteCoil( UCHAR ucSndAddr,
|
||||
USHORT usCoilAddr,
|
||||
USHORT usCoilData,
|
||||
LONG lTimeOut)
|
||||
```
|
||||
|
||||
| Parameters | Description |
|
||||
| ---------- | ----------------------------------------------------------- |
|
||||
| ucSndAddr | Requested slave address, 0 means broadcast. |
|
||||
| usCoilAddr | Write the address of the coil |
|
||||
| usCoilData | Number of write coils |
|
||||
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
|
||||
|
||||
### Write multiple coils
|
||||
|
||||
Write data to multiple coils of the slave.
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
|
||||
USHORT usCoilAddr,
|
||||
USHORT usNCoils,
|
||||
UCHAR * pucDataBuffer,
|
||||
LONG lTimeOut)
|
||||
```
|
||||
|
||||
| Parameters | Description |
|
||||
| ------------- | ----------------------------------------------------------- |
|
||||
| ucSndAddr | Requested slave address, 0 means broadcast. |
|
||||
| usCoilAddr | Write the start address of the coil |
|
||||
| usNCoils | Total number of write coils |
|
||||
| pucDataBuffer | Write coil data |
|
||||
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
|
||||
|
||||
### Read multiple coils
|
||||
|
||||
Read data from multiple coils
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqReadCoils( UCHAR ucSndAddr,
|
||||
USHORT usCoilAddr,
|
||||
USHORT usNCoils,
|
||||
LONG lTimeOut)
|
||||
```
|
||||
|
||||
| Parameters | Description |
|
||||
| ---------- | ------------------------------------------------------------ |
|
||||
| ucSndAddr | Requested slave address, 0 means broadcast. |
|
||||
| usCoilAddr | Read the address of the coil |
|
||||
| usNCoils | Number of reading coils |
|
||||
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
|
||||
|
||||
### Read multiple discrete inputs
|
||||
|
||||
Read data from multiple discrete inputs
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr,
|
||||
USHORT usDiscreteAddr,
|
||||
USHORT usNDiscreteIn,
|
||||
LONG lTimeOut)
|
||||
```
|
||||
|
||||
| Parameters | Description |
|
||||
| -------------- | ------------------------------------------------------------ |
|
||||
| ucSndAddr | Requested slave address, 0 means broadcast. |
|
||||
| usDiscreteAddr | Read the address of discrete input |
|
||||
| usNDiscreteIn | Read the number of discrete inputs |
|
||||
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
|
||||
|
||||
## Precautions
|
||||
|
||||
- The slave supports Modbus RTU, Modbus ASCII and Modbus TCP 3 modes. The master now only supports the commonly used **Modbus RTU** mode.
|
||||
- Currently the protocol stack only supports **continuous slave address**, and the starting address **starts from 1**.
|
||||
|
||||
## Contact information
|
||||
|
||||
- Maintenance: RT-Thread development team and community developers
|
||||
- Homepage: <https://github.com/RT-Thread-packages/freemodbus>
|
|
@ -0,0 +1,308 @@
|
|||
# Freemodbus
|
||||
|
||||
中文页 | [English](README.md)
|
||||
|
||||
## 简介
|
||||
|
||||
这是 armink 大神移植的 Freemodbus 协议栈。同时支持主机和从机的功能。
|
||||
|
||||
FreeModbus 是一款开源的 Modbus 协议栈,但是只有从机开源,主机源码是需要**收费**的。同时网上也没有发现比较好的开源的 Modbus 主机协议栈,所以才开发这款支持主机模式的 FreeModbus 协议栈。本版 FreeModbus版本号更改为V1.6,特性如下:
|
||||
|
||||
- 新增加的主机源码与原有从机的风格及接口保持一致;
|
||||
- 支持主机与从机在同一协议栈运行;
|
||||
- 支持实时操作系统及裸机移植;
|
||||
- 为应用提供多种请求模式,用户可以选择阻塞还是非阻塞模式,自定义超时时间等,方便应用层灵活调用;
|
||||
- 支持所有常用的Modbus方法。
|
||||
|
||||
### 文件结构
|
||||
|
||||
| 源文件 | 描述 |
|
||||
| --------------------------------------------- | ------------------------------------------------ |
|
||||
| FreeModbus\modbus\mb.c | 给应用层提供Modbus从机设置及轮询相关接口 |
|
||||
| FreeModbus\modbus\mb_m.c | 给应用层提供Modbus主机设置及轮询相关接口 |
|
||||
| FreeModbus\modbus\ascii\mbascii.c | ASCII模式设置及其状态机 |
|
||||
| FreeModbus\modbus\functions\mbfunccoils.c | 从机线圈相关功能 |
|
||||
| FreeModbus\modbus\functions\mbfunccoils_m.c | 主机线圈相关功能 |
|
||||
| FreeModbus\modbus\functions\mbfuncdisc.c | 从机离散输入相关功能 |
|
||||
| FreeModbus\modbus\functions\mbfuncdisc_m.c | 主机离散输入相关功能 |
|
||||
| FreeModbus\modbus\functions\mbfuncholding.c | 从机保持寄存器相关功能 |
|
||||
| FreeModbus\modbus\functions\mbfuncholding_m.c | 主机保持寄存器相关功能 |
|
||||
| FreeModbus\modbus\functions\mbfuncinput.c | 从机输入寄存器相关功能 |
|
||||
| FreeModbus\modbus\functions\mbfuncinput_m.c | 主机输入寄存器相关功能 |
|
||||
| FreeModbus\modbus\functions\mbfuncother.c | 其余Modbus功能 |
|
||||
| FreeModbus\modbus\functions\mbutils.c | 一些协议栈中需要用到的小工具 |
|
||||
| FreeModbus\modbus\rtu\mbcrc.c | CRC校验功能 |
|
||||
| FreeModbus\modbus\rtu\mbrtu.c | 从机RTU模式设置及其状态机 |
|
||||
| FreeModbus\modbus\rtu\mbrtu_m.c | 主机RTU模式设置及其状态机 |
|
||||
| FreeModbus\modbus\tcp\mbtcp.c | TCP模式设置及其状态机 |
|
||||
| FreeModbus\port\port.c | 实现硬件移植部分接口 |
|
||||
| FreeModbus\port\portevent.c | 实现从机事件移植接口 |
|
||||
| FreeModbus\port\portevent_m.c | 实现主机事件及错误处理移植接口 |
|
||||
| FreeModbus\port\portserial.c | 从机串口移植 |
|
||||
| FreeModbus\port\portserial_m.c | 主机串口移植 |
|
||||
| FreeModbus\port\porttimer.c | 从机定时器移植 |
|
||||
| FreeModbus\port\porttimer_m.c | 主机定时器移植 |
|
||||
| FreeModbus\port\user_mb_app.c | 定义从机数据缓冲区,实现从机Modbus功能的回调接口 |
|
||||
| FreeModbus\port\user_mb_app_m.c | 定义主机数据缓冲区,实现主机Modbus功能的回调接口 |
|
||||
| FreeModbus\samples\sample_mb_master.c | 主机使用示例代码 |
|
||||
| FreeModbus\samples\sample_mb_slave.c | 从机使用示例代码 |
|
||||
| FreeModbus\samples\README.md | 示例代码说明文档 |
|
||||
|
||||
> 注:所有带_m后缀的文件为主机模式下必须使用的文件,如使用从机模式则无需这些文件。
|
||||
|
||||
### 许可证
|
||||
|
||||
Freemodbus 软件包遵循 BSD 许可,详见 `LICENSE` 文件。
|
||||
|
||||
### 依赖
|
||||
|
||||
- RT_Thread UART 设备
|
||||
- XiUOS UART 设备
|
||||
|
||||
## 获取方式
|
||||
|
||||
使用 Freemodbus 软件包 需要在 RT-Thread 的包管理器中选择它,具体路径如下:
|
||||
|
||||
```
|
||||
RT-Thread online packages
|
||||
IoT - internet of things --->
|
||||
[*] FreeModbus: Modbus master and slave stack --->
|
||||
[*] Master mode --->
|
||||
[*] Slave mode --->
|
||||
```
|
||||
|
||||
最后让 RT-Thread 的包管理器自动更新,或者使用 `pkgs --update` 命令更新包到 BSP 中。
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 数据缓冲区
|
||||
|
||||
数据缓冲区定义的位置位于 `FreeModbus\port\user_mb_app_m.c` 文件顶部,共计 **4种** 数据类型。 FreeModbus从机默认使用 **一维数组** 作为缓存区数据结构,主机可以存储所有网内从机的数据,所以主机采用 **二维数组** 对所有从机节点数据进行存储。二维数组的列号代表寄存器、线圈及离散量地址,行号代表从机节点ID,但需要做减一处理,例如`usMRegHoldBuf[2][1]`代表从机ID为 3,保持寄存器地址为 1 的从机数据。
|
||||
|
||||
### Modbus 数据处理回调接口
|
||||
|
||||
Modbus 一共有4种不同的数据类型,所有的 Modbus 功能都围绕这些数据类型进行操作。由于不同的用户数据缓冲区结构可能有所不同,那么对应的 Modbus 数据处理方式也就存在差异,所以用户需要把每种数据类型对应的操作,按照自己的数据缓冲区结构进行定制实现。 所有的 Modbus 数据处理回调接口如下:
|
||||
|
||||
| 接口 | 功能描述 |
|
||||
| ---------------------- | ------------------ |
|
||||
| eMBMasterRegInputCB | 输入寄存器回调接口 |
|
||||
| eMBMasterRegHoldingCB | 保持寄存器回调接口 |
|
||||
| eMBMasterRegCoilsCB | 线圈回调接口 |
|
||||
| eMBMasterRegDiscreteCB | 离散输入回调接口 |
|
||||
|
||||
> 对于数组形式的数据缓冲区结构,源码中已经做好了移植,直接使用即可。
|
||||
|
||||
### 初始化配置流程
|
||||
|
||||
本协议栈所有配置参数都位于`FreeModbus\modbus\include\mbconfig.h`,目前协议栈支持主机及从机两种模式,并且支持**两种模式同时开启**。从机支持Modbus RTU 、Modbus ASCII 及Modbus TCP 3种模式,主机现在只支持常用的**Modbus RTU**模式。在使用主机的过程中,用户需要对广播的转换延时时间、命令响应超时时间及从机数量做以配置。需要注意的是,目前协议栈只支持**从机地址连续**,并且起始地址**从1开始**。
|
||||
|
||||
### 正常使用流程
|
||||
|
||||
1. 调用`eMBMasterInit`方法初始化Modbus主机协议栈,主机涉及到的一些硬件就在这个时候做了初始化
|
||||
2. 调用`eMBMasterEnable`方法启动Modbus主机
|
||||
3. 通过在线程或者定时器轮询调用`eMBMasterPoll`方法,轮询周期决定了命令的响应时间。
|
||||
4. 调用主机请求API方法,设定一定的请求超时时间,直到方法有结果后才会返回。如果方法执行成功并且命令是读命令,可以通过查看Modbus主机的数据缓冲区,获取最新从机数据。
|
||||
|
||||
> 具体的使用方法,可以参考 `/samples` 目录下的示例代码。调试 Modbus 的主从机程序可以在 PC 上使用 Modbus Poll 和 Modbus slave 软件配合调试。
|
||||
|
||||
### 异常处理流程
|
||||
|
||||
异常处理主要出现在主机正常使用过程中,所有的主机请求API的错误码都在第三章开头已经做以描述,针对的这些错误码,用户需要根据自己的产品特征去完成不同的动作。建议用户自己封装实现主机请求方法的重发机制,这样实现方式比较灵活,一般是在接收到帧数据出错及命令响应超时的错误码时需要重发,重发次数自动加一,如果重发次数超过设定值则认为从机掉线,以后所有只要是发给这个从机命令都被提前拦截掉;如果第二次重发命令响应成功,则**自动清零**该从机重发次数。 上述所有功能可以利用主机请求方法或者使用`FreeModbus\port\portevent_m.c`中的回调接口来实现,用户可以根据自己的需求灵活选择。
|
||||
|
||||
## API 详解
|
||||
|
||||
Modbus 主机使用过程中与从机有很大不同,从机是需要被动等待主机请求,而主机则是主动发出请求,并接收处理从机响应。在主机发送广播请求的时候,从机不需要返回响应,所以广播请求适合主机的写从机数据命令,不适合读从机数据命令。 主机请求API中的所有方法的返回值格式都相同,返回值意义如下。
|
||||
|
||||
| 返回值 | 描述 |
|
||||
| ------------------ | -------------------------------------------- |
|
||||
| MB_MRE_NO_ERR | 正常,没错误 |
|
||||
| MB_MRE_NO_REG | 寄存器、线圈或离散输入地址出错 |
|
||||
| MB_MRE_ILL_ARG | 入参格式有误 |
|
||||
| MB_MRE_REV_DATA | 接收数据出错 |
|
||||
| MB_MRE_TIMEDOUT | 响应超时。主机在设定的时间内未收到从机响应。 |
|
||||
| MB_MRE_MASTER_BUSY | 主机忙。在设定的时间内,请求没有被发送。 |
|
||||
| MB_MRE_EXE_FUN | 主机收到响应后,执行Modbus方法(功能)出错。 |
|
||||
|
||||
> 所有的主机请求方法都是 **线程安全** 的也是 **阻塞模式** 的。在使用过程中,只要在设定的超时时间内没有得到主机资源,就会返回主机忙;如果在设定的超时时间内得到主机资源,那么必须等待得到请求结果后才会返回。
|
||||
|
||||
### 写单个保持寄存器
|
||||
|
||||
往从机某个保持寄存器中写入数据
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr,
|
||||
USHORT usRegAddr,
|
||||
USHORT usRegData,
|
||||
LONG lTimeOut );
|
||||
```
|
||||
|
||||
| 参数 | 描述 |
|
||||
| --------- | ------------------------------------------------------------ |
|
||||
| ucSndAddr | 请求的从机地址,0代表广播。 |
|
||||
| usRegAddr | 写寄存器的地址 |
|
||||
| usRegData | 写寄存器的数据 |
|
||||
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
|
||||
|
||||
### 写多个保持寄存器
|
||||
|
||||
往从机多个保持寄存器中写入数据。
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr,
|
||||
USHORT usRegAddr,
|
||||
USHORT usNRegs,
|
||||
USHORT * pusDataBuffer,
|
||||
LONG lTimeOut )
|
||||
```
|
||||
|
||||
| 参数 | 描述 |
|
||||
| ------------- | ------------------------------------------------------------ |
|
||||
| ucSndAddr | 请求的从机地址,0代表广播。 |
|
||||
| usRegAddr | 写寄存器的起始地址 |
|
||||
| usNRegs | 写寄存器的总数 |
|
||||
| pusDataBuffer | 写寄存器的数据 |
|
||||
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
|
||||
|
||||
### 读多个保持寄存器
|
||||
|
||||
读取多个保持寄存器中的数据
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr,
|
||||
USHORT usRegAddr,
|
||||
USHORT usNRegs,
|
||||
LONG lTimeOut );
|
||||
```
|
||||
|
||||
| 参数 | 描述 |
|
||||
| --------- | ------------------------------------------------------------ |
|
||||
| ucSndAddr | 请求的从机地址,0代表广播。 |
|
||||
| usRegAddr | 读寄存器的地址 |
|
||||
| usRegData | 读寄存器的数量 |
|
||||
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
|
||||
|
||||
### 读写多个保持寄存器
|
||||
|
||||
先读多个寄存器,然后再写多个寄存器。
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
|
||||
USHORT usReadRegAddr,
|
||||
USHORT usNReadRegs,
|
||||
USHORT * pusDataBuffer,
|
||||
USHORT usWriteRegAddr,
|
||||
USHORT usNWriteRegs,
|
||||
LONG lTimeOut )
|
||||
```
|
||||
|
||||
| 参数 | 描述 |
|
||||
| -------------- | ------------------------------------------------------------ |
|
||||
| ucSndAddr | 请求的从机地址,0代表广播。 |
|
||||
| usReadRegAddr | 读寄存器的地址 |
|
||||
| usNReadRegs | 读寄存器的数量 |
|
||||
| pusDataBuffer | 写寄存器的数据 |
|
||||
| usWriteRegAddr | 写寄存器的地址 |
|
||||
| usNWriteRegs | 写寄存器的数量 |
|
||||
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
|
||||
|
||||
### 读多个输入寄存器
|
||||
|
||||
读取多个输入寄存器中的数据
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqReadInputRegister( UCHAR ucSndAddr,
|
||||
USHORT usRegAddr,
|
||||
USHORT usNRegs,
|
||||
LONG lTimeOut );
|
||||
```
|
||||
|
||||
| 参数 | 描述 |
|
||||
| --------- | ------------------------------------------------------------ |
|
||||
| ucSndAddr | 请求的从机地址,0代表广播。 |
|
||||
| usRegAddr | 读寄存器的地址 |
|
||||
| usRegData | 读寄存器的数量 |
|
||||
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
|
||||
|
||||
### 写单个线圈
|
||||
|
||||
往从机某个线圈中写入数据
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqWriteCoil( UCHAR ucSndAddr,
|
||||
USHORT usCoilAddr,
|
||||
USHORT usCoilData,
|
||||
LONG lTimeOut )
|
||||
```
|
||||
|
||||
| 参数 | 描述 |
|
||||
| ---------- | ------------------------------------------------------------ |
|
||||
| ucSndAddr | 请求的从机地址,0代表广播。 |
|
||||
| usCoilAddr | 写线圈的地址 |
|
||||
| usCoilData | 写线圈的数量 |
|
||||
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
|
||||
|
||||
### 写多个线圈
|
||||
|
||||
往从机多个线圈中写入数据。
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
|
||||
USHORT usCoilAddr,
|
||||
USHORT usNCoils,
|
||||
UCHAR * pucDataBuffer,
|
||||
LONG lTimeOut)
|
||||
```
|
||||
|
||||
| 参数 | 描述 |
|
||||
| ------------- | ------------------------------------------------------------ |
|
||||
| ucSndAddr | 请求的从机地址,0代表广播。 |
|
||||
| usCoilAddr | 写线圈的起始地址 |
|
||||
| usNCoils | 写线圈的总数 |
|
||||
| pucDataBuffer | 写线圈的数据 |
|
||||
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
|
||||
|
||||
### 读多个线圈
|
||||
|
||||
读取多个线圈中的数据
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqReadCoils( UCHAR ucSndAddr,
|
||||
USHORT usCoilAddr,
|
||||
USHORT usNCoils ,
|
||||
LONG lTimeOut )
|
||||
```
|
||||
|
||||
| 参数 | 描述 |
|
||||
| ---------- | ------------------------------------------------------------ |
|
||||
| ucSndAddr | 请求的从机地址,0代表广播。 |
|
||||
| usCoilAddr | 读线圈的地址 |
|
||||
| usNCoils | 读线圈的数量 |
|
||||
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
|
||||
|
||||
### 读多个离散输入
|
||||
|
||||
读取多个离散输入中的数据
|
||||
|
||||
```
|
||||
eMBMasterReqErrCode eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr,
|
||||
USHORT usDiscreteAddr,
|
||||
USHORT usNDiscreteIn,
|
||||
LONG lTimeOut )
|
||||
```
|
||||
|
||||
| 参数 | 描述 |
|
||||
| -------------- | ------------------------------------------------------------ |
|
||||
| ucSndAddr | 请求的从机地址,0代表广播。 |
|
||||
| usDiscreteAddr | 读离散输入的地址 |
|
||||
| usNDiscreteIn | 读离散输入的数量 |
|
||||
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 从机支持Modbus RTU 、Modbus ASCII 及Modbus TCP 3种模式,主机现在只支持常用的**Modbus RTU**模式。
|
||||
- 目前协议栈只支持**从机地址连续**,并且起始地址**从1开始**。
|
||||
|
||||
## 联系方式
|
||||
|
||||
- 维护:RT-Thread 开发团队及社区开发者
|
||||
- 主页:<https://github.com/RT-Thread-packages/freemodbus>
|
|
@ -0,0 +1,69 @@
|
|||
Import('RTT_ROOT')
|
||||
from building import *
|
||||
|
||||
src = Split("""
|
||||
modbus/functions/mbfuncdiag.c
|
||||
modbus/functions/mbutils.c
|
||||
modbus/functions/mbfuncother.c
|
||||
modbus/rtu/mbcrc.c
|
||||
port/port.c
|
||||
""")
|
||||
|
||||
master_rtu_src = Split("""
|
||||
modbus/functions/mbfunccoils_m.c
|
||||
modbus/functions/mbfuncdisc_m.c
|
||||
modbus/functions/mbfuncholding_m.c
|
||||
modbus/functions/mbfuncinput_m.c
|
||||
modbus/rtu/mbrtu_m.c
|
||||
modbus/mb_m.c
|
||||
port/portevent_m.c
|
||||
port/portserial_m.c
|
||||
port/porttimer_m.c
|
||||
port/user_mb_app_m.c
|
||||
""")
|
||||
|
||||
slave_src = Split("""
|
||||
modbus/functions/mbfunccoils.c
|
||||
modbus/functions/mbfuncdisc.c
|
||||
modbus/functions/mbfuncholding.c
|
||||
modbus/functions/mbfuncinput.c
|
||||
modbus/mb.c
|
||||
port/portevent.c
|
||||
port/portserial.c
|
||||
port/porttcp.c
|
||||
port/porttimer.c
|
||||
port/user_mb_app.c
|
||||
""")
|
||||
|
||||
# The set of source files associated with this SConscript file.
|
||||
path = [GetCurrentDir() + '/modbus/include',
|
||||
GetCurrentDir() + '/modbus/rtu',
|
||||
GetCurrentDir() + '/modbus/ascii',
|
||||
GetCurrentDir() + '/modbus/tcp',
|
||||
GetCurrentDir() + '/port']
|
||||
|
||||
if GetDepend(['PKG_MODBUS_MASTER_RTU']):
|
||||
src += master_rtu_src
|
||||
|
||||
if GetDepend(['PKG_MODBUS_SLAVE']):
|
||||
src += slave_src
|
||||
|
||||
if GetDepend(['PKG_MODBUS_SLAVE_RTU']):
|
||||
src += ['modbus/rtu/mbrtu.c']
|
||||
|
||||
if GetDepend(['PKG_MODBUS_SLAVE_ASCII']):
|
||||
src += ['modbus/ascii/mbascii.c']
|
||||
src += ['modbus/rtu/mbrtu.c']
|
||||
|
||||
if GetDepend(['PKG_MODBUS_SLAVE_TCP']):
|
||||
src += ['modbus/tcp/mbtcp.c']
|
||||
|
||||
if GetDepend(['PKG_MODBUS_MASTER_SAMPLE']):
|
||||
src += ['samples/sample_mb_master.c']
|
||||
|
||||
if GetDepend(['PKG_MODBUS_SLAVE_SAMPLE']):
|
||||
src += ['samples/sample_mb_slave.c']
|
||||
|
||||
group = DefineGroup('FreeModbus', src, depend = ['PKG_USING_FREEMODBUS'], CPPPATH = path)
|
||||
|
||||
Return('group')
|
|
@ -0,0 +1,26 @@
|
|||
Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||
Copyright (c) 2013-2019 Armink <armink.ztl@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
SRC_DIR := functions
|
||||
|
||||
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU),y)
|
||||
SRC_DIR += rtu
|
||||
|
||||
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_MASTER),y)
|
||||
SRC_FILES += mb_m.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_SLAVE),y)
|
||||
SRC_FILES += mb.c
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_TCP),y)
|
||||
SRC_DIR += tcp
|
||||
|
||||
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_TCP_SLAVE),y)
|
||||
SRC_FILES += mb.c
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
|
@ -25,6 +25,7 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbascii.c,v 1.15 2007/02/18 23:46:48 wolti Exp $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
|
@ -43,7 +44,7 @@
|
|||
#include "mbcrc.h"
|
||||
#include "mbport.h"
|
||||
|
||||
#if MB_ASCII_ENABLED > 0
|
||||
#if MB_SLAVE_ASCII_ENABLED > 0
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_ASCII_DEFAULT_CR '\r' /*!< Default CR character for Modbus ASCII. */
|
||||
|
@ -108,7 +109,7 @@ eMBASCIIInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eP
|
|||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
( void )ucSlaveAddress;
|
||||
|
||||
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
ucMBLFCharacter = MB_ASCII_DEFAULT_LF;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
|
@ -25,6 +25,7 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbascii.h,v 1.8 2006/12/07 22:10:34 wolti Exp $
|
||||
*/
|
||||
|
||||
#ifndef _MB_ASCII_H
|
||||
|
@ -34,7 +35,7 @@
|
|||
PR_BEGIN_EXTERN_C
|
||||
#endif
|
||||
|
||||
#if MB_ASCII_ENABLED > 0
|
||||
#if MB_SLAVE_ASCII_ENABLED > 0
|
||||
eMBErrorCode eMBASCIIInit( UCHAR slaveAddress, UCHAR ucPort,
|
||||
ULONG ulBaudRate, eMBParity eParity );
|
||||
void eMBASCIIStart( void );
|
|
@ -0,0 +1,15 @@
|
|||
SRC_FILES := mbfuncother.c mbutils.c mbfuncdiag.c
|
||||
|
||||
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_MASTER),y)
|
||||
SRC_FILES += mbfunccoils_m.c mbfuncdisc_m.c mbfuncholding_m.c mbfuncinput_m.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_SLAVE),y)
|
||||
SRC_FILES += mbfunccoils.c mbfuncdisc.c mbfuncholding.c mbfuncinput.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_TCP_SLAVE),y)
|
||||
SRC_FILES += mbfunccoils.c mbfuncdisc.c mbfuncholding.c mbfuncinput.c
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
|
@ -25,6 +25,7 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbfunccoils.c,v 1.8 2007/02/18 23:47:16 wolti Exp $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
|
@ -85,7 +86,7 @@ eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
|
|||
usCoilCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF + 1] );
|
||||
|
||||
/* Check if the number of registers to read is valid. If not
|
||||
* return Modbus illegal data value exception.
|
||||
* return Modbus illegal data value exception.
|
||||
*/
|
||||
if( ( usCoilCount >= 1 ) &&
|
||||
( usCoilCount < MB_PDU_FUNC_READ_COILCNT_MAX ) )
|
||||
|
@ -123,7 +124,7 @@ eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
|
|||
else
|
||||
{
|
||||
/* The response contains the function code, the starting address
|
||||
* and the quantity of registers. We reuse the old values in the
|
||||
* and the quantity of registers. We reuse the old values in the
|
||||
* buffer because they are still valid. */
|
||||
*usLen += ucNBytes;;
|
||||
}
|
||||
|
@ -141,6 +142,7 @@ eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
|
|||
}
|
||||
return eStatus;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_WRITE_COIL_ENABLED > 0
|
||||
eMBException
|
||||
|
@ -245,7 +247,7 @@ eMBFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
|
|||
else
|
||||
{
|
||||
/* The response contains the function code, the starting address
|
||||
* and the quantity of registers. We reuse the old values in the
|
||||
* and the quantity of registers. We reuse the old values in the
|
||||
* buffer because they are still valid. */
|
||||
*usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
|
||||
}
|
||||
|
@ -265,5 +267,3 @@ eMBFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbfunccoils_m.c,v 1.60 2013/10/12 15:10:12 Armink Add Master Functions
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbproto.h"
|
||||
#include "mbconfig.h"
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_PDU_REQ_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_REQ_READ_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_READ_SIZE ( 4 )
|
||||
#define MB_PDU_FUNC_READ_COILCNT_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_FUNC_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
|
||||
#define MB_PDU_FUNC_READ_SIZE_MIN ( 1 )
|
||||
|
||||
#define MB_PDU_REQ_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF )
|
||||
#define MB_PDU_REQ_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_WRITE_SIZE ( 4 )
|
||||
#define MB_PDU_FUNC_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF )
|
||||
#define MB_PDU_FUNC_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_FUNC_WRITE_SIZE ( 4 )
|
||||
|
||||
#define MB_PDU_REQ_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF )
|
||||
#define MB_PDU_REQ_WRITE_MUL_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF ( MB_PDU_DATA_OFF + 4 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_VALUES_OFF ( MB_PDU_DATA_OFF + 5 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_SIZE_MIN ( 5 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_COILCNT_MAX ( 0x07B0 )
|
||||
#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF )
|
||||
#define MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_FUNC_WRITE_MUL_SIZE ( 5 )
|
||||
|
||||
/* ----------------------- Static functions ---------------------------------*/
|
||||
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
#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 ,LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
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);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_COILS;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usCoilAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usCoilAddr;
|
||||
ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF ] = usNCoils >> 8;
|
||||
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;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
USHORT usRegAddress;
|
||||
USHORT usCoilCount;
|
||||
UCHAR ucByteCount;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
/* 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 );
|
||||
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
usCoilCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF] << 8 );
|
||||
usCoilCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF + 1] );
|
||||
|
||||
/* Test if the quantity of coils is a multiple of 8. If not last
|
||||
* byte is only partially field with unused coils set to zero. */
|
||||
if( ( usCoilCount & 0x0007 ) != 0 )
|
||||
{
|
||||
ucByteCount = ( UCHAR )( usCoilCount / 8 + 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ucByteCount = ( UCHAR )( usCoilCount / 8 );
|
||||
}
|
||||
|
||||
/* Check if the number of registers to read is valid. If not
|
||||
* return Modbus illegal data value exception.
|
||||
*/
|
||||
if( ( usCoilCount >= 1 ) &&
|
||||
( ucByteCount == pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF] ) )
|
||||
{
|
||||
/* Make callback to fill the buffer. */
|
||||
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 )
|
||||
{
|
||||
eStatus = prveMBError2Exception( eRegStatus );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Can't be a valid read coil register request because the length
|
||||
* is incorrect. */
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
#endif
|
||||
|
||||
#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, LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
if ( ucSndAddr > 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);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_SINGLE_COIL;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF] = usCoilAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF + 1] = usCoilAddr;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF ] = usCoilData >> 8;
|
||||
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;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
USHORT usRegAddress;
|
||||
UCHAR ucBuf[2];
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
|
||||
{
|
||||
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
if( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF + 1] == 0x00 ) &&
|
||||
( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF ) ||
|
||||
( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0x00 ) ) )
|
||||
{
|
||||
ucBuf[1] = 0;
|
||||
if( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF )
|
||||
{
|
||||
ucBuf[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ucBuf[0] = 0;
|
||||
}
|
||||
eRegStatus =
|
||||
eMBMasterRegCoilsCB( &ucBuf[0], usRegAddress, 1, MB_REG_WRITE );
|
||||
|
||||
/* If an error occured convert it into a Modbus exception. */
|
||||
if( eRegStatus != MB_ENOERR )
|
||||
{
|
||||
eStatus = prveMBError2Exception( eRegStatus );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Can't be a valid write coil register request because the length
|
||||
* is incorrect. */
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#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, LONG lTimeOut)
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
USHORT usRegIndex = 0;
|
||||
UCHAR ucByteCount;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
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);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_MULTIPLE_COILS;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] = usCoilAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1] = usCoilAddr;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_COILCNT_OFF] = usNCoils >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_COILCNT_OFF + 1] = usNCoils ;
|
||||
if( ( usNCoils & 0x0007 ) != 0 )
|
||||
{
|
||||
ucByteCount = ( UCHAR )( usNCoils / 8 + 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ucByteCount = ( UCHAR )( usNCoils / 8 );
|
||||
}
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF] = ucByteCount;
|
||||
ucMBFrame += MB_PDU_REQ_WRITE_MUL_VALUES_OFF;
|
||||
while( ucByteCount > usRegIndex)
|
||||
{
|
||||
*ucMBFrame++ = pucDataBuffer[usRegIndex++];
|
||||
}
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + ucByteCount );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
USHORT usRegAddress;
|
||||
USHORT usCoilCnt;
|
||||
UCHAR ucByteCount;
|
||||
UCHAR ucByteCountVerify;
|
||||
UCHAR *ucMBFrame;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
/* 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 );
|
||||
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
usCoilCnt = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF] << 8 );
|
||||
usCoilCnt |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF + 1] );
|
||||
|
||||
ucByteCount = ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF];
|
||||
|
||||
/* Compute the number of expected bytes in the request. */
|
||||
if( ( usCoilCnt & 0x0007 ) != 0 )
|
||||
{
|
||||
ucByteCountVerify = ( UCHAR )( usCoilCnt / 8 + 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ucByteCountVerify = ( UCHAR )( usCoilCnt / 8 );
|
||||
}
|
||||
|
||||
if( ( usCoilCnt >= 1 ) && ( ucByteCountVerify == ucByteCount ) )
|
||||
{
|
||||
eRegStatus =
|
||||
eMBMasterRegCoilsCB( &ucMBFrame[MB_PDU_REQ_WRITE_MUL_VALUES_OFF],
|
||||
usRegAddress, usCoilCnt, MB_REG_WRITE );
|
||||
|
||||
/* If an error occured convert it into a Modbus exception. */
|
||||
if( eRegStatus != MB_ENOERR )
|
||||
{
|
||||
eStatus = prveMBError2Exception( eRegStatus );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Can't be a valid write coil register request because the length
|
||||
* is incorrect. */
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbfuncdiag.c,v 1.3 2006/12/07 22:10:34 wolti Exp $
|
||||
*/
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
|
@ -74,7 +74,7 @@ eMBFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen )
|
|||
usDiscreteCnt |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF + 1] );
|
||||
|
||||
/* Check if the number of registers to read is valid. If not
|
||||
* return Modbus illegal data value exception.
|
||||
* return Modbus illegal data value exception.
|
||||
*/
|
||||
if( ( usDiscreteCnt >= 1 ) &&
|
||||
( usDiscreteCnt < MB_PDU_FUNC_READ_DISCCNT_MAX ) )
|
||||
|
@ -111,7 +111,7 @@ eMBFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen )
|
|||
else
|
||||
{
|
||||
/* The response contains the function code, the starting address
|
||||
* and the quantity of registers. We reuse the old values in the
|
||||
* and the quantity of registers. We reuse the old values in the
|
||||
* buffer because they are still valid. */
|
||||
*usLen += ucNBytes;;
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbfuncdisc_m.c,v 1.60 2013/10/15 8:48:20 Armink Add Master Functions Exp $
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbproto.h"
|
||||
#include "mbconfig.h"
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_PDU_REQ_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_REQ_READ_DISCCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_READ_SIZE ( 4 )
|
||||
#define MB_PDU_FUNC_READ_DISCCNT_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_FUNC_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
|
||||
#define MB_PDU_FUNC_READ_SIZE_MIN ( 1 )
|
||||
|
||||
/* ----------------------- Static functions ---------------------------------*/
|
||||
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_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, LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
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);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_DISCRETE_INPUTS;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usDiscreteAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usDiscreteAddr;
|
||||
ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF ] = usNDiscreteIn >> 8;
|
||||
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;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
USHORT usRegAddress;
|
||||
USHORT usDiscreteCnt;
|
||||
UCHAR ucNBytes;
|
||||
UCHAR *ucMBFrame;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
/* 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 );
|
||||
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
usDiscreteCnt = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF] << 8 );
|
||||
usDiscreteCnt |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF + 1] );
|
||||
|
||||
/* Test if the quantity of coils is a multiple of 8. If not last
|
||||
* byte is only partially field with unused coils set to zero. */
|
||||
if( ( usDiscreteCnt & 0x0007 ) != 0 )
|
||||
{
|
||||
ucNBytes = ( UCHAR )( usDiscreteCnt / 8 + 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ucNBytes = ( UCHAR )( usDiscreteCnt / 8 );
|
||||
}
|
||||
|
||||
/* Check if the number of registers to read is valid. If not
|
||||
* return Modbus illegal data value exception.
|
||||
*/
|
||||
if ((usDiscreteCnt >= 1) && ucNBytes == pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF])
|
||||
{
|
||||
/* Make callback to fill the buffer. */
|
||||
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 )
|
||||
{
|
||||
eStatus = prveMBError2Exception( eRegStatus );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Can't be a valid read coil register request because the length
|
||||
* is incorrect. */
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
|
@ -25,6 +25,7 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbfuncholding.c,v 1.12 2007/02/18 23:48:22 wolti Exp $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
|
@ -182,10 +183,10 @@ eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
|||
usRegAddress++;
|
||||
|
||||
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
|
||||
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
|
||||
usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
|
||||
|
||||
/* Check if the number of registers to read is valid. If not
|
||||
* return Modbus illegal data value exception.
|
||||
* return Modbus illegal data value exception.
|
||||
*/
|
||||
if( ( usRegCount >= 1 ) && ( usRegCount <= MB_PDU_FUNC_READ_REGCNT_MAX ) )
|
||||
{
|
|
@ -0,0 +1,455 @@
|
|||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbfuncholding_m.c,v 1.60 2013/09/02 14:13:40 Armink Add Master Functions Exp $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbproto.h"
|
||||
#include "mbconfig.h"
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_PDU_REQ_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_REQ_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_READ_SIZE ( 4 )
|
||||
#define MB_PDU_FUNC_READ_REGCNT_MAX ( 0x007D )
|
||||
#define MB_PDU_FUNC_READ_BYTECNT_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_FUNC_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
|
||||
#define MB_PDU_FUNC_READ_SIZE_MIN ( 1 )
|
||||
|
||||
#define MB_PDU_REQ_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF + 0)
|
||||
#define MB_PDU_REQ_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_WRITE_SIZE ( 4 )
|
||||
#define MB_PDU_FUNC_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF + 0)
|
||||
#define MB_PDU_FUNC_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_FUNC_WRITE_SIZE ( 4 )
|
||||
|
||||
#define MB_PDU_REQ_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF ( MB_PDU_DATA_OFF + 4 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_VALUES_OFF ( MB_PDU_DATA_OFF + 5 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_SIZE_MIN ( 5 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_REGCNT_MAX ( 0x0078 )
|
||||
#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_FUNC_WRITE_MUL_SIZE ( 4 )
|
||||
|
||||
#define MB_PDU_REQ_READWRITE_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_REQ_READWRITE_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF + 4 )
|
||||
#define MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF ( MB_PDU_DATA_OFF + 6 )
|
||||
#define MB_PDU_REQ_READWRITE_WRITE_BYTECNT_OFF ( MB_PDU_DATA_OFF + 8 )
|
||||
#define MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF ( MB_PDU_DATA_OFF + 9 )
|
||||
#define MB_PDU_REQ_READWRITE_SIZE_MIN ( 9 )
|
||||
#define MB_PDU_FUNC_READWRITE_READ_BYTECNT_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_FUNC_READWRITE_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
|
||||
#define MB_PDU_FUNC_READWRITE_SIZE_MIN ( 1 )
|
||||
|
||||
/* ----------------------- Static functions ---------------------------------*/
|
||||
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
#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, LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
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);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_REGISTER;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF] = usRegAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF + 1] = usRegAddr;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF] = usRegData >> 8;
|
||||
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;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
USHORT usRegAddress;
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
if( *usLen == ( MB_PDU_SIZE_MIN + MB_PDU_FUNC_WRITE_SIZE ) )
|
||||
{
|
||||
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
/* Make callback to update the value. */
|
||||
eRegStatus = eMBMasterRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF],
|
||||
usRegAddress, 1, MB_REG_WRITE );
|
||||
|
||||
/* If an error occured convert it into a Modbus exception. */
|
||||
if( eRegStatus != MB_ENOERR )
|
||||
{
|
||||
eStatus = prveMBError2Exception( eRegStatus );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Can't be a valid request because the length is incorrect. */
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
#endif
|
||||
|
||||
#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, LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
USHORT usRegIndex = 0;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
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);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_MULTIPLE_REGISTERS;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] = usRegAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1] = usRegAddr;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF] = usNRegs >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF + 1] = usNRegs ;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF] = usNRegs * 2;
|
||||
ucMBFrame += MB_PDU_REQ_WRITE_MUL_VALUES_OFF;
|
||||
while( usNRegs > usRegIndex)
|
||||
{
|
||||
*ucMBFrame++ = pusDataBuffer[usRegIndex] >> 8;
|
||||
*ucMBFrame++ = pusDataBuffer[usRegIndex++] ;
|
||||
}
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + 2*usNRegs );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
USHORT usRegAddress;
|
||||
USHORT usRegCount;
|
||||
UCHAR ucRegByteCount;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
/* 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 );
|
||||
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF] << 8 );
|
||||
usRegCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF + 1] );
|
||||
|
||||
ucRegByteCount = ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF];
|
||||
|
||||
if( ucRegByteCount == 2 * usRegCount )
|
||||
{
|
||||
/* Make callback to update the register values. */
|
||||
eRegStatus =
|
||||
eMBMasterRegHoldingCB( &ucMBFrame[MB_PDU_REQ_WRITE_MUL_VALUES_OFF],
|
||||
usRegAddress, usRegCount, MB_REG_WRITE );
|
||||
|
||||
/* If an error occured convert it into a Modbus exception. */
|
||||
if( eRegStatus != MB_ENOERR )
|
||||
{
|
||||
eStatus = prveMBError2Exception( eRegStatus );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Can't be a valid request because the length is incorrect. */
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
#endif
|
||||
|
||||
#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, LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
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);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_HOLDING_REGISTER;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usRegAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usRegAddr;
|
||||
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8;
|
||||
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;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
USHORT usRegAddress;
|
||||
USHORT usRegCount;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
/* 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 );
|
||||
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] << 8 );
|
||||
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.
|
||||
*/
|
||||
if( ( usRegCount >= 1 ) && ( 2 * usRegCount == pucFrame[MB_PDU_FUNC_READ_BYTECNT_OFF] ) )
|
||||
{
|
||||
/* Make callback to fill the buffer. */
|
||||
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 )
|
||||
{
|
||||
eStatus = prveMBError2Exception( eRegStatus );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Can't be a valid request because the length is incorrect. */
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#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, LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
USHORT usRegIndex = 0;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
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);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READWRITE_MULTIPLE_REGISTERS;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF] = usReadRegAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF + 1] = usReadRegAddr;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF] = usNReadRegs >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF + 1] = usNReadRegs ;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF] = usWriteRegAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF + 1] = usWriteRegAddr;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF] = usNWriteRegs >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF + 1] = usNWriteRegs ;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_BYTECNT_OFF] = usNWriteRegs * 2;
|
||||
ucMBFrame += MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF;
|
||||
while( usNWriteRegs > usRegIndex)
|
||||
{
|
||||
*ucMBFrame++ = pusDataBuffer[usRegIndex] >> 8;
|
||||
*ucMBFrame++ = pusDataBuffer[usRegIndex++] ;
|
||||
}
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READWRITE_SIZE_MIN + 2*usNWriteRegs );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
USHORT usRegReadAddress;
|
||||
USHORT usRegReadCount;
|
||||
USHORT usRegWriteAddress;
|
||||
USHORT usRegWriteCount;
|
||||
UCHAR *ucMBFrame;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
/* 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 );
|
||||
usRegReadAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF + 1] );
|
||||
usRegReadAddress++;
|
||||
|
||||
usRegReadCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF] << 8U );
|
||||
usRegReadCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF + 1] );
|
||||
|
||||
usRegWriteAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF] << 8U );
|
||||
usRegWriteAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF + 1] );
|
||||
usRegWriteAddress++;
|
||||
|
||||
usRegWriteCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF] << 8U );
|
||||
usRegWriteCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF + 1] );
|
||||
|
||||
if( ( 2 * usRegReadCount ) == pucFrame[MB_PDU_FUNC_READWRITE_READ_BYTECNT_OFF] )
|
||||
{
|
||||
/* Make callback to update the register values. */
|
||||
eRegStatus = eMBMasterRegHoldingCB( &ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF],
|
||||
usRegWriteAddress, usRegWriteCount, MB_REG_WRITE );
|
||||
|
||||
if( eRegStatus == MB_ENOERR )
|
||||
{
|
||||
/* Make the read callback. */
|
||||
eRegStatus = eMBMasterRegHoldingCB(&pucFrame[MB_PDU_FUNC_READWRITE_READ_VALUES_OFF],
|
||||
usRegReadAddress, usRegReadCount, MB_REG_READ);
|
||||
}
|
||||
if( eRegStatus != MB_ENOERR )
|
||||
{
|
||||
eStatus = prveMBError2Exception( eRegStatus );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbfuncinput.c,v 1.10 2007/09/12 10:15:56 wolti Exp $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbproto.h"
|
||||
#include "mbconfig.h"
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_PDU_FUNC_READ_ADDR_OFF ( MB_PDU_DATA_OFF )
|
||||
#define MB_PDU_FUNC_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_FUNC_READ_SIZE ( 4 )
|
||||
#define MB_PDU_FUNC_READ_REGCNT_MAX ( 0x007D )
|
||||
|
||||
#define MB_PDU_FUNC_READ_RSP_BYTECNT_OFF ( MB_PDU_DATA_OFF )
|
||||
|
||||
/* ----------------------- Static functions ---------------------------------*/
|
||||
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
#if MB_FUNC_READ_INPUT_ENABLED > 0
|
||||
|
||||
eMBException
|
||||
eMBFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
USHORT usRegAddress;
|
||||
USHORT usRegCount;
|
||||
UCHAR *pucFrameCur;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
|
||||
{
|
||||
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
|
||||
usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
|
||||
|
||||
/* Check if the number of registers to read is valid. If not
|
||||
* return Modbus illegal data value exception.
|
||||
*/
|
||||
if( ( usRegCount >= 1 )
|
||||
&& ( usRegCount < MB_PDU_FUNC_READ_REGCNT_MAX ) )
|
||||
{
|
||||
/* Set the current PDU data pointer to the beginning. */
|
||||
pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
|
||||
*usLen = MB_PDU_FUNC_OFF;
|
||||
|
||||
/* First byte contains the function code. */
|
||||
*pucFrameCur++ = MB_FUNC_READ_INPUT_REGISTER;
|
||||
*usLen += 1;
|
||||
|
||||
/* Second byte in the response contain the number of bytes. */
|
||||
*pucFrameCur++ = ( UCHAR )( usRegCount * 2 );
|
||||
*usLen += 1;
|
||||
|
||||
eRegStatus =
|
||||
eMBRegInputCB( pucFrameCur, usRegAddress, usRegCount );
|
||||
|
||||
/* If an error occured convert it into a Modbus exception. */
|
||||
if( eRegStatus != MB_ENOERR )
|
||||
{
|
||||
eStatus = prveMBError2Exception( eRegStatus );
|
||||
}
|
||||
else
|
||||
{
|
||||
*usLen += usRegCount * 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Can't be a valid read input register request because the length
|
||||
* is incorrect. */
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbfuncinput_m.c,v 1.60 2013/10/12 14:23:40 Armink Add Master Functions Exp $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbproto.h"
|
||||
#include "mbconfig.h"
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_PDU_REQ_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_REQ_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_READ_SIZE ( 4 )
|
||||
#define MB_PDU_FUNC_READ_BYTECNT_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_FUNC_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
|
||||
#define MB_PDU_FUNC_READ_SIZE_MIN ( 1 )
|
||||
|
||||
#define MB_PDU_FUNC_READ_RSP_BYTECNT_OFF ( MB_PDU_DATA_OFF )
|
||||
|
||||
/* ----------------------- Static functions ---------------------------------*/
|
||||
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
#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, LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
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);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_INPUT_REGISTER;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usRegAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usRegAddr;
|
||||
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8;
|
||||
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;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
USHORT usRegAddress;
|
||||
USHORT usRegCount;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
/* 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 );
|
||||
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] << 8 );
|
||||
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.
|
||||
*/
|
||||
if( ( usRegCount >= 1 ) && ( 2 * usRegCount == pucFrame[MB_PDU_FUNC_READ_BYTECNT_OFF] ) )
|
||||
{
|
||||
/* Make callback to fill the buffer. */
|
||||
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 )
|
||||
{
|
||||
eStatus = prveMBError2Exception( eRegStatus );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Can't be a valid request because the length is incorrect. */
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
|
@ -25,6 +25,7 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbfuncother.c,v 1.8 2006/12/07 22:10:34 wolti Exp $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbutils.c,v 1.6 2007/02/18 23:49:07 wolti Exp $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbproto.h"
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define BITS_UCHAR 8U
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
void
|
||||
xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits,
|
||||
UCHAR ucValue )
|
||||
{
|
||||
USHORT usWordBuf;
|
||||
USHORT usMask;
|
||||
USHORT usByteOffset;
|
||||
USHORT usNPreBits;
|
||||
USHORT usValue = ucValue;
|
||||
|
||||
#ifdef ADD_RTTHREAD_FEATURES
|
||||
RT_ASSERT( ucNBits <= 8 );
|
||||
RT_ASSERT( ( size_t )BITS_UCHAR == sizeof( UCHAR ) * 8 );
|
||||
#endif
|
||||
|
||||
#ifdef ADD_XIZI_FEATURES
|
||||
MB_CHECK( ucNBits <= 8 );
|
||||
MB_CHECK( ( size_t )BITS_UCHAR == sizeof( UCHAR ) * 8 );
|
||||
#endif
|
||||
|
||||
/* Calculate byte offset for first byte containing the bit values starting
|
||||
* at usBitOffset. */
|
||||
usByteOffset = ( USHORT )( ( usBitOffset ) / BITS_UCHAR );
|
||||
|
||||
/* How many bits precede our bits to set. */
|
||||
usNPreBits = ( USHORT )( usBitOffset - usByteOffset * BITS_UCHAR );
|
||||
|
||||
/* Move bit field into position over bits to set */
|
||||
usValue <<= usNPreBits;
|
||||
|
||||
/* Prepare a mask for setting the new bits. */
|
||||
usMask = ( USHORT )( ( 1 << ( USHORT ) ucNBits ) - 1 );
|
||||
usMask <<= usBitOffset - usByteOffset * BITS_UCHAR;
|
||||
|
||||
/* copy bits into temporary storage. */
|
||||
usWordBuf = ucByteBuf[usByteOffset];
|
||||
usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_UCHAR;
|
||||
|
||||
/* Zero out bit field bits and then or value bits into them. */
|
||||
usWordBuf = ( USHORT )( ( usWordBuf & ( ~usMask ) ) | usValue );
|
||||
|
||||
/* move bits back into storage */
|
||||
ucByteBuf[usByteOffset] = ( UCHAR )( usWordBuf & 0xFF );
|
||||
ucByteBuf[usByteOffset + 1] = ( UCHAR )( usWordBuf >> BITS_UCHAR );
|
||||
}
|
||||
|
||||
UCHAR
|
||||
xMBUtilGetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits )
|
||||
{
|
||||
USHORT usWordBuf;
|
||||
USHORT usMask;
|
||||
USHORT usByteOffset;
|
||||
USHORT usNPreBits;
|
||||
|
||||
/* Calculate byte offset for first byte containing the bit values starting
|
||||
* at usBitOffset. */
|
||||
usByteOffset = ( USHORT )( ( usBitOffset ) / BITS_UCHAR );
|
||||
|
||||
/* How many bits precede our bits to set. */
|
||||
usNPreBits = ( USHORT )( usBitOffset - usByteOffset * BITS_UCHAR );
|
||||
|
||||
/* Prepare a mask for setting the new bits. */
|
||||
usMask = ( USHORT )( ( 1 << ( USHORT ) ucNBits ) - 1 );
|
||||
|
||||
/* copy bits into temporary storage. */
|
||||
usWordBuf = ucByteBuf[usByteOffset];
|
||||
usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_UCHAR;
|
||||
|
||||
/* throw away unneeded bits. */
|
||||
usWordBuf >>= usNPreBits;
|
||||
|
||||
/* mask away bits above the requested bitfield. */
|
||||
usWordBuf &= usMask;
|
||||
|
||||
return ( UCHAR ) usWordBuf;
|
||||
}
|
||||
|
||||
eMBException
|
||||
prveMBError2Exception( eMBErrorCode eErrorCode )
|
||||
{
|
||||
eMBException eStatus;
|
||||
|
||||
switch ( eErrorCode )
|
||||
{
|
||||
case MB_ENOERR:
|
||||
eStatus = MB_EX_NONE;
|
||||
break;
|
||||
|
||||
case MB_ENOREG:
|
||||
eStatus = MB_EX_ILLEGAL_DATA_ADDRESS;
|
||||
break;
|
||||
|
||||
case MB_ETIMEDOUT:
|
||||
eStatus = MB_EX_SLAVE_BUSY;
|
||||
break;
|
||||
|
||||
default:
|
||||
eStatus = MB_EX_SLAVE_DEVICE_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
return eStatus;
|
||||
}
|
|
@ -0,0 +1,417 @@
|
|||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mb.h,v 1.17 2006/12/07 22:10:34 wolti Exp $
|
||||
*/
|
||||
|
||||
#ifndef _MB_H
|
||||
#define _MB_H
|
||||
|
||||
#include "port.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
PR_BEGIN_EXTERN_C
|
||||
#endif
|
||||
|
||||
#include "mbport.h"
|
||||
#include "mbproto.h"
|
||||
|
||||
/*! \defgroup modbus Modbus
|
||||
* \code #include "mb.h" \endcode
|
||||
*
|
||||
* This module defines the interface for the application. It contains
|
||||
* the basic functions and types required to use the Modbus protocol stack.
|
||||
* A typical application will want to call eMBInit() first. If the device
|
||||
* is ready to answer network requests it must then call eMBEnable() to activate
|
||||
* the protocol stack. In the main loop the function eMBPoll() must be called
|
||||
* periodically. The time interval between pooling depends on the configured
|
||||
* Modbus timeout. If an RTOS is available a separate task should be created
|
||||
* and the task should always call the function eMBPoll().
|
||||
*
|
||||
* \code
|
||||
* // Initialize protocol stack in RTU mode for a slave with address 10 = 0x0A
|
||||
* eMBInit( MB_RTU, 0x0A, 38400, MB_PAR_EVEN );
|
||||
* // Enable the Modbus Protocol Stack.
|
||||
* eMBEnable( );
|
||||
* for( ;; )
|
||||
* {
|
||||
* // Call the main polling loop of the Modbus protocol stack.
|
||||
* eMBPoll( );
|
||||
* ...
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Use the default Modbus TCP port (502)
|
||||
*/
|
||||
#define MB_TCP_PORT_USE_DEFAULT 0
|
||||
|
||||
/* ----------------------- Type definitions ---------------------------------*/
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Modbus serial transmission modes (RTU/ASCII).
|
||||
*
|
||||
* Modbus serial supports two transmission modes. Either ASCII or RTU. RTU
|
||||
* is faster but has more hardware requirements and requires a network with
|
||||
* a low jitter. ASCII is slower and more reliable on slower links (E.g. modems)
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
MB_RTU, /*!< RTU transmission mode. */
|
||||
MB_ASCII, /*!< ASCII transmission mode. */
|
||||
MB_TCP /*!< TCP mode. */
|
||||
} eMBMode;
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief If register should be written or read.
|
||||
*
|
||||
* This value is passed to the callback functions which support either
|
||||
* reading or writing register values. Writing means that the application
|
||||
* registers should be updated and reading means that the modbus protocol
|
||||
* stack needs to know the current register values.
|
||||
*
|
||||
* \see eMBRegHoldingCB( ), eMBRegCoilsCB( ), eMBRegDiscreteCB( ) and
|
||||
* eMBRegInputCB( ).
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
MB_REG_READ, /*!< Read register values and pass to protocol stack. */
|
||||
MB_REG_WRITE /*!< Update register values. */
|
||||
} eMBRegisterMode;
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Errorcodes used by all function in the protocol stack.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
MB_ENOERR, /*!< no error. */
|
||||
MB_ENOREG, /*!< illegal register address. */
|
||||
MB_EINVAL, /*!< illegal argument. */
|
||||
MB_EPORTERR, /*!< porting layer error. */
|
||||
MB_ENORES, /*!< insufficient resources. */
|
||||
MB_EIO, /*!< I/O error. */
|
||||
MB_EILLSTATE, /*!< protocol stack in illegal state. */
|
||||
MB_ETIMEDOUT /*!< timeout error occurred. */
|
||||
} eMBErrorCode;
|
||||
|
||||
|
||||
/* ----------------------- Function prototypes ------------------------------*/
|
||||
/*! \ingroup modbus
|
||||
* \brief Initialize the Modbus protocol stack.
|
||||
*
|
||||
* This functions initializes the ASCII or RTU module and calls the
|
||||
* init functions of the porting layer to prepare the hardware. Please
|
||||
* note that the receiver is still disabled and no Modbus frames are
|
||||
* processed until eMBEnable( ) has been called.
|
||||
*
|
||||
* \param eMode If ASCII or RTU mode should be used.
|
||||
* \param ucSlaveAddress The slave address. Only frames sent to this
|
||||
* address or to the broadcast address are processed.
|
||||
* \param ucPort The port to use. E.g. 1 for COM1 on windows. This value
|
||||
* is platform dependent and some ports simply choose to ignore it.
|
||||
* \param ulBaudRate The baudrate. E.g. 19200. Supported baudrates depend
|
||||
* on the porting layer.
|
||||
* \param eParity Parity used for serial transmission.
|
||||
*
|
||||
* \return If no error occurs the function returns eMBErrorCode::MB_ENOERR.
|
||||
* The protocol is then in the disabled state and ready for activation
|
||||
* by calling eMBEnable( ). Otherwise one of the following error codes
|
||||
* is returned:
|
||||
* - eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid
|
||||
* slave addresses are in the range 1 - 247.
|
||||
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
|
||||
*/
|
||||
eMBErrorCode eMBInit( eMBMode eMode, UCHAR ucSlaveAddress,
|
||||
UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Initialize the Modbus protocol stack for Modbus TCP.
|
||||
*
|
||||
* This function initializes the Modbus TCP Module. Please note that
|
||||
* frame processing is still disabled until eMBEnable( ) is called.
|
||||
*
|
||||
* \param usTCPPort The TCP port to listen on.
|
||||
* \return If the protocol stack has been initialized correctly the function
|
||||
* returns eMBErrorCode::MB_ENOERR. Otherwise one of the following error
|
||||
* codes is returned:
|
||||
* - eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid
|
||||
* slave addresses are in the range 1 - 247.
|
||||
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
|
||||
*/
|
||||
eMBErrorCode eMBTCPInit( USHORT usTCPPort );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Release resources used by the protocol stack.
|
||||
*
|
||||
* This function disables the Modbus protocol stack and release all
|
||||
* hardware resources. It must only be called when the protocol stack
|
||||
* is disabled.
|
||||
*
|
||||
* \note Note all ports implement this function. A port which wants to
|
||||
* get an callback must define the macro MB_PORT_HAS_CLOSE to 1.
|
||||
*
|
||||
* \return If the resources where released it return eMBErrorCode::MB_ENOERR.
|
||||
* If the protocol stack is not in the disabled state it returns
|
||||
* eMBErrorCode::MB_EILLSTATE.
|
||||
*/
|
||||
eMBErrorCode eMBClose( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Enable the Modbus protocol stack.
|
||||
*
|
||||
* This function enables processing of Modbus frames. Enabling the protocol
|
||||
* stack is only possible if it is in the disabled state.
|
||||
*
|
||||
* \return If the protocol stack is now in the state enabled it returns
|
||||
* eMBErrorCode::MB_ENOERR. If it was not in the disabled state it
|
||||
* return eMBErrorCode::MB_EILLSTATE.
|
||||
*/
|
||||
eMBErrorCode eMBEnable( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Disable the Modbus protocol stack.
|
||||
*
|
||||
* This function disables processing of Modbus frames.
|
||||
*
|
||||
* \return If the protocol stack has been disabled it returns
|
||||
* eMBErrorCode::MB_ENOERR. If it was not in the enabled state it returns
|
||||
* eMBErrorCode::MB_EILLSTATE.
|
||||
*/
|
||||
eMBErrorCode eMBDisable( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief The main pooling loop of the Modbus protocol stack.
|
||||
*
|
||||
* This function must be called periodically. The timer interval required
|
||||
* is given by the application dependent Modbus slave timeout. Internally the
|
||||
* function calls xMBPortEventGet() and waits for an event from the receiver or
|
||||
* transmitter state machines.
|
||||
*
|
||||
* \return If the protocol stack is not in the enabled state the function
|
||||
* returns eMBErrorCode::MB_EILLSTATE. Otherwise it returns
|
||||
* eMBErrorCode::MB_ENOERR.
|
||||
*/
|
||||
eMBErrorCode eMBPoll( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Configure the slave id of the device.
|
||||
*
|
||||
* This function should be called when the Modbus function <em>Report Slave ID</em>
|
||||
* is enabled ( By defining MB_FUNC_OTHER_REP_SLAVEID_ENABLED in mbconfig.h ).
|
||||
*
|
||||
* \param ucSlaveID Values is returned in the <em>Slave ID</em> byte of the
|
||||
* <em>Report Slave ID</em> response.
|
||||
* \param xIsRunning If TRUE the <em>Run Indicator Status</em> byte is set to 0xFF.
|
||||
* otherwise the <em>Run Indicator Status</em> is 0x00.
|
||||
* \param pucAdditional Values which should be returned in the <em>Additional</em>
|
||||
* bytes of the <em> Report Slave ID</em> response.
|
||||
* \param usAdditionalLen Length of the buffer <code>pucAdditonal</code>.
|
||||
*
|
||||
* \return If the static buffer defined by MB_FUNC_OTHER_REP_SLAVEID_BUF in
|
||||
* mbconfig.h is to small it returns eMBErrorCode::MB_ENORES. Otherwise
|
||||
* it returns eMBErrorCode::MB_ENOERR.
|
||||
*/
|
||||
eMBErrorCode eMBSetSlaveID( UCHAR ucSlaveID, BOOL xIsRunning,
|
||||
UCHAR const *pucAdditional,
|
||||
USHORT usAdditionalLen );
|
||||
|
||||
/*! \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 eMBRegisterCB( UCHAR ucFunctionCode,
|
||||
pxMBFunctionHandler pxHandler );
|
||||
|
||||
/* ----------------------- Callback -----------------------------------------*/
|
||||
|
||||
/*! \defgroup modbus_registers Modbus Registers
|
||||
* \code #include "mb.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 can not supply values
|
||||
* for registers within this range. In this case a
|
||||
* <b>ILLEGAL DATA ADDRESS</b> exception frame is sent as a response.
|
||||
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
|
||||
* currently not available and the application dependent response
|
||||
* timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
|
||||
* exception is sent as a response.
|
||||
* - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
|
||||
* a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
|
||||
*/
|
||||
eMBErrorCode eMBRegInputCB( 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 can not supply values
|
||||
* for registers within this range. In this case a
|
||||
* <b>ILLEGAL DATA ADDRESS</b> exception frame is sent as a response.
|
||||
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
|
||||
* currently not available and the application dependent response
|
||||
* timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
|
||||
* exception is sent as a response.
|
||||
* - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
|
||||
* a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
|
||||
*/
|
||||
eMBErrorCode eMBRegHoldingCB( 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::MB_ETIMEDOUT If the requested register block is
|
||||
* currently not available and the application dependent response
|
||||
* timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
|
||||
* exception is sent as a response.
|
||||
* - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
|
||||
* a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
|
||||
*/
|
||||
eMBErrorCode eMBRegCoilsCB( 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 no such discrete inputs exists.
|
||||
* In this case a <b>ILLEGAL DATA ADDRESS</b> exception frame is sent
|
||||
* as a response.
|
||||
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
|
||||
* currently not available and the application dependent response
|
||||
* timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
|
||||
* exception is sent as a response.
|
||||
* - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
|
||||
* a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
|
||||
*/
|
||||
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
USHORT usNDiscrete );
|
||||
|
||||
#ifdef __cplusplus
|
||||
PR_END_EXTERN_C
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,414 @@
|
|||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mb_m.h,v 1.60 2013/09/03 10:20:05 Armink Add Master Functions $
|
||||
*/
|
||||
|
||||
#ifndef _MB_M_H
|
||||
#define _MB_M_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
PR_BEGIN_EXTERN_C
|
||||
#endif
|
||||
|
||||
/*! \defgroup modbus Modbus
|
||||
* \code #include "mb_m.h" \endcode
|
||||
*
|
||||
* This module defines the interface for the application. It contains
|
||||
* the basic functions and types required to use the Modbus Master protocol stack.
|
||||
* A typical application will want to call eMBMasterInit() first. If the device
|
||||
* is ready to answer network requests it must then call eMBEnable() to activate
|
||||
* the protocol stack. In the main loop the function eMBMasterPoll() must be called
|
||||
* periodically. The time interval between pooling depends on the configured
|
||||
* Modbus timeout. If an RTOS is available a separate task should be created
|
||||
* and the task should always call the function eMBMasterPoll().
|
||||
*
|
||||
* \code
|
||||
* // Initialize protocol stack in RTU mode for a Master
|
||||
* eMBMasterInit( MB_RTU, 38400, MB_PAR_EVEN );
|
||||
* // Enable the Modbus Protocol Stack.
|
||||
* eMBMasterEnable( );
|
||||
* for( ;; )
|
||||
* {
|
||||
* // Call the main polling loop of the Modbus Master protocol stack.
|
||||
* eMBMasterPoll( );
|
||||
* ...
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Use the default Modbus Master TCP port (502)
|
||||
*/
|
||||
#define MB_MASTER_TCP_PORT_USE_DEFAULT 0
|
||||
|
||||
/* ----------------------- Type definitions ---------------------------------*/
|
||||
/*! \ingroup modbus
|
||||
* \brief Errorcodes used by all function in the Master request.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
MB_MRE_NO_ERR, /*!< no error. */
|
||||
MB_MRE_NO_REG, /*!< illegal register address. */
|
||||
MB_MRE_ILL_ARG, /*!< illegal argument. */
|
||||
MB_MRE_REV_DATA, /*!< receive data error. */
|
||||
MB_MRE_TIMEDOUT, /*!< timeout error occurred. */
|
||||
MB_MRE_MASTER_BUSY, /*!< master is busy now. */
|
||||
MB_MRE_EXE_FUN /*!< execute function error. */
|
||||
} eMBMasterReqErrCode;
|
||||
/*! \ingroup modbus
|
||||
* \brief TimerMode is Master 3 kind of Timer modes.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
MB_TMODE_T35, /*!< Master receive frame T3.5 timeout. */
|
||||
MB_TMODE_RESPOND_TIMEOUT, /*!< Master wait respond for slave. */
|
||||
MB_TMODE_CONVERT_DELAY /*!< Master sent broadcast ,then delay sometime.*/
|
||||
}eMBMasterTimerMode;
|
||||
|
||||
/* ----------------------- Function prototypes ------------------------------*/
|
||||
/*! \ingroup modbus
|
||||
* \brief Initialize the Modbus Master protocol stack.
|
||||
*
|
||||
* This functions initializes the ASCII or RTU module and calls the
|
||||
* init functions of the porting layer to prepare the hardware. Please
|
||||
* note that the receiver is still disabled and no Modbus frames are
|
||||
* processed until eMBMasterEnable( ) has been called.
|
||||
*
|
||||
* \param eMode If ASCII or RTU mode should be used.
|
||||
* \param ucPort The port to use. E.g. 1 for COM1 on windows. This value
|
||||
* is platform dependent and some ports simply choose to ignore it.
|
||||
* \param ulBaudRate The baudrate. E.g. 19200. Supported baudrates depend
|
||||
* on the porting layer.
|
||||
* \param eParity Parity used for serial transmission.
|
||||
*
|
||||
* \return If no error occurs the function returns eMBErrorCode::MB_ENOERR.
|
||||
* The protocol is then in the disabled state and ready for activation
|
||||
* by calling eMBMasterEnable( ). Otherwise one of the following error codes
|
||||
* is returned:
|
||||
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
|
||||
*/
|
||||
eMBErrorCode eMBMasterInit( eMBMode eMode, UCHAR ucPort,
|
||||
ULONG ulBaudRate, eMBParity eParity );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Initialize the Modbus Master protocol stack for Modbus TCP.
|
||||
*
|
||||
* This function initializes the Modbus TCP Module. Please note that
|
||||
* frame processing is still disabled until eMBEnable( ) is called.
|
||||
*
|
||||
* \param usTCPPort The TCP port to listen on.
|
||||
* \return If the protocol stack has been initialized correctly the function
|
||||
* returns eMBErrorCode::MB_ENOERR. Otherwise one of the following error
|
||||
* codes is returned:
|
||||
* - eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid
|
||||
* slave addresses are in the range 1 - 247.
|
||||
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
|
||||
*/
|
||||
eMBErrorCode eMBMasterTCPInit( USHORT usTCPPort );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Release resources used by the protocol stack.
|
||||
*
|
||||
* This function disables the Modbus Master protocol stack and release all
|
||||
* hardware resources. It must only be called when the protocol stack
|
||||
* is disabled.
|
||||
*
|
||||
* \note Note all ports implement this function. A port which wants to
|
||||
* get an callback must define the macro MB_PORT_HAS_CLOSE to 1.
|
||||
*
|
||||
* \return If the resources where released it return eMBErrorCode::MB_ENOERR.
|
||||
* If the protocol stack is not in the disabled state it returns
|
||||
* eMBErrorCode::MB_EILLSTATE.
|
||||
*/
|
||||
eMBErrorCode eMBMasterClose( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Enable the Modbus Master protocol stack.
|
||||
*
|
||||
* This function enables processing of Modbus Master frames. Enabling the protocol
|
||||
* stack is only possible if it is in the disabled state.
|
||||
*
|
||||
* \return If the protocol stack is now in the state enabled it returns
|
||||
* eMBErrorCode::MB_ENOERR. If it was not in the disabled state it
|
||||
* return eMBErrorCode::MB_EILLSTATE.
|
||||
*/
|
||||
eMBErrorCode eMBMasterEnable( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Disable the Modbus Master protocol stack.
|
||||
*
|
||||
* This function disables processing of Modbus frames.
|
||||
*
|
||||
* \return If the protocol stack has been disabled it returns
|
||||
* eMBErrorCode::MB_ENOERR. If it was not in the enabled state it returns
|
||||
* eMBErrorCode::MB_EILLSTATE.
|
||||
*/
|
||||
eMBErrorCode eMBMasterDisable( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Check the Modbus Master protocol stack has established or not.
|
||||
*
|
||||
* This function must be called and check the return value before calling
|
||||
* any other functions.
|
||||
*
|
||||
* \return If the protocol stack has been established or not
|
||||
* TRUE. the protocol stack has established
|
||||
* FALSE. the protocol stack hasn't established
|
||||
*/
|
||||
BOOL eMBMasterIsEstablished( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief The main pooling loop of the Modbus Master protocol stack.
|
||||
*
|
||||
* This function must be called periodically. The timer interval required
|
||||
* is given by the application dependent Modbus slave timeout. Internally the
|
||||
* function calls xMBMasterPortEventGet() and waits for an event from the receiver or
|
||||
* transmitter state machines.
|
||||
*
|
||||
* \return If the protocol stack is not in the enabled state the function
|
||||
* returns eMBErrorCode::MB_EILLSTATE. Otherwise it returns
|
||||
* eMBErrorCode::MB_ENOERR.
|
||||
*/
|
||||
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, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRegData, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr,
|
||||
USHORT usNRegs, USHORT * pusDataBuffer, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
|
||||
USHORT usReadRegAddr, USHORT usNReadRegs, USHORT * pusDataBuffer,
|
||||
USHORT usWriteRegAddr, USHORT usNWriteRegs, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadCoils( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usNCoils, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqWriteCoil( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usCoilData, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
|
||||
USHORT usCoilAddr, USHORT usNCoils, UCHAR * pucDataBuffer, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr, USHORT usDiscreteAddr, USHORT usNDiscreteIn, LONG lTimeOut );
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncReadCoils( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
|
||||
/*\ingroup modbus
|
||||
*\brief These functions are interface for Modbus Master
|
||||
*/
|
||||
void vMBMasterGetPDUSndBuf( UCHAR ** pucFrame );
|
||||
UCHAR ucMBMasterGetDestAddress( void );
|
||||
void vMBMasterSetDestAddress( UCHAR Address );
|
||||
BOOL xMBMasterGetCBRunInMasterMode( void );
|
||||
void vMBMasterSetCBRunInMasterMode( BOOL IsMasterMode );
|
||||
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 -----------------------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
PR_END_EXTERN_C
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbconfig.h,v 1.14 2006/12/07 22:10:34 wolti Exp $
|
||||
* $Id: mbconfig.h,v 1.60 2013/08/13 21:19:55 Armink Add Master Functions $
|
||||
*/
|
||||
|
||||
#ifndef _MB_CONFIG_H
|
||||
#define _MB_CONFIG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
PR_BEGIN_EXTERN_C
|
||||
#endif
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
/*! \defgroup modbus_cfg Modbus Configuration
|
||||
*
|
||||
* Most modules in the protocol stack are completly optional and can be
|
||||
* excluded. This is specially important if target resources are very small
|
||||
* and program memory space should be saved.<br>
|
||||
*
|
||||
* All of these settings are available in the file <code>mbconfig.h</code>
|
||||
*/
|
||||
#include <transform.h>
|
||||
|
||||
#ifdef ADD_RTTHREAD_FEATURES
|
||||
#include <rtconfig.h>
|
||||
#endif
|
||||
|
||||
/*! \addtogroup modbus_cfg
|
||||
* @{
|
||||
*/
|
||||
/*! \brief If Modbus Master ASCII support is enabled. */
|
||||
#define MB_MASTER_ASCII_ENABLED ( 0 )
|
||||
/*! \brief If Modbus Master RTU support is enabled. */
|
||||
#define MB_MASTER_RTU_ENABLED ( 1 )
|
||||
/*! \brief If Modbus Master TCP support is enabled. */
|
||||
#define MB_MASTER_TCP_ENABLED ( 0 )
|
||||
|
||||
#ifdef ADD_RTTHREAD_FEATURES
|
||||
/*! \brief If Modbus Slave ASCII support is enabled. */
|
||||
#ifdef PKG_MODBUS_SLAVE_ASCII
|
||||
#define MB_SLAVE_ASCII_ENABLED ( 1 )
|
||||
#else
|
||||
#define MB_SLAVE_ASCII_ENABLED ( 0 )
|
||||
#endif
|
||||
|
||||
/*! \brief If Modbus Slave RTU support is enabled. */
|
||||
#ifdef PKG_MODBUS_SLAVE_RTU
|
||||
#define MB_SLAVE_RTU_ENABLED ( 1 )
|
||||
#else
|
||||
#define MB_SLAVE_RTU_ENABLED ( 0 )
|
||||
#endif
|
||||
|
||||
/*! \brief If Modbus Slave TCP support is enabled. */
|
||||
#ifdef PKG_MODBUS_SLAVE_TCP
|
||||
#define MB_SLAVE_TCP_ENABLED ( 1 )
|
||||
#else
|
||||
#define MB_SLAVE_TCP_ENABLED ( 0 )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ADD_XIZI_FEATURES
|
||||
/*! \brief If Modbus Slave ASCII support is enabled. */
|
||||
#ifdef CONNECTION_MODBUS_USING_ASCII_SLAVE
|
||||
#define MB_SLAVE_ASCII_ENABLED ( 1 )
|
||||
#else
|
||||
#define MB_SLAVE_ASCII_ENABLED ( 0 )
|
||||
#endif
|
||||
|
||||
/*! \brief If Modbus Slave RTU support is enabled. */
|
||||
#ifdef CONNECTION_MODBUS_USING_RTU_SLAVE
|
||||
#define MB_SLAVE_RTU_ENABLED ( 1 )
|
||||
#else
|
||||
#define MB_SLAVE_RTU_ENABLED ( 0 )
|
||||
#endif
|
||||
|
||||
/*! \brief If Modbus Slave TCP support is enabled. */
|
||||
#ifdef CONNECTION_MODBUS_USING_TCP_SLAVE
|
||||
#define MB_SLAVE_TCP_ENABLED ( 1 )
|
||||
#else
|
||||
#define MB_SLAVE_TCP_ENABLED ( 0 )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*! \brief The character timeout value for Modbus ASCII.
|
||||
*
|
||||
* The character timeout value is not fixed for Modbus ASCII and is therefore
|
||||
* a configuration option. It should be set to the maximum expected delay
|
||||
* time of the network.
|
||||
*/
|
||||
#define MB_ASCII_TIMEOUT_SEC ( 1 )
|
||||
/*! \brief Maximum number of Modbus functions codes the protocol stack
|
||||
* should support.
|
||||
*
|
||||
* The maximum number of supported Modbus functions must be greater than
|
||||
* the sum of all enabled functions in this file and custom function
|
||||
* handlers. If set to small adding more functions will fail.
|
||||
*/
|
||||
#define MB_FUNC_HANDLERS_MAX ( 16 )
|
||||
/*! \brief Number of bytes which should be allocated for the <em>Report Slave ID
|
||||
* </em>command.
|
||||
*
|
||||
* This number limits the maximum size of the additional segment in the
|
||||
* report slave id function. See eMBSetSlaveID( ) for more information on
|
||||
* how to set this value. It is only used if MB_FUNC_OTHER_REP_SLAVEID_ENABLED
|
||||
* is set to <code>1</code>.
|
||||
*/
|
||||
#define MB_FUNC_OTHER_REP_SLAVEID_BUF ( 32 )
|
||||
/*! \brief If the <em>Report Slave ID</em> function should be enabled. */
|
||||
#define MB_FUNC_OTHER_REP_SLAVEID_ENABLED ( 1 )
|
||||
/*! \brief If the <em>Read Input Registers</em> function should be enabled. */
|
||||
#define MB_FUNC_READ_INPUT_ENABLED ( 1 )
|
||||
/*! \brief If the <em>Read Holding Registers</em> function should be enabled. */
|
||||
#define MB_FUNC_READ_HOLDING_ENABLED ( 1 )
|
||||
/*! \brief If the <em>Write Single Register</em> function should be enabled. */
|
||||
#define MB_FUNC_WRITE_HOLDING_ENABLED ( 1 )
|
||||
/*! \brief If the <em>Write Multiple registers</em> function should be enabled. */
|
||||
#define MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED ( 1 )
|
||||
/*! \brief If the <em>Read Coils</em> function should be enabled. */
|
||||
#define MB_FUNC_READ_COILS_ENABLED ( 1 )
|
||||
/*! \brief If the <em>Write Coils</em> function should be enabled. */
|
||||
#define MB_FUNC_WRITE_COIL_ENABLED ( 1 )
|
||||
/*! \brief If the <em>Write Multiple Coils</em> function should be enabled. */
|
||||
#define MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED ( 1 )
|
||||
/*! \brief If the <em>Read Discrete Inputs</em> function should be enabled. */
|
||||
#define MB_FUNC_READ_DISCRETE_INPUTS_ENABLED ( 1 )
|
||||
/*! \brief If the <em>Read/Write Multiple Registers</em> function should be enabled. */
|
||||
#define MB_FUNC_READWRITE_HOLDING_ENABLED ( 1 )
|
||||
/*! @} */
|
||||
#ifdef __cplusplus
|
||||
PR_END_EXTERN_C
|
||||
#endif
|
||||
|
||||
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
|
||||
/*! \brief If master send a broadcast frame,the master will wait time of convert to delay,
|
||||
* then master can send other frame */
|
||||
#define MB_MASTER_DELAY_MS_CONVERT (200 )
|
||||
/*! \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 (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
|
||||
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
|
@ -25,6 +25,7 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbframe.h,v 1.9 2006/12/07 22:10:34 wolti Exp $
|
||||
*/
|
||||
|
||||
#ifndef _MB_FRAME_H
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbfunc.h,v 1.12 2006/12/07 22:10:34 wolti Exp $
|
||||
*/
|
||||
|
||||
#ifndef _MB_FUNC_H
|
||||
#define _MB_FUNC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
PR_BEGIN_EXTERN_C
|
||||
#endif
|
||||
#if MB_FUNC_OTHER_REP_SLAVEID_BUF > 0
|
||||
eMBException eMBFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen );
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_READ_INPUT_ENABLED > 0
|
||||
eMBException eMBFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_READ_HOLDING_ENABLED > 0
|
||||
eMBException eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
|
||||
eMBException eMBFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
|
||||
eMBException eMBFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_READ_COILS_ENABLED > 0
|
||||
eMBException eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen );
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_WRITE_COIL_ENABLED > 0
|
||||
eMBException eMBFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen );
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
|
||||
eMBException eMBFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen );
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
|
||||
eMBException eMBFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen );
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
|
||||
eMBException eMBFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
PR_END_EXTERN_C
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbport.h,v 1.17 2006/12/07 22:10:34 wolti Exp $
|
||||
* mbport.h,v 1.60 2013/08/17 11:42:56 Armink Add Master Functions $
|
||||
*/
|
||||
|
||||
#ifndef _MB_PORT_H
|
||||
#define _MB_PORT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
PR_BEGIN_EXTERN_C
|
||||
#endif
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
|
||||
/* ----------------------- Type definitions ---------------------------------*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
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 = 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.
|
||||
*
|
||||
* The parity which should be applied to the characters sent over the serial
|
||||
* link. Please note that this values are actually passed to the porting
|
||||
* layer and therefore not all parity modes might be available.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
MB_PAR_NONE, /*!< No parity. */
|
||||
MB_PAR_ODD, /*!< Odd parity. */
|
||||
MB_PAR_EVEN /*!< Even parity. */
|
||||
} eMBParity;
|
||||
|
||||
/* ----------------------- Supporting functions -----------------------------*/
|
||||
BOOL xMBPortEventInit( void );
|
||||
|
||||
BOOL xMBPortEventPost( eMBEventType eEvent );
|
||||
|
||||
BOOL xMBPortEventGet( /*@out@ */ eMBEventType * eEvent );
|
||||
|
||||
BOOL xMBMasterPortEventInit( void );
|
||||
|
||||
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,
|
||||
UCHAR ucDataBits, eMBParity eParity );
|
||||
|
||||
void vMBPortClose( void );
|
||||
|
||||
void xMBPortSerialClose( void );
|
||||
|
||||
void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable );
|
||||
|
||||
INLINE BOOL xMBPortSerialGetByte( CHAR * pucByte );
|
||||
|
||||
INLINE BOOL xMBPortSerialPutByte( CHAR ucByte );
|
||||
|
||||
BOOL xMBMasterPortSerialInit( UCHAR ucPort, ULONG ulBaudRate,
|
||||
UCHAR ucDataBits, eMBParity eParity );
|
||||
|
||||
void vMBMasterPortClose( void );
|
||||
|
||||
void xMBMasterPortSerialClose( void );
|
||||
|
||||
void vMBMasterPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable );
|
||||
|
||||
INLINE BOOL xMBMasterPortSerialGetByte( CHAR * pucByte );
|
||||
|
||||
INLINE BOOL xMBMasterPortSerialPutByte( CHAR ucByte );
|
||||
|
||||
/* ----------------------- Timers functions ---------------------------------*/
|
||||
BOOL xMBPortTimersInit( USHORT usTimeOut50us );
|
||||
|
||||
void xMBPortTimersClose( void );
|
||||
|
||||
INLINE void vMBPortTimersEnable( void );
|
||||
|
||||
INLINE void vMBPortTimersDisable( void );
|
||||
|
||||
BOOL xMBMasterPortTimersInit( USHORT usTimeOut50us );
|
||||
|
||||
void xMBMasterPortTimersClose( void );
|
||||
|
||||
INLINE void vMBMasterPortTimersT35Enable( void );
|
||||
|
||||
INLINE void vMBMasterPortTimersConvertDelayEnable( void );
|
||||
|
||||
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 ------------------*/
|
||||
|
||||
/*!
|
||||
* \brief Callback function for the porting layer when a new byte is
|
||||
* available.
|
||||
*
|
||||
* Depending upon the mode this callback function is used by the RTU or
|
||||
* ASCII transmission layers. In any case a call to xMBPortSerialGetByte()
|
||||
* must immediately return a new character.
|
||||
*
|
||||
* \return <code>TRUE</code> if a event was posted to the queue because
|
||||
* a new byte was received. The port implementation should wake up the
|
||||
* tasks which are currently blocked on the eventqueue.
|
||||
*/
|
||||
extern BOOL( *pxMBFrameCBTransmitterEmpty ) ( void );
|
||||
|
||||
extern BOOL( *pxMBPortCBTimerExpired ) ( void );
|
||||
|
||||
#ifdef ADD_RTTHREAD_FEATURES
|
||||
extern BOOL( *pxMBFrameCBByteReceived ) ( void );
|
||||
extern BOOL( *pxMBMasterFrameCBByteReceived ) ( void );
|
||||
#endif
|
||||
|
||||
#ifdef ADD_XIZI_FEATURES
|
||||
extern BOOL( *pxMBFrameCBByteReceived ) ( CHAR pucByte );
|
||||
extern BOOL( *pxMBMasterFrameCBByteReceived ) ( CHAR pucByte );
|
||||
#endif
|
||||
|
||||
extern BOOL( *pxMBMasterFrameCBTransmitterEmpty ) ( void );
|
||||
|
||||
extern BOOL( *pxMBMasterPortCBTimerExpired ) ( void );
|
||||
|
||||
/* ----------------------- TCP port functions -------------------------------*/
|
||||
BOOL xMBTCPPortInit( USHORT usTCPPort );
|
||||
|
||||
void vMBTCPPortClose( void );
|
||||
|
||||
void vMBTCPPortDisable( void );
|
||||
|
||||
BOOL xMBTCPPortGetRequest( UCHAR **ppucMBTCPFrame, USHORT * usTCPLength );
|
||||
|
||||
BOOL xMBTCPPortSendResponse( const UCHAR *pucMBTCPFrame, USHORT usTCPLength );
|
||||
|
||||
#ifdef __cplusplus
|
||||
PR_END_EXTERN_C
|
||||
#endif
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
|
@ -25,6 +25,7 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbproto.h,v 1.14 2006/12/07 22:10:34 wolti Exp $
|
||||
*/
|
||||
|
||||
#ifndef _MB_PROTO_H
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
|
@ -25,6 +25,7 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbutils.h,v 1.5 2006/12/07 22:10:34 wolti Exp $
|
||||
*/
|
||||
|
||||
#ifndef _MB_UTILS_H
|
|
@ -0,0 +1,417 @@
|
|||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mb.c,v 1.27 2007/02/18 23:45:41 wolti Exp $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
|
||||
#include "mb.h"
|
||||
#include "mbconfig.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbproto.h"
|
||||
#include "mbfunc.h"
|
||||
|
||||
#include "mbport.h"
|
||||
#if MB_SLAVE_RTU_ENABLED == 1
|
||||
#include "mbrtu.h"
|
||||
#endif
|
||||
#if MB_SLAVE_ASCII_ENABLED == 1
|
||||
#include "mbascii.h"
|
||||
#endif
|
||||
#if MB_SLAVE_TCP_ENABLED == 1
|
||||
#include "mbtcp.h"
|
||||
#endif
|
||||
|
||||
#ifndef MB_PORT_HAS_CLOSE
|
||||
#define MB_PORT_HAS_CLOSE 0
|
||||
#endif
|
||||
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
|
||||
static UCHAR ucMBAddress;
|
||||
static eMBMode eMBCurrentMode;
|
||||
|
||||
static enum
|
||||
{
|
||||
STATE_ENABLED,
|
||||
STATE_DISABLED,
|
||||
STATE_NOT_INITIALIZED
|
||||
} eMBState = STATE_NOT_INITIALIZED;
|
||||
|
||||
/* Functions pointer which are initialized in eMBInit( ). Depending on the
|
||||
* mode (RTU or ASCII) the are set to the correct implementations.
|
||||
* Using for Modbus Slave
|
||||
*/
|
||||
static peMBFrameSend peMBFrameSendCur;
|
||||
static pvMBFrameStart pvMBFrameStartCur;
|
||||
static pvMBFrameStop pvMBFrameStopCur;
|
||||
static peMBFrameReceive peMBFrameReceiveCur;
|
||||
static pvMBFrameClose pvMBFrameCloseCur;
|
||||
|
||||
/* Callback functions required by the porting layer. They are called when
|
||||
* an external event has happend which includes a timeout or the reception
|
||||
* or transmission of a character.
|
||||
* Using for Modbus Slave
|
||||
*/
|
||||
#ifdef ADD_RTTHREAD_FEATURES
|
||||
BOOL( *pxMBFrameCBByteReceived ) ( void );
|
||||
#endif
|
||||
#ifdef ADD_XIZI_FEATURES
|
||||
BOOL( *pxMBFrameCBByteReceived ) ( CHAR pucByte );
|
||||
#endif
|
||||
BOOL( *pxMBFrameCBTransmitterEmpty ) ( void );
|
||||
BOOL( *pxMBPortCBTimerExpired ) ( void );
|
||||
|
||||
BOOL( *pxMBFrameCBReceiveFSMCur ) ( void );
|
||||
BOOL( *pxMBFrameCBTransmitFSMCur ) ( void );
|
||||
|
||||
/* An array of Modbus functions handlers which associates Modbus function
|
||||
* codes with implementing functions.
|
||||
*/
|
||||
static xMBFunctionHandler xFuncHandlers[MB_FUNC_HANDLERS_MAX] = {
|
||||
#if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0
|
||||
{MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID},
|
||||
#endif
|
||||
#if MB_FUNC_READ_INPUT_ENABLED > 0
|
||||
{MB_FUNC_READ_INPUT_REGISTER, eMBFuncReadInputRegister},
|
||||
#endif
|
||||
#if MB_FUNC_READ_HOLDING_ENABLED > 0
|
||||
{MB_FUNC_READ_HOLDING_REGISTER, eMBFuncReadHoldingRegister},
|
||||
#endif
|
||||
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
|
||||
{MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBFuncWriteMultipleHoldingRegister},
|
||||
#endif
|
||||
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
|
||||
{MB_FUNC_WRITE_REGISTER, eMBFuncWriteHoldingRegister},
|
||||
#endif
|
||||
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
|
||||
{MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBFuncReadWriteMultipleHoldingRegister},
|
||||
#endif
|
||||
#if MB_FUNC_READ_COILS_ENABLED > 0
|
||||
{MB_FUNC_READ_COILS, eMBFuncReadCoils},
|
||||
#endif
|
||||
#if MB_FUNC_WRITE_COIL_ENABLED > 0
|
||||
{MB_FUNC_WRITE_SINGLE_COIL, eMBFuncWriteCoil},
|
||||
#endif
|
||||
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
|
||||
{MB_FUNC_WRITE_MULTIPLE_COILS, eMBFuncWriteMultipleCoils},
|
||||
#endif
|
||||
#if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
|
||||
{MB_FUNC_READ_DISCRETE_INPUTS, eMBFuncReadDiscreteInputs},
|
||||
#endif
|
||||
};
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
eMBErrorCode
|
||||
eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
/* check preconditions */
|
||||
if( ( ucSlaveAddress == MB_ADDRESS_BROADCAST ) ||
|
||||
( ucSlaveAddress < MB_ADDRESS_MIN ) || ( ucSlaveAddress > MB_ADDRESS_MAX ) )
|
||||
{
|
||||
eStatus = MB_EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ucMBAddress = ucSlaveAddress;
|
||||
|
||||
switch ( eMode )
|
||||
{
|
||||
#if MB_SLAVE_RTU_ENABLED > 0
|
||||
case MB_RTU:
|
||||
pvMBFrameStartCur = eMBRTUStart;
|
||||
pvMBFrameStopCur = eMBRTUStop;
|
||||
peMBFrameSendCur = eMBRTUSend;
|
||||
peMBFrameReceiveCur = eMBRTUReceive;
|
||||
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
|
||||
pxMBFrameCBByteReceived = xMBRTUReceiveFSM;
|
||||
pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM;
|
||||
pxMBPortCBTimerExpired = xMBRTUTimerT35Expired;
|
||||
|
||||
eStatus = eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity );
|
||||
break;
|
||||
#endif
|
||||
#if MB_SLAVE_ASCII_ENABLED > 0
|
||||
case MB_ASCII:
|
||||
pvMBFrameStartCur = eMBASCIIStart;
|
||||
pvMBFrameStopCur = eMBASCIIStop;
|
||||
peMBFrameSendCur = eMBASCIISend;
|
||||
peMBFrameReceiveCur = eMBASCIIReceive;
|
||||
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
|
||||
pxMBFrameCBByteReceived = xMBASCIIReceiveFSM;
|
||||
pxMBFrameCBTransmitterEmpty = xMBASCIITransmitFSM;
|
||||
pxMBPortCBTimerExpired = xMBASCIITimerT1SExpired;
|
||||
|
||||
eStatus = eMBASCIIInit( ucMBAddress, ucPort, ulBaudRate, eParity );
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
eStatus = MB_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if( eStatus == MB_ENOERR )
|
||||
{
|
||||
if( !xMBPortEventInit( ) )
|
||||
{
|
||||
/* port dependent event module initalization failed. */
|
||||
eStatus = MB_EPORTERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
eMBCurrentMode = eMode;
|
||||
eMBState = STATE_DISABLED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#if MB_SLAVE_TCP_ENABLED > 0
|
||||
eMBErrorCode
|
||||
eMBTCPInit( USHORT ucTCPPort )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
if( ( eStatus = eMBTCPDoInit( ucTCPPort ) ) != MB_ENOERR )
|
||||
{
|
||||
eMBState = STATE_DISABLED;
|
||||
}
|
||||
else if( !xMBPortEventInit( ) )
|
||||
{
|
||||
/* Port dependent event module initalization failed. */
|
||||
eStatus = MB_EPORTERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
pvMBFrameStartCur = eMBTCPStart;
|
||||
pvMBFrameStopCur = eMBTCPStop;
|
||||
peMBFrameReceiveCur = eMBTCPReceive;
|
||||
peMBFrameSendCur = eMBTCPSend;
|
||||
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBTCPPortClose : NULL;
|
||||
ucMBAddress = MB_TCP_PSEUDO_ADDRESS;
|
||||
eMBCurrentMode = MB_TCP;
|
||||
eMBState = STATE_DISABLED;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
#endif
|
||||
|
||||
eMBErrorCode
|
||||
eMBRegisterCB( UCHAR ucFunctionCode, pxMBFunctionHandler pxHandler )
|
||||
{
|
||||
int i;
|
||||
eMBErrorCode eStatus;
|
||||
|
||||
if( ( 0 < ucFunctionCode ) && ( ucFunctionCode <= 127 ) )
|
||||
{
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
if( pxHandler != NULL )
|
||||
{
|
||||
for( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
|
||||
{
|
||||
if( ( xFuncHandlers[i].pxHandler == NULL ) ||
|
||||
( xFuncHandlers[i].pxHandler == pxHandler ) )
|
||||
{
|
||||
xFuncHandlers[i].ucFunctionCode = ucFunctionCode;
|
||||
xFuncHandlers[i].pxHandler = pxHandler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
eStatus = ( i != MB_FUNC_HANDLERS_MAX ) ? MB_ENOERR : MB_ENORES;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
|
||||
{
|
||||
if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode )
|
||||
{
|
||||
xFuncHandlers[i].ucFunctionCode = 0;
|
||||
xFuncHandlers[i].pxHandler = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Remove can't fail. */
|
||||
eStatus = MB_ENOERR;
|
||||
}
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EINVAL;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
|
||||
eMBErrorCode
|
||||
eMBClose( void )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
if( eMBState == STATE_DISABLED )
|
||||
{
|
||||
if( pvMBFrameCloseCur != NULL )
|
||||
{
|
||||
pvMBFrameCloseCur( );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EILLSTATE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
|
||||
eMBErrorCode
|
||||
eMBEnable( void )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
if( eMBState == STATE_DISABLED )
|
||||
{
|
||||
/* Activate the protocol stack. */
|
||||
pvMBFrameStartCur( );
|
||||
eMBState = STATE_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EILLSTATE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBDisable( void )
|
||||
{
|
||||
eMBErrorCode eStatus;
|
||||
|
||||
if( eMBState == STATE_ENABLED )
|
||||
{
|
||||
pvMBFrameStopCur( );
|
||||
eMBState = STATE_DISABLED;
|
||||
eStatus = MB_ENOERR;
|
||||
}
|
||||
else if( eMBState == STATE_DISABLED )
|
||||
{
|
||||
eStatus = MB_ENOERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EILLSTATE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode eMBPoll( void )
|
||||
{
|
||||
static UCHAR *ucMBFrame;
|
||||
static UCHAR ucRcvAddress;
|
||||
static UCHAR ucFunctionCode;
|
||||
static USHORT usLength;
|
||||
static eMBException eException;
|
||||
|
||||
int i;
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
eMBEventType eEvent;
|
||||
|
||||
/* Check if the protocol stack is ready. */
|
||||
if( eMBState != STATE_ENABLED )
|
||||
{
|
||||
return MB_EILLSTATE;
|
||||
}
|
||||
|
||||
/* Check if there is a event available. If not return control to caller.
|
||||
* Otherwise we will handle the event. */
|
||||
if( xMBPortEventGet( &eEvent ) == TRUE )
|
||||
{
|
||||
switch ( eEvent )
|
||||
{
|
||||
case EV_READY:
|
||||
break;
|
||||
|
||||
case EV_FRAME_RECEIVED:
|
||||
eStatus = peMBFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
|
||||
if( eStatus == MB_ENOERR )
|
||||
{
|
||||
/* Check if the frame is for us. If not ignore the frame. */
|
||||
if( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) )
|
||||
{
|
||||
( void )xMBPortEventPost( EV_EXECUTE );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_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( xFuncHandlers[i].ucFunctionCode == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode )
|
||||
{
|
||||
eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the request was not sent to the broadcast address we
|
||||
* return a reply. */
|
||||
if( ucRcvAddress != MB_ADDRESS_BROADCAST )
|
||||
{
|
||||
if( eException != MB_EX_NONE )
|
||||
{
|
||||
/* An exception occured. Build an error frame. */
|
||||
usLength = 0;
|
||||
ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR );
|
||||
ucMBFrame[usLength++] = eException;
|
||||
}
|
||||
eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_FRAME_SENT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return MB_ENOERR;
|
||||
}
|
|
@ -0,0 +1,431 @@
|
|||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbrtu_m.c,v 1.60 2013/08/20 11:18:10 Armink Add Master Functions $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbconfig.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbproto.h"
|
||||
#include "mbfunc.h"
|
||||
|
||||
#include "mbport.h"
|
||||
#if MB_MASTER_RTU_ENABLED == 1
|
||||
#include "mbrtu.h"
|
||||
#endif
|
||||
#if MB_MASTER_ASCII_ENABLED == 1
|
||||
#include "mbascii.h"
|
||||
#endif
|
||||
#if MB_MASTER_TCP_ENABLED == 1
|
||||
#include "mbtcp.h"
|
||||
#endif
|
||||
|
||||
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
|
||||
|
||||
#ifndef MB_PORT_HAS_CLOSE
|
||||
#define MB_PORT_HAS_CLOSE 0
|
||||
#endif
|
||||
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
|
||||
static UCHAR ucMBMasterDestAddress;
|
||||
static BOOL xMBRunInMasterMode = FALSE;
|
||||
static eMBMasterErrorEventType eMBMasterCurErrorType;
|
||||
|
||||
static enum
|
||||
{
|
||||
STATE_ENABLED,
|
||||
STATE_DISABLED,
|
||||
STATE_NOT_INITIALIZED,
|
||||
STATE_ESTABLISHED,
|
||||
} eMBState = STATE_NOT_INITIALIZED;
|
||||
|
||||
/* Functions pointer which are initialized in eMBInit( ). Depending on the
|
||||
* mode (RTU or ASCII) the are set to the correct implementations.
|
||||
* Using for Modbus Master,Add by Armink 20130813
|
||||
*/
|
||||
static peMBFrameSend peMBMasterFrameSendCur;
|
||||
static pvMBFrameStart pvMBMasterFrameStartCur;
|
||||
static pvMBFrameStop pvMBMasterFrameStopCur;
|
||||
static peMBFrameReceive peMBMasterFrameReceiveCur;
|
||||
static pvMBFrameClose pvMBMasterFrameCloseCur;
|
||||
|
||||
/* Callback functions required by the porting layer. They are called when
|
||||
* an external event has happend which includes a timeout or the reception
|
||||
* or transmission of a character.
|
||||
* Using for Modbus Master,Add by Armink 20130813
|
||||
*/
|
||||
#ifdef ADD_RTTHREAD_FEATURES
|
||||
BOOL( *pxMBMasterFrameCBByteReceived ) ( void );
|
||||
#endif
|
||||
#ifdef ADD_XIZI_FEATURES
|
||||
BOOL( *pxMBMasterFrameCBByteReceived ) ( CHAR pucByte );
|
||||
#endif
|
||||
BOOL( *pxMBMasterFrameCBTransmitterEmpty ) ( void );
|
||||
BOOL( *pxMBMasterPortCBTimerExpired ) ( void );
|
||||
|
||||
BOOL( *pxMBMasterFrameCBReceiveFSMCur ) ( void );
|
||||
BOOL( *pxMBMasterFrameCBTransmitFSMCur ) ( void );
|
||||
|
||||
/* An array of Modbus functions handlers which associates Modbus function
|
||||
* codes with implementing functions.
|
||||
*/
|
||||
static xMBFunctionHandler xMasterFuncHandlers[MB_FUNC_HANDLERS_MAX] = {
|
||||
#if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0
|
||||
//TODO Add Master function define
|
||||
{MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID},
|
||||
#endif
|
||||
#if MB_FUNC_READ_INPUT_ENABLED > 0
|
||||
{MB_FUNC_READ_INPUT_REGISTER, eMBMasterFuncReadInputRegister},
|
||||
#endif
|
||||
#if MB_FUNC_READ_HOLDING_ENABLED > 0
|
||||
{MB_FUNC_READ_HOLDING_REGISTER, eMBMasterFuncReadHoldingRegister},
|
||||
#endif
|
||||
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
|
||||
{MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBMasterFuncWriteMultipleHoldingRegister},
|
||||
#endif
|
||||
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
|
||||
{MB_FUNC_WRITE_REGISTER, eMBMasterFuncWriteHoldingRegister},
|
||||
#endif
|
||||
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
|
||||
{MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBMasterFuncReadWriteMultipleHoldingRegister},
|
||||
#endif
|
||||
#if MB_FUNC_READ_COILS_ENABLED > 0
|
||||
{MB_FUNC_READ_COILS, eMBMasterFuncReadCoils},
|
||||
#endif
|
||||
#if MB_FUNC_WRITE_COIL_ENABLED > 0
|
||||
{MB_FUNC_WRITE_SINGLE_COIL, eMBMasterFuncWriteCoil},
|
||||
#endif
|
||||
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
|
||||
{MB_FUNC_WRITE_MULTIPLE_COILS, eMBMasterFuncWriteMultipleCoils},
|
||||
#endif
|
||||
#if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
|
||||
{MB_FUNC_READ_DISCRETE_INPUTS, eMBMasterFuncReadDiscreteInputs},
|
||||
#endif
|
||||
};
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
eMBErrorCode
|
||||
eMBMasterInit( eMBMode eMode, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
switch (eMode)
|
||||
{
|
||||
#if MB_MASTER_RTU_ENABLED > 0
|
||||
case MB_RTU:
|
||||
pvMBMasterFrameStartCur = eMBMasterRTUStart;
|
||||
pvMBMasterFrameStopCur = eMBMasterRTUStop;
|
||||
peMBMasterFrameSendCur = eMBMasterRTUSend;
|
||||
peMBMasterFrameReceiveCur = eMBMasterRTUReceive;
|
||||
pvMBMasterFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBMasterPortClose : NULL;
|
||||
pxMBMasterFrameCBByteReceived = xMBMasterRTUReceiveFSM;
|
||||
pxMBMasterFrameCBTransmitterEmpty = xMBMasterRTUTransmitFSM;
|
||||
pxMBMasterPortCBTimerExpired = xMBMasterRTUTimerExpired;
|
||||
|
||||
eStatus = eMBMasterRTUInit(ucPort, ulBaudRate, eParity);
|
||||
break;
|
||||
#endif
|
||||
#if MB_MASTER_ASCII_ENABLED > 0
|
||||
case MB_ASCII:
|
||||
pvMBMasterFrameStartCur = eMBMasterASCIIStart;
|
||||
pvMBMasterFrameStopCur = eMBMasterASCIIStop;
|
||||
peMBMasterFrameSendCur = eMBMasterASCIISend;
|
||||
peMBMasterFrameReceiveCur = eMBMasterASCIIReceive;
|
||||
pvMBMasterFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBMasterPortClose : NULL;
|
||||
pxMBMasterFrameCBByteReceived = xMBMasterASCIIReceiveFSM;
|
||||
pxMBMasterFrameCBTransmitterEmpty = xMBMasterASCIITransmitFSM;
|
||||
pxMBMasterPortCBTimerExpired = xMBMasterASCIITimerT1SExpired;
|
||||
|
||||
eStatus = eMBMasterASCIIInit(ucPort, ulBaudRate, eParity );
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
eStatus = MB_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (eStatus == MB_ENOERR)
|
||||
{
|
||||
if (!xMBMasterPortEventInit())
|
||||
{
|
||||
/* port dependent event module initalization failed. */
|
||||
eStatus = MB_EPORTERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
eMBState = STATE_DISABLED;
|
||||
}
|
||||
/* initialize the OS resource for modbus master. */
|
||||
vMBMasterOsResInit();
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBMasterClose( void )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
if( eMBState == STATE_DISABLED )
|
||||
{
|
||||
if( pvMBMasterFrameCloseCur != NULL )
|
||||
{
|
||||
pvMBMasterFrameCloseCur( );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EILLSTATE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBMasterEnable( void )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
if( eMBState == STATE_DISABLED )
|
||||
{
|
||||
/* Activate the protocol stack. */
|
||||
pvMBMasterFrameStartCur( );
|
||||
eMBState = STATE_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EILLSTATE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBMasterDisable( void )
|
||||
{
|
||||
eMBErrorCode eStatus;
|
||||
|
||||
if(( eMBState == STATE_ENABLED ) || ( eMBState == STATE_ESTABLISHED))
|
||||
{
|
||||
pvMBMasterFrameStopCur( );
|
||||
eMBState = STATE_DISABLED;
|
||||
eStatus = MB_ENOERR;
|
||||
}
|
||||
else if( eMBState == STATE_DISABLED )
|
||||
{
|
||||
eStatus = MB_ENOERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EILLSTATE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
BOOL
|
||||
eMBMasterIsEstablished( void )
|
||||
{
|
||||
if(eMBState == STATE_ESTABLISHED)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
eMBErrorCode
|
||||
eMBMasterPoll( void )
|
||||
{
|
||||
static UCHAR *ucMBFrame;
|
||||
static UCHAR ucRcvAddress;
|
||||
static UCHAR ucFunctionCode;
|
||||
static USHORT usLength;
|
||||
static eMBException eException;
|
||||
|
||||
int i , j;
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
eMBMasterEventType eEvent;
|
||||
eMBMasterErrorEventType errorType;
|
||||
|
||||
/* Check if the protocol stack is ready. */
|
||||
if(( eMBState != STATE_ENABLED ) && ( eMBState != STATE_ESTABLISHED))
|
||||
{
|
||||
return MB_EILLSTATE;
|
||||
}
|
||||
|
||||
/* Check if there is a event available. If not return control to caller.
|
||||
* Otherwise we will handle the event. */
|
||||
if( xMBMasterPortEventGet( &eEvent ) == TRUE )
|
||||
{
|
||||
switch ( eEvent )
|
||||
{
|
||||
case EV_MASTER_READY:
|
||||
eMBState = STATE_ESTABLISHED;
|
||||
break;
|
||||
|
||||
case EV_MASTER_FRAME_RECEIVED:
|
||||
eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
|
||||
/* Check if the frame is for us. If not ,send an error process event. */
|
||||
if ( ( eStatus == MB_ENOERR ) && ( ucRcvAddress == ucMBMasterGetDestAddress() ) )
|
||||
{
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE );
|
||||
}
|
||||
else
|
||||
{
|
||||
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_MASTER_EXECUTE:
|
||||
ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
|
||||
eException = MB_EX_ILLEGAL_FUNCTION;
|
||||
/* If receive frame has exception .The receive function code highest bit is 1.*/
|
||||
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) {
|
||||
vMBMasterSetErrorType(EV_ERROR_EXECUTE_FUNCTION);
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
|
||||
}
|
||||
else {
|
||||
vMBMasterCBRequestScuuess( );
|
||||
vMBMasterRunResRelease( );
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_MASTER_FRAME_SENT:
|
||||
/* Master is busy now. */
|
||||
vMBMasterGetPDUSndBuf( &ucMBFrame );
|
||||
eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBFrame, usMBMasterGetPDUSndLength() );
|
||||
break;
|
||||
|
||||
case EV_MASTER_ERROR_PROCESS:
|
||||
/* 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;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return MB_ENOERR;
|
||||
}
|
||||
|
||||
/* Get whether the Modbus Master is run in master mode.*/
|
||||
BOOL xMBMasterGetCBRunInMasterMode( void )
|
||||
{
|
||||
return xMBRunInMasterMode;
|
||||
}
|
||||
/* Set whether the Modbus Master is run in master mode.*/
|
||||
void vMBMasterSetCBRunInMasterMode( BOOL IsMasterMode )
|
||||
{
|
||||
xMBRunInMasterMode = IsMasterMode;
|
||||
}
|
||||
/* Get Modbus Master send destination address. */
|
||||
UCHAR ucMBMasterGetDestAddress( void )
|
||||
{
|
||||
return ucMBMasterDestAddress;
|
||||
}
|
||||
/* 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
|
|
@ -0,0 +1,11 @@
|
|||
SRC_FILES := mbcrc.c
|
||||
|
||||
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_MASTER),y)
|
||||
SRC_FILES += mbrtu_m.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_SLAVE),y)
|
||||
SRC_FILES += mbrtu.c
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
|
@ -25,6 +25,7 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbcrc.c,v 1.7 2007/02/18 23:50:27 wolti Exp $
|
||||
*/
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
|
@ -42,12 +43,12 @@ static const UCHAR aucCRCHi[] = {
|
|||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
|
@ -63,12 +64,12 @@ static const UCHAR aucCRCLo[] = {
|
|||
0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
|
||||
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
|
||||
0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
|
||||
0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
|
||||
0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
|
||||
0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
|
||||
0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
|
||||
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
|
||||
0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
|
||||
0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
|
||||
0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
|
||||
0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
|
||||
0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
|
||||
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
|
||||
* All rights reserved.
|
||||
|
@ -25,6 +25,7 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: mbcrc.h,v 1.5 2006/12/07 22:10:34 wolti Exp $
|
||||
*/
|
||||
|
||||
#ifndef _MB_CRC_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue