TCP broadcasting chat server to exchange CAN messages between CanFestival nodes on windows. This let user simulate a CANopen network on windows.
authoretisserant
Tue, 15 Jan 2008 09:29:29 +0100
changeset 355 12adbd08e10c
parent 354 396ac66670ad
child 356 171830d836ce
TCP broadcasting chat server to exchange CAN messages between CanFestival nodes on windows. This let user simulate a CANopen network on windows.
drivers/can_tcp_win32/.cvsignore
drivers/can_tcp_win32/Makefile.in
drivers/can_tcp_win32/Socket.cpp
drivers/can_tcp_win32/Socket.h
drivers/can_tcp_win32/can_tcp_win32.cpp
drivers/can_tcp_win32/can_tcp_win32_server.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/can_tcp_win32/.cvsignore	Tue Jan 15 09:29:29 2008 +0100
@@ -0,0 +1,4 @@
+libcanfestival_can_socket.so
+Makefile
+*.exe
+*.dll
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/can_tcp_win32/Makefile.in	Tue Jan 15 09:29:29 2008 +0100
@@ -0,0 +1,86 @@
+#! gmake
+
+#
+# Copyright (C) 2006 Edouard TISSERANT
+# 
+# This file is part of canfestival, a library implementing the canopen
+# stack
+# 
+# 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+# 
+
+CC = SUB_CC
+CXX = SUB_CXX
+LD = SUB_LD
+OPT_CFLAGS = -O2
+CFLAGS = SUB_OPT_CFLAGS
+PROG_CFLAGS = SUB_PROG_CFLAGS
+PREFIX = SUB_PREFIX
+TARGET = SUB_TARGET
+CAN_DRIVER = SUB_CAN_DRIVER
+TIMERS_DRIVER = SUB_TIMERS_DRIVER
+ENABLE_DLL_DRIVERS=SUB_ENABLE_DLL_DRIVERS
+CAN_DLL_CFLAGS=SUB_CAN_DLL_CFLAGS
+
+INCLUDES = -I../../include -I../../include/$(TARGET) -I../../include/$(CAN_DRIVER)
+
+OBJS =  Socket.o $(CAN_DRIVER).o
+
+ifeq ($(ENABLE_DLL_DRIVERS),1)
+#CFLAGS += -fPIC
+DRIVER = cyg$(CAN_DRIVER).dll
+else
+DRIVER = $(OBJS)
+endif
+
+SERVER = $(CAN_DRIVER)_server
+
+TARGET_SOFILES = $(PREFIX)/lib/$(DRIVER)
+
+all: driver
+
+driver: $(DRIVER) $(SERVER).exe
+
+$(SERVER).exe: Socket.o $(SERVER).cpp
+	$(CXX) $(CFLAGS) $(PROG_CFLAGS) ${PROGDEFINES} $(INCLUDES) $^ -o $@ -lws2_32
+
+Socket.o: Socket.cpp Socket.h
+	$(CXX) $(CFLAGS) $(PROG_CFLAGS) ${PROGDEFINES} $(INCLUDES) -c $< -o $@
+
+%o: %c
+	$(CC) $(CFLAGS) $(PROG_CFLAGS) ${PROGDEFINES} $(INCLUDES) -o $@ -c $<
+
+%o: %cpp
+	$(CXX) $(CFLAGS) $(PROG_CFLAGS) ${PROGDEFINES} $(INCLUDES) -o $@ -c $<
+
+$(DRIVER): $(OBJS)
+	$(LD) $(PROG_CFLAGS) -shared -o $@ \
+	-Wl,--export-all-symbols \
+	-Wl,--enable-auto-import \
+	-Wl,--whole-archive $^ \
+	-Wl,--no-whole-archive $(CAN_DLL_CFLAGS) \
+	-Wl,--exclude-libs,ALL -lws2_32
+		
+install: libcanfestival_$(CAN_DRIVER).so
+	mkdir -p $(PREFIX)/lib/
+	cp $< $(PREFIX)/lib/
+		
+uninstall:
+	rm -f $(TARGET_SOFILES)
+
+clean:
+	rm -f $(OBJS)
+
+mrproper: clean
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/can_tcp_win32/Socket.cpp	Tue Jan 15 09:29:29 2008 +0100
@@ -0,0 +1,249 @@
+/* 
+   Socket.cpp
+
+   Copyright (C) 2002-2004 René Nyffenegger
+
+   This source code is provided 'as-is', without any express or implied
+   warranty. In no event will the author be held liable for any damages
+   arising from the use of this software.
+
+   Permission is granted to anyone to use this software for any purpose,
+   including commercial applications, and to alter it and redistribute it
+   freely, subject to the following restrictions:
+
+   1. The origin of this source code must not be misrepresented; you must not
+      claim that you wrote the original source code. If you use this source code
+      in a product, an acknowledgment in the product documentation would be
+      appreciated but is not required.
+
+   2. Altered source versions must be plainly marked as such, and must not be
+      misrepresented as being the original source code.
+
+   3. This notice may not be removed or altered from any source distribution.
+
+   René Nyffenegger rene.nyffenegger@adp-gmbh.ch
+*/
+
+
+#include "Socket.h"
+#include <iostream>
+
+using namespace std;
+
+int Socket::nofSockets_= 0;
+
+void Socket::Start() {
+  if (!nofSockets_) {
+    WSADATA info;
+    if (WSAStartup(MAKEWORD(2,0), &info)) {
+      throw "Could not start WSA";
+    }
+  }
+  ++nofSockets_;
+}
+
+void Socket::End() {
+  WSACleanup();
+}
+
+Socket::Socket() : s_(0) {
+  Start();
+  // UDP: use SOCK_DGRAM instead of SOCK_STREAM
+  s_ = socket(AF_INET,SOCK_STREAM,0);
+
+  if (s_ == INVALID_SOCKET) {
+    throw "INVALID_SOCKET";
+  }
+
+  refCounter_ = new int(1);
+}
+
+Socket::Socket(SOCKET s) : s_(s) {
+  Start();
+  refCounter_ = new int(1);
+};
+
+Socket::~Socket() {
+  if (! --(*refCounter_)) {
+    Close();
+    delete refCounter_;
+  }
+
+  --nofSockets_;
+  if (!nofSockets_) End();
+}
+
+Socket::Socket(const Socket& o) {
+  refCounter_=o.refCounter_;
+  (*refCounter_)++;
+  s_         =o.s_;
+
+  nofSockets_++;
+}
+
+Socket& Socket::operator=(Socket& o) {
+  (*o.refCounter_)++;
+
+  refCounter_=o.refCounter_;
+  s_         =o.s_;
+
+  nofSockets_++;
+
+  return *this;
+}
+
+void Socket::Close() {
+  closesocket(s_);
+}
+
+std::string Socket::ReceiveBytes() {
+  std::string ret;
+  char buf[1024];
+ 
+  while (1) {
+    u_long arg = 0;
+    if (ioctlsocket(s_, FIONREAD, &arg) != 0)
+      break;
+
+    if (arg == 0)
+      break;
+
+    if (arg > 1024) arg = 1024;
+
+    int rv = recv (s_, buf, arg, 0);
+    if (rv <= 0) break;
+
+    std::string t;
+
+    t.assign (buf, rv);
+    ret += t;
+  }
+ 
+  return ret;
+}
+
+std::string Socket::ReceiveLine() {
+  std::string ret;
+  while (1) {
+    char r;
+
+    switch(recv(s_, &r, 1, 0)) {
+      case 0: // not connected anymore;
+              // ... but last line sent
+              // might not end in \n,
+              // so return ret anyway.
+        return ret;
+      case -1:
+        return "";
+//      if (errno == EAGAIN) {
+//        return ret;
+//      } else {
+//      // not connected anymore
+//      return "";
+//      }
+    }
+
+    if (r == '\n')  return ret;
+    ret += r;
+  }
+}
+
+void Socket::SendLine(std::string s) {
+  s += '\n';
+  send(s_,s.c_str(),s.length(),0);
+}
+
+void Socket::SendBytes(const std::string& s) {
+  send(s_,s.c_str(),s.length(),0);
+}
+
+SocketServer::SocketServer(int port, int connections, TypeSocket type) {
+  sockaddr_in sa;
+
+  memset(&sa, 0, sizeof(sa));
+
+  sa.sin_family = PF_INET;             
+  sa.sin_port = htons(port);          
+  s_ = socket(AF_INET, SOCK_STREAM, 0);
+  if (s_ == INVALID_SOCKET) {
+    throw "INVALID_SOCKET";
+  }
+
+  if(type==NonBlockingSocket) {
+    u_long arg = 1;
+    ioctlsocket(s_, FIONBIO, &arg);
+  }
+
+  /* bind the socket to the internet address */
+  if (bind(s_, (sockaddr *)&sa, sizeof(sockaddr_in)) == SOCKET_ERROR) {
+    closesocket(s_);
+    throw "INVALID_SOCKET";
+  }
+  
+  listen(s_, connections);                               
+}
+
+Socket* SocketServer::Accept() {
+  SOCKET new_sock = accept(s_, 0, 0);
+  if (new_sock == INVALID_SOCKET) {
+    int rc = WSAGetLastError();
+    if(rc==WSAEWOULDBLOCK) {
+      return 0; // non-blocking call, no request pending
+    }
+    else {
+      throw "Invalid Socket";
+    }
+  }
+
+  Socket* r = new Socket(new_sock);
+  return r;
+}
+
+SocketClient::SocketClient(const std::string& host, int port) : Socket() {
+  std::string error;
+
+  hostent *he;
+  if ((he = gethostbyname(host.c_str())) == 0) {
+    error = strerror(errno);
+    throw error;
+  }
+
+  sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons(port);
+  addr.sin_addr = *((in_addr *)he->h_addr);
+  memset(&(addr.sin_zero), 0, 8); 
+
+  if (::connect(s_, (sockaddr *) &addr, sizeof(sockaddr))) {
+    error = strerror(WSAGetLastError());
+    throw error;
+  }
+}
+
+SocketSelect::SocketSelect(Socket const * const s1, Socket const * const s2, TypeSocket type) {
+  FD_ZERO(&fds_);
+  FD_SET(const_cast<Socket*>(s1)->s_,&fds_);
+  if(s2) {
+    FD_SET(const_cast<Socket*>(s2)->s_,&fds_);
+  }     
+
+  TIMEVAL tval;
+  tval.tv_sec  = 0;
+  tval.tv_usec = 1;
+
+  TIMEVAL *ptval;
+  if(type==NonBlockingSocket) {
+    ptval = &tval;
+  }
+  else { 
+    ptval = 0;
+  }
+
+  if (select (0, &fds_, (fd_set*) 0, (fd_set*) 0, ptval) == SOCKET_ERROR) 
+    throw "Error in select";
+}
+
+bool SocketSelect::Readable(Socket const* const s) {
+  if (FD_ISSET(s->s_,&fds_)) return true;
+  return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/can_tcp_win32/Socket.h	Tue Jan 15 09:29:29 2008 +0100
@@ -0,0 +1,100 @@
+/* 
+   Socket.h
+
+   Copyright (C) 2002-2004 René Nyffenegger
+
+   This source code is provided 'as-is', without any express or implied
+   warranty. In no event will the author be held liable for any damages
+   arising from the use of this software.
+
+   Permission is granted to anyone to use this software for any purpose,
+   including commercial applications, and to alter it and redistribute it
+   freely, subject to the following restrictions:
+
+   1. The origin of this source code must not be misrepresented; you must not
+      claim that you wrote the original source code. If you use this source code
+      in a product, an acknowledgment in the product documentation would be
+      appreciated but is not required.
+
+   2. Altered source versions must be plainly marked as such, and must not be
+      misrepresented as being the original source code.
+
+   3. This notice may not be removed or altered from any source distribution.
+
+   René Nyffenegger rene.nyffenegger@adp-gmbh.ch
+*/
+
+#ifndef SOCKET_H
+#define SOCKET_H
+
+#include <winsock2.h>
+
+#include <string>
+
+enum TypeSocket {BlockingSocket, NonBlockingSocket};
+
+class Socket {
+public:
+
+  virtual ~Socket();
+  Socket(const Socket&);
+  Socket& operator=(Socket&);
+
+  std::string ReceiveLine();
+  std::string ReceiveBytes();
+
+  void   Close();
+
+  // The parameter of SendLine is not a const reference
+  // because SendLine modifes the std::string passed.
+  void   SendLine (std::string);
+
+  // The parameter of SendBytes is a const reference
+  // because SendBytes does not modify the std::string passed 
+  // (in contrast to SendLine).
+  void   SendBytes(const std::string&);
+
+protected:
+  friend class SocketServer;
+  friend class SocketSelect;
+
+  Socket(SOCKET s);
+  Socket();
+
+
+  SOCKET s_;
+
+  int* refCounter_;
+
+private:
+  static void Start();
+  static void End();
+  static int  nofSockets_;
+};
+
+class SocketClient : public Socket {
+public:
+  SocketClient(const std::string& host, int port);
+};
+
+class SocketServer : public Socket {
+public:
+  SocketServer(int port, int connections, TypeSocket type=BlockingSocket);
+
+  Socket* Accept();
+};
+
+// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/wsapiref_2tiq.asp
+class SocketSelect {
+  public:
+    SocketSelect(Socket const * const s1, Socket const * const s2=NULL, TypeSocket type=BlockingSocket);
+
+    bool Readable(Socket const * const s);
+
+  private:
+    fd_set fds_;
+}; 
+
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/can_tcp_win32/can_tcp_win32.cpp	Tue Jan 15 09:29:29 2008 +0100
@@ -0,0 +1,120 @@
+/*
+This file is part of CanFestival, a library implementing CanOpen Stack. 
+
+Copyright (C): Edouard TISSERANT
+
+See COPYING file for copyrights details.
+
+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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "Socket.h"
+
+#include <iostream>
+
+using namespace std;
+
+extern "C" {
+#include "can_driver.h"
+}
+
+//------------------------------------------------------------------------
+extern "C"
+   UNS8 canReceive_driver(CAN_HANDLE fd0, Message *m)
+   {
+
+      string l = reinterpret_cast<SocketClient*>(fd0)->ReceiveLine();
+
+      int res = sscanf(l.c_str(),"{0x%3hx,%1hhd,%1hhd,{0x%2hhx,0x%2hhx,0x%2hhx,0x%2hhx,0x%2hhx,0x%2hhx,0x%2hhx,0x%2hhx}}",
+                &m->cob_id,
+                &m->rtr,
+                &m->len,
+                &m->data[0],
+                &m->data[1],
+                &m->data[2],
+                &m->data[3],
+                &m->data[4],
+                &m->data[5],
+                &m->data[6],
+                &m->data[7]
+                );
+
+
+#if defined DEBUG_MSG_CONSOLE_ON
+  printf("in : ");
+  print_message(m);
+#endif
+   
+      return res==11 ? 0 : 1 ;
+   }
+
+extern "C"
+   UNS8 canSend_driver(CAN_HANDLE fd0, Message *m)
+   {
+        char s[1024];        
+        sprintf(s,"{0x%3.3x,%1d,%1d,{0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x}}",
+                m->cob_id,
+                m->rtr,
+                m->len,
+                m->data[0],
+                m->data[1],
+                m->data[2],
+                m->data[3],
+                m->data[4],
+                m->data[5],
+                m->data[6],
+                m->data[7]
+                );
+    
+        reinterpret_cast<SocketClient*>(fd0)->SendLine(s);
+#if defined DEBUG_MSG_CONSOLE_ON
+  printf("out : ");
+  print_message(m);
+#endif
+        return 0;
+   }
+
+extern "C"
+   CAN_HANDLE canOpen_driver(s_BOARD *board)
+   {
+      Socket* s;
+      try {
+        s = new SocketClient(board->busname, 11898);
+    
+        //s.SendLine("GET / HTTP/1.0");
+        //s.SendLine("Host: www.google.com");
+      } 
+      catch (const char* _s) {
+        cerr << _s << endl;
+        return NULL;
+      } 
+      catch (std::string _s) {
+        cerr << _s << endl;
+        return NULL;
+      } 
+      catch (...) {
+        cerr << "unhandled exception\n";
+        return NULL;
+      }
+      return (CAN_HANDLE) s;
+   }
+
+extern "C"
+   int canClose_driver(CAN_HANDLE inst)
+   {
+   delete reinterpret_cast<SocketClient*>(inst);
+   return 1;
+   }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/can_tcp_win32/can_tcp_win32_server.cpp	Tue Jan 15 09:29:29 2008 +0100
@@ -0,0 +1,86 @@
+/*
+This file is part of CanFestival, a library implementing CanOpen Stack. 
+
+Copyright (C): Edouard TISSERANT
+
+See COPYING file for copyrights details.
+
+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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "Socket.h"
+#include <iostream>
+#include <process.h>
+#include <string>
+#include <list>
+
+using namespace std;
+
+typedef std::list<Socket*> socket_list;
+
+socket_list g_connections;
+
+unsigned __stdcall Connection(void* a) {
+  Socket* s = (Socket*) a;
+
+  g_connections.push_back(s);
+
+  //s->SendLine("Welcome to the Message Distributor");
+  printf("Accepted new connection (0x%x).\n");
+  while (1) {
+    std::string r = s->ReceiveLine();
+    if (r.empty()) break;
+    //cout << r  << endl;    
+    for (socket_list::iterator os =g_connections.begin();
+                               os!=g_connections.end(); 
+                               os++) {
+      if (*os != s) (*os)->SendLine(r);
+    }
+  }
+
+  g_connections.remove(s);
+
+  delete s;
+
+  printf("Connection closed (0x%x).\n",s);
+
+  return 0;
+}
+
+int main() {
+  printf("************************************************\n"
+		 "* TCP broadcasting chat server for CanFestival *\n"
+		 "*  for use with can_tcp_win32 CAN driver DLL   *\n"
+		 "************************************************\n"
+		 "\n"
+		 "Accepts connections on port 11898\n"
+		 "and repeat '\\n' terminated lines \n"
+		 "to each connected client\n"
+		 "\n"
+		 "Use netcat to monitor trafic\n"
+		 " nc 127.0.0.1 11898\n"
+		 "\n");
+  
+  SocketServer in(11898,5);
+  
+  while (1) {
+    Socket* s=in.Accept();
+  
+    unsigned ret;
+    _beginthreadex(0,0,Connection,(void*) s,0,&ret);
+  }
+  
+  return 0;
+}