Tom Martins
/
Probleme_implementation_lwip
test public
Fork of Modbus by
Revision 1:a3ee8cb24540, committed 2018-07-02
- Comitter:
- TomTom83
- Date:
- Mon Jul 02 14:36:46 2018 +0000
- Parent:
- 0:0453a0a7e500
- Child:
- 2:9e76d51d9fb6
- Commit message:
- adaptation de bafian modbus
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ethernetif.cpp Mon Jul 02 14:36:46 2018 +0000 @@ -0,0 +1,304 @@ +/** + * @file + * Ethernet Interface for standalone applications (without RTOS) - works only for + * ethernet polling mode (polling for ethernet frame reception) + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/mem.h" +#include "netif/etharp.h" +#include "ethernetif.h" +#include "main.h" +#include <string.h> + +/* Network interface name */ +#define IFNAME0 's' +#define IFNAME1 't' + + +/* Ethernet Rx & Tx DMA Descriptors */ +extern ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB], DMATxDscrTab[ETH_TXBUFNB]; + +/* Ethernet Driver Receive buffers */ +extern uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE]; + +/* Ethernet Driver Transmit buffers */ +extern uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE]; + +/* Global pointers to track current transmit and receive descriptors */ +extern ETH_DMADESCTypeDef *DMATxDescToSet; +extern ETH_DMADESCTypeDef *DMARxDescToGet; + +/* Global pointer for last received frame infos */ +extern ETH_DMA_Rx_Frame_infos *DMA_RX_FRAME_infos; + + + + +/** + * In this function, the hardware should be initialized. + * Called from ethernetif_init(). + * + * @param netif the already initialized lwip network interface structure + * for this ethernetif + */ +static void low_level_init(struct netif *netif) +{ +#ifdef CHECKSUM_BY_HARDWARE + int i; +#endif + /* set MAC hardware address length */ + netif->hwaddr_len = ETHARP_HWADDR_LEN; + + /* set MAC hardware address */ + netif->hwaddr[0] = MAC_ADDR0; + netif->hwaddr[1] = MAC_ADDR1; + netif->hwaddr[2] = MAC_ADDR2; + netif->hwaddr[3] = MAC_ADDR3; + netif->hwaddr[4] = MAC_ADDR4; + netif->hwaddr[5] = MAC_ADDR5; + + /* initialize MAC address in ethernet MAC */ + ETH_MACAddressConfig(ETH_MAC_Address0, netif->hwaddr); + + /* maximum transfer unit */ + netif->mtu = 1500; + + /* device capabilities */ + /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; + + /* Initialize Tx Descriptors list: Chain Mode */ + ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB); + /* Initialize Rx Descriptors list: Chain Mode */ + ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB); + +#ifdef CHECKSUM_BY_HARDWARE + /* Enable the TCP, UDP and ICMP checksum insertion for the Tx frames */ + for(i=0; i<ETH_TXBUFNB; i++) + { + ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull); + } +#endif + + /* Note: TCP, UDP, ICMP checksum checking for received frame are enabled in DMA config */ + + /* Enable MAC and DMA transmission and reception */ + ETH_Start(); + +} + +/** + * This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + * @param netif the lwip network interface structure for this ethernetif + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return ERR_OK if the packet could be sent + * an err_t value if the packet couldn't be sent + * + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to + * strange results. You might consider waiting for space in the DMA queue + * to become availale since the stack doesn't retry to send a packet + * dropped because of memory failure (except for the TCP timers). + */ + +static err_t low_level_output(struct netif *netif, struct pbuf *p) +{ + struct pbuf *q; + int framelength = 0; + u8 *buffer = (u8 *)(DMATxDescToSet->Buffer1Addr); + + /* copy frame from pbufs to driver buffers */ + for(q = p; q != NULL; q = q->next) + { + memcpy((u8_t*)&buffer[framelength], q->payload, q->len); + framelength = framelength + q->len; + } + + /* Note: padding and CRC for transmitted frame + are automatically inserted by DMA */ + + /* Prepare transmit descriptors to give to DMA*/ + ETH_Prepare_Transmit_Descriptors(framelength); + + return ERR_OK; +} + +/** + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + * @param netif the lwip network interface structure for this ethernetif + * @return a pbuf filled with the received packet (including MAC header) + * NULL on memory error + */ +static struct pbuf * low_level_input(struct netif *netif) +{ + struct pbuf *p, *q; + u16_t len; + int l =0; + FrameTypeDef frame; + u8 *buffer; + uint32_t i=0; + __IO ETH_DMADESCTypeDef *DMARxNextDesc; + + + p = NULL; + + /* get received frame */ + frame = ETH_Get_Received_Frame(); + + /* Obtain the size of the packet and put it into the "len" variable. */ + len = frame.length; + buffer = (u8 *)frame.buffer; + + /* We allocate a pbuf chain of pbufs from the Lwip buffer pool */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + + /* copy received frame to pbuf chain */ + if (p != NULL) + { + for (q = p; q != NULL; q = q->next) + { + memcpy((u8_t*)q->payload, (u8_t*)&buffer[l], q->len); + l = l + q->len; + } + } + + /* Release descriptors to DMA */ + /* Check if frame with multiple DMA buffer segments */ + if (DMA_RX_FRAME_infos->Seg_Count > 1) + { + DMARxNextDesc = DMA_RX_FRAME_infos->FS_Rx_Desc; + } + else + { + DMARxNextDesc = frame.descriptor; + } + + /* Set Own bit in Rx descriptors: gives the buffers back to DMA */ + for (i=0; i<DMA_RX_FRAME_infos->Seg_Count; i++) + { + DMARxNextDesc->Status = ETH_DMARxDesc_OWN; + DMARxNextDesc = (ETH_DMADESCTypeDef *)(DMARxNextDesc->Buffer2NextDescAddr); + } + + /* Clear Segment_Count */ + DMA_RX_FRAME_infos->Seg_Count =0; + + /* When Rx Buffer unavailable flag is set: clear it and resume reception */ + if ((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET) + { + /* Clear RBUS ETHERNET DMA flag */ + ETH->DMASR = ETH_DMASR_RBUS; + /* Resume DMA reception */ + ETH->DMARPDR = 0; + } + return p; +} + +/** + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * @param netif the lwip network interface structure for this ethernetif + */ +err_t ethernetif_input(struct netif *netif) +{ + err_t err; + struct pbuf *p; + + /* move received packet into a new pbuf */ + p = low_level_input(netif); + + /* no packet could be read, silently ignore this */ + if (p == NULL) return ERR_MEM; + + /* entry point to the LwIP stack */ + err = netif->input(p, netif); + + if (err != ERR_OK) + { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + pbuf_free(p); + p = NULL; + } + return err; +} + +/** + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this ethernetif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + * any other err_t on error + */ +err_t ethernetif_init(struct netif *netif) +{ + LWIP_ASSERT("netif != NULL", (netif != NULL)); + +#if LWIP_NETIF_HOSTNAME + /* Initialize interface hostname */ + netif->hostname = "RAIMA"; +#endif /* LWIP_NETIF_HOSTNAME */ + + strncpy(netif->name,"RAIMA",5); + + /* We directly use etharp_output() here to save a function call. + * You can instead declare your own function an call etharp_output() + * from it if you have to do some checks before sending (e.g. if link + * is available...) */ + netif->output = etharp_output; + netif->linkoutput = low_level_output; + + /* initialize the hardware */ + low_level_init(netif); + + return ERR_OK; +} + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ethernetif.h Mon Jul 02 14:36:46 2018 +0000 @@ -0,0 +1,12 @@ +#ifndef __ETHERNETIF_H__ +#define __ETHERNETIF_H__ + + +#include "lwip/err.h" +#include "lwip/netif.h" + +err_t ethernetif_init(struct netif *netif); +err_t ethernetif_input(struct netif *netif); + +#endif +
--- a/main.cpp Thu Apr 15 12:10:34 2010 +0000 +++ b/main.cpp Mon Jul 02 14:36:46 2018 +0000 @@ -22,12 +22,15 @@ /* ----------------------- System includes --------------------------------*/ /* ----------------------- Modbus includes ----------------------------------*/ +#include "mbed.h" +#include "EthernetInterface.h" #include "mb.h" #include "mbport.h" +#include "netconf.h" /* ----------------------- Defines ------------------------------------------*/ #define REG_INPUT_START 1000 -#define REG_INPUT_NREGS 4 +#define REG_INPUT_NREGS 5 #define SLAVE_ID 0x0A /* ----------------------- Static variables ---------------------------------*/ @@ -35,24 +38,39 @@ static USHORT usRegInputBuf[REG_INPUT_NREGS]; /* ----------------------- Start implementation -----------------------------*/ + +DigitalIn mybutton(USER_BUTTON); +DigitalOut myled2(LED2); + int main( void ) { eMBErrorCode eStatus; - eStatus = eMBInit( MB_RTU, SLAVE_ID, 0, 9600, MB_PAR_NONE ); - + //eStatus = eMBInit( MB_RTU, SLAVE_ID, 0, 9600, MB_PAR_NONE ); + + EthernetInterface eth; + eth.set_network("169.254.178.1","255.255.0.0","169.254.178.3"); + eth.connect(); + + /* inicializacion del Stack de Modbus */ + eMBTCPInit(502); + /* Enable the Modbus Protocol Stack. */ eStatus = eMBEnable( ); + myled2=1; // Initialise some registers - usRegInputBuf[1] = 0x1234; - usRegInputBuf[2] = 0x5678; - usRegInputBuf[3] = 0x9abc; + usRegInputBuf[1] = 83; + usRegInputBuf[2] = 65; + usRegInputBuf[3] = 76; + usRegInputBuf[4] = 85; for( ;; ) { ( void )eMBPoll( ); + + LwIP_Pkt_Handle(); /* Here we simply count the number of poll cycles. */ usRegInputBuf[0]++;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.h Mon Jul 02 14:36:46 2018 +0000 @@ -0,0 +1,110 @@ +/** + ****************************************************************************** + * @file main.h + * @author MCD Application Team + * @version V1.1.0 + * @date 31-July-2013 + * @brief This file contains all the functions prototypes for the main.c + * file. + ****************************************************************************** + * @attention + * + * <h2><center>© COPYRIGHT 2013 STMicroelectronics</center></h2> + * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __MAIN_H +#define __MAIN_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +//#define USE_LCD /* enable LCD */ +//#define USE_DHCP /* enable DHCP, if disabled static address is used */ + +/* Uncomment SERIAL_DEBUG to enables retarget of printf to serial port (COM1 on STM32 evalboard) + for debug purpose */ +//#define SERIAL_DEBUG + + +/*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */ +#define IP_ADDR0 192 +#define IP_ADDR1 168 +#define IP_ADDR2 2 +#define IP_ADDR3 10 + +/*NETMASK*/ +#define NETMASK_ADDR0 255 +#define NETMASK_ADDR1 255 +#define NETMASK_ADDR2 255 +#define NETMASK_ADDR3 0 + +/*Gateway Address*/ +#define GW_ADDR0 192 +#define GW_ADDR1 168 +#define GW_ADDR2 2 +#define GW_ADDR3 5 + +/* MII and RMII mode selection, for STM324xG-EVAL Board(MB786) RevB ***********/ +//#define RMII_MODE // User have to provide the 50 MHz clock by soldering a 50 MHz + // oscillator (ref SM7745HEV-50.0M or equivalent) on the U3 + // footprint located under CN3 and also removing jumper on JP5. + // This oscillator is not provided with the board. + // For more details, please refer to STM3240G-EVAL evaluation + // board User manual (UM1461). + + +#define MII_MODE + +/* Uncomment the define below to clock the PHY from external 25MHz crystal (only for MII mode) */ +#ifdef MII_MODE + #define PHY_CLOCK_MCO +#endif + +/* STM324xG-EVAL jumpers setting + +==========================================================================================+ + + Jumper | MII mode configuration | RMII mode configuration + + +==========================================================================================+ + + JP5 | 2-3 provide 25MHz clock by MCO(PA8) | Not fitted + + + | 1-2 provide 25MHz clock by ext. Crystal | + + + -----------------------------------------------------------------------------------------+ + + JP6 | 2-3 | 1-2 + + + -----------------------------------------------------------------------------------------+ + + JP8 | Open | Close + + +==========================================================================================+ + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +void Time_Update(void); +void Delay(uint32_t nCount); + + +#ifdef __cplusplus +} +#endif + +#endif /* __MAIN_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + +
--- a/mbconfig.h Thu Apr 15 12:10:34 2010 +0000 +++ b/mbconfig.h Mon Jul 02 14:36:46 2018 +0000 @@ -49,9 +49,9 @@ /*! \brief If Modbus ASCII support is enabled. */ #define MB_ASCII_ENABLED ( 0 ) /*! \brief If Modbus RTU support is enabled. */ -#define MB_RTU_ENABLED ( 1 ) +#define MB_RTU_ENABLED ( 0 ) /*! \brief If Modbus TCP support is enabled. */ -#define MB_TCP_ENABLED ( 0 ) +#define MB_TCP_ENABLED ( 1 ) /*! \brief The character timeout value for Modbus ASCII. * * The character timeout value is not fixed for Modbus ASCII and is therefore
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os.lib Mon Jul 02 14:36:46 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os/#62f8b922b420626514fd4690107aff4188469833
--- a/mbed.bld Thu Apr 15 12:10:34 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbtcp.cpp Mon Jul 02 14:36:46 2018 +0000 @@ -0,0 +1,159 @@ +/* + * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU. + * Copyright (c) 2006 Christian Walter <wolti@sil.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: mbtcp.c,v 1.3 2006/12/07 22:10:34 wolti Exp $ + */ + +/* ----------------------- System includes ----------------------------------*/ +#include "stdlib.h" +#include "string.h" + +/* ----------------------- Platform includes --------------------------------*/ +#include "port.h" + +/* ----------------------- Modbus includes ----------------------------------*/ +#include "mb.h" +#include "mbconfig.h" +#include "mbtcp.h" +#include "mbframe.h" +#include "mbport.h" + +#if MB_TCP_ENABLED > 0 + +/* ----------------------- Defines ------------------------------------------*/ + +/* ----------------------- MBAP Header --------------------------------------*/ +/* + * + * <------------------------ MODBUS TCP/IP ADU(1) -------------------------> + * <----------- MODBUS PDU (1') ----------------> + * +-----------+---------------+------------------------------------------+ + * | TID | PID | Length | UID |Code | Data | + * +-----------+---------------+------------------------------------------+ + * | | | | | + * (2) (3) (4) (5) (6) + * + * (2) ... MB_TCP_TID = 0 (Transaction Identifier - 2 Byte) + * (3) ... MB_TCP_PID = 2 (Protocol Identifier - 2 Byte) + * (4) ... MB_TCP_LEN = 4 (Number of bytes - 2 Byte) + * (5) ... MB_TCP_UID = 6 (Unit Identifier - 1 Byte) + * (6) ... MB_TCP_FUNC = 7 (Modbus Function Code) + * + * (1) ... Modbus TCP/IP Application Data Unit + * (1') ... Modbus Protocol Data Unit + */ + +#define MB_TCP_TID 0 +#define MB_TCP_PID 2 +#define MB_TCP_LEN 4 +#define MB_TCP_UID 6 +#define MB_TCP_FUNC 7 + +#define MB_TCP_PROTOCOL_ID 0 /* 0 = Modbus Protocol */ + + +/* ----------------------- Start implementation -----------------------------*/ +eMBErrorCode +eMBTCPDoInit( USHORT ucTCPPort ) +{ + eMBErrorCode eStatus = MB_ENOERR; + + if( xMBTCPPortInit( ucTCPPort ) == FALSE ) + { + eStatus = MB_EPORTERR; + } + return eStatus; +} + +void +eMBTCPStart( void ) +{ +} + +void +eMBTCPStop( void ) +{ + /* Make sure that no more clients are connected. */ + vMBTCPPortDisable( ); +} + +eMBErrorCode +eMBTCPReceive( UCHAR * pucRcvAddress, UCHAR ** ppucFrame, USHORT * pusLength ) +{ + eMBErrorCode eStatus = MB_EIO; + UCHAR *pucMBTCPFrame; + USHORT usLength; + USHORT usPID; + + if( xMBTCPPortGetRequest( &pucMBTCPFrame, &usLength ) != FALSE ) + { + usPID = pucMBTCPFrame[MB_TCP_PID] << 8U; + usPID |= pucMBTCPFrame[MB_TCP_PID + 1]; + + if( usPID == MB_TCP_PROTOCOL_ID ) + { + *ppucFrame = &pucMBTCPFrame[MB_TCP_FUNC]; + *pusLength = usLength - MB_TCP_FUNC; + eStatus = MB_ENOERR; + + /* Modbus TCP does not use any addresses. Fake the source address such + * that the processing part deals with this frame. + */ + *pucRcvAddress = MB_TCP_PSEUDO_ADDRESS; + } + } + else + { + eStatus = MB_EIO; + } + return eStatus; +} + +eMBErrorCode +eMBTCPSend( UCHAR _unused, const UCHAR * pucFrame, USHORT usLength ) +{ + eMBErrorCode eStatus = MB_ENOERR; + UCHAR *pucMBTCPFrame = ( UCHAR * ) pucFrame - MB_TCP_FUNC; + USHORT usTCPLength = usLength + MB_TCP_FUNC; + + /* The MBAP header is already initialized because the caller calls this + * function with the buffer returned by the previous call. Therefore we + * only have to update the length in the header. Note that the length + * header includes the size of the Modbus PDU and the UID Byte. Therefore + * the length is usLength plus one. + */ + pucMBTCPFrame[MB_TCP_LEN] = ( usLength + 1 ) >> 8U; + pucMBTCPFrame[MB_TCP_LEN + 1] = ( usLength + 1 ) & 0xFF; + if( xMBTCPPortSendResponse( pucMBTCPFrame, usTCPLength ) == FALSE ) + { + eStatus = MB_EIO; + } + return eStatus; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbtcp.h Mon Jul 02 14:36:46 2018 +0000 @@ -0,0 +1,54 @@ +/* + * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU. + * Copyright (c) 2006 Christian Walter <wolti@sil.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: mbtcp.h,v 1.2 2006/12/07 22:10:34 wolti Exp $ + */ + +#ifndef _MB_TCP_H +#define _MB_TCP_H + +#ifdef __cplusplus +PR_BEGIN_EXTERN_C +#endif + +/* ----------------------- Defines ------------------------------------------*/ +#define MB_TCP_PSEUDO_ADDRESS 1 + +/* ----------------------- Function prototypes ------------------------------*/ + eMBErrorCode eMBTCPDoInit( USHORT ucTCPPort ); +void eMBTCPStart( void ); +void eMBTCPStop( void ); +eMBErrorCode eMBTCPReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, + USHORT * pusLength ); +eMBErrorCode eMBTCPSend( UCHAR _unused, const UCHAR * pucFrame, + USHORT usLength ); + +#ifdef __cplusplus +PR_END_EXTERN_C +#endif +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/netconf.cpp Mon Jul 02 14:36:46 2018 +0000 @@ -0,0 +1,297 @@ +/** + ****************************************************************************** + * @file netconf.c + * @author MCD Application Team + * @version V1.0.0 + * @date 31-October-2011 + * @brief Network connection configuration + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * <h2><center>© Portions COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ +/** + ****************************************************************************** + * <h2><center>© Portions COPYRIGHT 2012 Embest Tech. Co., Ltd.</center></h2> + * @file netconf.c + * @author CMP Team + * @version V1.0.0 + * @date 28-December-2012 + * @brief Network connection configuration + * Modified to support the STM32F4DISCOVERY, STM32F4DIS-BB and + * STM32F4DIS-LCD modules. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, Embest SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT + * OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT + * OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION + * CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + ****************************************************************************** + */ +/* Includes ------------------------------------------------------------------*/ +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/tcp.h" +#include "lwip/udp.h" +#include "netif/etharp.h" +#include "lwip/dhcp.h" +#include "ethernetif.h" +#include "main.h" +#include "netconf.h" +#include <stdio.h> + +/* Private typedef -----------------------------------------------------------*/ +#define MAX_DHCP_TRIES 4 + +/* Private define ------------------------------------------------------------*/ +typedef enum +{ + DHCP_START=0, + DHCP_WAIT_ADDRESS, + DHCP_ADDRESS_ASSIGNED, + DHCP_TIMEOUT +} +DHCP_State_TypeDef; +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +struct netif netif; +uint32_t TCPTimer = 0; +uint32_t ARPTimer = 0; +uint32_t IPaddress = 0; + +#ifdef USE_DHCP +uint32_t DHCPfineTimer = 0; +uint32_t DHCPcoarseTimer = 0; +DHCP_State_TypeDef DHCP_state = DHCP_START; +#endif + +/* Private functions ---------------------------------------------------------*/ +void LwIP_DHCP_Process_Handle(void); +/** + * @brief Initializes the lwIP stack + * @param None + * @retval None + */ +void LwIP_Init(void) +{ + struct ip_addr ipaddr; + struct ip_addr netmask; + struct ip_addr gw; +#ifndef USE_DHCP + uint8_t iptab[4]; + uint8_t iptxt[20]; +#endif + + /* Initializes the dynamic memory heap defined by MEM_SIZE.*/ + mem_init(); + + /* Initializes the memory pools defined by MEMP_NUM_x.*/ + memp_init(); + +#ifdef USE_DHCP + ipaddr.addr = 0; + netmask.addr = 0; + gw.addr = 0; +#else + IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3); + IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1 , NETMASK_ADDR2, NETMASK_ADDR3); + IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3); + +#ifdef USE_LCD + iptab[0] = IP_ADDR3; + iptab[1] = IP_ADDR2; + iptab[2] = IP_ADDR1; + iptab[3] = IP_ADDR0; + + sprintf((char*)iptxt, " %d.%d.%d.%d", iptab[3], iptab[2], iptab[1], iptab[0]); + + LCD_DisplayStringLine(Line8, (uint8_t*)" Static IP address "); + LCD_DisplayStringLine(Line9, iptxt); +#endif +#endif + + /* - netif_add(struct netif *netif, struct ip_addr *ipaddr, + struct ip_addr *netmask, struct ip_addr *gw, + void *state, err_t (* init)(struct netif *netif), + err_t (* input)(struct pbuf *p, struct netif *netif)) + + Adds your network interface to the netif_list. Allocate a struct + netif and pass a pointer to this structure as the first argument. + Give pointers to cleared ip_addr structures when using DHCP, + or fill them with sane numbers otherwise. The state pointer may be NULL. + + The init function pointer must point to a initialization function for + your ethernet netif interface. The following code illustrates it's use.*/ + netif_add(&netif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input); + + /* Registers the default network interface.*/ + netif_set_default(&netif); + + /* When the netif is fully configured this function must be called.*/ + netif_set_up(&netif); +} + +/** + * @brief Called when a frame is received + * @param None + * @retval None + */ +void LwIP_Pkt_Handle(void) +{ + /* Read a received packet from the Ethernet buffers and send it to the lwIP for handling */ + ethernetif_input(&netif); +} + +/** + * @brief LwIP periodic tasks + * @param localtime the current LocalTime value + * @retval None + */ +void LwIP_Periodic_Handle(__IO uint32_t localtime) +{ +#if LWIP_TCP + /* TCP periodic process every 250 ms */ + if (localtime - TCPTimer >= TCP_TMR_INTERVAL) { + TCPTimer = localtime; + tcp_tmr(); + } +#endif + + /* ARP periodic process every 5s */ + if ((localtime - ARPTimer) >= ARP_TMR_INTERVAL) { + ARPTimer = localtime; + etharp_tmr(); + } + +#ifdef USE_DHCP + /* Fine DHCP periodic process every 500ms */ + if (localtime - DHCPfineTimer >= DHCP_FINE_TIMER_MSECS) { + DHCPfineTimer = localtime; + dhcp_fine_tmr(); + if ((DHCP_state != DHCP_ADDRESS_ASSIGNED)&&(DHCP_state != DHCP_TIMEOUT)) { + /* process DHCP state machine */ + LwIP_DHCP_Process_Handle(); + } + } + + /* DHCP Coarse periodic process every 60s */ + if (localtime - DHCPcoarseTimer >= DHCP_COARSE_TIMER_MSECS) { + DHCPcoarseTimer = localtime; + dhcp_coarse_tmr(); + } + +#endif +} + +#ifdef USE_DHCP +/** + * @brief LwIP_DHCP_Process_Handle + * @param None + * @retval None + */ +void LwIP_DHCP_Process_Handle() +{ + struct ip_addr ipaddr; + struct ip_addr netmask; + struct ip_addr gw; + uint8_t iptab[4]; + uint8_t iptxt[20]; + + switch (DHCP_state) + { + case DHCP_START: + { + dhcp_start(&netif); + IPaddress = 0; + DHCP_state = DHCP_WAIT_ADDRESS; +#ifdef USE_LCD + LCD_DisplayStringLine(Line4, (uint8_t*)" Looking for "); + LCD_DisplayStringLine(Line5, (uint8_t*)" DHCP server "); + LCD_DisplayStringLine(Line6, (uint8_t*)" please wait... "); +#endif + } + break; + + case DHCP_WAIT_ADDRESS: + { + /* Read the new IP address */ + IPaddress = netif.ip_addr.addr; + + if (IPaddress!=0) { + DHCP_state = DHCP_ADDRESS_ASSIGNED; + + /* Stop DHCP */ + dhcp_stop(&netif); + + iptab[0] = (uint8_t)(IPaddress >> 24); + iptab[1] = (uint8_t)(IPaddress >> 16); + iptab[2] = (uint8_t)(IPaddress >> 8); + iptab[3] = (uint8_t)(IPaddress); + + sprintf((char*)iptxt, " %d.%d.%d.%d", iptab[3], iptab[2], iptab[1], iptab[0]); + +#ifdef USE_LCD + + + LCD_ClearLine(Line4); + LCD_ClearLine(Line5); + LCD_ClearLine(Line6); + + /* Display the IP address */ + LCD_DisplayStringLine(Line7, (uint8_t*)"IP address assigned "); + LCD_DisplayStringLine(Line8, (uint8_t*)" by a DHCP server "); + LCD_DisplayStringLine(Line9, iptxt); +#endif + } else { + /* DHCP timeout */ + if (netif.dhcp->tries > MAX_DHCP_TRIES) { + DHCP_state = DHCP_TIMEOUT; + + /* Stop DHCP */ + dhcp_stop(&netif); + + /* Static address used */ + IP4_ADDR(&ipaddr, IP_ADDR0 ,IP_ADDR1 , IP_ADDR2 , IP_ADDR3 ); + IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3); + IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3); + netif_set_addr(&netif, &ipaddr , &netmask, &gw); + +#ifdef USE_LCD + LCD_DisplayStringLine(Line7, (uint8_t*)" DHCP timeout "); + + iptab[0] = IP_ADDR3; + iptab[1] = IP_ADDR2; + iptab[2] = IP_ADDR1; + iptab[3] = IP_ADDR0; + + sprintf((char*)iptxt, " %d.%d.%d.%d", iptab[3], iptab[2], iptab[1], iptab[0]); + + LCD_ClearLine(Line4); + LCD_ClearLine(Line5); + LCD_ClearLine(Line6); + + LCD_DisplayStringLine(Line8, (uint8_t*)" Static IP address "); + LCD_DisplayStringLine(Line9, iptxt); +#endif + } + } + } + break; + default: break; + } +} +#endif + +/*********** Portions COPYRIGHT 2012 Embest Tech. Co., Ltd.*****END OF FILE****/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/netconf.h Mon Jul 02 14:36:46 2018 +0000 @@ -0,0 +1,70 @@ +/** + ****************************************************************************** + * @file netconf.h + * @author MCD Application Team + * @version V1.0.0 + * @date 31-October-2011 + * @brief This file contains all the functions prototypes for the netconf.c + * file. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * <h2><center>© Portions COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ +/** + ****************************************************************************** + * <h2><center>© Portions COPYRIGHT 2012 Embest Tech. Co., Ltd.</center></h2> + * @file netconf.h + * @author CMP Team + * @version V1.0.0 + * @date 28-December-2012 + * @brief This file contains all the functions prototypes for the netconf.c + * file. + * Modified to support the STM32F4DISCOVERY, STM32F4DIS-BB and + * STM32F4DIS-LCD modules. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, Embest SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT + * OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT + * OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION + * CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __NETCONF_H +#define __NETCONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +void LwIP_Init(void); +void LwIP_Pkt_Handle(void); +void LwIP_Periodic_Handle(__IO uint32_t localtime); + +#ifdef __cplusplus +} +#endif + +#endif /* __NETCONF_H */ + + +/*********** Portions COPYRIGHT 2012 Embest Tech. Co., Ltd.*****END OF FILE****/ + +
--- a/port.h Thu Apr 15 12:10:34 2010 +0000 +++ b/port.h Mon Jul 02 14:36:46 2018 +0000 @@ -51,4 +51,23 @@ #define FALSE 0 #endif +#define MB_TCP_DEBUG 1 + +#ifdef MB_TCP_DEBUG +typedef enum +{ + MB_LOG_DEBUG, + MB_LOG_INFO, + MB_LOG_WARN, + MB_LOG_ERROR +} eMBPortLogLevel; #endif + +/* ----------------------- Function prototypes ------------------------------*/ +#ifdef MB_TCP_DEBUG +void vMBPortLog( eMBPortLogLevel eLevel, const CHAR * szModule, + const CHAR * szFmt, ... ); +void prvvMBTCPLogFrame( UCHAR * pucMsg, UCHAR * pucFrame, USHORT usFrameLen ); +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/portother.cpp Mon Jul 02 14:36:46 2018 +0000 @@ -0,0 +1,125 @@ +/* + * FreeModbus Libary: lwIP 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: portother.c,v 1.2 2006/09/04 14:39:20 wolti Exp $ + */ + +/* ----------------------- System includes ----------------------------------*/ +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +#include "port.h" + +/* ----------------------- Defines ------------------------------------------*/ +#define MB_FRAME_LOG_BUFSIZE 512 + +/* ----------------------- Start implementation -----------------------------*/ + +#ifdef MB_TCP_DEBUG +void +prvvMBTCPLogFrame( UCHAR * pucMsg, UCHAR * pucFrame, USHORT usFrameLen ) +{ + int i; + int res = 0; + int iBufPos = 0; + size_t iBufLeft = MB_FRAME_LOG_BUFSIZE; + static CHAR arcBuffer[MB_FRAME_LOG_BUFSIZE]; + + assert( pucFrame != NULL ); + + for( i = 0; i < usFrameLen; i++ ) + { + /* Print some additional frame information. */ + switch ( i ) + { + case 0: + /* TID = Transaction Identifier. */ + res = snprintf( &arcBuffer[iBufPos], iBufLeft, "| TID = " ); + break; + case 2: + /* PID = Protocol Identifier. */ + res = snprintf( &arcBuffer[iBufPos], iBufLeft, " | PID = " ); + break; + case 4: + /* Length */ + res = snprintf( &arcBuffer[iBufPos], iBufLeft, " | LEN = " ); + break; + case 6: + /* UID = Unit Identifier. */ + res = snprintf( &arcBuffer[iBufPos], iBufLeft, " | UID = " ); + break; + case 7: + /* MB Function Code. */ + res = snprintf( &arcBuffer[iBufPos], iBufLeft, "|| FUNC = " ); + break; + case 8: + /* MB PDU rest. */ + res = snprintf( &arcBuffer[iBufPos], iBufLeft, " | DATA = " ); + break; + default: + res = 0; + break; + } + if( res == -1 ) + { + break; + } + else + { + iBufPos += res; + iBufLeft -= res; + } + + /* Print the data. */ + res = snprintf( &arcBuffer[iBufPos], iBufLeft, "%02X", pucFrame[i] ); + if( res == -1 ) + { + break; + } + else + { + iBufPos += res; + iBufLeft -= res; + } + } + + if( res != -1 ) + { + /* Append an end of frame string. */ + res = snprintf( &arcBuffer[iBufPos], iBufLeft, " |\r\n" ); + if( res != -1 ) + { + vMBPortLog( MB_LOG_DEBUG, (const char*)pucMsg, "%s", arcBuffer ); + } + } +} +#endif + +void +vMBPortLog( eMBPortLogLevel eLevel, const CHAR * szModule, const CHAR * szFmt, ... ) +{ + va_list args; + static const char *arszLevel2Str[] = { "DEBUG", "INFO", "WARN", "ERROR" }; + + ( void )printf( "%s: %s: ", arszLevel2Str[eLevel], szModule ); + va_start( args, szFmt ); + vprintf( szFmt, args ); + va_end( args ); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/porttcp.cpp Mon Jul 02 14:36:46 2018 +0000 @@ -0,0 +1,332 @@ +/* + * FreeModbus Libary: lwIP 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: porttcp.c,v 1.2 2006/09/04 14:39:20 wolti Exp $ + */ + +/* ----------------------- System includes ----------------------------------*/ +#include <stdio.h> +#include "string.h" + +#include "port.h" + +/* ----------------------- lwIP includes ------------------------------------*/ +#include "lwip/api.h" +#include "lwip/tcp.h" + +/* ----------------------- Modbus includes ----------------------------------*/ +#include "mb.h" +#include "mbport.h" + +/* ----------------------- MBAP Header --------------------------------------*/ +#define MB_TCP_UID 6 +#define MB_TCP_LEN 4 +#define MB_TCP_FUNC 7 + +/* ----------------------- Defines -----------------------------------------*/ +#define MB_TCP_DEFAULT_PORT 502 /* TCP listening port. */ +#define MB_TCP_BUF_SIZE ( 256 + 7 ) /* Must hold a complete Modbus TCP frame. */ + +/* ----------------------- Prototypes ---------------------------------------*/ +void vMBPortEventClose( void ){}; +void vMBPortLog( eMBPortLogLevel eLevel, const CHAR * szModule, + const CHAR * szFmt, ... ); + +/* ----------------------- Static variables ---------------------------------*/ +static struct tcp_pcb *pxPCBListen; +static struct tcp_pcb *pxPCBClient; + +static UCHAR aucTCPBuf[MB_TCP_BUF_SIZE]; +static USHORT usTCPBufPos; + +/* ----------------------- Static functions ---------------------------------*/ +static err_t prvxMBTCPPortAccept( void *pvArg, struct tcp_pcb *pxPCB, err_t xErr ); +static err_t prvxMBTCPPortReceive( void *pvArg, struct tcp_pcb *pxPCB, struct pbuf *p, + err_t xErr ); +static void prvvMBTCPPortError( void *pvArg, err_t xErr ); + +/* ----------------------- Begin implementation -----------------------------*/ +BOOL +xMBTCPPortInit( USHORT usTCPPort ) +{ + struct tcp_pcb *pxPCBListenNew, *pxPCBListenOld; + BOOL bOkay = FALSE; + USHORT usPort; + + if( usTCPPort == 0 ) + { + usPort = MB_TCP_DEFAULT_PORT; + } + else + { + usPort = ( USHORT ) usTCPPort; + } + + if( ( pxPCBListenNew = pxPCBListenOld = tcp_new( ) ) == NULL ) + { + /* Can't create TCP socket. */ + bOkay = FALSE; + } + else if( tcp_bind( pxPCBListenNew, IP_ADDR_ANY, ( u16_t ) usPort ) != ERR_OK ) + { + /* Bind failed - Maybe illegal port value or in use. */ + ( void )tcp_close( pxPCBListenOld ); + bOkay = FALSE; + } + else if( ( pxPCBListenNew = tcp_listen( pxPCBListenNew ) ) == NULL ) + { + ( void )tcp_close( pxPCBListenOld ); + bOkay = FALSE; + } + else + { + /* Register callback function for new clients. */ + tcp_accept( pxPCBListenNew, prvxMBTCPPortAccept ); + + /* Everything okay. Set global variable. */ + pxPCBListen = pxPCBListenNew; + +#ifdef MB_TCP_DEBUG + vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Protocol stack ready.\r\n" ); +#endif + } + bOkay = TRUE; + return bOkay; +} + +void +prvvMBPortReleaseClient( struct tcp_pcb *pxPCB ) +{ + if( pxPCB != NULL ) + { + if( tcp_close( pxPCB ) != ERR_OK ) + { + tcp_abort( pxPCB ); + } + // vPortEnterCritical( ); + if( pxPCB == pxPCBClient ) + { +#ifdef MB_TCP_DEBUG + vMBPortLog( MB_LOG_DEBUG, "MBTCP-CLOSE", "Closed connection to %d.%d.%d.%d.\r\n", + ip4_addr1( &( pxPCB->remote_ip ) ), + ip4_addr2( &( pxPCB->remote_ip ) ), + ip4_addr3( &( pxPCB->remote_ip ) ), ip4_addr4( &( pxPCB->remote_ip ) ) ); +#endif + pxPCBClient = NULL; + } + if( pxPCB == pxPCBListen ) + { + pxPCBListen = NULL; + } + //vPortExitCritical( ); + } +} +void +vMBTCPPortClose( ) +{ + /* Shutdown any open client sockets. */ + prvvMBPortReleaseClient( pxPCBClient ); + + /* Shutdown or listening socket. */ + prvvMBPortReleaseClient( pxPCBListen ); + + /* Release resources for the event queue. */ + vMBPortEventClose( ); +} + +void +vMBTCPPortDisable( void ) +{ + prvvMBPortReleaseClient( pxPCBClient ); +} + +err_t +prvxMBTCPPortAccept( void *pvArg, struct tcp_pcb *pxPCB, err_t xErr ) +{ + err_t error; + + if( xErr != ERR_OK ) + { + return xErr; + } + + /* We can handle only one client. */ + if( pxPCBClient == NULL ) + { + /* Register the client. */ + pxPCBClient = pxPCB; + + /* Set up the receive function prvxMBTCPPortReceive( ) to be called when data + * arrives. + */ + tcp_recv( pxPCB, prvxMBTCPPortReceive ); + + /* Register error handler. */ + tcp_err( pxPCB, prvvMBTCPPortError ); + + /* Set callback argument later used in the error handler. */ + tcp_arg( pxPCB, pxPCB ); + + /* Reset the buffers and state variables. */ + usTCPBufPos = 0; + +#ifdef MB_TCP_DEBUG + vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Accepted new client %d.%d.%d.%d\r\n", + ip4_addr1( &( pxPCB->remote_ip ) ), + ip4_addr2( &( pxPCB->remote_ip ) ), + ip4_addr3( &( pxPCB->remote_ip ) ), ip4_addr4( &( pxPCB->remote_ip ) ) ); +#endif + + error = ERR_OK; + } + else + { + prvvMBPortReleaseClient( pxPCB ); + error = ERR_OK; + } + return error; +} + +/* Called in case of an unrecoverable error. In any case we drop the client + * connection. */ +void +prvvMBTCPPortError( void *pvArg, err_t xErr ) +{ + struct tcp_pcb *pxPCB = (struct tcp_pcb *)pvArg; + + if( pxPCB != NULL ) + { +#ifdef MB_TCP_DEBUG + vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", "Error with client connection! Droping it.\r\n" ); +#endif + prvvMBPortReleaseClient( pxPCB ); + } +} + +err_t +prvxMBTCPPortReceive( void *pvArg, struct tcp_pcb *pxPCB, struct pbuf *p, err_t xErr ) +{ + USHORT usLength; + + err_t error = xErr; + + if( error != ERR_OK ) + { + return error; + } + + /* If pbuf is NULL then remote end has closed connection. */ + if( p == NULL ) + { + prvvMBPortReleaseClient( pxPCB ); + return ERR_OK; + } + + /* Acknowledge that we have received the data bytes. */ + tcp_recved( pxPCB, p->len ); + + /* Check for internal buffer overflow. In case of an error drop the + * client. */ + if( ( usTCPBufPos + p->len ) >= MB_TCP_BUF_SIZE ) + { + prvvMBPortReleaseClient( pxPCB ); + error = ERR_OK; + } + else + { + memcpy( &aucTCPBuf[usTCPBufPos], p->payload, p->len ); + usTCPBufPos += p->len; + + /* If we have received the MBAP header we can analyze it and calculate + * the number of bytes left to complete the current request. If complete + * notify the protocol stack. + */ + if( usTCPBufPos >= MB_TCP_FUNC ) + { + /* Length is a byte count of Modbus PDU (function code + data) and the + * unit identifier. */ + usLength = aucTCPBuf[MB_TCP_LEN] << 8U; + usLength |= aucTCPBuf[MB_TCP_LEN + 1]; + + /* Is the frame already complete. */ + if( usTCPBufPos < ( MB_TCP_UID + usLength ) ) + { + } + else if( usTCPBufPos == ( MB_TCP_UID + usLength ) ) + { +#ifdef MB_TCP_DEBUG + prvvMBTCPLogFrame( (UCHAR*)"MBTCP-RECV", &aucTCPBuf[0], usTCPBufPos ); +#endif + ( void )xMBPortEventPost( EV_FRAME_RECEIVED ); + } + else + { +#ifdef MB_TCP_DEBUG + vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", + "Received to many bytes! Droping client.\r\n" ); +#endif + /* This should not happen. We can't deal with such a client and + * drop the connection for security reasons. + */ + prvvMBPortReleaseClient( pxPCB ); + } + } + } + pbuf_free( p ); + return error; +} + +BOOL +xMBTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength ) +{ + *ppucMBTCPFrame = &aucTCPBuf[0]; + *usTCPLength = usTCPBufPos; + + /* Reset the buffer. */ + usTCPBufPos = 0; + return TRUE; +} + +BOOL +xMBTCPPortSendResponse( const UCHAR * pucMBTCPFrame, USHORT usTCPLength ) +{ + BOOL bFrameSent = FALSE; + + if( pxPCBClient ) + { + /* Make sure we can send the packet. */ + assert( tcp_sndbuf( pxPCBClient ) >= usTCPLength ); + + if( tcp_write( pxPCBClient, pucMBTCPFrame, ( u16_t ) usTCPLength, TCP_WRITE_FLAG_COPY ) == ERR_OK ) + { +#ifdef MB_TCP_DEBUG + prvvMBTCPLogFrame( (UCHAR*)"MBTCP-SENT", &aucTCPBuf[0], usTCPLength ); +#endif + /* Make sure data gets sent immediately. */ + ( void )tcp_output( pxPCBClient ); + bFrameSent = TRUE; + } + else + { + /* Drop the connection in case of an write error. */ + prvvMBPortReleaseClient( pxPCBClient ); + } + } + return bFrameSent; +} +