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