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 == _LINUX_) && defined(__KERNEL__)
114 struct completion m_CompletionUdpThread;
116 int m_iTerminateThread;
119 } tEplSdoUdpInstance;
121 //---------------------------------------------------------------------------
122 // modul globale vars
123 //---------------------------------------------------------------------------
125 static tEplSdoUdpInstance SdoUdpInstance_g;
127 //---------------------------------------------------------------------------
128 // local function prototypes
129 //---------------------------------------------------------------------------
131 #if (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
132 static int EplSdoUdpThread(void *pArg_p);
135 /***************************************************************************/
138 /* C L A S S <EPL-SDO-UDP-Layer> */
141 /***************************************************************************/
143 // Description: Protocolabstraction layer for UDP
146 /***************************************************************************/
148 //=========================================================================//
150 // P U B L I C F U N C T I O N S //
152 //=========================================================================//
154 //---------------------------------------------------------------------------
156 // Function: EplSdoUdpuInit
158 // Description: init first instance of the module
162 // Parameters: pReceiveCb_p = functionpointer to Sdo-Sequence layer
166 // Returns: tEplKernel = Errorcode
171 //---------------------------------------------------------------------------
172 tEplKernel EplSdoUdpuInit(tEplSequLayerReceiveCb fpReceiveCb_p)
176 Ret = EplSdoUdpuAddInstance(fpReceiveCb_p);
181 //---------------------------------------------------------------------------
183 // Function: EplSdoUdpuAddInstance
185 // Description: init additional instance of the module
186 // înit socket and start Listen-Thread
190 // Parameters: pReceiveCb_p = functionpointer to Sdo-Sequence layer
194 // Returns: tEplKernel = Errorcode
199 //---------------------------------------------------------------------------
200 tEplKernel EplSdoUdpuAddInstance(tEplSequLayerReceiveCb fpReceiveCb_p)
204 // set instance variables to 0
205 EPL_MEMSET(&SdoUdpInstance_g, 0x00, sizeof(SdoUdpInstance_g));
207 Ret = kEplSuccessful;
209 // save pointer to callback-function
210 if (fpReceiveCb_p != NULL) {
211 SdoUdpInstance_g.m_fpSdoAsySeqCb = fpReceiveCb_p;
213 Ret = kEplSdoUdpMissCb;
217 #if (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
218 init_completion(&SdoUdpInstance_g.m_CompletionUdpThread);
219 SdoUdpInstance_g.m_iTerminateThread = 0;
222 SdoUdpInstance_g.m_ThreadHandle = 0;
223 SdoUdpInstance_g.m_UdpSocket = INVALID_SOCKET;
225 Ret = EplSdoUdpuConfig(INADDR_ANY, 0);
231 //---------------------------------------------------------------------------
233 // Function: EplSdoUdpuDelInstance
235 // Description: del instance of the module
236 // del socket and del Listen-Thread
243 // Returns: tEplKernel = Errorcode
248 //---------------------------------------------------------------------------
249 tEplKernel EplSdoUdpuDelInstance(void)
253 Ret = kEplSuccessful;
255 if (SdoUdpInstance_g.m_ThreadHandle != 0) { // listen thread was started
257 #if (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
258 SdoUdpInstance_g.m_iTerminateThread = 1;
259 /* kill_proc(SdoUdpInstance_g.m_ThreadHandle, SIGTERM, 1 ); */
260 send_sig(SIGTERM, SdoUdpInstance_g.m_ThreadHandle, 1);
261 wait_for_completion(&SdoUdpInstance_g.m_CompletionUdpThread);
264 SdoUdpInstance_g.m_ThreadHandle = 0;
267 if (SdoUdpInstance_g.m_UdpSocket != INVALID_SOCKET) {
269 closesocket(SdoUdpInstance_g.m_UdpSocket);
270 SdoUdpInstance_g.m_UdpSocket = INVALID_SOCKET;
275 //---------------------------------------------------------------------------
277 // Function: EplSdoUdpuConfig
279 // Description: reconfigurate socket with new IP-Address
280 // -> needed for NMT ResetConfiguration
282 // Parameters: ulIpAddr_p = IpAddress in platform byte order
283 // uiPort_p = port number in platform byte order
286 // Returns: tEplKernel = Errorcode
291 //---------------------------------------------------------------------------
292 tEplKernel EplSdoUdpuConfig(unsigned long ulIpAddr_p, unsigned int uiPort_p)
295 struct sockaddr_in Addr;
298 Ret = kEplSuccessful;
300 if (uiPort_p == 0) { // set UDP port to default port number
301 uiPort_p = EPL_C_SDO_EPL_PORT;
302 } else if (uiPort_p > 65535) {
303 Ret = kEplSdoUdpSocketError;
307 if (SdoUdpInstance_g.m_ThreadHandle != 0) { // listen thread was started
310 #if (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
311 SdoUdpInstance_g.m_iTerminateThread = 1;
312 /* kill_proc(SdoUdpInstance_g.m_ThreadHandle, SIGTERM, 1 ); */
313 send_sig(SIGTERM, SdoUdpInstance_g.m_ThreadHandle, 1);
314 wait_for_completion(&SdoUdpInstance_g.m_CompletionUdpThread);
315 SdoUdpInstance_g.m_iTerminateThread = 0;
318 SdoUdpInstance_g.m_ThreadHandle = 0;
321 if (SdoUdpInstance_g.m_UdpSocket != INVALID_SOCKET) {
323 iError = closesocket(SdoUdpInstance_g.m_UdpSocket);
324 SdoUdpInstance_g.m_UdpSocket = INVALID_SOCKET;
326 Ret = kEplSdoUdpSocketError;
331 SdoUdpInstance_g.m_UdpSocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
332 if (SdoUdpInstance_g.m_UdpSocket == INVALID_SOCKET) {
333 Ret = kEplSdoUdpNoSocket;
334 EPL_DBGLVL_SDO_TRACE0("EplSdoUdpuConfig: socket() failed\n");
338 Addr.sin_family = AF_INET;
339 Addr.sin_port = htons((unsigned short)uiPort_p);
340 Addr.sin_addr.s_addr = htonl(ulIpAddr_p);
342 bind(SdoUdpInstance_g.m_UdpSocket, (struct sockaddr *)&Addr,
345 //iError = WSAGetLastError();
346 EPL_DBGLVL_SDO_TRACE1
347 ("EplSdoUdpuConfig: bind() finished with %i\n", iError);
348 Ret = kEplSdoUdpNoSocket;
351 // create Listen-Thread
352 #if (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
354 SdoUdpInstance_g.m_ThreadHandle =
355 kernel_thread(EplSdoUdpThread, &SdoUdpInstance_g, CLONE_KERNEL);
356 if (SdoUdpInstance_g.m_ThreadHandle == 0) {
357 Ret = kEplSdoUdpThreadError;
367 //---------------------------------------------------------------------------
369 // Function: EplSdoUdpuInitCon
371 // Description: init a new connect
375 // Parameters: pSdoConHandle_p = pointer for the new connection handle
376 // uiTargetNodeId_p = NodeId of the target node
379 // Returns: tEplKernel = Errorcode
384 //---------------------------------------------------------------------------
385 tEplKernel EplSdoUdpuInitCon(tEplSdoConHdl *pSdoConHandle_p,
386 unsigned int uiTargetNodeId_p)
389 unsigned int uiCount;
390 unsigned int uiFreeCon;
391 tEplSdoUdpCon *pSdoUdpCon;
393 Ret = kEplSuccessful;
395 // get free entry in control structure
397 uiFreeCon = EPL_SDO_MAX_CONNECTION_UDP;
398 pSdoUdpCon = &SdoUdpInstance_g.m_aSdoAbsUdpConnection[0];
399 while (uiCount < EPL_SDO_MAX_CONNECTION_UDP) {
400 if ((pSdoUdpCon->m_ulIpAddr & htonl(0xFF)) == htonl(uiTargetNodeId_p)) { // existing connection to target node found
402 *pSdoConHandle_p = (uiCount | EPL_SDO_UDP_HANDLE);
405 } else if ((pSdoUdpCon->m_ulIpAddr == 0)
406 && (pSdoUdpCon->m_uiPort == 0)) {
413 if (uiFreeCon == EPL_SDO_MAX_CONNECTION_UDP) {
414 // error no free handle
415 Ret = kEplSdoUdpNoFreeHandle;
418 &SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiFreeCon];
419 // save infos for connection
420 pSdoUdpCon->m_uiPort = htons(EPL_C_SDO_EPL_PORT);
421 pSdoUdpCon->m_ulIpAddr = htonl(0xC0A86400 | uiTargetNodeId_p); // 192.168.100.uiTargetNodeId_p
424 *pSdoConHandle_p = (uiFreeCon | EPL_SDO_UDP_HANDLE);
433 //---------------------------------------------------------------------------
435 // Function: EplSdoUdpuSendData
437 // Description: send data using exisiting connection
441 // Parameters: SdoConHandle_p = connection handle
442 // pSrcData_p = pointer to data
443 // dwDataSize_p = number of databyte
444 // -> without asend-header!!!
446 // Returns: tEplKernel = Errorcode
451 //---------------------------------------------------------------------------
452 tEplKernel EplSdoUdpuSendData(tEplSdoConHdl SdoConHandle_p,
453 tEplFrame *pSrcData_p, DWORD dwDataSize_p)
457 unsigned int uiArray;
458 struct sockaddr_in Addr;
460 Ret = kEplSuccessful;
462 uiArray = (SdoConHandle_p & ~EPL_SDO_ASY_HANDLE_MASK);
463 if (uiArray >= EPL_SDO_MAX_CONNECTION_UDP) {
464 Ret = kEplSdoUdpInvalidHdl;
468 AmiSetByteToLe(&pSrcData_p->m_le_bMessageType, 0x06); // SDO
469 // target node id (for Udp = 0)
470 AmiSetByteToLe(&pSrcData_p->m_le_bDstNodeId, 0x00);
471 // set source-nodeid (for Udp = 0)
472 AmiSetByteToLe(&pSrcData_p->m_le_bSrcNodeId, 0x00);
475 dwDataSize_p += EPL_ASND_HEADER_SIZE;
478 Addr.sin_family = AF_INET;
480 (unsigned short)SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].
482 Addr.sin_addr.s_addr =
483 SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_ulIpAddr;
485 iError = sendto(SdoUdpInstance_g.m_UdpSocket, // sockethandle
486 (const char *)&pSrcData_p->m_le_bMessageType, // data to send
487 dwDataSize_p, // number of bytes to send
489 (struct sockaddr *)&Addr, // target
490 sizeof(struct sockaddr_in)); // sizeof targetadress
492 EPL_DBGLVL_SDO_TRACE1
493 ("EplSdoUdpuSendData: sendto() finished with %i\n", iError);
494 Ret = kEplSdoUdpSendError;
503 //---------------------------------------------------------------------------
505 // Function: EplSdoUdpuDelCon
507 // Description: delete connection from intern structure
511 // Parameters: SdoConHandle_p = connection handle
513 // Returns: tEplKernel = Errorcode
518 //---------------------------------------------------------------------------
519 tEplKernel EplSdoUdpuDelCon(tEplSdoConHdl SdoConHandle_p)
522 unsigned int uiArray;
524 uiArray = (SdoConHandle_p & ~EPL_SDO_ASY_HANDLE_MASK);
526 if (uiArray >= EPL_SDO_MAX_CONNECTION_UDP) {
527 Ret = kEplSdoUdpInvalidHdl;
530 Ret = kEplSuccessful;
534 SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_ulIpAddr = 0;
535 SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_uiPort = 0;
541 //=========================================================================//
543 // P R I V A T E F U N C T I O N S //
545 //=========================================================================//
547 //---------------------------------------------------------------------------
549 // Function: EplSdoUdpThread
551 // Description: thread check socket for new data
555 // Parameters: lpParameter = pointer to parameter type tEplSdoUdpThreadPara
558 // Returns: DWORD = errorcode
563 //---------------------------------------------------------------------------
564 static int EplSdoUdpThread(void *pArg_p)
567 tEplSdoUdpInstance *pInstance;
568 struct sockaddr_in RemoteAddr;
572 BYTE abBuffer[EPL_MAX_SDO_REC_FRAME_SIZE];
574 tEplSdoConHdl SdoConHdl;
576 #if (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
577 pInstance = (tEplSdoUdpInstance *) pArg_p;
578 daemonize("EplSdoUdpThread");
579 allow_signal(SIGTERM);
581 for (; pInstance->m_iTerminateThread == 0;)
586 uiSize = sizeof(struct sockaddr);
587 iError = recvfrom(pInstance->m_UdpSocket, // Socket
588 (char *)&abBuffer[0], // buffer for data
589 sizeof(abBuffer), // size of the buffer
591 (struct sockaddr *)&RemoteAddr,
593 #if (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
594 if (iError == -ERESTARTSYS) {
599 // get handle for higher layer
602 while (iCount < EPL_SDO_MAX_CONNECTION_UDP) {
603 // check if this connection is already known
604 if ((pInstance->m_aSdoAbsUdpConnection[iCount].
605 m_ulIpAddr == RemoteAddr.sin_addr.s_addr)
607 m_aSdoAbsUdpConnection[iCount].
608 m_uiPort == RemoteAddr.sin_port)) {
612 if ((pInstance->m_aSdoAbsUdpConnection[iCount].
615 m_aSdoAbsUdpConnection[iCount].
617 && (iFreeEntry == 0xFFFF))
625 if (iCount == EPL_SDO_MAX_CONNECTION_UDP) {
626 // connection unknown
627 // see if there is a free handle
628 if (iFreeEntry != 0xFFFF) {
631 m_aSdoAbsUdpConnection[iFreeEntry].
633 RemoteAddr.sin_addr.s_addr;
635 m_aSdoAbsUdpConnection[iFreeEntry].
636 m_uiPort = RemoteAddr.sin_port;
638 SdoConHdl = iFreeEntry;
639 SdoConHdl |= EPL_SDO_UDP_HANDLE;
640 // offset 4 -> start of SDO Sequence header
641 pInstance->m_fpSdoAsySeqCb(SdoConHdl,
648 EPL_DBGLVL_SDO_TRACE0
649 ("Error in EplSdoUdpThread() no free handle\n");
654 // call callback with correct handle
656 SdoConHdl |= EPL_SDO_UDP_HANDLE;
657 // offset 4 -> start of SDO Sequence header
658 pInstance->m_fpSdoAsySeqCb(SdoConHdl,
663 } // end of if(iError!=SOCKET_ERROR)
666 #if (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
667 complete_and_exit(&SdoUdpInstance_g.m_CompletionUdpThread, 0);
673 #endif // end of #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)