From 2a14e4071c6aaba74a345197623ea7ebec9e7806 Mon Sep 17 00:00:00 2001 From: armink Date: Thu, 5 Feb 2015 19:27:24 +0800 Subject: [PATCH] [modbus]port modbus master and slave by rtt device framework. --- components/net/freemodbus-v1.6.0/port/port.c | 15 +- components/net/freemodbus-v1.6.0/port/port.h | 14 +- .../net/freemodbus-v1.6.0/port/portevent.c | 38 +- .../net/freemodbus-v1.6.0/port/portevent_m.c | 208 ++++++++- .../net/freemodbus-v1.6.0/port/portserial.c | 277 +++++++----- .../net/freemodbus-v1.6.0/port/portserial_m.c | 275 +++++++----- .../net/freemodbus-v1.6.0/port/porttimer.c | 72 +-- .../net/freemodbus-v1.6.0/port/porttimer_m.c | 118 ++--- .../net/freemodbus-v1.6.0/port/user_mb_app.c | 425 ++++++++---------- .../net/freemodbus-v1.6.0/port/user_mb_app.h | 60 ++- .../freemodbus-v1.6.0/port/user_mb_app_m.c | 294 ++++++++++++ 11 files changed, 1087 insertions(+), 709 deletions(-) create mode 100644 components/net/freemodbus-v1.6.0/port/user_mb_app_m.c diff --git a/components/net/freemodbus-v1.6.0/port/port.c b/components/net/freemodbus-v1.6.0/port/port.c index 459481cc1..527af909a 100644 --- a/components/net/freemodbus-v1.6.0/port/port.c +++ b/components/net/freemodbus-v1.6.0/port/port.c @@ -1,6 +1,6 @@ /* - * FreeModbus Libary: LPC214X Port - * Copyright (C) 2007 Tiago Prado Lone + * FreeModbus Libary: RT-Thread Port + * Copyright (C) 2013 Armink * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * - * File: $Id: port.c,v 1.1 2007/04/24 23:15:18 wolti Exp $ + * File: $Id: portevent.c,v 1.60 2015/02/01 9:18:05 Armink $ */ /* ----------------------- System includes --------------------------------*/ @@ -24,16 +24,15 @@ /* ----------------------- Modbus includes ----------------------------------*/ #include "port.h" /* ----------------------- Variables ----------------------------------------*/ - +static rt_base_t level; /* ----------------------- Start implementation -----------------------------*/ void EnterCriticalSection(void) { - //关闭全局中断 - __disable_irq(); + level = rt_hw_interrupt_disable(); } void ExitCriticalSection(void) { - //开启全局中断 - __enable_irq(); + rt_hw_interrupt_enable(level); } + diff --git a/components/net/freemodbus-v1.6.0/port/port.h b/components/net/freemodbus-v1.6.0/port/port.h index c79df3d88..92056116b 100644 --- a/components/net/freemodbus-v1.6.0/port/port.h +++ b/components/net/freemodbus-v1.6.0/port/port.h @@ -1,6 +1,6 @@ /* * FreeModbus Libary: BARE Port - * Copyright (C) 2006 Christian Walter + * Copyright (C) 2013 Armink * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -34,18 +34,9 @@ #define PR_BEGIN_EXTERN_C extern "C" { #define PR_END_EXTERN_C } -//TODO 暂时先写B13引脚,等组网测试时再确认 -#define SLAVE_RS485_SEND_MODE GPIO_SetBits(GPIOB,GPIO_Pin_13) -#define SLAVE_RS485_RECEIVE_MODE GPIO_ResetBits(GPIOB,GPIO_Pin_13) -#define MASTER_RS485_SEND_MODE GPIO_SetBits(GPIOB,GPIO_Pin_13) -#define MASTER_RS485_RECEIVE_MODE GPIO_ResetBits(GPIOB,GPIO_Pin_13) - #define ENTER_CRITICAL_SECTION() EnterCriticalSection() #define EXIT_CRITICAL_SECTION() ExitCriticalSection() -void EnterCriticalSection(void); -void ExitCriticalSection(void); - typedef uint8_t BOOL; typedef unsigned char UCHAR; @@ -65,4 +56,7 @@ typedef int32_t LONG; #define FALSE 0 #endif +void EnterCriticalSection(void); +void ExitCriticalSection(void); + #endif diff --git a/components/net/freemodbus-v1.6.0/port/portevent.c b/components/net/freemodbus-v1.6.0/port/portevent.c index 86c7b5e7a..1a881166b 100644 --- a/components/net/freemodbus-v1.6.0/port/portevent.c +++ b/components/net/freemodbus-v1.6.0/port/portevent.c @@ -1,5 +1,5 @@ /* - * FreeModbus Libary: STM32 Port + * FreeModbus Libary: RT-Thread Port * Copyright (C) 2013 Armink * * This library is free software; you can redistribute it and/or @@ -24,35 +24,45 @@ #include "mbport.h" /* ----------------------- Variables ----------------------------------------*/ -static eMBEventType eQueuedEvent; -static BOOL xEventInQueue; - +static struct rt_event xSlaveOsEvent; /* ----------------------- Start implementation -----------------------------*/ BOOL xMBPortEventInit( void ) { - xEventInQueue = FALSE; + rt_event_init(&xSlaveOsEvent,"slave event",RT_IPC_FLAG_PRIO); return TRUE; } BOOL xMBPortEventPost( eMBEventType eEvent ) { - xEventInQueue = TRUE; - eQueuedEvent = eEvent; + rt_event_send(&xSlaveOsEvent, eEvent); return TRUE; } BOOL xMBPortEventGet( eMBEventType * eEvent ) { - BOOL xEventHappened = FALSE; - - if( xEventInQueue ) + rt_uint32_t recvedEvent; + /* waiting forever OS event */ + rt_event_recv(&xSlaveOsEvent, + EV_READY | EV_FRAME_RECEIVED | EV_EXECUTE | EV_FRAME_SENT, + RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, + &recvedEvent); + switch (recvedEvent) { - *eEvent = eQueuedEvent; - xEventInQueue = FALSE; - xEventHappened = TRUE; + case EV_READY: + *eEvent = EV_READY; + break; + case EV_FRAME_RECEIVED: + *eEvent = EV_FRAME_RECEIVED; + break; + case EV_EXECUTE: + *eEvent = EV_EXECUTE; + break; + case EV_FRAME_SENT: + *eEvent = EV_FRAME_SENT; + break; } - return xEventHappened; + return TRUE; } diff --git a/components/net/freemodbus-v1.6.0/port/portevent_m.c b/components/net/freemodbus-v1.6.0/port/portevent_m.c index c78b6cbcb..031a3b84e 100644 --- a/components/net/freemodbus-v1.6.0/port/portevent_m.c +++ b/components/net/freemodbus-v1.6.0/port/portevent_m.c @@ -1,5 +1,5 @@ /* - * FreeModbus Libary: STM32 Port + * FreeModbus Libary: RT-Thread Port * Copyright (C) 2013 Armink * * This library is free software; you can redistribute it and/or @@ -21,41 +21,219 @@ /* ----------------------- Modbus includes ----------------------------------*/ #include "mb.h" +#include "mb_m.h" #include "mbport.h" +#include "port.h" -#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED +#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0 +/* ----------------------- Defines ------------------------------------------*/ /* ----------------------- Variables ----------------------------------------*/ -static eMBMasterEventType eMasterQueuedEvent; -static BOOL xMasterEventInQueue; - +static struct rt_semaphore xMasterRunRes; +static struct rt_event xMasterOsEvent; /* ----------------------- Start implementation -----------------------------*/ BOOL xMBMasterPortEventInit( void ) { - xMasterEventInQueue = FALSE; + rt_event_init(&xMasterOsEvent,"master event",RT_IPC_FLAG_PRIO); return TRUE; } BOOL xMBMasterPortEventPost( eMBMasterEventType eEvent ) { - xMasterEventInQueue = TRUE; - eMasterQueuedEvent = eEvent; + rt_event_send(&xMasterOsEvent, eEvent); return TRUE; } BOOL xMBMasterPortEventGet( eMBMasterEventType * eEvent ) { - BOOL xEventHappened = FALSE; - - if( xMasterEventInQueue ) + rt_uint32_t recvedEvent; + /* waiting forever OS event */ + rt_event_recv(&xMasterOsEvent, + EV_MASTER_READY | EV_MASTER_FRAME_RECEIVED | EV_MASTER_EXECUTE | + EV_MASTER_FRAME_SENT | EV_MASTER_ERROR_PROCESS, + RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, + &recvedEvent); + /* the enum type couldn't convert to int type */ + switch (recvedEvent) { - *eEvent = eMasterQueuedEvent; - xMasterEventInQueue = FALSE; - xEventHappened = TRUE; + case EV_MASTER_READY: + *eEvent = EV_MASTER_READY; + break; + case EV_MASTER_FRAME_RECEIVED: + *eEvent = EV_MASTER_FRAME_RECEIVED; + break; + case EV_MASTER_EXECUTE: + *eEvent = EV_MASTER_EXECUTE; + break; + case EV_MASTER_FRAME_SENT: + *eEvent = EV_MASTER_FRAME_SENT; + break; + case EV_MASTER_ERROR_PROCESS: + *eEvent = EV_MASTER_ERROR_PROCESS; + break; } - return xEventHappened; + return TRUE; +} +/** + * This function is initialize the OS resource for modbus master. + * Note:The resource is define by OS.If you not use OS this function can be empty. + * + */ +void vMBMasterOsResInit( void ) +{ + rt_sem_init(&xMasterRunRes, "master res", 0x01 , RT_IPC_FLAG_PRIO); +} + +/** + * This function is take Mobus Master running resource. + * Note:The resource is define by Operating System.If you not use OS this function can be just return TRUE. + * + * @param lTimeOut the waiting time. + * + * @return resource taked result + */ +BOOL xMBMasterRunResTake( LONG lTimeOut ) +{ + /*If waiting time is -1 .It will wait forever */ + return rt_sem_take(&xMasterRunRes, lTimeOut) ? FALSE : TRUE ; +} + +/** + * This function is release Mobus Master running resource. + * Note:The resource is define by Operating System.If you not use OS this function can be empty. + * + */ +void vMBMasterRunResRelease( void ) +{ + /* release resource */ + rt_sem_release(&xMasterRunRes); +} + +/** + * This is modbus master respond timeout error process callback function. + * @note There functions will block modbus master poll while execute OS waiting. + * So,for real-time of system.Do not execute too much waiting process. + * + * @param ucDestAddress destination salve address + * @param pucPDUData PDU buffer data + * @param ucPDULength PDU buffer length + * + */ +void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData, + USHORT ucPDULength) { + /** + * @note This code is use OS's event mechanism for modbus master protocol stack. + * If you don't use OS, you can change it. + */ + rt_event_send(&xMasterOsEvent, EV_MASTER_ERROR_RESPOND_TIMEOUT); + + /* You can add your code under here. */ + +} + +/** + * This is modbus master receive data error process callback function. + * @note There functions will block modbus master poll while execute OS waiting. + * So,for real-time of system.Do not execute too much waiting process. + * + * @param ucDestAddress destination salve address + * @param pucPDUData PDU buffer data + * @param ucPDULength PDU buffer length + * + */ +void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData, + USHORT ucPDULength) { + /** + * @note This code is use OS's event mechanism for modbus master protocol stack. + * If you don't use OS, you can change it. + */ + rt_event_send(&xMasterOsEvent, EV_MASTER_ERROR_RECEIVE_DATA); + + /* You can add your code under here. */ + +} + +/** + * This is modbus master execute function error process callback function. + * @note There functions will block modbus master poll while execute OS waiting. + * So,for real-time of system.Do not execute too much waiting process. + * + * @param ucDestAddress destination salve address + * @param pucPDUData PDU buffer data + * @param ucPDULength PDU buffer length + * + */ +void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUData, + USHORT ucPDULength) { + /** + * @note This code is use OS's event mechanism for modbus master protocol stack. + * If you don't use OS, you can change it. + */ + rt_event_send(&xMasterOsEvent, EV_MASTER_ERROR_EXECUTE_FUNCTION); + + /* You can add your code under here. */ + +} + +/** + * This is modbus master request process success callback function. + * @note There functions will block modbus master poll while execute OS waiting. + * So,for real-time of system.Do not execute too much waiting process. + * + */ +void vMBMasterCBRequestScuuess( void ) { + /** + * @note This code is use OS's event mechanism for modbus master protocol stack. + * If you don't use OS, you can change it. + */ + rt_event_send(&xMasterOsEvent, EV_MASTER_PROCESS_SUCESS); + + /* You can add your code under here. */ + +} + +/** + * This function is wait for modbus master request finish and return result. + * Waiting result include request process success, request respond timeout, + * receive data error and execute function error.You can use the above callback function. + * @note If you are use OS, you can use OS's event mechanism. Otherwise you have to run + * much user custom delay for waiting. + * + * @return request error code + */ +eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) { + eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR; + rt_uint32_t recvedEvent; + /* waiting for OS event */ + rt_event_recv(&xMasterOsEvent, + EV_MASTER_PROCESS_SUCESS | EV_MASTER_ERROR_RESPOND_TIMEOUT + | EV_MASTER_ERROR_RECEIVE_DATA + | EV_MASTER_ERROR_EXECUTE_FUNCTION, + RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, + &recvedEvent); + switch (recvedEvent) + { + case EV_MASTER_PROCESS_SUCESS: + break; + case EV_MASTER_ERROR_RESPOND_TIMEOUT: + { + eErrStatus = MB_MRE_TIMEDOUT; + break; + } + case EV_MASTER_ERROR_RECEIVE_DATA: + { + eErrStatus = MB_MRE_REV_DATA; + break; + } + case EV_MASTER_ERROR_EXECUTE_FUNCTION: + { + eErrStatus = MB_MRE_EXE_FUN; + break; + } + } + return eErrStatus; } #endif diff --git a/components/net/freemodbus-v1.6.0/port/portserial.c b/components/net/freemodbus-v1.6.0/port/portserial.c index 376870208..0ba8dfbae 100644 --- a/components/net/freemodbus-v1.6.0/port/portserial.c +++ b/components/net/freemodbus-v1.6.0/port/portserial.c @@ -1,5 +1,5 @@ /* - * FreeModbus Libary: STM32 Port + * FreeModbus Libary: RT-Thread Port * Copyright (C) 2013 Armink * * This library is free software; you can redistribute it and/or @@ -24,122 +24,148 @@ /* ----------------------- Modbus includes ----------------------------------*/ #include "mb.h" #include "mbport.h" +#include "rtdevice.h" +#include "bsp.h" + +/* ----------------------- Static variables ---------------------------------*/ +ALIGN(RT_ALIGN_SIZE) +/* software simulation serial transmit IRQ handler thread stack */ +static rt_uint8_t serial_soft_trans_irq_stack[512]; +/* software simulation serial transmit IRQ handler thread */ +static struct rt_thread thread_serial_soft_trans_irq; +/* serial event */ +static struct rt_event event_serial; +/* modbus slave serial device */ +static rt_serial_t *serial; + +/* ----------------------- Defines ------------------------------------------*/ +/* serial transmit event */ +#define EVENT_SERIAL_TRANS_START (1<<0) + /* ----------------------- static functions ---------------------------------*/ static void prvvUARTTxReadyISR(void); static void prvvUARTRxISR(void); +static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size); +static void serial_soft_trans_irq(void* parameter); + /* ----------------------- Start implementation -----------------------------*/ +BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, + eMBParity eParity) +{ + /** + * set 485 mode receive and transmit control IO + * @note MODBUS_SLAVE_RT_CONTROL_PIN_INDEX need be defined by user + */ + rt_pin_mode(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_MODE_OUTPUT); + + /* set serial name */ + if (ucPORT == 1) { +#if defined(RT_USING_UART1) || defined(RT_USING_REMAP_UART1) + extern struct rt_serial_device serial1; + serial = &serial1; +#endif + } else if (ucPORT == 2) { +#if defined(RT_USING_UART2) + extern struct rt_serial_device serial2; + serial = &serial2; +#endif + } else if (ucPORT == 3) { +#if defined(RT_USING_UART3) + extern struct rt_serial_device serial3; + serial = &serial3; +#endif + } + /* set serial configure parameter */ + serial->config.baud_rate = ulBaudRate; + serial->config.stop_bits = STOP_BITS_1; + switch(eParity){ + case MB_PAR_NONE: { + serial->config.data_bits = DATA_BITS_8; + serial->config.parity = PARITY_NONE; + break; + } + case MB_PAR_ODD: { + serial->config.data_bits = DATA_BITS_9; + serial->config.parity = PARITY_ODD; + break; + } + case MB_PAR_EVEN: { + serial->config.data_bits = DATA_BITS_9; + serial->config.parity = PARITY_EVEN; + break; + } + } + /* set serial configure */ + serial->ops->configure(serial, &(serial->config)); + + /* open serial device */ + if (!serial->parent.open(&serial->parent, + RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX )) { + serial->parent.rx_indicate = serial_rx_ind; + } else { + return FALSE; + } + + /* software initialize */ + rt_thread_init(&thread_serial_soft_trans_irq, + "slave trans", + serial_soft_trans_irq, + RT_NULL, + serial_soft_trans_irq_stack, + sizeof(serial_soft_trans_irq_stack), + 10, 5); + rt_thread_startup(&thread_serial_soft_trans_irq); + rt_event_init(&event_serial, "slave event", RT_IPC_FLAG_PRIO); + + return TRUE; +} void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable) { - if (xRxEnable) - { - SLAVE_RS485_RECEIVE_MODE; - USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); - } - else - { - SLAVE_RS485_SEND_MODE; - USART_ITConfig(USART1, USART_IT_RXNE, DISABLE); - } - if (xTxEnable) - { - USART_ITConfig(USART1, USART_IT_TXE, ENABLE); - } - else - { - USART_ITConfig(USART1, USART_IT_TXE, DISABLE); - } + rt_uint32_t recved_event; + if (xRxEnable) + { + /* enable RX interrupt */ + serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX); + /* switch 485 to receive mode */ + rt_pin_write(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_LOW); + } + else + { + /* switch 485 to transmit mode */ + rt_pin_write(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_HIGH); + /* disable RX interrupt */ + serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX); + } + if (xTxEnable) + { + /* start serial transmit */ + rt_event_send(&event_serial, EVENT_SERIAL_TRANS_START); + } + else + { + /* stop serial transmit */ + rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START, + RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 0, + &recved_event); + } } void vMBPortClose(void) { - USART_ITConfig(USART1, USART_IT_TXE | USART_IT_RXNE, DISABLE); - USART_Cmd(USART1, DISABLE); -} -//默认一个从机 串口1 波特率可设置 奇偶检验可设置 -BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, - eMBParity eParity) -{ - GPIO_InitTypeDef GPIO_InitStructure; - USART_InitTypeDef USART_InitStructure; - NVIC_InitTypeDef NVIC_InitStructure; - //======================时钟初始化======================================= - RCC_APB2PeriphClockCmd( - RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_USART1, - ENABLE); - //======================IO初始化======================================= - //USART1_TX - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; - GPIO_Init(GPIOA, &GPIO_InitStructure); - //USART1_RX - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; - GPIO_Init(GPIOA, &GPIO_InitStructure); - //配置485发送和接收模式 -// TODO 暂时先写B13 等之后组网测试时再修改 - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; - GPIO_Init(GPIOB, &GPIO_InitStructure); - //======================串口初始化======================================= - USART_InitStructure.USART_BaudRate = ulBaudRate; - //设置校验模式 - switch (eParity) - { - case MB_PAR_NONE: //无校验 - USART_InitStructure.USART_Parity = USART_Parity_No; - USART_InitStructure.USART_WordLength = USART_WordLength_8b; - break; - case MB_PAR_ODD: //奇校验 - USART_InitStructure.USART_Parity = USART_Parity_Odd; - USART_InitStructure.USART_WordLength = USART_WordLength_9b; - break; - case MB_PAR_EVEN: //偶校验 - USART_InitStructure.USART_Parity = USART_Parity_Even; - USART_InitStructure.USART_WordLength = USART_WordLength_9b; - break; - default: - return FALSE; - } - - USART_InitStructure.USART_StopBits = USART_StopBits_1; - USART_InitStructure.USART_HardwareFlowControl = - USART_HardwareFlowControl_None; - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; - if (ucPORT != 1) - return FALSE; - - ENTER_CRITICAL_SECTION(); //关全局中断 - - USART_Init(USART1, &USART_InitStructure); - USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); - USART_Cmd(USART1, ENABLE); - - //=====================中断初始化====================================== - //设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级 - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); - NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); - - EXIT_CRITICAL_SECTION(); //开全局中断 - - return TRUE; + serial->parent.close(&(serial->parent)); } BOOL xMBPortSerialPutByte(CHAR ucByte) { - USART_SendData(USART1, ucByte); - return TRUE; + serial->parent.write(&(serial->parent), 0, &ucByte, 1); + return TRUE; } BOOL xMBPortSerialGetByte(CHAR * pucByte) { - *pucByte = USART_ReceiveData(USART1); - return TRUE; + serial->parent.read(&(serial->parent), 0, pucByte, 1); + return TRUE; } /* @@ -151,7 +177,7 @@ BOOL xMBPortSerialGetByte(CHAR * pucByte) */ void prvvUARTTxReadyISR(void) { - pxMBFrameCBTransmitterEmpty(); + pxMBFrameCBTransmitterEmpty(); } /* @@ -162,28 +188,35 @@ void prvvUARTTxReadyISR(void) */ void prvvUARTRxISR(void) { - pxMBFrameCBByteReceived(); + pxMBFrameCBByteReceived(); } -/******************************************************************************* - * Function Name : USART1_IRQHandler - * Description : This function handles USART1 global interrupt request. - * Input : None - * Output : None - * Return : None - *******************************************************************************/ -void USART1_IRQHandler(void) -{ - rt_interrupt_enter(); - //接收中断 - if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) - { - USART_ClearITPendingBit(USART1, USART_IT_RXNE); - prvvUARTRxISR(); - } - //发送中断 - if (USART_GetITStatus(USART1, USART_IT_TXE) == SET) - { - prvvUARTTxReadyISR(); - } - rt_interrupt_leave(); + +/** + * Software simulation serial transmit IRQ handler. + * + * @param parameter parameter + */ +static void serial_soft_trans_irq(void* parameter) { + rt_uint32_t recved_event; + while (1) + { + /* waiting for serial transmit start */ + rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START, RT_EVENT_FLAG_OR, + RT_WAITING_FOREVER, &recved_event); + /* execute modbus callback */ + prvvUARTTxReadyISR(); + } +} + +/** + * This function is serial receive callback function + * + * @param dev the device of serial + * @param size the data size that receive + * + * @return return RT_EOK + */ +static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size) { + prvvUARTRxISR(); + return RT_EOK; } diff --git a/components/net/freemodbus-v1.6.0/port/portserial_m.c b/components/net/freemodbus-v1.6.0/port/portserial_m.c index ca76a8196..4dc02d92b 100644 --- a/components/net/freemodbus-v1.6.0/port/portserial_m.c +++ b/components/net/freemodbus-v1.6.0/port/portserial_m.c @@ -1,5 +1,5 @@ /* - * FreeModbus Libary: STM32 Port + * FreeModbus Libary: RT-Thread Port * Copyright (C) 2013 Armink * * This library is free software; you can redistribute it and/or @@ -24,123 +24,149 @@ /* ----------------------- Modbus includes ----------------------------------*/ #include "mb.h" #include "mbport.h" +#include "rtdevice.h" +#include "bsp.h" + +#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0 +/* ----------------------- Static variables ---------------------------------*/ +ALIGN(RT_ALIGN_SIZE) +/* software simulation serial transmit IRQ handler thread stack */ +static rt_uint8_t serial_soft_trans_irq_stack[512]; +/* software simulation serial transmit IRQ handler thread */ +static struct rt_thread thread_serial_soft_trans_irq; +/* serial event */ +static struct rt_event event_serial; +/* modbus slave serial device */ +static rt_serial_t *serial; + +/* ----------------------- Defines ------------------------------------------*/ +/* serial transmit event */ +#define EVENT_SERIAL_TRANS_START (1<<0) -#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED /* ----------------------- static functions ---------------------------------*/ static void prvvUARTTxReadyISR(void); static void prvvUARTRxISR(void); +static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size); +static void serial_soft_trans_irq(void* parameter); + /* ----------------------- Start implementation -----------------------------*/ +BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, + eMBParity eParity) +{ + /** + * set 485 mode receive and transmit control IO + * @note MODBUS_MASTER_RT_CONTROL_PIN_INDEX need be defined by user + */ + rt_pin_mode(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_MODE_OUTPUT); + + /* set serial name */ + if (ucPORT == 1) { +#if defined(RT_USING_UART1) || defined(RT_USING_REMAP_UART1) + extern struct rt_serial_device serial1; + serial = &serial1; +#endif + } else if (ucPORT == 2) { +#if defined(RT_USING_UART2) + extern struct rt_serial_device serial2; + serial = &serial2; +#endif + } else if (ucPORT == 3) { +#if defined(RT_USING_UART3) + extern struct rt_serial_device serial3; + serial = &serial3; +#endif + } + /* set serial configure parameter */ + serial->config.baud_rate = ulBaudRate; + serial->config.stop_bits = STOP_BITS_1; + switch(eParity){ + case MB_PAR_NONE: { + serial->config.data_bits = DATA_BITS_8; + serial->config.parity = PARITY_NONE; + break; + } + case MB_PAR_ODD: { + serial->config.data_bits = DATA_BITS_9; + serial->config.parity = PARITY_ODD; + break; + } + case MB_PAR_EVEN: { + serial->config.data_bits = DATA_BITS_9; + serial->config.parity = PARITY_EVEN; + break; + } + } + /* set serial configure */ + serial->ops->configure(serial, &(serial->config)); + + /* open serial device */ + if (!serial->parent.open(&serial->parent, + RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX )) { + serial->parent.rx_indicate = serial_rx_ind; + } else { + return FALSE; + } + + /* software initialize */ + rt_thread_init(&thread_serial_soft_trans_irq, + "slave trans", + serial_soft_trans_irq, + RT_NULL, + serial_soft_trans_irq_stack, + sizeof(serial_soft_trans_irq_stack), + 10, 5); + rt_thread_startup(&thread_serial_soft_trans_irq); + rt_event_init(&event_serial, "slave event", RT_IPC_FLAG_PRIO); + + return TRUE; +} void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable) { - if (xRxEnable) - { - MASTER_RS485_RECEIVE_MODE; - USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); - } - else - { - MASTER_RS485_SEND_MODE; - USART_ITConfig(USART2, USART_IT_RXNE, DISABLE); - } - if (xTxEnable) - { - USART_ITConfig(USART2, USART_IT_TXE, ENABLE); - } - else - { - USART_ITConfig(USART2, USART_IT_TXE, DISABLE); - } + rt_uint32_t recved_event; + if (xRxEnable) + { + /* enable RX interrupt */ + serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX); + /* switch 485 to receive mode */ + rt_pin_write(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_LOW); + } + else + { + /* switch 485 to transmit mode */ + rt_pin_write(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_HIGH); + /* disable RX interrupt */ + serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX); + } + if (xTxEnable) + { + /* start serial transmit */ + rt_event_send(&event_serial, EVENT_SERIAL_TRANS_START); + } + else + { + /* stop serial transmit */ + rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START, + RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 0, + &recved_event); + } } void vMBMasterPortClose(void) { - USART_ITConfig(USART2, USART_IT_TXE | USART_IT_RXNE, DISABLE); - USART_Cmd(USART2, DISABLE); -} -//默认一个主机 串口2 波特率可设置 奇偶检验可设置 -BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, - eMBParity eParity) -{ - GPIO_InitTypeDef GPIO_InitStructure; - USART_InitTypeDef USART_InitStructure; - NVIC_InitTypeDef NVIC_InitStructure; - //======================时钟初始化======================================= - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); - RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); - //======================IO初始化======================================= - //USART2_TX - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; - GPIO_Init(GPIOA, &GPIO_InitStructure); - //USART2_RX - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; - GPIO_Init(GPIOA, &GPIO_InitStructure); - //配置485发送和接收模式 -// TODO 暂时先写B13 等之后组网测试时再修改 - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; - GPIO_Init(GPIOB, &GPIO_InitStructure); - //======================串口初始化======================================= - USART_InitStructure.USART_BaudRate = ulBaudRate; - //设置校验模式 - switch (eParity) - { - case MB_PAR_NONE: //无校验 - USART_InitStructure.USART_Parity = USART_Parity_No; - USART_InitStructure.USART_WordLength = USART_WordLength_8b; - break; - case MB_PAR_ODD: //奇校验 - USART_InitStructure.USART_Parity = USART_Parity_Odd; - USART_InitStructure.USART_WordLength = USART_WordLength_9b; - break; - case MB_PAR_EVEN: //偶校验 - USART_InitStructure.USART_Parity = USART_Parity_Even; - USART_InitStructure.USART_WordLength = USART_WordLength_9b; - break; - default: - return FALSE; - } - - USART_InitStructure.USART_StopBits = USART_StopBits_1; - USART_InitStructure.USART_HardwareFlowControl = - USART_HardwareFlowControl_None; - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; - if (ucPORT != 2) - return FALSE; - - ENTER_CRITICAL_SECTION(); //关全局中断 - - USART_Init(USART2, &USART_InitStructure); - USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); - USART_Cmd(USART2, ENABLE); - - //=====================中断初始化====================================== - //设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级 - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); - NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); - - EXIT_CRITICAL_SECTION(); //开全局中断 - - return TRUE; + serial->parent.close(&(serial->parent)); } BOOL xMBMasterPortSerialPutByte(CHAR ucByte) { - USART_SendData(USART2, ucByte); + serial->parent.write(&(serial->parent), 0, &ucByte, 1); return TRUE; } BOOL xMBMasterPortSerialGetByte(CHAR * pucByte) { - *pucByte = USART_ReceiveData(USART2); - return TRUE; + serial->parent.read(&(serial->parent), 0, pucByte, 1); + return TRUE; } /* @@ -152,7 +178,7 @@ BOOL xMBMasterPortSerialGetByte(CHAR * pucByte) */ void prvvUARTTxReadyISR(void) { - pxMBMasterFrameCBTransmitterEmpty(); + pxMBMasterFrameCBTransmitterEmpty(); } /* @@ -163,30 +189,37 @@ void prvvUARTTxReadyISR(void) */ void prvvUARTRxISR(void) { - pxMBMasterFrameCBByteReceived(); + pxMBMasterFrameCBByteReceived(); } -/******************************************************************************* - * Function Name : USART2_IRQHandler - * Description : This function handles USART2 global interrupt request. - * Input : None - * Output : None - * Return : None - *******************************************************************************/ -void USART2_IRQHandler(void) -{ - rt_interrupt_enter(); - //接收中断 - if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET) - { - USART_ClearITPendingBit(USART2, USART_IT_RXNE); - prvvUARTRxISR(); - } - //发送中断 - if (USART_GetITStatus(USART2, USART_IT_TXE) == SET) - { - prvvUARTTxReadyISR(); - } - rt_interrupt_leave(); + +/** + * Software simulation serial transmit IRQ handler. + * + * @param parameter parameter + */ +static void serial_soft_trans_irq(void* parameter) { + rt_uint32_t recved_event; + while (1) + { + /* waiting for serial transmit start */ + rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START, RT_EVENT_FLAG_OR, + RT_WAITING_FOREVER, &recved_event); + /* execute modbus callback */ + prvvUARTTxReadyISR(); + } +} + +/** + * This function is serial receive callback function + * + * @param dev the device of serial + * @param size the data size that receive + * + * @return return RT_EOK + */ +static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size) { + prvvUARTRxISR(); + return RT_EOK; } #endif diff --git a/components/net/freemodbus-v1.6.0/port/porttimer.c b/components/net/freemodbus-v1.6.0/port/porttimer.c index b7b74ce07..6f017d875 100644 --- a/components/net/freemodbus-v1.6.0/port/porttimer.c +++ b/components/net/freemodbus-v1.6.0/port/porttimer.c @@ -1,5 +1,5 @@ /* - * FreeModbus Libary: STM32 Port + * FreeModbus Libary: RT-Thread Port * Copyright (C) 2013 Armink * * This library is free software; you can redistribute it and/or @@ -27,81 +27,37 @@ #include "mbport.h" /* ----------------------- static functions ---------------------------------*/ +static struct rt_timer timer; static void prvvTIMERExpiredISR(void); +static void timer_timeout_ind(void* parameter); /* ----------------------- Start implementation -----------------------------*/ BOOL xMBPortTimersInit(USHORT usTim1Timerout50us) { - - uint16_t PrescalerValue = 0; - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; - NVIC_InitTypeDef NVIC_InitStructure; - //====================================时钟初始化=========================== - //使能定时器3时钟 - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); - //====================================定时器初始化=========================== - //定时器时间基配置说明 - //HCLK为72MHz,APB1经过2分频为36MHz - //TIM3的时钟倍频后为72MHz(硬件自动倍频,达到最大) - //TIM3的分频系数为3599,时间基频率为72 / (1 + Prescaler) = 20KHz,基准为50us - //TIM最大计数值为usTim1Timerout50u - - PrescalerValue = (uint16_t) (SystemCoreClock / 20000) - 1; - //定时器1初始化 - TIM_TimeBaseStructure.TIM_Period = (uint16_t) usTim1Timerout50us; - TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue; - TIM_TimeBaseStructure.TIM_ClockDivision = 0; - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; - TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); - //预装载使能 - TIM_ARRPreloadConfig(TIM3, ENABLE); - //====================================中断初始化=========================== - //设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级 - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); - NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); - //清除溢出中断标志位 - TIM_ClearITPendingBit(TIM3, TIM_IT_Update); - //定时器3溢出中断关闭 - TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE); - //定时器3禁能 - TIM_Cmd(TIM3, DISABLE); - return TRUE; + rt_timer_init(&timer, "slave timer", + timer_timeout_ind, /* bind timeout callback function */ + RT_NULL, + (50*usTim1Timerout50us)/(1000*1000/RT_TICK_PER_SECOND), + RT_TIMER_FLAG_ONE_SHOT); /* one shot */ + return TRUE; } void vMBPortTimersEnable() { - TIM_ClearITPendingBit(TIM3, TIM_IT_Update); - TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); - TIM_SetCounter(TIM3, 0); - TIM_Cmd(TIM3, ENABLE); + rt_timer_start(&timer); } void vMBPortTimersDisable() { - TIM_ClearITPendingBit(TIM3, TIM_IT_Update); - TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE); - TIM_SetCounter(TIM3, 0); - TIM_Cmd(TIM3, DISABLE); + rt_timer_stop(&timer); } void prvvTIMERExpiredISR(void) { - (void) pxMBPortCBTimerExpired(); + (void) pxMBPortCBTimerExpired(); } -void TIM3_IRQHandler(void) +static void timer_timeout_ind(void* parameter) { - rt_interrupt_enter(); - if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) - { - - TIM_ClearFlag(TIM3, TIM_FLAG_Update); //清中断标记 - TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除定时器T3溢出中断标志位 - prvvTIMERExpiredISR(); - } - rt_interrupt_leave(); + prvvTIMERExpiredISR(); } diff --git a/components/net/freemodbus-v1.6.0/port/porttimer_m.c b/components/net/freemodbus-v1.6.0/port/porttimer_m.c index 1881b4705..69bdc5487 100644 --- a/components/net/freemodbus-v1.6.0/port/porttimer_m.c +++ b/components/net/freemodbus-v1.6.0/port/porttimer_m.c @@ -1,5 +1,5 @@ /* - * FreeModbus Libary: STM32 Port + * FreeModbus Libary: RT-Thread Port * Copyright (C) 2013 Armink * * This library is free software; you can redistribute it and/or @@ -27,10 +27,12 @@ #include "mb_m.h" #include "mbport.h" -#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED +#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0 /* ----------------------- Variables ----------------------------------------*/ static USHORT usT35TimeOut50us; -static USHORT usPrescalerValue = 0; +static struct rt_timer timer; +static void prvvTIMERExpiredISR(void); +static void timer_timeout_ind(void* parameter); /* ----------------------- static functions ---------------------------------*/ static void prvvTIMERExpiredISR(void); @@ -38,120 +40,68 @@ static void prvvTIMERExpiredISR(void); /* ----------------------- Start implementation -----------------------------*/ BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us) { - NVIC_InitTypeDef NVIC_InitStructure; - //====================================时钟初始化=========================== - //使能定时器2时钟 - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); - //====================================定时器初始化=========================== - //定时器时间基配置说明 - //HCLK为72MHz,APB1经过2分频为36MHz - //TIM2的时钟倍频后为72MHz(硬件自动倍频,达到最大) - //TIM2的分频系数为3599,时间基频率为72 / (1 + Prescaler) = 20KHz,基准为50us - //TIM最大计数值为usTim1Timerout50u - usPrescalerValue = (uint16_t) (SystemCoreClock / 20000) - 1; - //保存T35定时器计数值 - usT35TimeOut50us = usTimeOut50us; + /* backup T35 ticks */ + usT35TimeOut50us = usTimeOut50us; - //预装载使能 - TIM_ARRPreloadConfig(TIM2, ENABLE); - //====================================中断初始化=========================== - //设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级 - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); - NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); - //清除溢出中断标志位 - TIM_ClearITPendingBit(TIM2, TIM_IT_Update); - //定时器3溢出中断关闭 - TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE); - //定时器3禁能 - TIM_Cmd(TIM2, DISABLE); - return TRUE; + rt_timer_init(&timer, "master timer", + timer_timeout_ind, /* bind timeout callback function */ + RT_NULL, + (50 * usT35TimeOut50us) / (1000 * 1000 / RT_TICK_PER_SECOND), + RT_TIMER_FLAG_ONE_SHOT); /* one shot */ + + return TRUE; } void vMBMasterPortTimersT35Enable() { - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; + rt_tick_t timer_tick = (50 * usT35TimeOut50us) + / (1000 * 1000 / RT_TICK_PER_SECOND); - /* Set current timer mode,don't change it.*/ - vMBMasterSetCurTimerMode(MB_TMODE_T35); + /* Set current timer mode, don't change it.*/ + vMBMasterSetCurTimerMode(MB_TMODE_T35); - TIM_TimeBaseStructure.TIM_Prescaler = usPrescalerValue; - TIM_TimeBaseStructure.TIM_ClockDivision = 0; - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; - TIM_TimeBaseStructure.TIM_Period = (uint16_t) usT35TimeOut50us; - TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); + rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick); - TIM_ClearITPendingBit(TIM2, TIM_IT_Update); - TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); - TIM_SetCounter(TIM2, 0); - TIM_Cmd(TIM2, ENABLE); + rt_timer_start(&timer); } void vMBMasterPortTimersConvertDelayEnable() { - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; + rt_tick_t timer_tick = MB_MASTER_DELAY_MS_CONVERT * RT_TICK_PER_SECOND / 1000; - /* Set current timer mode,don't change it.*/ - vMBMasterSetCurTimerMode(MB_TMODE_CONVERT_DELAY); + /* Set current timer mode, don't change it.*/ + vMBMasterSetCurTimerMode(MB_TMODE_CONVERT_DELAY); - TIM_TimeBaseStructure.TIM_Prescaler = usPrescalerValue; - TIM_TimeBaseStructure.TIM_ClockDivision = 0; - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; - TIM_TimeBaseStructure.TIM_Period = (uint16_t)(MB_MASTER_DELAY_MS_CONVERT * 1000 / 50); - TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); + rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick); - TIM_ClearITPendingBit(TIM2, TIM_IT_Update); - TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); - TIM_SetCounter(TIM2, 0); - TIM_Cmd(TIM2, ENABLE); + rt_timer_start(&timer); } void vMBMasterPortTimersRespondTimeoutEnable() { - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; + rt_tick_t timer_tick = MB_MASTER_TIMEOUT_MS_RESPOND * RT_TICK_PER_SECOND / 1000; - /* Set current timer mode,don't change it.*/ - vMBMasterSetCurTimerMode(MB_TMODE_RESPOND_TIMEOUT); + /* Set current timer mode, don't change it.*/ + vMBMasterSetCurTimerMode(MB_TMODE_RESPOND_TIMEOUT); - TIM_TimeBaseStructure.TIM_Prescaler = usPrescalerValue; - TIM_TimeBaseStructure.TIM_ClockDivision = 0; - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; - TIM_TimeBaseStructure.TIM_Period = (uint16_t)(MB_MASTER_TIMEOUT_MS_RESPOND * 1000 / 50); - TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); + rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick); - TIM_ClearITPendingBit(TIM2, TIM_IT_Update); - TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); - TIM_SetCounter(TIM2, 0); - TIM_Cmd(TIM2, ENABLE); + rt_timer_start(&timer); } void vMBMasterPortTimersDisable() { - TIM_ClearITPendingBit(TIM2, TIM_IT_Update); - TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE); - TIM_SetCounter(TIM2, 0); - TIM_Cmd(TIM2, DISABLE); + rt_timer_stop(&timer); } void prvvTIMERExpiredISR(void) { - (void) pxMBMasterPortCBTimerExpired(); + (void) pxMBMasterPortCBTimerExpired(); } -void TIM2_IRQHandler(void) +static void timer_timeout_ind(void* parameter) { - rt_interrupt_enter(); - if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) - { - - TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清中断标记 - TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除定时器TIM2溢出中断标志位 - prvvTIMERExpiredISR(); - } - rt_interrupt_leave(); + prvvTIMERExpiredISR(); } #endif diff --git a/components/net/freemodbus-v1.6.0/port/user_mb_app.c b/components/net/freemodbus-v1.6.0/port/user_mb_app.c index a99615c23..e6fdede11 100644 --- a/components/net/freemodbus-v1.6.0/port/user_mb_app.c +++ b/components/net/freemodbus-v1.6.0/port/user_mb_app.c @@ -1,4 +1,25 @@ +/* + * FreeModbus Libary: user callback functions and buffer define in slave mode + * Copyright (C) 2013 Armink + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * File: $Id: user_mb_app.c,v 1.60 2013/11/23 11:49:05 Armink $ + */ #include "user_mb_app.h" + /*------------------------Slave mode use these variables----------------------*/ //Slave mode:DiscreteInputs variables USHORT usSDiscInStart = S_DISCRETE_INPUT_START; @@ -20,81 +41,41 @@ USHORT usSRegInBuf[S_REG_INPUT_NREGS] ; //Slave mode:HoldingRegister variables USHORT usSRegHoldStart = S_REG_HOLDING_START; USHORT usSRegHoldBuf[S_REG_HOLDING_NREGS] ; -/*-----------------------Master mode use these variables----------------------*/ -#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0 -//Master mode:DiscreteInputs variables -USHORT usMDiscInStart = M_DISCRETE_INPUT_START; -#if M_DISCRETE_INPUT_NDISCRETES%8 -UCHAR ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES/8+1]; -#else -UCHAR ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES/8]; -#endif -//Master mode:Coils variables -USHORT usMCoilStart = M_COIL_START; -#if M_COIL_NCOILS%8 -UCHAR ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS/8+1]; -#else -UCHAR ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS/8]; -#endif -//Master mode:InputRegister variables -USHORT usMRegInStart = M_REG_INPUT_START; -USHORT usMRegInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_INPUT_NREGS]; -//Master mode:HoldingRegister variables -USHORT usMRegHoldStart = M_REG_HOLDING_START; -USHORT usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS]; -#endif -//******************************输入寄存器回调函数********************************** -//函数定义: eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs ) -//描 述:输入寄存器相关的功能(读、连续读) -//入口参数:pucRegBuffer : 回调函数将Modbus寄存器的当前值写入的缓冲区 -// usAddress : 寄存器的起始地址,输入寄存器的地址范围是1-65535。 -// usNRegs : 寄存器数量 -//出口参数:eMBErrorCode : 这个函数将返回的错误码 -//备 注:Editor:Armink 2010-10-31 Company: BXXJS -//********************************************************************************** -eMBErrorCode -eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs ) + +/** + * Modbus slave input register callback function. + * + * @param pucRegBuffer input register buffer + * @param usAddress input register address + * @param usNRegs input register number + * + * @return result + */ +eMBErrorCode eMBRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs ) { eMBErrorCode eStatus = MB_ENOERR; - int iRegIndex; + USHORT iRegIndex; USHORT * pusRegInputBuf; - UCHAR REG_INPUT_START; - UCHAR REG_INPUT_NREGS; - UCHAR usRegInStart; + USHORT REG_INPUT_START; + USHORT REG_INPUT_NREGS; + USHORT usRegInStart; - //Determine the master or slave - if (xMBMasterGetCBRunInMasterMode()) - { - pusRegInputBuf = usMRegInBuf[ucMBMasterGetDestAddress()]; - REG_INPUT_START = M_REG_INPUT_START; - REG_INPUT_NREGS = M_REG_INPUT_NREGS; - usRegInStart = usMRegInStart; - } - else - { - pusRegInputBuf = usSRegInBuf; - REG_INPUT_START = S_REG_INPUT_START; - REG_INPUT_NREGS = S_REG_INPUT_NREGS; - usRegInStart = usSRegInStart; - } + pusRegInputBuf = usSRegInBuf; + REG_INPUT_START = S_REG_INPUT_START; + REG_INPUT_NREGS = S_REG_INPUT_NREGS; + usRegInStart = usSRegInStart; - if( ( usAddress >= REG_INPUT_START ) - && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) ) + /* it already plus one in modbus function method. */ + usAddress--; + + if ((usAddress >= REG_INPUT_START) + && (usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS)) { - iRegIndex = ( int )( usAddress - usRegInStart ); - while( usNRegs > 0 ) + iRegIndex = usAddress - usRegInStart; + while (usNRegs > 0) { - //Determine the master or slave - if (xMBMasterGetCBRunInMasterMode()) - { - pusRegInputBuf[iRegIndex] = *pucRegBuffer++ << 8; - pusRegInputBuf[iRegIndex] |= *pucRegBuffer++; - } - else - { - *pucRegBuffer++ = ( unsigned char )( pusRegInputBuf[iRegIndex] >> 8 ); - *pucRegBuffer++ = ( unsigned char )( pusRegInputBuf[iRegIndex] & 0xFF ); - } + *pucRegBuffer++ = (UCHAR) (pusRegInputBuf[iRegIndex] >> 8); + *pucRegBuffer++ = (UCHAR) (pusRegInputBuf[iRegIndex] & 0xFF); iRegIndex++; usNRegs--; } @@ -106,67 +87,55 @@ eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs ) return eStatus; } -//******************************保持寄存器回调函数********************************** -//函数定义: eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode ) -//描 述:保持寄存器相关的功能(读、连续读、写、连续写) -//入口参数:pucRegBuffer : 如果需要更新用户寄存器数值,这个缓冲区必须指向新的寄存器数值。 -// 如果协议栈想知道当前的数值,回调函数必须将当前值写入这个缓冲区 -// usAddress : 寄存器的起始地址。 -// usNRegs : 寄存器数量 -// eMode : 如果该参数为eMBRegisterMode::MB_REG_WRITE,用户的应用数值将从pucRegBuffer中得到更新。 -// 如果该参数为eMBRegisterMode::MB_REG_READ,用户需要将当前的应用数据存储在pucRegBuffer中 -//出口参数:eMBErrorCode : 这个函数将返回的错误码 -//备 注:Editor:Armink 2010-10-31 Company: BXXJS -//********************************************************************************** -eMBErrorCode -eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode ) + +/** + * Modbus slave holding register callback function. + * + * @param pucRegBuffer holding register buffer + * @param usAddress holding register address + * @param usNRegs holding register number + * @param eMode read or write + * + * @return result + */ +eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress, + USHORT usNRegs, eMBRegisterMode eMode) { eMBErrorCode eStatus = MB_ENOERR; - int iRegIndex; + USHORT iRegIndex; USHORT * pusRegHoldingBuf; - UCHAR REG_HOLDING_START; - UCHAR REG_HOLDING_NREGS; - UCHAR usRegHoldStart; + USHORT REG_HOLDING_START; + USHORT REG_HOLDING_NREGS; + USHORT usRegHoldStart; - //Determine the master or slave - if (xMBMasterGetCBRunInMasterMode()) - { - pusRegHoldingBuf = usMRegHoldBuf[ucMBMasterGetDestAddress()]; - REG_HOLDING_START = M_REG_HOLDING_START; - REG_HOLDING_NREGS = M_REG_HOLDING_NREGS; - usRegHoldStart = usMRegHoldStart; - //If mode is read,the master will wirte the received date to bufffer. - eMode = MB_REG_WRITE; - } - else - { - pusRegHoldingBuf = usSRegHoldBuf; - REG_HOLDING_START = S_REG_HOLDING_START; - REG_HOLDING_NREGS = S_REG_HOLDING_NREGS; - usRegHoldStart = usSRegHoldStart; - } + pusRegHoldingBuf = usSRegHoldBuf; + REG_HOLDING_START = S_REG_HOLDING_START; + REG_HOLDING_NREGS = S_REG_HOLDING_NREGS; + usRegHoldStart = usSRegHoldStart; - if( ( usAddress >= REG_HOLDING_START ) && - ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) ) + /* it already plus one in modbus function method. */ + usAddress--; + + if ((usAddress >= REG_HOLDING_START) + && (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS)) { - iRegIndex = ( int )( usAddress - usRegHoldStart ); - switch ( eMode ) + iRegIndex = usAddress - usRegHoldStart; + switch (eMode) { - /* Pass current register values to the protocol stack. */ + /* read current register values from the protocol stack. */ case MB_REG_READ: - while( usNRegs > 0 ) + while (usNRegs > 0) { - *pucRegBuffer++ = ( unsigned char )( pusRegHoldingBuf[iRegIndex] >> 8 ); - *pucRegBuffer++ = ( unsigned char )( pusRegHoldingBuf[iRegIndex] & 0xFF ); + *pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] >> 8); + *pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] & 0xFF); iRegIndex++; usNRegs--; } break; - /* Update current register values with new values from the - * protocol stack. */ + /* write current register values with new values from the protocol stack. */ case MB_REG_WRITE: - while( usNRegs > 0 ) + while (usNRegs > 0) { pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8; pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++; @@ -182,83 +151,76 @@ eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegi } return eStatus; } -//****************************线圈状态寄存器回调函数******************************** -//函数定义: eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode ) -//描 述:线圈状态寄存器相关的功能(读、连续读、写、连续写) -//入口参数:pucRegBuffer : 位组成一个字节,起始寄存器对应的位处于该字节pucRegBuffer的最低位LSB。 -// 如果回调函数要写这个缓冲区,没有用到的线圈(例如不是8个一组的线圈状态)对应的位的数值必须设置位0。 -// usAddress : 第一个线圈地址。 -// usNCoils : 请求的线圈个数 -// eMode ;如果该参数为eMBRegisterMode::MB_REG_WRITE,用户的应用数值将从pucRegBuffer中得到更新。 -// 如果该参数为eMBRegisterMode::MB_REG_READ,用户需要将当前的应用数据存储在pucRegBuffer中 -//出口参数:eMBErrorCode : 这个函数将返回的错误码 -//备 注:Editor:Armink 2010-10-31 Company: BXXJS -//********************************************************************************** -eMBErrorCode -eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode ) + +/** + * Modbus slave coils callback function. + * + * @param pucRegBuffer coils buffer + * @param usAddress coils address + * @param usNCoils coils number + * @param eMode read or write + * + * @return result + */ +eMBErrorCode eMBRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress, + USHORT usNCoils, eMBRegisterMode eMode) { eMBErrorCode eStatus = MB_ENOERR; - int iRegIndex , iRegBitIndex , iNReg; - UCHAR * pucCoilBuf; - UCHAR COIL_START; - UCHAR COIL_NCOILS; - UCHAR usCoilStart; - iNReg = usNCoils / 8 + 1; //占用寄存器数量 + USHORT iRegIndex , iRegBitIndex , iNReg; + UCHAR * pucCoilBuf; + USHORT COIL_START; + USHORT COIL_NCOILS; + USHORT usCoilStart; + iNReg = usNCoils / 8 + 1; + pucCoilBuf = ucSCoilBuf; + COIL_START = S_COIL_START; + COIL_NCOILS = S_COIL_NCOILS; + usCoilStart = usSCoilStart; - //Determine the master or slave - if (xMBMasterGetCBRunInMasterMode()) - { - pucCoilBuf = ucMCoilBuf[ucMBMasterGetDestAddress()]; - COIL_START = M_COIL_START; - COIL_NCOILS = M_COIL_NCOILS; - usCoilStart = usMCoilStart; - //If mode is read,the master will wirte the received date to bufffer. - eMode = MB_REG_WRITE; - } - else - { - pucCoilBuf = ucSCoilBuf; - COIL_START = S_COIL_START; - COIL_NCOILS = S_COIL_NCOILS; - usCoilStart = usSCoilStart; - } + /* it already plus one in modbus function method. */ + usAddress--; if( ( usAddress >= COIL_START ) && ( usAddress + usNCoils <= COIL_START + COIL_NCOILS ) ) { - iRegIndex = ( int )( usAddress - usCoilStart ) / 8 ; //每个寄存器存8个 - iRegBitIndex = ( int )( usAddress - usCoilStart ) % 8 ; //相对于寄存器内部的位地址 + iRegIndex = (USHORT) (usAddress - usCoilStart) / 8; + iRegBitIndex = (USHORT) (usAddress - usCoilStart) % 8; switch ( eMode ) { - /* Pass current coil values to the protocol stack. */ + /* read current coil values from the protocol stack. */ case MB_REG_READ: - while( iNReg > 0 ) + while (iNReg > 0) { - *pucRegBuffer++ = xMBUtilGetBits(&pucCoilBuf[iRegIndex++] , iRegBitIndex , 8); - iNReg --; - } - pucRegBuffer --; - usNCoils = usNCoils % 8; //余下的线圈数 - *pucRegBuffer = *pucRegBuffer <<(8 - usNCoils); //高位补零 - *pucRegBuffer = *pucRegBuffer >>(8 - usNCoils); - break; - - /* Update current coil values with new values from the - * protocol stack. */ - case MB_REG_WRITE: - while(iNReg > 1) //最后面余下来的数单独算 - { - xMBUtilSetBits(&pucCoilBuf[iRegIndex++] , iRegBitIndex , 8 , *pucRegBuffer++); + *pucRegBuffer++ = xMBUtilGetBits(&pucCoilBuf[iRegIndex++], + iRegBitIndex, 8); iNReg--; } - usNCoils = usNCoils % 8; //余下的线圈数 - if (usNCoils != 0) //xMBUtilSetBits方法 在操作位数量为0时存在bug - { - xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, usNCoils, - *pucRegBuffer++); - } - break; + pucRegBuffer--; + /* last coils */ + usNCoils = usNCoils % 8; + /* filling zero to high bit */ + *pucRegBuffer = *pucRegBuffer << (8 - usNCoils); + *pucRegBuffer = *pucRegBuffer >> (8 - usNCoils); + break; + + /* write current coil values with new values from the protocol stack. */ + case MB_REG_WRITE: + while (iNReg > 1) + { + xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, 8, + *pucRegBuffer++); + iNReg--; + } + /* last coils */ + usNCoils = usNCoils % 8; + /* xMBUtilSetBits has bug when ucNBits is zero */ + if (usNCoils != 0) + { + xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, usNCoils, + *pucRegBuffer++); + } + break; } } else @@ -267,78 +229,52 @@ eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegis } return eStatus; } -//****************************离散输入寄存器回调函数******************************** -//函数定义: eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete ) -//描 述:离散输入寄存器相关的功能(读、连续读) -//入口参数:pucRegBuffer : 用当前的线圈数据更新这个寄存器,起始寄存器对应的位处于该字节pucRegBuffer的最低位LSB。 -// 如果回调函数要写这个缓冲区,没有用到的线圈(例如不是8个一组的线圈状态)对应的位的数值必须设置为0。 -// usAddress : 离散输入的起始地址 -// usNDiscrete : 离散输入点数量 -//出口参数:eMBErrorCode : 这个函数将返回的错误码 -//备 注:Editor:Armink 2010-10-31 Company: BXXJS -//********************************************************************************** -eMBErrorCode -eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete ) + +/** + * Modbus slave discrete callback function. + * + * @param pucRegBuffer discrete buffer + * @param usAddress discrete address + * @param usNDiscrete discrete number + * + * @return result + */ +eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete ) { eMBErrorCode eStatus = MB_ENOERR; - int iRegIndex , iRegBitIndex , iNReg; - UCHAR * pucDiscreteInputBuf; - UCHAR DISCRETE_INPUT_START; - UCHAR DISCRETE_INPUT_NDISCRETES; - UCHAR usDiscreteInputStart; - iNReg = usNDiscrete / 8 + 1; //占用寄存器数量 + USHORT iRegIndex , iRegBitIndex , iNReg; + UCHAR * pucDiscreteInputBuf; + USHORT DISCRETE_INPUT_START; + USHORT DISCRETE_INPUT_NDISCRETES; + USHORT usDiscreteInputStart; + iNReg = usNDiscrete / 8 + 1; - //Determine the master or slave - if (xMBMasterGetCBRunInMasterMode()) - { - pucDiscreteInputBuf = ucMDiscInBuf[ucMBMasterGetDestAddress()]; - DISCRETE_INPUT_START = M_DISCRETE_INPUT_START; - DISCRETE_INPUT_NDISCRETES = M_DISCRETE_INPUT_NDISCRETES; - usDiscreteInputStart = usMDiscInStart; - } - else - { - pucDiscreteInputBuf = ucSDiscInBuf; - DISCRETE_INPUT_START = S_DISCRETE_INPUT_START; - DISCRETE_INPUT_NDISCRETES = S_DISCRETE_INPUT_NDISCRETES; - usDiscreteInputStart = usSDiscInStart; - } + pucDiscreteInputBuf = ucSDiscInBuf; + DISCRETE_INPUT_START = S_DISCRETE_INPUT_START; + DISCRETE_INPUT_NDISCRETES = S_DISCRETE_INPUT_NDISCRETES; + usDiscreteInputStart = usSDiscInStart; - if( ( usAddress >= DISCRETE_INPUT_START ) - && ( usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES ) ) - { - iRegIndex = ( int )( usAddress - usDiscreteInputStart ) / 8 ; //每个寄存器存8个 - iRegBitIndex = ( int )( usAddress - usDiscreteInputStart ) % 8 ; //相对于寄存器内部的位地址 + /* it already plus one in modbus function method. */ + usAddress--; - //Determine the master or slave - if (xMBMasterGetCBRunInMasterMode()) - { - /* Update current coil values with new values from the - * protocol stack. */ - while(iNReg > 1) //最后面余下来的数单独算 - { - xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++] , iRegBitIndex , 8 , *pucRegBuffer++); - iNReg--; - } - usNDiscrete = usNDiscrete % 8; //余下的线圈数 - if (usNDiscrete != 0) //xMBUtilSetBits方法 在操作位数量为0时存在bug - { - xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex, - usNDiscrete, *pucRegBuffer++); - } - } - else - { - while( iNReg > 0 ) - { - *pucRegBuffer++ = xMBUtilGetBits(&pucDiscreteInputBuf[iRegIndex++] , iRegBitIndex , 8); - iNReg --; - } - pucRegBuffer --; - usNDiscrete = usNDiscrete % 8; //余下的线圈数 - *pucRegBuffer = *pucRegBuffer <<(8 - usNDiscrete); //高位补零 - *pucRegBuffer = *pucRegBuffer >>(8 - usNDiscrete); - } + if ((usAddress >= DISCRETE_INPUT_START) + && (usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES)) + { + iRegIndex = (USHORT) (usAddress - usDiscreteInputStart) / 8; //每个寄存器存8个 + iRegBitIndex = (USHORT) (usAddress - usDiscreteInputStart) % 8; //相对于寄存器内部的位地址 + + while (iNReg > 0) + { + *pucRegBuffer++ = xMBUtilGetBits(&pucDiscreteInputBuf[iRegIndex++], + iRegBitIndex, 8); + iNReg--; + } + pucRegBuffer--; + /* last discrete */ + usNDiscrete = usNDiscrete % 8; + /* filling zero to high bit */ + *pucRegBuffer = *pucRegBuffer << (8 - usNDiscrete); + *pucRegBuffer = *pucRegBuffer >> (8 - usNDiscrete); } else { @@ -347,3 +283,4 @@ eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete ) return eStatus; } + diff --git a/components/net/freemodbus-v1.6.0/port/user_mb_app.h b/components/net/freemodbus-v1.6.0/port/user_mb_app.h index 440ca8213..846b9a3a4 100644 --- a/components/net/freemodbus-v1.6.0/port/user_mb_app.h +++ b/components/net/freemodbus-v1.6.0/port/user_mb_app.h @@ -1,4 +1,4 @@ -#ifndef USER_APP +#ifndef USER_APP #define USER_APP /* ----------------------- Modbus includes ----------------------------------*/ #include "mb.h" @@ -8,47 +8,41 @@ #include "mbutils.h" /* -----------------------Slave Defines -------------------------------------*/ -#define S_DISCRETE_INPUT_START 1 +#define S_DISCRETE_INPUT_START 0 #define S_DISCRETE_INPUT_NDISCRETES 16 -#define S_COIL_START 1 +#define S_COIL_START 0 #define S_COIL_NCOILS 64 -#define S_REG_INPUT_START 1 +#define S_REG_INPUT_START 0 #define S_REG_INPUT_NREGS 100 -#define S_REG_HOLDING_START 1 +#define S_REG_HOLDING_START 0 #define S_REG_HOLDING_NREGS 100 -//从机模式:在保持寄存器中,各个地址对应的功能定义 -#define S_HD_RESERVE 0 //保留 -#define S_HD_CPU_USAGE_MAJOR 1 //当前CPU利用率的整数位 -#define S_HD_CPU_USAGE_MINOR 2 //当前CPU利用率的小数位 - -//从机模式:在输入寄存器中,各个地址对应的功能定义 -#define S_IN_RESERVE 0 //保留 - -//从机模式:在线圈中,各个地址对应的功能定义 -#define S_CO_RESERVE 2 //保留 - -//从机模式:在离散输入中,各个地址对应的功能定义 -#define S_DI_RESERVE 1 //保留 +/* salve mode: holding register's all address */ +#define S_HD_RESERVE 0 +#define S_HD_CPU_USAGE_MAJOR 1 +#define S_HD_CPU_USAGE_MINOR 2 +/* salve mode: input register's all address */ +#define S_IN_RESERVE 0 +/* salve mode: coil's all address */ +#define S_CO_RESERVE 0 +/* salve mode: discrete's all address */ +#define S_DI_RESERVE 0 /* -----------------------Master Defines -------------------------------------*/ -#define M_DISCRETE_INPUT_START 1 +#define M_DISCRETE_INPUT_START 0 #define M_DISCRETE_INPUT_NDISCRETES 16 -#define M_COIL_START 1 +#define M_COIL_START 0 #define M_COIL_NCOILS 64 -#define M_REG_INPUT_START 1 +#define M_REG_INPUT_START 0 #define M_REG_INPUT_NREGS 100 -#define M_REG_HOLDING_START 1 +#define M_REG_HOLDING_START 0 #define M_REG_HOLDING_NREGS 100 -//主机模式:在保持寄存器中,各个地址对应的功能定义 -#define M_HD_RESERVE 0 //保留 - -//主机模式:在输入寄存器中,各个地址对应的功能定义 -#define M_IN_RESERVE 0 //保留 - -//主机模式:在线圈中,各个地址对应的功能定义 -#define M_CO_RESERVE 2 //保留 - -//主机模式:在离散输入中,各个地址对应的功能定义 -#define M_DI_RESERVE 1 //保留 +/* master mode: holding register's all address */ +#define M_HD_RESERVE 0 +/* master mode: input register's all address */ +#define M_IN_RESERVE 0 +/* master mode: coil's all address */ +#define M_CO_RESERVE 0 +/* master mode: discrete's all address */ +#define M_DI_RESERVE 0 #endif diff --git a/components/net/freemodbus-v1.6.0/port/user_mb_app_m.c b/components/net/freemodbus-v1.6.0/port/user_mb_app_m.c new file mode 100644 index 000000000..12fabf21a --- /dev/null +++ b/components/net/freemodbus-v1.6.0/port/user_mb_app_m.c @@ -0,0 +1,294 @@ +/* + * FreeModbus Libary: user callback functions and buffer define in master mode + * Copyright (C) 2013 Armink + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * File: $Id: user_mb_app_m.c,v 1.60 2013/11/23 11:49:05 Armink $ + */ +#include "user_mb_app.h" + +/*-----------------------Master mode use these variables----------------------*/ +#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0 +//Master mode:DiscreteInputs variables +USHORT usMDiscInStart = M_DISCRETE_INPUT_START; +#if M_DISCRETE_INPUT_NDISCRETES%8 +UCHAR ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES/8+1]; +#else +UCHAR ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES/8]; +#endif +//Master mode:Coils variables +USHORT usMCoilStart = M_COIL_START; +#if M_COIL_NCOILS%8 +UCHAR ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS/8+1]; +#else +UCHAR ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS/8]; +#endif +//Master mode:InputRegister variables +USHORT usMRegInStart = M_REG_INPUT_START; +USHORT usMRegInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_INPUT_NREGS]; +//Master mode:HoldingRegister variables +USHORT usMRegHoldStart = M_REG_HOLDING_START; +USHORT usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS]; + +/** + * Modbus master input register callback function. + * + * @param pucRegBuffer input register buffer + * @param usAddress input register address + * @param usNRegs input register number + * + * @return result + */ +eMBErrorCode eMBMasterRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs ) +{ + eMBErrorCode eStatus = MB_ENOERR; + USHORT iRegIndex; + USHORT * pusRegInputBuf; + USHORT REG_INPUT_START; + USHORT REG_INPUT_NREGS; + USHORT usRegInStart; + + pusRegInputBuf = usMRegInBuf[ucMBMasterGetDestAddress() - 1]; + REG_INPUT_START = M_REG_INPUT_START; + REG_INPUT_NREGS = M_REG_INPUT_NREGS; + usRegInStart = usMRegInStart; + + /* it already plus one in modbus function method. */ + usAddress--; + + if ((usAddress >= REG_INPUT_START) + && (usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS)) + { + iRegIndex = usAddress - usRegInStart; + while (usNRegs > 0) + { + pusRegInputBuf[iRegIndex] = *pucRegBuffer++ << 8; + pusRegInputBuf[iRegIndex] |= *pucRegBuffer++; + iRegIndex++; + usNRegs--; + } + } + else + { + eStatus = MB_ENOREG; + } + + return eStatus; +} + +/** + * Modbus master holding register callback function. + * + * @param pucRegBuffer holding register buffer + * @param usAddress holding register address + * @param usNRegs holding register number + * @param eMode read or write + * + * @return result + */ +eMBErrorCode eMBMasterRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress, + USHORT usNRegs, eMBRegisterMode eMode) +{ + eMBErrorCode eStatus = MB_ENOERR; + USHORT iRegIndex; + USHORT * pusRegHoldingBuf; + USHORT REG_HOLDING_START; + USHORT REG_HOLDING_NREGS; + USHORT usRegHoldStart; + + pusRegHoldingBuf = usMRegHoldBuf[ucMBMasterGetDestAddress() - 1]; + REG_HOLDING_START = M_REG_HOLDING_START; + REG_HOLDING_NREGS = M_REG_HOLDING_NREGS; + usRegHoldStart = usMRegHoldStart; + /* if mode is read, the master will write the received date to buffer. */ + eMode = MB_REG_WRITE; + + /* it already plus one in modbus function method. */ + usAddress--; + + if ((usAddress >= REG_HOLDING_START) + && (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS)) + { + iRegIndex = usAddress - usRegHoldStart; + switch (eMode) + { + /* read current register values from the protocol stack. */ + case MB_REG_READ: + while (usNRegs > 0) + { + *pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] >> 8); + *pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] & 0xFF); + iRegIndex++; + usNRegs--; + } + break; + /* write current register values with new values from the protocol stack. */ + case MB_REG_WRITE: + while (usNRegs > 0) + { + pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8; + pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++; + iRegIndex++; + usNRegs--; + } + break; + } + } + else + { + eStatus = MB_ENOREG; + } + return eStatus; +} + +/** + * Modbus master coils callback function. + * + * @param pucRegBuffer coils buffer + * @param usAddress coils address + * @param usNCoils coils number + * @param eMode read or write + * + * @return result + */ +eMBErrorCode eMBMasterRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress, + USHORT usNCoils, eMBRegisterMode eMode) +{ + eMBErrorCode eStatus = MB_ENOERR; + USHORT iRegIndex , iRegBitIndex , iNReg; + UCHAR * pucCoilBuf; + USHORT COIL_START; + USHORT COIL_NCOILS; + USHORT usCoilStart; + iNReg = usNCoils / 8 + 1; + + pucCoilBuf = ucMCoilBuf[ucMBMasterGetDestAddress() - 1]; + COIL_START = M_COIL_START; + COIL_NCOILS = M_COIL_NCOILS; + usCoilStart = usMCoilStart; + + /* if mode is read,the master will write the received date to buffer. */ + eMode = MB_REG_WRITE; + + /* it already plus one in modbus function method. */ + usAddress--; + + if ((usAddress >= COIL_START) + && (usAddress + usNCoils <= COIL_START + COIL_NCOILS)) + { + iRegIndex = (USHORT) (usAddress - usCoilStart) / 8; + iRegBitIndex = (USHORT) (usAddress - usCoilStart) % 8; + switch (eMode) + { + /* read current coil values from the protocol stack. */ + case MB_REG_READ: + while (iNReg > 0) + { + *pucRegBuffer++ = xMBUtilGetBits(&pucCoilBuf[iRegIndex++], + iRegBitIndex, 8); + iNReg--; + } + pucRegBuffer--; + /* last coils */ + usNCoils = usNCoils % 8; + /* filling zero to high bit */ + *pucRegBuffer = *pucRegBuffer << (8 - usNCoils); + *pucRegBuffer = *pucRegBuffer >> (8 - usNCoils); + break; + + /* write current coil values with new values from the protocol stack. */ + case MB_REG_WRITE: + while (iNReg > 1) + { + xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, 8, + *pucRegBuffer++); + iNReg--; + } + /* last coils */ + usNCoils = usNCoils % 8; + /* xMBUtilSetBits has bug when ucNBits is zero */ + if (usNCoils != 0) + { + xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, usNCoils, + *pucRegBuffer++); + } + break; + } + } + else + { + eStatus = MB_ENOREG; + } + return eStatus; +} + +/** + * Modbus master discrete callback function. + * + * @param pucRegBuffer discrete buffer + * @param usAddress discrete address + * @param usNDiscrete discrete number + * + * @return result + */ +eMBErrorCode eMBMasterRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete ) +{ + eMBErrorCode eStatus = MB_ENOERR; + USHORT iRegIndex , iRegBitIndex , iNReg; + UCHAR * pucDiscreteInputBuf; + USHORT DISCRETE_INPUT_START; + USHORT DISCRETE_INPUT_NDISCRETES; + USHORT usDiscreteInputStart; + iNReg = usNDiscrete / 8 + 1; + + pucDiscreteInputBuf = ucMDiscInBuf[ucMBMasterGetDestAddress() - 1]; + DISCRETE_INPUT_START = M_DISCRETE_INPUT_START; + DISCRETE_INPUT_NDISCRETES = M_DISCRETE_INPUT_NDISCRETES; + usDiscreteInputStart = usMDiscInStart; + + /* it already plus one in modbus function method. */ + usAddress--; + + if ((usAddress >= DISCRETE_INPUT_START) + && (usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES)) + { + iRegIndex = (USHORT) (usAddress - usDiscreteInputStart) / 8; + iRegBitIndex = (USHORT) (usAddress - usDiscreteInputStart) % 8; + + /* write current discrete values with new values from the protocol stack. */ + while (iNReg > 1) + { + xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex, 8, + *pucRegBuffer++); + iNReg--; + } + /* last discrete */ + usNDiscrete = usNDiscrete % 8; + /* xMBUtilSetBits has bug when ucNBits is zero */ + if (usNDiscrete != 0) + { + xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex, + usNDiscrete, *pucRegBuffer++); + } + } + else + { + eStatus = MB_ENOREG; + } + + return eStatus; +} +#endif