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, CLONE_KERNEL);
338 if (SdoUdpInstance_g.m_ThreadHandle == 0) {
339 Ret = kEplSdoUdpThreadError;
348 //---------------------------------------------------------------------------
350 // Function: EplSdoUdpuInitCon
352 // Description: init a new connect
356 // Parameters: pSdoConHandle_p = pointer for the new connection handle
357 // uiTargetNodeId_p = NodeId of the target node
360 // Returns: tEplKernel = Errorcode
365 //---------------------------------------------------------------------------
366 tEplKernel EplSdoUdpuInitCon(tEplSdoConHdl *pSdoConHandle_p,
367 unsigned int uiTargetNodeId_p)
370 unsigned int uiCount;
371 unsigned int uiFreeCon;
372 tEplSdoUdpCon *pSdoUdpCon;
374 Ret = kEplSuccessful;
376 // get free entry in control structure
378 uiFreeCon = EPL_SDO_MAX_CONNECTION_UDP;
379 pSdoUdpCon = &SdoUdpInstance_g.m_aSdoAbsUdpConnection[0];
380 while (uiCount < EPL_SDO_MAX_CONNECTION_UDP) {
381 if ((pSdoUdpCon->m_ulIpAddr & htonl(0xFF)) == htonl(uiTargetNodeId_p)) { // existing connection to target node found
383 *pSdoConHandle_p = (uiCount | EPL_SDO_UDP_HANDLE);
386 } else if ((pSdoUdpCon->m_ulIpAddr == 0)
387 && (pSdoUdpCon->m_uiPort == 0)) {
394 if (uiFreeCon == EPL_SDO_MAX_CONNECTION_UDP) {
395 // error no free handle
396 Ret = kEplSdoUdpNoFreeHandle;
399 &SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiFreeCon];
400 // save infos for connection
401 pSdoUdpCon->m_uiPort = htons(EPL_C_SDO_EPL_PORT);
402 pSdoUdpCon->m_ulIpAddr = htonl(0xC0A86400 | uiTargetNodeId_p); // 192.168.100.uiTargetNodeId_p
405 *pSdoConHandle_p = (uiFreeCon | EPL_SDO_UDP_HANDLE);
414 //---------------------------------------------------------------------------
416 // Function: EplSdoUdpuSendData
418 // Description: send data using exisiting connection
422 // Parameters: SdoConHandle_p = connection handle
423 // pSrcData_p = pointer to data
424 // dwDataSize_p = number of databyte
425 // -> without asend-header!!!
427 // Returns: tEplKernel = Errorcode
432 //---------------------------------------------------------------------------
433 tEplKernel EplSdoUdpuSendData(tEplSdoConHdl SdoConHandle_p,
434 tEplFrame *pSrcData_p, u32 dwDataSize_p)
438 unsigned int uiArray;
439 struct sockaddr_in Addr;
441 Ret = kEplSuccessful;
443 uiArray = (SdoConHandle_p & ~EPL_SDO_ASY_HANDLE_MASK);
444 if (uiArray >= EPL_SDO_MAX_CONNECTION_UDP) {
445 Ret = kEplSdoUdpInvalidHdl;
449 AmiSetByteToLe(&pSrcData_p->m_le_bMessageType, 0x06); // SDO
450 // target node id (for Udp = 0)
451 AmiSetByteToLe(&pSrcData_p->m_le_bDstNodeId, 0x00);
452 // set source-nodeid (for Udp = 0)
453 AmiSetByteToLe(&pSrcData_p->m_le_bSrcNodeId, 0x00);
456 dwDataSize_p += EPL_ASND_HEADER_SIZE;
459 Addr.sin_family = AF_INET;
461 (unsigned short)SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].
463 Addr.sin_addr.s_addr =
464 SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_ulIpAddr;
466 iError = sendto(SdoUdpInstance_g.m_UdpSocket, // sockethandle
467 (const char *)&pSrcData_p->m_le_bMessageType, // data to send
468 dwDataSize_p, // number of bytes to send
470 (struct sockaddr *)&Addr, // target
471 sizeof(struct sockaddr_in)); // sizeof targetadress
473 EPL_DBGLVL_SDO_TRACE1
474 ("EplSdoUdpuSendData: sendto() finished with %i\n", iError);
475 Ret = kEplSdoUdpSendError;
484 //---------------------------------------------------------------------------
486 // Function: EplSdoUdpuDelCon
488 // Description: delete connection from intern structure
492 // Parameters: SdoConHandle_p = connection handle
494 // Returns: tEplKernel = Errorcode
499 //---------------------------------------------------------------------------
500 tEplKernel EplSdoUdpuDelCon(tEplSdoConHdl SdoConHandle_p)
503 unsigned int uiArray;
505 uiArray = (SdoConHandle_p & ~EPL_SDO_ASY_HANDLE_MASK);
507 if (uiArray >= EPL_SDO_MAX_CONNECTION_UDP) {
508 Ret = kEplSdoUdpInvalidHdl;
511 Ret = kEplSuccessful;
515 SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_ulIpAddr = 0;
516 SdoUdpInstance_g.m_aSdoAbsUdpConnection[uiArray].m_uiPort = 0;
522 //=========================================================================//
524 // P R I V A T E F U N C T I O N S //
526 //=========================================================================//
528 //---------------------------------------------------------------------------
530 // Function: EplSdoUdpThread
532 // Description: thread check socket for new data
536 // Parameters: lpParameter = pointer to parameter type tEplSdoUdpThreadPara
539 // Returns: u32 = errorcode
544 //---------------------------------------------------------------------------
545 static int EplSdoUdpThread(void *pArg_p)
548 tEplSdoUdpInstance *pInstance;
549 struct sockaddr_in RemoteAddr;
553 u8 abBuffer[EPL_MAX_SDO_REC_FRAME_SIZE];
555 tEplSdoConHdl SdoConHdl;
557 pInstance = (tEplSdoUdpInstance *) pArg_p;
558 daemonize("EplSdoUdpThread");
559 allow_signal(SIGTERM);
561 for (; pInstance->m_iTerminateThread == 0;)
565 uiSize = sizeof(struct sockaddr);
566 iError = recvfrom(pInstance->m_UdpSocket, // Socket
567 (char *)&abBuffer[0], // buffer for data
568 sizeof(abBuffer), // size of the buffer
570 (struct sockaddr *)&RemoteAddr,
572 if (iError == -ERESTARTSYS) {
576 // get handle for higher layer
579 while (iCount < EPL_SDO_MAX_CONNECTION_UDP) {
580 // check if this connection is already known
581 if ((pInstance->m_aSdoAbsUdpConnection[iCount].
582 m_ulIpAddr == RemoteAddr.sin_addr.s_addr)
584 m_aSdoAbsUdpConnection[iCount].
585 m_uiPort == RemoteAddr.sin_port)) {
589 if ((pInstance->m_aSdoAbsUdpConnection[iCount].
592 m_aSdoAbsUdpConnection[iCount].
594 && (iFreeEntry == 0xFFFF))
602 if (iCount == EPL_SDO_MAX_CONNECTION_UDP) {
603 // connection unknown
604 // see if there is a free handle
605 if (iFreeEntry != 0xFFFF) {
608 m_aSdoAbsUdpConnection[iFreeEntry].
610 RemoteAddr.sin_addr.s_addr;
612 m_aSdoAbsUdpConnection[iFreeEntry].
613 m_uiPort = RemoteAddr.sin_port;
615 SdoConHdl = iFreeEntry;
616 SdoConHdl |= EPL_SDO_UDP_HANDLE;
617 // offset 4 -> start of SDO Sequence header
618 pInstance->m_fpSdoAsySeqCb(SdoConHdl,
625 EPL_DBGLVL_SDO_TRACE0
626 ("Error in EplSdoUdpThread() no free handle\n");
631 // call callback with correct handle
633 SdoConHdl |= EPL_SDO_UDP_HANDLE;
634 // offset 4 -> start of SDO Sequence header
635 pInstance->m_fpSdoAsySeqCb(SdoConHdl,
640 } // end of if(iError!=SOCKET_ERROR)
643 complete_and_exit(&SdoUdpInstance_g.m_CompletionUdpThread, 0);
647 #endif // end of #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)