1 /****************************************************************************
3 (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
4 www.systec-electronic.com
8 Description: source file for SDO/UDP-Protocolabstractionlayer module
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions
16 1. Redistributions of source code must retain the above copyright
17 notice, this list of conditions and the following disclaimer.
19 2. Redistributions in binary form must reproduce the above copyright
20 notice, this list of conditions and the following disclaimer in the
21 documentation and/or other materials provided with the distribution.
23 3. Neither the name of SYSTEC electronic GmbH nor the names of its
24 contributors may be used to endorse or promote products derived
25 from this software without prior written permission. For written
26 permission, please contact info@systec-electronic.com.
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32 COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
34 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
35 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
36 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
38 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 POSSIBILITY OF SUCH DAMAGE.
43 If a provision of this License is or becomes illegal, invalid or
44 unenforceable in any jurisdiction, that shall not affect:
45 1. the validity or enforceability in that jurisdiction of any other
46 provision of this License; or
47 2. the validity or enforceability in other jurisdictions of that or
48 any other provision of this License.
50 -------------------------------------------------------------------------
52 $RCSfile: EplSdoUdpu.c,v $
56 $Revision: 1.8 $ $Date: 2008/10/17 15:32:32 $
63 -------------------------------------------------------------------------
67 2006/06/26 k.t.: start of the implementation
69 ****************************************************************************/
71 #include "user/EplSdoUdpu.h"
73 #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)
75 #if (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
76 #include "SocketLinuxKernel.h"
77 #include <linux/completion.h>
78 #include <linux/sched.h>
81 /***************************************************************************/
84 /* G L O B A L D E F I N I T I O N S */
87 /***************************************************************************/
89 //---------------------------------------------------------------------------
91 //---------------------------------------------------------------------------
93 #ifndef EPL_SDO_MAX_CONNECTION_UDP
94 #define EPL_SDO_MAX_CONNECTION_UDP 5
97 //---------------------------------------------------------------------------
99 //---------------------------------------------------------------------------
102 unsigned long m_ulIpAddr; // in network byte order
103 unsigned int m_uiPort; // in network byte order
109 tEplSdoUdpCon m_aSdoAbsUdpConnection[EPL_SDO_MAX_CONNECTION_UDP];
110 tEplSequLayerReceiveCb m_fpSdoAsySeqCb;
113 #if (TARGET_SYSTEM == _WIN32_)
114 HANDLE m_ThreadHandle;
115 LPCRITICAL_SECTION m_pCriticalSection;
116 CRITICAL_SECTION m_CriticalSection;
118 #elif (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
119 struct completion m_CompletionUdpThread;
121 int m_iTerminateThread;
124 } tEplSdoUdpInstance;
126 //---------------------------------------------------------------------------
127 // modul globale vars
128 //---------------------------------------------------------------------------
130 static tEplSdoUdpInstance SdoUdpInstance_g;
132 //---------------------------------------------------------------------------
133 // local function prototypes
134 //---------------------------------------------------------------------------
136 #if (TARGET_SYSTEM == _WIN32_)
137 static DWORD PUBLIC EplSdoUdpThread(LPVOID lpParameter);
139 #elif (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
140 static int EplSdoUdpThread(void *pArg_p);
143 /***************************************************************************/
146 /* C L A S S <EPL-SDO-UDP-Layer> */
149 /***************************************************************************/
151 // Description: Protocolabstraction layer for UDP
154 /***************************************************************************/
156 //=========================================================================//
158 // P U B L I C F U N C T I O N S //
160 //=========================================================================//
162 //---------------------------------------------------------------------------
164 // Function: EplSdoUdpuInit
166 // Description: init first instance of the module
170 // Parameters: pReceiveCb_p = functionpointer to Sdo-Sequence layer
174 // Returns: tEplKernel = Errorcode
179 //---------------------------------------------------------------------------
180 tEplKernel PUBLIC EplSdoUdpuInit(tEplSequLayerReceiveCb fpReceiveCb_p)
184 Ret = EplSdoUdpuAddInstance(fpReceiveCb_p);
189 //---------------------------------------------------------------------------
191 // Function: EplSdoUdpuAddInstance
193 // Description: init additional instance of the module
194 // înit socket and start Listen-Thread
198 // Parameters: pReceiveCb_p = functionpointer to Sdo-Sequence layer
202 // Returns: tEplKernel = Errorcode
207 //---------------------------------------------------------------------------
208 tEplKernel PUBLIC EplSdoUdpuAddInstance(tEplSequLayerReceiveCb fpReceiveCb_p)
212 #if (TARGET_SYSTEM == _WIN32_)
218 // set instance variables to 0
219 EPL_MEMSET(&SdoUdpInstance_g, 0x00, sizeof(SdoUdpInstance_g));
221 Ret = kEplSuccessful;
223 // save pointer to callback-function
224 if (fpReceiveCb_p != NULL) {
225 SdoUdpInstance_g.m_fpSdoAsySeqCb = fpReceiveCb_p;
227 Ret = kEplSdoUdpMissCb;
231 #if (TARGET_SYSTEM == _WIN32_)
232 // start winsock2 for win32
233 // windows specific start of socket
234 iError = WSAStartup(MAKEWORD(2, 0), &Wsa);
236 Ret = kEplSdoUdpNoSocket;
239 // create critical section for acccess of instnace variables
240 SdoUdpInstance_g.m_pCriticalSection =
241 &SdoUdpInstance_g.m_CriticalSection;
242 InitializeCriticalSection(SdoUdpInstance_g.m_pCriticalSection);
244 #elif (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
245 init_completion(&SdoUdpInstance_g.m_CompletionUdpThread);
246 SdoUdpInstance_g.m_iTerminateThread = 0;
249 SdoUdpInstance_g.m_ThreadHandle = 0;
250 SdoUdpInstance_g.m_UdpSocket = INVALID_SOCKET;
252 Ret = EplSdoUdpuConfig(INADDR_ANY, 0);
258 //---------------------------------------------------------------------------
260 // Function: EplSdoUdpuDelInstance
262 // Description: del instance of the module
263 // del socket and del Listen-Thread
270 // Returns: tEplKernel = Errorcode
275 //---------------------------------------------------------------------------
276 tEplKernel PUBLIC EplSdoUdpuDelInstance()
280 #if (TARGET_SYSTEM == _WIN32_)
284 Ret = kEplSuccessful;
286 if (SdoUdpInstance_g.m_ThreadHandle != 0) { // listen thread was started
288 #if (TARGET_SYSTEM == _WIN32_)
290 TerminateThread(SdoUdpInstance_g.m_ThreadHandle, 0);
291 if (fTermError == FALSE) {
292 Ret = kEplSdoUdpThreadError;
295 #elif (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
296 SdoUdpInstance_g.m_iTerminateThread = 1;
297 /* kill_proc(SdoUdpInstance_g.m_ThreadHandle, SIGTERM, 1 ); */
298 send_sig(SIGTERM, SdoUdpInstance_g.m_ThreadHandle, 1);
299 wait_for_completion(&SdoUdpInstance_g.m_CompletionUdpThread);
302 SdoUdpInstance_g.m_ThreadHandle = 0;
305 if (SdoUdpInstance_g.m_UdpSocket != INVALID_SOCKET) {
307 closesocket(SdoUdpInstance_g.m_UdpSocket);
308 SdoUdpInstance_g.m_UdpSocket = INVALID_SOCKET;
310 #if (TARGET_SYSTEM == _WIN32_)
311 // delete critical section
312 DeleteCriticalSection(SdoUdpInstance_g.m_pCriticalSection);
315 #if (TARGET_SYSTEM == _WIN32_)
320 #if (TARGET_SYSTEM == _WIN32_)
326 //---------------------------------------------------------------------------
328 // Function: EplSdoUdpuConfig
330 // Description: reconfigurate socket with new IP-Address
331 // -> needed for NMT ResetConfiguration
333 // Parameters: ulIpAddr_p = IpAddress in platform byte order
334 // uiPort_p = port number in platform byte order
337 // Returns: tEplKernel = Errorcode
342 //---------------------------------------------------------------------------
343 tEplKernel PUBLIC EplSdoUdpuConfig(unsigned long ulIpAddr_p,
344 unsigned int uiPort_p)
347 struct sockaddr_in Addr;
350 #if (TARGET_SYSTEM == _WIN32_)
352 unsigned long ulThreadId;
355 Ret = kEplSuccessful;
357 if (uiPort_p == 0) { // set UDP port to default port number
358 uiPort_p = EPL_C_SDO_EPL_PORT;
359 } else if (uiPort_p > 65535) {
360 Ret = kEplSdoUdpSocketError;
364 if (SdoUdpInstance_g.m_ThreadHandle != 0) { // listen thread was started
367 #if (TARGET_SYSTEM == _WIN32_)
369 TerminateThread(SdoUdpInstance_g.m_ThreadHandle, 0);
370 if (fTermError == FALSE) {
371 Ret = kEplSdoUdpThreadError;
374 #elif (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
375 SdoUdpInstance_g.m_iTerminateThread = 1;
376 /* kill_proc(SdoUdpInstance_g.m_ThreadHandle, SIGTERM, 1 ); */
377 send_sig(SIGTERM, SdoUdpInstance_g.m_ThreadHandle, 1);
378 wait_for_completion(&SdoUdpInstance_g.m_CompletionUdpThread);
379 SdoUdpInstance_g.m_iTerminateThread = 0;
382 SdoUdpInstance_g.m_ThreadHandle = 0;
385 if (SdoUdpInstance_g.m_UdpSocket != INVALID_SOCKET) {
387 iError = closesocket(SdoUdpInstance_g.m_UdpSocket);
388 SdoUdpInstance_g.m_UdpSocket = INVALID_SOCKET;
390 Ret = kEplSdoUdpSocketError;
395 SdoUdpInstance_g.m_UdpSocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
396 if (SdoUdpInstance_g.m_UdpSocket == INVALID_SOCKET) {
397 Ret = kEplSdoUdpNoSocket;
398 EPL_DBGLVL_SDO_TRACE0("EplSdoUdpuConfig: socket() failed\n");
402 Addr.sin_family = AF_INET;
403 Addr.sin_port = htons((unsigned short)uiPort_p);
404 Addr.sin_addr.s_addr = htonl(ulIpAddr_p);
406 bind(SdoUdpInstance_g.m_UdpSocket, (struct sockaddr *)&Addr,
409 //iError = WSAGetLastError();
410 EPL_DBGLVL_SDO_TRACE1
411 ("EplSdoUdpuConfig: bind() finished with %i\n", iError);
412 Ret = kEplSdoUdpNoSocket;
415 // create Listen-Thread
416 #if (TARGET_SYSTEM == _WIN32_)
420 SdoUdpInstance_g.m_ThreadHandle = CreateThread(NULL,
425 if (SdoUdpInstance_g.m_ThreadHandle == NULL) {
426 Ret = kEplSdoUdpThreadError;
429 #elif (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
431 SdoUdpInstance_g.m_ThreadHandle =
432 kernel_thread(EplSdoUdpThread, &SdoUdpInstance_g, CLONE_KERNEL);
433 if (SdoUdpInstance_g.m_ThreadHandle == 0) {
434 Ret = kEplSdoUdpThreadError;
444 //---------------------------------------------------------------------------
446 // Function: EplSdoUdpuInitCon
448 // Description: init a new connect
452 // Parameters: pSdoConHandle_p = pointer for the new connection handle
453 // uiTargetNodeId_p = NodeId of the target node
456 // Returns: tEplKernel = Errorcode
461 //---------------------------------------------------------------------------
462 tEplKernel PUBLIC EplSdoUdpuInitCon(tEplSdoConHdl * pSdoConHandle_p,
463 unsigned int uiTargetNodeId_p)
466 unsigned int uiCount;
467 unsigned int uiFreeCon;
468 tEplSdoUdpCon *pSdoUdpCon;
470 Ret = kEplSuccessful;
472 // get free entry in control structure
474 uiFreeCon = EPL_SDO_MAX_CONNECTION_UDP;
475 pSdoUdpCon = &SdoUdpInstance_g.m_aSdoAbsUdpConnection[0];
476 while (uiCount < EPL_SDO_MAX_CONNECTION_UDP) {
477 if ((pSdoUdpCon->m_ulIpAddr & htonl(0xFF)) == htonl(uiTargetNodeId_p)) { // existing connection to target node found
479 *pSdoConHandle_p = (uiCount | EPL_SDO_UDP_HANDLE);
482 } else if ((pSdoUdpCon->m_ulIpAddr == 0)
483 && (pSdoUdpCon->m_uiPort == 0)) {
490 if (uiFreeCon == EPL_SDO_MAX_CONNECTION_UDP) {
491 // error no free handle
492 Ret = kEplSdoUdpNoFreeHandle;
495 &SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiFreeCon];
496 // save infos for connection
497 pSdoUdpCon->m_uiPort = htons(EPL_C_SDO_EPL_PORT);
498 pSdoUdpCon->m_ulIpAddr = htonl(0xC0A86400 | uiTargetNodeId_p); // 192.168.100.uiTargetNodeId_p
501 *pSdoConHandle_p = (uiFreeCon | EPL_SDO_UDP_HANDLE);
510 //---------------------------------------------------------------------------
512 // Function: EplSdoUdpuSendData
514 // Description: send data using exisiting connection
518 // Parameters: SdoConHandle_p = connection handle
519 // pSrcData_p = pointer to data
520 // dwDataSize_p = number of databyte
521 // -> without asend-header!!!
523 // Returns: tEplKernel = Errorcode
528 //---------------------------------------------------------------------------
529 tEplKernel PUBLIC EplSdoUdpuSendData(tEplSdoConHdl SdoConHandle_p,
530 tEplFrame * pSrcData_p, DWORD dwDataSize_p)
534 unsigned int uiArray;
535 struct sockaddr_in Addr;
537 Ret = kEplSuccessful;
539 uiArray = (SdoConHandle_p & ~EPL_SDO_ASY_HANDLE_MASK);
540 if (uiArray >= EPL_SDO_MAX_CONNECTION_UDP) {
541 Ret = kEplSdoUdpInvalidHdl;
545 AmiSetByteToLe(&pSrcData_p->m_le_bMessageType, 0x06); // SDO
546 // target node id (for Udp = 0)
547 AmiSetByteToLe(&pSrcData_p->m_le_bDstNodeId, 0x00);
548 // set source-nodeid (for Udp = 0)
549 AmiSetByteToLe(&pSrcData_p->m_le_bSrcNodeId, 0x00);
552 dwDataSize_p += EPL_ASND_HEADER_SIZE;
555 Addr.sin_family = AF_INET;
556 #if (TARGET_SYSTEM == _WIN32_)
557 // enter critical section for process function
558 EnterCriticalSection(SdoUdpInstance_g.m_pCriticalSection);
562 (unsigned short)SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].
564 Addr.sin_addr.s_addr =
565 SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_ulIpAddr;
567 #if (TARGET_SYSTEM == _WIN32_)
568 // leave critical section for process function
569 LeaveCriticalSection(SdoUdpInstance_g.m_pCriticalSection);
572 iError = sendto(SdoUdpInstance_g.m_UdpSocket, // sockethandle
573 (const char *)&pSrcData_p->m_le_bMessageType, // data to send
574 dwDataSize_p, // number of bytes to send
576 (struct sockaddr *)&Addr, // target
577 sizeof(struct sockaddr_in)); // sizeof targetadress
579 EPL_DBGLVL_SDO_TRACE1
580 ("EplSdoUdpuSendData: sendto() finished with %i\n", iError);
581 Ret = kEplSdoUdpSendError;
590 //---------------------------------------------------------------------------
592 // Function: EplSdoUdpuDelCon
594 // Description: delete connection from intern structure
598 // Parameters: SdoConHandle_p = connection handle
600 // Returns: tEplKernel = Errorcode
605 //---------------------------------------------------------------------------
606 tEplKernel PUBLIC EplSdoUdpuDelCon(tEplSdoConHdl SdoConHandle_p)
609 unsigned int uiArray;
611 uiArray = (SdoConHandle_p & ~EPL_SDO_ASY_HANDLE_MASK);
613 if (uiArray >= EPL_SDO_MAX_CONNECTION_UDP) {
614 Ret = kEplSdoUdpInvalidHdl;
617 Ret = kEplSuccessful;
621 SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_ulIpAddr = 0;
622 SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_uiPort = 0;
628 //=========================================================================//
630 // P R I V A T E F U N C T I O N S //
632 //=========================================================================//
634 //---------------------------------------------------------------------------
636 // Function: EplSdoUdpThread
638 // Description: thread check socket for new data
642 // Parameters: lpParameter = pointer to parameter type tEplSdoUdpThreadPara
645 // Returns: DWORD = errorcode
650 //---------------------------------------------------------------------------
651 #if (TARGET_SYSTEM == _WIN32_)
652 static DWORD PUBLIC EplSdoUdpThread(LPVOID lpParameter)
653 #elif (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
654 static int EplSdoUdpThread(void *pArg_p)
658 tEplSdoUdpInstance *pInstance;
659 struct sockaddr_in RemoteAddr;
663 BYTE abBuffer[EPL_MAX_SDO_REC_FRAME_SIZE];
665 tEplSdoConHdl SdoConHdl;
667 #if (TARGET_SYSTEM == _WIN32_)
668 pInstance = (tEplSdoUdpInstance *) lpParameter;
671 #elif (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
672 pInstance = (tEplSdoUdpInstance *) pArg_p;
673 daemonize("EplSdoUdpThread");
674 allow_signal(SIGTERM);
676 for (; pInstance->m_iTerminateThread == 0;)
681 uiSize = sizeof(struct sockaddr);
682 iError = recvfrom(pInstance->m_UdpSocket, // Socket
683 (char *)&abBuffer[0], // buffer for data
684 sizeof(abBuffer), // size of the buffer
686 (struct sockaddr *)&RemoteAddr,
688 #if (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
689 if (iError == -ERESTARTSYS) {
694 // get handle for higher layer
697 #if (TARGET_SYSTEM == _WIN32_)
698 // enter critical section for process function
699 EnterCriticalSection(SdoUdpInstance_g.
702 while (iCount < EPL_SDO_MAX_CONNECTION_UDP) {
703 // check if this connection is already known
704 if ((pInstance->m_aSdoAbsUdpConnection[iCount].
705 m_ulIpAddr == RemoteAddr.sin_addr.s_addr)
707 m_aSdoAbsUdpConnection[iCount].
708 m_uiPort == RemoteAddr.sin_port)) {
712 if ((pInstance->m_aSdoAbsUdpConnection[iCount].
715 m_aSdoAbsUdpConnection[iCount].
717 && (iFreeEntry == 0xFFFF))
725 if (iCount == EPL_SDO_MAX_CONNECTION_UDP) {
726 // connection unknown
727 // see if there is a free handle
728 if (iFreeEntry != 0xFFFF) {
731 m_aSdoAbsUdpConnection[iFreeEntry].
733 RemoteAddr.sin_addr.s_addr;
735 m_aSdoAbsUdpConnection[iFreeEntry].
736 m_uiPort = RemoteAddr.sin_port;
737 #if (TARGET_SYSTEM == _WIN32_)
738 // leave critical section for process function
739 LeaveCriticalSection(SdoUdpInstance_g.
743 SdoConHdl = iFreeEntry;
744 SdoConHdl |= EPL_SDO_UDP_HANDLE;
745 // offset 4 -> start of SDO Sequence header
746 pInstance->m_fpSdoAsySeqCb(SdoConHdl,
753 EPL_DBGLVL_SDO_TRACE0
754 ("Error in EplSdoUdpThread() no free handle\n");
755 #if (TARGET_SYSTEM == _WIN32_)
756 // leave critical section for process function
757 LeaveCriticalSection(SdoUdpInstance_g.
764 // call callback with correct handle
766 SdoConHdl |= EPL_SDO_UDP_HANDLE;
767 #if (TARGET_SYSTEM == _WIN32_)
768 // leave critical section for process function
769 LeaveCriticalSection(SdoUdpInstance_g.
772 // offset 4 -> start of SDO Sequence header
773 pInstance->m_fpSdoAsySeqCb(SdoConHdl,
778 } // end of if(iError!=SOCKET_ERROR)
781 #if (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
782 complete_and_exit(&SdoUdpInstance_g.m_CompletionUdpThread, 0);
788 #endif // end of #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)