1 /*
2  * MBDyn (C) is a multibody analysis code.
3  * http://www.mbdyn.org
4  *
5  * Copyright (C) 1996-2005
6  *
7  * Pierangelo Masarati	<masarati@aero.polimi.it>
8  * Paolo Mantegazza	<mantegazza@aero.polimi.it>
9  *
10  * Dipartimento di Ingegneria Aerospaziale - Politecnico di Milano
11  * via La Masa, 34 - 20156 Milano, Italy
12  * http://www.aero.polimi.it
13  *
14  * Changing this copyright notice is forbidden.
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation (version 2 of the License).
19  *
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29  */
30 
31 /*
32  * COPYRIGHT (C) 2003-2004
33  *
34  * Michele Attolico <attolico@aero.polimi.it>
35  *
36  * This library is free software; you can redistribute it and/or
37  * modify it under the terms of the GNU Lesser General Public
38  * License as published by the Free Software Foundation; either
39  * version 2 of the License, or (at your option) any later version.
40  *
41  * This library is distributed in the hope that it will be useful,
42  * but WITHOUT ANY WARRANTY; without even the implied warranty of
43  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
44  * Lesser General Public License for more details.
45  *
46  * You should have received a copy of the GNU Lesser General Public
47  * License along with this library; if not, write to the Free Software
48  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
49  */
50 
51 #undef VERBOSE
52 
53 #define S_FUNCTION_NAME		sfun_mbdyn_com_read
54 #define S_FUNCTION_LEVEL	2
55 
56 #ifdef MATLAB_MEX_FILE
57 #include "mex.h"
58 #endif
59 #include "simstruc.h"
60 
61 #define HOST_NAME_PARAM		ssGetSFcnParam(S, 0)
62 #define MBD_NAME_PARAM		ssGetSFcnParam(S, 1)
63 #define MBX_NAME_PARAM		ssGetSFcnParam(S, 2)
64 #define MBX_N_CHN_PARAM		ssGetSFcnParam(S, 3)
65 #define SAMPLE_TIME_PARAM	ssGetSFcnParam(S, 4)
66 
67 #define NET_PARAM		ssGetSFcnParam(S, 5)
68 #define PORT_PARAM		ssGetSFcnParam(S, 6)
69 #define PATH_PARAM		ssGetSFcnParam(S, 7)
70 
71 #define NUMBER_OF_PARAMS	(8)
72 
73 #define WAIT_LOOP  (10000)
74 
75 #define MBX_N_CHN		((uint_T) mxGetPr(MBX_N_CHN_PARAM)[0])
76 #define SAMPLE_TIME		((real_T) mxGetPr(SAMPLE_TIME_PARAM)[0])
77 
78 #define NET			((uint_T) mxGetPr(NET_PARAM)[0])
79 #define PORT			((uint_T) mxGetPr(PORT_PARAM)[0])
80 
81 #define NANO_SAMPLE_TIME	((long int)(SAMPLE_TIME*1000000000))
82 
83 #include <errno.h>
84 #include <stdio.h>
85 #include <unistd.h>
86 #include <sys/types.h>
87 #include <sys/mman.h>
88 #include <sys/stat.h>
89 #include <fcntl.h>
90 #include <sys/param.h>
91 #include <netdb.h>
92 #include <netinet/in.h>
93 #include <arpa/inet.h>
94 
95 #ifndef MATLAB_MEX_FILE
96 
97 #define KEEP_STATIC_INLINE
98 #include <math.h>
99 #include <rtai_lxrt.h>
100 #include <rtai_mbx.h>
101 #include <rtai_netrpc.h>
102 #include "mbdyn_rtai.h"
103 
104 extern long int 	MBDynNode[];
105 extern unsigned long	MBDynName[];
106 extern bool		MBDynTaskActive[];
107 
108 static char		msg = 't';
109 extern RT_TASK		*rt_HostInterfaceTask;
110 struct mbd_t {
111 	void		*comptr;
112 	unsigned long	node;
113 	int		port;
114 	int		mbdtask_count;
115 	int		err_count;
116 	int		step_count;
117 	double		*buffer;
118 };
119 
120 #else
121 
122 #include <string.h>
123 #include <stdlib.h>
124 #include <sys/socket.h>
125 #include <sys/un.h>
126 #include <sys/poll.h>
127 
128 #define TIME_OUT	10000	/* milliseconds */
129 
130 #endif /* MATLAB_MEX_FILE */
131 
132 #define MDL_CHECK_PARAMETERS
133 #if defined(MDL_CHECK_PARAMETERS) && defined(MATLAB_MEX_FILE)
134 static void
mdlCheckParameters(SimStruct * S)135 mdlCheckParameters(SimStruct *S)
136 {
137 	static char_T errMsg[BUFSIZ];
138 
139 	if (mxGetNumberOfElements(MBX_N_CHN_PARAM) != 1) {
140 		snprintf(errMsg, sizeof(errMsg),
141 			"Channel parameter must be a scalar.\n");
142 		ssSetErrorStatus(S, errMsg);
143 	}
144 
145 	if (mxGetNumberOfElements(SAMPLE_TIME_PARAM) != 1) {
146 		snprintf(errMsg, sizeof(errMsg),
147 			"Sample time parameter must be a scalar\n");
148 		ssSetErrorStatus(S, errMsg);
149 	}
150 
151 	if (mxGetNumberOfElements(PORT_PARAM) != 1) {
152 		snprintf(errMsg, sizeof(errMsg),
153 			"Port parameter must be a scalar\n");
154 		ssSetErrorStatus(S, errMsg);
155 	}
156 
157 	if (NET) {
158 		if (PORT == 0) {
159 			snprintf(errMsg, sizeof(errMsg),
160 				"Port must be defined\n");
161 			ssSetErrorStatus(S, errMsg);
162 		}
163 	}
164 }
165 #endif /* MDL_CHECK_PARAMETERS && MATLAB_MEX_FILE */
166 
167 static void
mdlInitializeSizes(SimStruct * S)168 mdlInitializeSizes(SimStruct *S)
169 {
170 	uint_T i;
171 
172 	ssSetNumSFcnParams(S, NUMBER_OF_PARAMS);
173 #if defined(MATLAB_MEX_FILE)
174 	if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) {
175 		mdlCheckParameters(S);
176 		if (ssGetErrorStatus(S) != NULL) {
177 			return;
178 		}
179 
180 	} else {
181 		return;
182 	}
183 #endif /* MATLAB_MEX_FILE */
184 
185 	for (i = 0; i < NUMBER_OF_PARAMS; i++) {
186 		ssSetSFcnParamNotTunable(S, i);
187 	}
188 	ssSetNumInputPorts(S, 0);
189 	ssSetNumOutputPorts(S, MBX_N_CHN);
190 	for (i = 0; i < MBX_N_CHN; i++) {
191 		ssSetOutputPortWidth(S, i, 1);
192 	}
193 
194 	ssSetNumContStates(S, 0);
195 	ssSetNumDiscStates(S, 0);
196 	ssSetNumSampleTimes(S, 1);
197 	ssSetNumPWork(S, 1);
198 
199 #ifdef MATLAB_MEX_FILE
200 	ssSetNumIWork(S, 2);
201 #endif /* MATLAB_MEX_FILE */
202 }
203 
204 static void
mdlInitializeSampleTimes(SimStruct * S)205 mdlInitializeSampleTimes(SimStruct *S)
206 {
207 	ssSetSampleTime(S, 0, SAMPLE_TIME);
208 	ssSetOffsetTime(S, 0, 0.0);
209 }
210 
211 #define MDL_START
212 #if defined(MDL_START)
213 static void
mdlStart(SimStruct * S)214 mdlStart(SimStruct *S)
215 {
216 #ifndef MATLAB_MEX_FILE
217 	struct mbd_t		*ptrstr = NULL;
218 	static char_T		errMsg[BUFSIZ];
219 	register int		i;
220 	char			mbx_name[7], mbd_name[7];
221 	struct in_addr		addr;
222 
223 	char			host_name[MAXHOSTNAMELEN];
224 	void			*mbdtask = NULL;
225 	int			timerflag = 0, count = 0;
226 
227 	mxGetString(MBD_NAME_PARAM, mbd_name, 7);
228 	mxGetString(MBX_NAME_PARAM, mbx_name, 7);
229 
230 	/******************************************************************
231 	 * alloc struct
232 	 ******************************************************************/
233 
234 	ptrstr = (struct mbd_t *)malloc(sizeof(struct mbd_t));
235 	if (!ptrstr) {
236 		snprintf(errMsg, sizeof(errMsg),
237 			"\ncannot alloc memory for struct mbd_t\n");
238 		ssSetErrorStatus(S, errMsg);
239 		printf("%s", errMsg);
240 	}
241 	ssGetPWork(S)[0] = ptrstr;
242 
243 	/******************************************************************
244 	 * converting host_name into node
245 	 ******************************************************************/
246 	mxGetString(HOST_NAME_PARAM, host_name, sizeof(host_name));
247 
248 	inet_aton(host_name, &addr);
249 	ptrstr->node = addr.s_addr;
250 	if (ptrstr->node) {
251 		ptrstr->port = rt_request_hard_port(ptrstr->node);
252 		if (!ptrstr->port) {
253 			snprintf(errMsg, sizeof(errMsg),
254 				"rt_request_hard_port(%s) failed\n",
255 				ptrstr->node );
256 			ssSetErrorStatus(S, errMsg);
257 			printf("%s", errMsg);
258 			return;
259 		}
260 
261 	} else {
262 		ptrstr->port = 0;
263 	}
264 
265 	/* start real-time timer */
266 	if (!rt_is_hard_timer_running()) {
267 		rt_set_oneshot_mode();
268 		start_rt_timer(0);
269 		timerflag = 1;
270 	}
271 
272 	/******************************************************************
273 	 * find mbdyn task
274 	 ******************************************************************/
275 	count = 0;
276 	printf("\nread: nam2num(mbd_name) %x\n", nam2num(mbd_name));
277 	while (count < MAX_MBDYN_TASK) {
278 		if (MBDynNode[count] == ptrstr->node
279 			&& MBDynName[count] == nam2num(mbd_name))
280 		{
281 			printf("\nread: RT_get MBDYN_task addy node: "
282 				"%x, port %d\n",
283 				ptrstr->node, ptrstr->port);
284 			mbdtask = (void *)RT_get_adr(ptrstr->node,
285 				ptrstr->port, mbd_name);
286 			printf("\nread: RT_GOT MBDYN_task addy!\n");
287 			ptrstr->mbdtask_count = count;
288 			break;
289 		}
290 
291 		if (MBDynNode[count] == 1 && MBDynName[count] == 0xFFFFFFFF) {
292 			i = WAIT_LOOP;
293 			printf("\nread: Connecting to MBDYN task\n");
294 
295 			while (!(mbdtask = (void *)RT_get_adr(ptrstr->node,
296 				ptrstr->port,mbd_name)))
297 			{
298 				if (!i) {
299 					snprintf(errMsg, sizeof(errMsg),
300 						"\ncannot find MBDyn task\n");
301 					ssSetErrorStatus(S, errMsg);
302 					printf("%s", errMsg);
303 					return;
304 				}
305 				rt_sleep(nano2count(1000000));
306 				i--;
307 			}
308 
309 			MBDynNode[count] = ptrstr->node;
310 			MBDynName[count] = nam2num(mbd_name);
311 			MBDynTaskActive[count] = true;
312 			ptrstr->mbdtask_count = count;
313 			break;
314 		}
315 
316 		count++;
317 	}
318 
319 	if (count == MAX_MBDYN_TASK) {
320 		snprintf(errMsg, sizeof(errMsg), "\nToo many MBDyn tasks\n");
321 		ssSetErrorStatus(S, errMsg);
322 		printf("%s", errMsg);
323 		return;
324 	}
325 
326 	/******************************************************************
327 	 * find mailbox
328 	 ******************************************************************/
329 
330 	i = WAIT_LOOP;
331 
332 	while (!(ptrstr->comptr = (void *)RT_get_adr(ptrstr->node,
333 		ptrstr->port, mbx_name)))
334 	{
335 		if (!i) {
336 			snprintf(errMsg, sizeof(errMsg),
337 				"\ncannot find input mailbox %s\n",
338 				mbx_name);
339 			ssSetErrorStatus(S, errMsg);
340 			printf("%s", errMsg);
341 			return;
342 		}
343 		rt_sleep(nano2count(1000000));
344 		i--;
345 	}
346 
347 	/******************************************************************
348 	 * alloc buffer memory
349 	 ******************************************************************/
350 	ptrstr->buffer = malloc(sizeof(double)*MBX_N_CHN);
351 	if (!ptrstr->buffer) {
352 		snprintf(errMsg, sizeof(errMsg),
353 			"\ncannot alloc buffer memory:\n");
354 		ssSetErrorStatus(S, errMsg);
355 		printf("%s", errMsg);
356 		return;
357 	}
358 
359 	ptrstr->err_count = 0;
360 	ptrstr->step_count = 0;
361 
362 	printf("\nsfun_mbdyn_com_read:\n\n");
363 	printf("Host name: %s\n", host_name);
364 	printf("node: %lx\n", ptrstr->node);
365 	printf("port: %d\n", ptrstr->port);
366 	printf("mbdtask: %p\n", mbdtask);
367 	printf("mbx name: %s\n", mbx_name);
368 	printf("mbx: %p\n", ptrstr->comptr);
369 	printf("mbx channel: %d\n", MBX_N_CHN);
370 	printf("NANO_SAMPLE_TIME: %ld\n", NANO_SAMPLE_TIME);
371 
372 	if (timerflag) {
373 		stop_rt_timer();
374 	}
375 #else
376 	/* inizializza la socket */
377 	int sock = 0;
378 	int conn = 0;
379 	/* salva la socket */
380 	ssGetIWork(S)[0] = (int_T)sock;
381 	/* imposta conn a 0 */
382 	ssGetIWork(S)[1] = (int_T)conn;
383 #endif /* MATLAB_MEX_FILE */
384 }
385 #endif /* MDL_START */
386 
387 static void
mdlOutputs(SimStruct * S,int_T tid)388 mdlOutputs(SimStruct *S, int_T tid)
389 {
390 #ifndef MATLAB_MEX_FILE
391 	struct mbd_t *ptrstr= (struct mbd_t *)ssGetPWork(S)[0];
392 
393 	register int	i;
394 	double		y[MBX_N_CHN];
395 	int		flag;
396 
397 	/* to synchronize */
398 	if (ptrstr->step_count < 2) {
399 		flag = RT_mbx_receive_timed(ptrstr->node, ptrstr->port,
400 			ptrstr->comptr, y,
401 			sizeof(double)*MBX_N_CHN, NANO_SAMPLE_TIME);
402 		ptrstr->step_count++;
403 
404 	} else {
405 		flag = RT_mbx_receive_if(ptrstr->node, ptrstr->port,
406 			ptrstr->comptr, y,
407 			sizeof(double)*MBX_N_CHN);
408 	}
409 
410 	if (flag == 0) {
411 		for (i = 0; i < MBX_N_CHN; i++) {
412 			ssGetOutputPortRealSignal(S, i)[0] = (ptrstr->buffer)[i] = y[i];
413 		}
414 
415  	} else if (flag == sizeof(double)*MBX_N_CHN) {
416 		for (i = 0; i < MBX_N_CHN; i++) {
417 			ssGetOutputPortRealSignal(S, i)[0] = (ptrstr->buffer)[i];
418 		}
419 		ptrstr->err_count++;
420 
421 	} else {
422 		MBDynTaskActive[ptrstr->mbdtask_count] = false;
423 		rt_send(rt_HostInterfaceTask, (int)msg);
424 	}
425 #else
426 	register int	i;
427 	double		y[MBX_N_CHN];
428 	int		sock = ssGetIWork(S)[0];
429 	int		conn = ssGetIWork(S)[1];
430 	static char_T	errMsg[BUFSIZ];
431 	int		save_errno;
432 
433 	if (conn == 0) {
434 		if (sock == 0) {
435 			if (NET) {
436 				/* usa il protocollo tcp/ip */
437 				struct sockaddr_in	addr;
438 				char			*host = NULL;
439 				int			flags;
440 
441 				/* crea una socket */
442 				sock = socket(PF_INET, SOCK_STREAM, 0);
443 				if (sock < 0) {
444 					snprintf(errMsg, sizeof(errMsg),
445 						"\nREAD sfunction: unable to create a INET socket\n");
446 					ssSetErrorStatus(S, errMsg);
447 					printf("%s", errMsg);
448 					return;
449 				}
450 
451 				/* imposta la socket come non bloccante */
452         			flags = fcntl(sock, F_GETFL, 0);
453 				if (flags == -1) {
454 					snprintf(errMsg, sizeof(errMsg),
455 						"\nREAD sfunction: unable to get socket flags\n");
456 					ssSetErrorStatus(S, errMsg);
457 					printf("%s", errMsg);
458 					return;
459 				}
460 
461 				flags |= O_NONBLOCK;
462 				if (fcntl(sock, F_SETFL, flags) == -1) {
463 					snprintf(errMsg, sizeof(errMsg),
464 						"\nREAD sfunction: unable to set socket flags\n");
465 					ssSetErrorStatus(S, errMsg);
466 					printf("%s", errMsg);
467 					return;
468 				}
469 
470 				/* get host data */
471 				host = mxArrayToString(HOST_NAME_PARAM);
472 				if (host == NULL ) {
473 					snprintf(errMsg, sizeof(errMsg),
474 						"\nREAD sfunction: unable to get host parameter\n");
475 					ssSetErrorStatus(S, errMsg);
476 					printf("%s", errMsg);
477 					return;
478 				}
479 
480 				addr.sin_family = AF_INET;
481 				addr.sin_port = htons(PORT);
482 				if (inet_aton(host, &addr.sin_addr) == 0) {
483 					snprintf(errMsg, sizeof(errMsg),
484 						"\nREAD sfunction: unknown host '%s'\n", host);
485 					ssSetErrorStatus(S, errMsg);
486 					printf("%s", errMsg);
487 					mxFree(host);
488 					return;
489 				}
490 				mxFree(host);
491 
492 				/* connect */
493 				if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != -1) {
494 					conn = 1;
495 					/* reimposta la socket come bloccante */
496 					flags &= (~O_NONBLOCK);
497 					if (fcntl(sock, F_SETFL, flags) == -1) {
498 						snprintf(errMsg, sizeof(errMsg),
499 							"\nREAD sfunction: unable to set socket flags\n");
500 						ssSetErrorStatus(S, errMsg);
501 						printf("%s", errMsg);
502 						return;
503 					}
504 				}
505 
506 			} else {
507 				/* usa le socket local */
508 				struct sockaddr_un	*addrp;
509 				char			*path = NULL;
510 				int			flags;
511 				size_t			len, size;
512 
513 				/* crea una socket */
514 				sock = socket(PF_LOCAL, SOCK_STREAM, 0);
515 				if (sock < 0) {
516 					snprintf(errMsg, sizeof(errMsg),
517 						"\nREAD sfunction: unable to create a LOCAL socket\n");
518 					ssSetErrorStatus(S, errMsg);
519 					printf("%s", errMsg);
520 					return;
521 				}
522 
523 				/* imposta la socket come non bloccante */
524 	        		flags = fcntl(sock, F_GETFL, 0);
525 	        		if (flags == -1) {
526 					snprintf(errMsg, sizeof(errMsg),
527 						"\nREAD sfunction: unable to get socket flags\n");
528 					ssSetErrorStatus(S, errMsg);
529 					printf("%s", errMsg);
530 					return;
531 				}
532 				flags |= O_NONBLOCK;
533 				if (fcntl(sock, F_SETFL, flags) == -1) {
534 					snprintf(errMsg, sizeof(errMsg),
535 						"\nREAD sfunction: unable to set socket flags\n");
536 					ssSetErrorStatus(S, errMsg);
537 					printf("%s", errMsg);
538 					return;
539 				}
540 
541 				/* get path data */
542 				path = mxArrayToString(PATH_PARAM);
543 				if (path == NULL ) {
544 					snprintf(errMsg, sizeof(errMsg),
545 						"\nREAD sfunction: unable to get path parameter\n");
546 					ssSetErrorStatus(S, errMsg);
547 					printf("%s", errMsg);
548 					return;
549 				}
550 
551 				len = strlen(path);
552 				addrp = malloc(sizeof(struct sockaddr_un) + len + 1);
553 				addrp->sun_family = AF_LOCAL;
554 				strncpy(addrp->sun_path, path, len);
555 				mxFree(path);
556 
557 				addrp->sun_path[len] = '\0';
558 				size = (offsetof (struct sockaddr_un, sun_path) + len + 1);
559 
560 				/* connect */
561 				if (connect(sock, (struct sockaddr *)addrp, size) == 0)
562 				{
563 					conn = 1;
564 					/* reimposta la socket come bloccante */
565 					flags &= (~O_NONBLOCK);
566 					if (fcntl(sock, F_SETFL, flags) == -1) {
567 						snprintf(errMsg, sizeof(errMsg),
568 							"\nREAD sfunction: unable to set socket flags\n");
569 						ssSetErrorStatus(S, errMsg);
570 						printf("%s", errMsg);
571 						return;
572 					}
573 				}
574 			}
575 
576 			/* salva la socket */
577 			ssGetIWork(S)[0] = (int_T)sock;
578 
579 		} else {
580 			/* poll */
581 			struct pollfd	ufds;
582 			int		rc;
583 			int		retries = 0;
584 
585 retry:;
586 			ufds.fd = sock;
587 			ufds.events = (POLLIN | POLLOUT);
588 			rc = poll(&ufds, 1, TIME_OUT);
589 			switch (rc) {
590 			case -1:
591 				save_errno = errno;
592 				snprintf(errMsg, sizeof(errMsg),
593 					"\nREAD sfunction: POLL error (%d: %s)\n",
594 					save_errno, strerror(save_errno));
595 				ssSetErrorStatus(S, errMsg);
596 				printf("%s", errMsg);
597 				return;
598 
599 			case 0:
600 				snprintf(errMsg, sizeof(errMsg),
601 					"\nREAD sfunction: connection timeout reached\n");
602 				ssSetErrorStatus(S, errMsg);
603 				printf("%s", errMsg);
604 				return;
605 
606 			default :
607 			{
608 				int	flags;
609 
610 				if ((ufds.revents & POLLHUP) && ++retries < 200) {
611 					usleep(10000);
612 					goto retry;
613 				}
614 
615 				if (ufds.revents & (POLLERR | POLLHUP | POLLNVAL)) {
616 					snprintf(errMsg, sizeof(errMsg),
617 						"\nREAD sfunction: POLL error "
618 						"(%d ERR=%d HUP=%d NVAL=%d)\n",
619 						rc,
620 						ufds.revents & POLLERR,
621 						ufds.revents & POLLHUP,
622 						ufds.revents & POLLNVAL);
623 					ssSetErrorStatus(S, errMsg);
624 					printf("%s", errMsg);
625 					return;
626 				}
627 
628 				conn = 1;
629 				/* reimposta la socket come bloccante */
630         			flags = fcntl(sock, F_GETFL, 0);
631         			if (flags == -1) {
632 					snprintf(errMsg, sizeof(errMsg),
633 						"\nREAD sfunction: unable to get socket flags\n");
634 					ssSetErrorStatus(S, errMsg);
635 					printf("%s", errMsg);
636 					return;
637 				}
638 				flags &= (~O_NONBLOCK);
639 				if (fcntl(sock, F_SETFL, flags) == -1) {
640 					snprintf(errMsg, sizeof(errMsg),
641 						"\nREAD sfunction: unable to set socket flags\n");
642 					ssSetErrorStatus(S, errMsg);
643 					printf("%s", errMsg);
644 					return;
645 				}
646 			}
647 			}
648 			/* imposta conn a 1 */
649 
650 		} /* socket == 0 */
651 		ssGetIWork(S)[1] = (int_T)conn;
652 	} /* conn == 0 */
653 
654 	if (conn) {
655 		/* legge dalla socket */
656 		if (recv(sock, y, sizeof(double)*MBX_N_CHN, 0) == -1) {
657 			snprintf(errMsg, sizeof(errMsg),
658 				"\nReadSfunction: Communication closed by host\n");
659 			ssSetStopRequested(S, 1);
660 			printf("%s", errMsg);
661 			return;
662 		}
663 
664 		for (i = 0; i < MBX_N_CHN; i++) {
665 			ssGetOutputPortRealSignal(S,i)[0] = y[i];
666 		}
667 	}
668 #endif /* MATLAB_MEX_FILE */
669 }
670 
671 static void
mdlTerminate(SimStruct * S)672 mdlTerminate(SimStruct *S)
673 {
674 #ifndef MATLAB_MEX_FILE
675 	struct 	mbd_t *ptrstr = (struct mbd_t *)ssGetPWork(S)[0];
676 	void	*mbdtask;
677 	char 	mbd_name[7];
678 
679 	printf("\nsfun_mbdyn_com_read, %s:\n", ssGetModelName(S));
680 
681 	if (ptrstr) {
682 		printf("Number of communication errors: %d\n\n", ptrstr->err_count);
683 
684 		/****************************************************************
685 		 * terminate mbdyn task
686 		 ****************************************************************/
687 		if (MBDynTaskActive[ptrstr->mbdtask_count]) {
688 			mxGetString(MBD_NAME_PARAM, mbd_name, 7);
689 			mbdtask = (void *)RT_get_adr(ptrstr->node,
690 				ptrstr->port, mbd_name);
691 			printf("MBDyn is stopped by read s-function\n");
692 			RT_send_timed(ptrstr->node, ptrstr->port, mbdtask, 1, NANO_SAMPLE_TIME*2);
693 			MBDynTaskActive[ptrstr->mbdtask_count] = false;
694 		}
695 
696 		/****************************************************************
697 		 * free buffer memory
698 		 ****************************************************************/
699 
700 		if (ptrstr->buffer) {
701 			free(ptrstr->buffer);
702 		}
703 		/****************************************************************
704 		 * release port
705 		 ****************************************************************/
706 
707 		if (ptrstr->node) {
708 			rt_release_port(ptrstr->node, ptrstr->port);
709 		}
710 
711 		/****************************************************************
712 		 * free structure memory
713 		 ****************************************************************/
714 
715 		free(ptrstr);
716 	}
717 #else
718 	int sock = ssGetIWork(S)[0];
719 	double y[MBX_N_CHN];
720 #ifdef VERBOSE
721 	fprintf(stderr, "READ: closing socket...\n");
722 	fprintf(stderr, "%d\n", recv(sock, y, sizeof(double)*MBX_N_CHN, 0));
723 #endif /* VERBOSE */
724 	/* chiude la socket */
725 	shutdown(sock, SHUT_RDWR);
726 #endif /* MATLAB_MEX_FILE */
727 }
728 
729 #ifdef  MATLAB_MEX_FILE
730 #include "simulink.c"
731 #else
732 #include "cg_sfun.h"
733 #endif
734 
735