From a8147944eaaba6f0deca268245c9ea43f02969e4 Mon Sep 17 00:00:00 2001 From: Jakub Date: Wed, 28 Aug 2019 10:52:38 +0200 Subject: [PATCH] Add TCP/IP interface for extmode Support basic communication and reconnecting to target. Basic communication and reconnecting stress tested. Implementation inspired from http://git.savannah.nongnu.org/cgit/lwip/lwip-contrib.git/tree/apps/tcpecho/tcpecho.c matlabroot/rtw/c/src/rtiostream/rtiostreamtcpip/rtiostream_tcpip.c --- rpp/rpp/.gitattributes | 1 + rpp/rpp/rtiostream_tcpip.c | 242 +++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 rpp/rpp/rtiostream_tcpip.c diff --git a/rpp/rpp/.gitattributes b/rpp/rpp/.gitattributes index 0967701..a150324 100644 --- a/rpp/rpp/.gitattributes +++ b/rpp/rpp/.gitattributes @@ -12,5 +12,6 @@ /rpp_simulink_runtime.h eaton /rpp_srmain.tlc eaton /rtiostream_serial.c eaton +/rtiostream_tcpip.c eaton /sl_customization.m eaton /target_tools.mk eaton diff --git a/rpp/rpp/rtiostream_tcpip.c b/rpp/rpp/rtiostream_tcpip.c new file mode 100644 index 0000000..c20a47d --- /dev/null +++ b/rpp/rpp/rtiostream_tcpip.c @@ -0,0 +1,242 @@ +/* + * Copyright 1994-2012 The MathWorks, Inc. + * + * Modified for RPP target by Jakub Nejedlý + * + * File: rtiostream_tcpip.c + * + * Abstract: + + */ + +#include "rtiostream.h" + +#include "rpp/rpp.h" + +#include "lwip/mem.h" +#include "lwip/raw.h" +#include "lwip/icmp.h" +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/timers.h" +#include "lwip/inet_chksum.h" +#include "lwip/sockets.h" +#include "lwip/inet.h" + + +typedef int SOCKET; +typedef const char * send_buffer_t; +typedef socklen_t rtiostream_socklen_t; + +SOCKET socketBase = 0; +SOCKET socketNum = 0; + +int sockStatus = 0; + + + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) + +#define RECEIVE_TIMEOUT 1000 //ms +#define PORT_RPP 17725U + +#define INT_MAX 2147483647 + +# define INVALID_SOCKET (-1) +# define SOCK_ERR (-1) + + +int ethinit(){ + // // test eth init + int8_t retVal = rpp_eth_init_postInit(0, NULL); /* post OS startup init of eth (LwIP) for application usage -- waits for a while, for auto-negotiation of ethernet speed and DHCP if used */ + + switch (retVal) { + case FAILURE: + rpp_sci_printf("already initialized\n"); + break; + case NETIF_ADD_ERR: + rpp_sci_printf("initialization of physical part of ethernet failed\n"); + break; + case DHCP_MEM_ERR: + rpp_sci_printf("DHCP couldn't be started due to insufficient memory\n"); + break; + case PHY_LINK_DOWN: + rpp_sci_printf("cable is not connected\n"); + break; + default: + rpp_sci_printf("ethinit DONE\n"); + } + return retVal; +} + +int acceptComunication(){ + + // accept communication + struct sockaddr_in clientAddr; + rtiostream_socklen_t sFdAddSize = sizeof(struct sockaddr_in); + + sockStatus = lwip_accept(socketBase, (struct sockaddr *)&clientAddr, &sFdAddSize); + socketNum = sockStatus; + + if (sockStatus == INVALID_SOCKET) { + rpp_sci_printf("accept() for comm socket failed.\n"); + lwip_close(socketBase); + return RTIOSTREAM_ERROR; + } + + return sockStatus; + +} + + +/****** VISIBLE FUNCTIONS ***************/ + +/* Function: rtIOStreamOpen ================================================= + * Abstract: + * Open the connection with the target. + */ +int rtIOStreamOpen(int argc, void * argv[]) +{ + + // rpp_sci_printf("## Open ##\n"); + + if (!isPostInitialized()) { + int errStat = ethinit(); + if (errStat < 0){ + rpp_sci_printf("Eth not initialized"); + return RTIOSTREAM_ERROR; + } + } + + // socket creation + socketBase = lwip_socket(AF_INET, SOCK_STREAM, 0); + if (socketBase == -1){ + rpp_sci_printf("ERR: lwip socket init\r\n"); + return RTIOSTREAM_ERROR; + } + + // socket options + int option = 1; + sockStatus = lwip_setsockopt(socketBase,SOL_SOCKET,SO_KEEPALIVE,(char*)&option,sizeof(option)); + if (sockStatus == -1){ + rpp_sci_printf("ERR: lwip socket opts\r\n"); + return RTIOSTREAM_ERROR; + } + + // Bind socket + struct sockaddr_in serverAddr; + rtiostream_socklen_t socketSize = (rtiostream_socklen_t) sizeof(struct sockaddr_in); + + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons((unsigned short int) PORT_RPP); + serverAddr.sin_addr.s_addr = htonl(INADDR_ANY ); + + + sockStatus = lwip_bind(socketBase, (struct sockaddr *) &serverAddr, socketSize); + if (sockStatus == -1){ + rpp_sci_printf("bind() call failed. \r\n"); + lwip_close(socketBase); + return RTIOSTREAM_ERROR; + } + + // listen socket + sockStatus = lwip_listen(socketBase, 2); + if (sockStatus == SOCK_ERR) { + rpp_sci_printf("listen() call failed.\n"); + lwip_close(socketBase); + return RTIOSTREAM_ERROR; + } + + int sockStatus = acceptComunication(); + + return sockStatus; +} + + +/* Function: rtIOStreamSend ===================================================== + * Abstract: + * Sends the specified number of bytes on the comm line. Returns the number of + * bytes sent (if successful) or a negative value if an error occurred. As long + * as an error does not occur, this function is guaranteed to set the requested + * number of bytes. + */ +int rtIOStreamSend( + int streamID, + const void * const src, + size_t size, + size_t *sizeSent) +{ + + int nSend; + const void *sendSrc = src; + + /* Ensure size is not out of range for socket API send function */ + int sizeLim = (int) MIN(size, INT_MAX); + + nSend = lwip_send(socketNum, (send_buffer_t)sendSrc, sizeLim, 0); + + if(nSend == -1){ + return RTIOSTREAM_ERROR; + } + *sizeSent = (size_t)nSend; + + return nSend; +} + + +int testCounter = 0; + +/* Function: rtIOStreamRecv ================================================ + * Abstract: + * Attempts to gets the specified number of bytes from socket. + * The number of bytes read is returned via the 'sizeRecvd' parameter. + * RTIOSTREAM_NO_ERROR is returned on success, RTIOSTREAM_ERROR is returned on + * failure. + * Function waiting for reconecting if read EOF from stream. + * + */ +int rtIOStreamRecv( + int streamID, + void * const dst, + size_t size, + size_t * sizeRecvd) +{ + + int nRecv = 0; + + /* Ensure size is not out of range for socket API recv function */ + int sizeLim = (int) MIN(size, INT_MAX); + + nRecv = lwip_recv(socketNum, dst, sizeLim, 0U); + + if (nRecv == 0 ){ + lwip_close(socketNum); + + int sockStatus = acceptComunication(); + if (sockStatus == RTIOSTREAM_ERROR){ + rpp_sci_printf("acceptComunication() failed reconnecting \n"); + } + + } + + if (nRecv == -1) { + return RTIOSTREAM_ERROR; + } + *sizeRecvd = (size_t) nRecv; + + return RTIOSTREAM_NO_ERROR; + +} + + +/* Function: rtIOStreamClose ================================================ + * Abstract: + * Close the connection. + * + */ +int rtIOStreamClose(int streamID) +{ + lwip_close(socketNum); + lwip_close(socketBase); + return RTIOSTREAM_NO_ERROR; +} -- 2.39.2