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 #include "SocketLinuxKernel.h"
76 #include <linux/completion.h>
77 #include <linux/sched.h>
79 /***************************************************************************/
82 /* G L O B A L D E F I N I T I O N S */
85 /***************************************************************************/
87 //---------------------------------------------------------------------------
89 //---------------------------------------------------------------------------
91 #ifndef EPL_SDO_MAX_CONNECTION_UDP
92 #define EPL_SDO_MAX_CONNECTION_UDP 5
95 //---------------------------------------------------------------------------
97 //---------------------------------------------------------------------------
100 unsigned long m_ulIpAddr
; // in network byte order
101 unsigned int m_uiPort
; // in network byte order
107 tEplSdoUdpCon m_aSdoAbsUdpConnection
[EPL_SDO_MAX_CONNECTION_UDP
];
108 tEplSequLayerReceiveCb m_fpSdoAsySeqCb
;
111 struct completion m_CompletionUdpThread
;
113 int m_iTerminateThread
;
114 } tEplSdoUdpInstance
;
116 //---------------------------------------------------------------------------
117 // modul globale vars
118 //---------------------------------------------------------------------------
120 static tEplSdoUdpInstance SdoUdpInstance_g
;
122 //---------------------------------------------------------------------------
123 // local function prototypes
124 //---------------------------------------------------------------------------
126 static int EplSdoUdpThread(void *pArg_p
);
128 /***************************************************************************/
131 /* C L A S S <EPL-SDO-UDP-Layer> */
134 /***************************************************************************/
136 // Description: Protocolabstraction layer for UDP
139 /***************************************************************************/
141 //=========================================================================//
143 // P U B L I C F U N C T I O N S //
145 //=========================================================================//
147 //---------------------------------------------------------------------------
149 // Function: EplSdoUdpuInit
151 // Description: init first instance of the module
155 // Parameters: pReceiveCb_p = functionpointer to Sdo-Sequence layer
159 // Returns: tEplKernel = Errorcode
164 //---------------------------------------------------------------------------
165 tEplKernel
EplSdoUdpuInit(tEplSequLayerReceiveCb fpReceiveCb_p
)
169 Ret
= EplSdoUdpuAddInstance(fpReceiveCb_p
);
174 //---------------------------------------------------------------------------
176 // Function: EplSdoUdpuAddInstance
178 // Description: init additional instance of the module
179 // înit socket and start Listen-Thread
183 // Parameters: pReceiveCb_p = functionpointer to Sdo-Sequence layer
187 // Returns: tEplKernel = Errorcode
192 //---------------------------------------------------------------------------
193 tEplKernel
EplSdoUdpuAddInstance(tEplSequLayerReceiveCb fpReceiveCb_p
)
197 // set instance variables to 0
198 EPL_MEMSET(&SdoUdpInstance_g
, 0x00, sizeof(SdoUdpInstance_g
));
200 Ret
= kEplSuccessful
;
202 // save pointer to callback-function
203 if (fpReceiveCb_p
!= NULL
) {
204 SdoUdpInstance_g
.m_fpSdoAsySeqCb
= fpReceiveCb_p
;
206 Ret
= kEplSdoUdpMissCb
;
210 init_completion(&SdoUdpInstance_g
.m_CompletionUdpThread
);
211 SdoUdpInstance_g
.m_iTerminateThread
= 0;
212 SdoUdpInstance_g
.m_ThreadHandle
= 0;
213 SdoUdpInstance_g
.m_UdpSocket
= INVALID_SOCKET
;
215 Ret
= EplSdoUdpuConfig(INADDR_ANY
, 0);
221 //---------------------------------------------------------------------------
223 // Function: EplSdoUdpuDelInstance
225 // Description: del instance of the module
226 // del socket and del Listen-Thread
233 // Returns: tEplKernel = Errorcode
238 //---------------------------------------------------------------------------
239 tEplKernel
EplSdoUdpuDelInstance(void)
243 Ret
= kEplSuccessful
;
245 if (SdoUdpInstance_g
.m_ThreadHandle
!= 0) { // listen thread was started
247 SdoUdpInstance_g
.m_iTerminateThread
= 1;
248 /* kill_proc(SdoUdpInstance_g.m_ThreadHandle, SIGTERM, 1 ); */
249 send_sig(SIGTERM
, SdoUdpInstance_g
.m_ThreadHandle
, 1);
250 wait_for_completion(&SdoUdpInstance_g
.m_CompletionUdpThread
);
251 SdoUdpInstance_g
.m_ThreadHandle
= 0;
254 if (SdoUdpInstance_g
.m_UdpSocket
!= INVALID_SOCKET
) {
256 closesocket(SdoUdpInstance_g
.m_UdpSocket
);
257 SdoUdpInstance_g
.m_UdpSocket
= INVALID_SOCKET
;
262 //---------------------------------------------------------------------------
264 // Function: EplSdoUdpuConfig
266 // Description: reconfigurate socket with new IP-Address
267 // -> needed for NMT ResetConfiguration
269 // Parameters: ulIpAddr_p = IpAddress in platform byte order
270 // uiPort_p = port number in platform byte order
273 // Returns: tEplKernel = Errorcode
278 //---------------------------------------------------------------------------
279 tEplKernel
EplSdoUdpuConfig(unsigned long ulIpAddr_p
, unsigned int uiPort_p
)
282 struct sockaddr_in Addr
;
285 Ret
= kEplSuccessful
;
287 if (uiPort_p
== 0) { // set UDP port to default port number
288 uiPort_p
= EPL_C_SDO_EPL_PORT
;
289 } else if (uiPort_p
> 65535) {
290 Ret
= kEplSdoUdpSocketError
;
294 if (SdoUdpInstance_g
.m_ThreadHandle
!= 0) { // listen thread was started
297 SdoUdpInstance_g
.m_iTerminateThread
= 1;
298 /* kill_proc(SdoUdpInstance_g.m_ThreadHandle, SIGTERM, 1 ); */
299 send_sig(SIGTERM
, SdoUdpInstance_g
.m_ThreadHandle
, 1);
300 wait_for_completion(&SdoUdpInstance_g
.m_CompletionUdpThread
);
301 SdoUdpInstance_g
.m_iTerminateThread
= 0;
302 SdoUdpInstance_g
.m_ThreadHandle
= 0;
305 if (SdoUdpInstance_g
.m_UdpSocket
!= INVALID_SOCKET
) {
307 iError
= closesocket(SdoUdpInstance_g
.m_UdpSocket
);
308 SdoUdpInstance_g
.m_UdpSocket
= INVALID_SOCKET
;
310 Ret
= kEplSdoUdpSocketError
;
315 SdoUdpInstance_g
.m_UdpSocket
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
316 if (SdoUdpInstance_g
.m_UdpSocket
== INVALID_SOCKET
) {
317 Ret
= kEplSdoUdpNoSocket
;
318 EPL_DBGLVL_SDO_TRACE0("EplSdoUdpuConfig: socket() failed\n");
322 Addr
.sin_family
= AF_INET
;
323 Addr
.sin_port
= htons((unsigned short)uiPort_p
);
324 Addr
.sin_addr
.s_addr
= htonl(ulIpAddr_p
);
326 bind(SdoUdpInstance_g
.m_UdpSocket
, (struct sockaddr
*)&Addr
,
329 //iError = WSAGetLastError();
330 EPL_DBGLVL_SDO_TRACE1
331 ("EplSdoUdpuConfig: bind() finished with %i\n", iError
);
332 Ret
= kEplSdoUdpNoSocket
;
335 // create Listen-Thread
336 SdoUdpInstance_g
.m_ThreadHandle
=
337 kernel_thread(EplSdoUdpThread
, &SdoUdpInstance_g
,
338 CLONE_FS
| CLONE_FILES
);
339 if (SdoUdpInstance_g
.m_ThreadHandle
== 0) {
340 Ret
= kEplSdoUdpThreadError
;
349 //---------------------------------------------------------------------------
351 // Function: EplSdoUdpuInitCon
353 // Description: init a new connect
357 // Parameters: pSdoConHandle_p = pointer for the new connection handle
358 // uiTargetNodeId_p = NodeId of the target node
361 // Returns: tEplKernel = Errorcode
366 //---------------------------------------------------------------------------
367 tEplKernel
EplSdoUdpuInitCon(tEplSdoConHdl
*pSdoConHandle_p
,
368 unsigned int uiTargetNodeId_p
)
371 unsigned int uiCount
;
372 unsigned int uiFreeCon
;
373 tEplSdoUdpCon
*pSdoUdpCon
;
375 Ret
= kEplSuccessful
;
377 // get free entry in control structure
379 uiFreeCon
= EPL_SDO_MAX_CONNECTION_UDP
;
380 pSdoUdpCon
= &SdoUdpInstance_g
.m_aSdoAbsUdpConnection
[0];
381 while (uiCount
< EPL_SDO_MAX_CONNECTION_UDP
) {
382 if ((pSdoUdpCon
->m_ulIpAddr
& htonl(0xFF)) == htonl(uiTargetNodeId_p
)) { // existing connection to target node found
384 *pSdoConHandle_p
= (uiCount
| EPL_SDO_UDP_HANDLE
);
387 } else if ((pSdoUdpCon
->m_ulIpAddr
== 0)
388 && (pSdoUdpCon
->m_uiPort
== 0)) {
395 if (uiFreeCon
== EPL_SDO_MAX_CONNECTION_UDP
) {
396 // error no free handle
397 Ret
= kEplSdoUdpNoFreeHandle
;
400 &SdoUdpInstance_g
.m_aSdoAbsUdpConnection
[uiFreeCon
];
401 // save infos for connection
402 pSdoUdpCon
->m_uiPort
= htons(EPL_C_SDO_EPL_PORT
);
403 pSdoUdpCon
->m_ulIpAddr
= htonl(0xC0A86400 | uiTargetNodeId_p
); // 192.168.100.uiTargetNodeId_p
406 *pSdoConHandle_p
= (uiFreeCon
| EPL_SDO_UDP_HANDLE
);
415 //---------------------------------------------------------------------------
417 // Function: EplSdoUdpuSendData
419 // Description: send data using exisiting connection
423 // Parameters: SdoConHandle_p = connection handle
424 // pSrcData_p = pointer to data
425 // dwDataSize_p = number of databyte
426 // -> without asend-header!!!
428 // Returns: tEplKernel = Errorcode
433 //---------------------------------------------------------------------------
434 tEplKernel
EplSdoUdpuSendData(tEplSdoConHdl SdoConHandle_p
,
435 tEplFrame
*pSrcData_p
, u32 dwDataSize_p
)
439 unsigned int uiArray
;
440 struct sockaddr_in Addr
;
442 Ret
= kEplSuccessful
;
444 uiArray
= (SdoConHandle_p
& ~EPL_SDO_ASY_HANDLE_MASK
);
445 if (uiArray
>= EPL_SDO_MAX_CONNECTION_UDP
) {
446 Ret
= kEplSdoUdpInvalidHdl
;
450 AmiSetByteToLe(&pSrcData_p
->m_le_bMessageType
, 0x06); // SDO
451 // target node id (for Udp = 0)
452 AmiSetByteToLe(&pSrcData_p
->m_le_bDstNodeId
, 0x00);
453 // set source-nodeid (for Udp = 0)
454 AmiSetByteToLe(&pSrcData_p
->m_le_bSrcNodeId
, 0x00);
457 dwDataSize_p
+= EPL_ASND_HEADER_SIZE
;
460 Addr
.sin_family
= AF_INET
;
462 (unsigned short)SdoUdpInstance_g
.m_aSdoAbsUdpConnection
[uiArray
].
464 Addr
.sin_addr
.s_addr
=
465 SdoUdpInstance_g
.m_aSdoAbsUdpConnection
[uiArray
].m_ulIpAddr
;
467 iError
= sendto(SdoUdpInstance_g
.m_UdpSocket
, // sockethandle
468 (const char *)&pSrcData_p
->m_le_bMessageType
, // data to send
469 dwDataSize_p
, // number of bytes to send
471 (struct sockaddr
*)&Addr
, // target
472 sizeof(struct sockaddr_in
)); // sizeof targetadress
474 EPL_DBGLVL_SDO_TRACE1
475 ("EplSdoUdpuSendData: sendto() finished with %i\n", iError
);
476 Ret
= kEplSdoUdpSendError
;
485 //---------------------------------------------------------------------------
487 // Function: EplSdoUdpuDelCon
489 // Description: delete connection from intern structure
493 // Parameters: SdoConHandle_p = connection handle
495 // Returns: tEplKernel = Errorcode
500 //---------------------------------------------------------------------------
501 tEplKernel
EplSdoUdpuDelCon(tEplSdoConHdl SdoConHandle_p
)
504 unsigned int uiArray
;
506 uiArray
= (SdoConHandle_p
& ~EPL_SDO_ASY_HANDLE_MASK
);
508 if (uiArray
>= EPL_SDO_MAX_CONNECTION_UDP
) {
509 Ret
= kEplSdoUdpInvalidHdl
;
512 Ret
= kEplSuccessful
;
516 SdoUdpInstance_g
.m_aSdoAbsUdpConnection
[uiArray
].m_ulIpAddr
= 0;
517 SdoUdpInstance_g
.m_aSdoAbsUdpConnection
[uiArray
].m_uiPort
= 0;
523 //=========================================================================//
525 // P R I V A T E F U N C T I O N S //
527 //=========================================================================//
529 //---------------------------------------------------------------------------
531 // Function: EplSdoUdpThread
533 // Description: thread check socket for new data
537 // Parameters: lpParameter = pointer to parameter type tEplSdoUdpThreadPara
540 // Returns: u32 = errorcode
545 //---------------------------------------------------------------------------
546 static int EplSdoUdpThread(void *pArg_p
)
549 tEplSdoUdpInstance
*pInstance
;
550 struct sockaddr_in RemoteAddr
;
554 u8 abBuffer
[EPL_MAX_SDO_REC_FRAME_SIZE
];
556 tEplSdoConHdl SdoConHdl
;
558 pInstance
= (tEplSdoUdpInstance
*) pArg_p
;
559 daemonize("EplSdoUdpThread");
560 allow_signal(SIGTERM
);
562 for (; pInstance
->m_iTerminateThread
== 0;)
566 uiSize
= sizeof(struct sockaddr
);
567 iError
= recvfrom(pInstance
->m_UdpSocket
, // Socket
568 (char *)&abBuffer
[0], // buffer for data
569 sizeof(abBuffer
), // size of the buffer
571 (struct sockaddr
*)&RemoteAddr
,
573 if (iError
== -ERESTARTSYS
) {
577 // get handle for higher layer
580 while (iCount
< EPL_SDO_MAX_CONNECTION_UDP
) {
581 // check if this connection is already known
582 if ((pInstance
->m_aSdoAbsUdpConnection
[iCount
].
583 m_ulIpAddr
== RemoteAddr
.sin_addr
.s_addr
)
585 m_aSdoAbsUdpConnection
[iCount
].
586 m_uiPort
== RemoteAddr
.sin_port
)) {
590 if ((pInstance
->m_aSdoAbsUdpConnection
[iCount
].
593 m_aSdoAbsUdpConnection
[iCount
].
595 && (iFreeEntry
== 0xFFFF))
603 if (iCount
== EPL_SDO_MAX_CONNECTION_UDP
) {
604 // connection unknown
605 // see if there is a free handle
606 if (iFreeEntry
!= 0xFFFF) {
609 m_aSdoAbsUdpConnection
[iFreeEntry
].
611 RemoteAddr
.sin_addr
.s_addr
;
613 m_aSdoAbsUdpConnection
[iFreeEntry
].
614 m_uiPort
= RemoteAddr
.sin_port
;
616 SdoConHdl
= iFreeEntry
;
617 SdoConHdl
|= EPL_SDO_UDP_HANDLE
;
618 // offset 4 -> start of SDO Sequence header
619 pInstance
->m_fpSdoAsySeqCb(SdoConHdl
,
626 EPL_DBGLVL_SDO_TRACE0
627 ("Error in EplSdoUdpThread() no free handle\n");
632 // call callback with correct handle
634 SdoConHdl
|= EPL_SDO_UDP_HANDLE
;
635 // offset 4 -> start of SDO Sequence header
636 pInstance
->m_fpSdoAsySeqCb(SdoConHdl
,
641 } // end of if(iError!=SOCKET_ERROR)
644 complete_and_exit(&SdoUdpInstance_g
.m_CompletionUdpThread
, 0);
648 #endif // end of #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)