@@ -467,6 +467,11 @@ function generateFmi2FunctionsC(
467467 lines . push ( "#include <stdlib.h>" ) ;
468468 lines . push ( "#include <string.h>" ) ;
469469 lines . push ( "#include <stdio.h>" ) ;
470+ lines . push ( "#ifdef _WIN32" ) ;
471+ lines . push ( " #include <windows.h>" ) ;
472+ lines . push ( "#else" ) ;
473+ lines . push ( " #include <pthread.h>" ) ;
474+ lines . push ( "#endif" ) ;
470475 lines . push ( "" ) ;
471476 lines . push ( "typedef struct {" ) ;
472477 lines . push ( ` ${ id } _Instance model;` ) ;
@@ -476,6 +481,19 @@ function generateFmi2FunctionsC(
476481 lines . push ( " double startTime;" ) ;
477482 lines . push ( " double stopTime;" ) ;
478483 lines . push ( " double stepSize;" ) ;
484+ lines . push ( " /* Async co-simulation fields */" ) ;
485+ lines . push ( " int asyncMode; /* 0 = synchronous, 1 = asynchronous */" ) ;
486+ lines . push ( " volatile int asyncDone; /* 0 = running, 1 = done */" ) ;
487+ lines . push ( " volatile int cancelRequested;" ) ;
488+ lines . push ( " fmi2Status asyncResult;" ) ;
489+ lines . push ( " double asyncCurrentT;" ) ;
490+ lines . push ( " double asyncTEnd;" ) ;
491+ lines . push ( "#ifdef _WIN32" ) ;
492+ lines . push ( " HANDLE stepThread;" ) ;
493+ lines . push ( "#else" ) ;
494+ lines . push ( " pthread_t stepThread;" ) ;
495+ lines . push ( " int stepThreadActive;" ) ;
496+ lines . push ( "#endif" ) ;
479497 lines . push ( "} FMUInstance;" ) ;
480498 lines . push ( "" ) ;
481499
@@ -635,81 +653,91 @@ function generateFmi2FunctionsC(
635653 lines . push ( "}" ) ;
636654 lines . push ( "" ) ;
637655
638- // ── Co-Simulation: fmi2DoStep ──
639- lines . push ( "/* --- Co-Simulation --- */" ) ;
640- lines . push ( "fmi2Status fmi2DoStep(fmi2Component c, fmi2Real currentCommunicationPoint," ) ;
641- lines . push ( " fmi2Real communicationStepSize, fmi2Boolean noSetFMUStatePriorToCurrentPoint) {" ) ;
642- lines . push ( " (void)noSetFMUStatePriorToCurrentPoint;" ) ;
643- lines . push ( " FMUInstance* inst = (FMUInstance*)c;" ) ;
644- lines . push ( " double t = currentCommunicationPoint;" ) ;
645- lines . push ( " double tEnd = t + communicationStepSize;" ) ;
656+ // ── Static worker function for async co-simulation ──
657+ lines . push ( "/* --- Async Co-Simulation worker --- */" ) ;
658+ lines . push ( "static void doStep_sync(FMUInstance* inst) {" ) ;
659+ lines . push ( " double t = inst->asyncCurrentT;" ) ;
660+ lines . push ( " double tEnd = inst->asyncTEnd;" ) ;
646661 lines . push ( " double h = inst->stepSize;" ) ;
647662 lines . push ( " if (h <= 0) h = 0.001;" ) ;
648663 lines . push ( "" ) ;
649- lines . push ( " /* Fixed-step RK4 integration */" ) ;
650- lines . push ( " while (t < tEnd - 1e-15) {" ) ;
664+ lines . push ( " while (t < tEnd - 1e-15 && !inst->cancelRequested) {" ) ;
651665 lines . push ( " if (t + h > tEnd) h = tEnd - t;" ) ;
652666 lines . push ( " double states[N_STATES + 1];" ) ;
653667 lines . push ( " double k1[N_STATES + 1], k2[N_STATES + 1], k3[N_STATES + 1], k4[N_STATES + 1];" ) ;
654668 lines . push ( "" ) ;
655-
656669 // Save states
657670 for ( let i = 0 ; i < stateRefs2 . length ; i ++ ) {
658671 lines . push ( ` states[${ i } ] = inst->model.vars[${ stateRefs2 [ i ] } ];` ) ;
659672 }
660- lines . push ( "" ) ;
661-
662673 // k1
663- lines . push ( " inst->model.time = t;" ) ;
664- lines . push ( ` ${ id } _getDerivatives(&inst->model);` ) ;
674+ lines . push ( ` inst->model.time = t; ${ id } _getDerivatives(&inst->model);` ) ;
665675 lines . push ( " for (int i = 0; i < N_STATES; i++) k1[i] = inst->model.derivatives[i];" ) ;
666- lines . push ( "" ) ;
667-
668676 // k2
669677 lines . push ( " inst->model.time = t + 0.5 * h;" ) ;
670678 for ( let i = 0 ; i < stateRefs2 . length ; i ++ ) {
671679 lines . push ( ` inst->model.vars[${ stateRefs2 [ i ] } ] = states[${ i } ] + 0.5 * h * k1[${ i } ];` ) ;
672680 }
673681 lines . push ( ` ${ id } _getDerivatives(&inst->model);` ) ;
674682 lines . push ( " for (int i = 0; i < N_STATES; i++) k2[i] = inst->model.derivatives[i];" ) ;
675- lines . push ( "" ) ;
676-
677683 // k3
678684 for ( let i = 0 ; i < stateRefs2 . length ; i ++ ) {
679685 lines . push ( ` inst->model.vars[${ stateRefs2 [ i ] } ] = states[${ i } ] + 0.5 * h * k2[${ i } ];` ) ;
680686 }
681687 lines . push ( ` ${ id } _getDerivatives(&inst->model);` ) ;
682688 lines . push ( " for (int i = 0; i < N_STATES; i++) k3[i] = inst->model.derivatives[i];" ) ;
683- lines . push ( "" ) ;
684-
685689 // k4
686690 lines . push ( " inst->model.time = t + h;" ) ;
687691 for ( let i = 0 ; i < stateRefs2 . length ; i ++ ) {
688692 lines . push ( ` inst->model.vars[${ stateRefs2 [ i ] } ] = states[${ i } ] + h * k3[${ i } ];` ) ;
689693 }
690694 lines . push ( ` ${ id } _getDerivatives(&inst->model);` ) ;
691695 lines . push ( " for (int i = 0; i < N_STATES; i++) k4[i] = inst->model.derivatives[i];" ) ;
692- lines . push ( "" ) ;
693-
694696 // Update
695697 for ( let i = 0 ; i < stateRefs2 . length ; i ++ ) {
696698 lines . push (
697699 ` inst->model.vars[${ stateRefs2 [ i ] } ] = states[${ i } ] + (h / 6.0) * (k1[${ i } ] + 2.0*k2[${ i } ] + 2.0*k3[${ i } ] + k4[${ i } ]);` ,
698700 ) ;
699701 }
700702 lines . push ( " t += h;" ) ;
703+ lines . push ( " }" ) ;
704+ lines . push ( " inst->model.time = tEnd;" ) ;
705+ lines . push ( " inst->asyncResult = inst->cancelRequested ? fmi2Error : fmi2OK;" ) ;
706+ lines . push ( " inst->asyncDone = 1;" ) ;
707+ lines . push ( "}" ) ;
708+ lines . push ( "" ) ;
709+ lines . push ( "#ifndef _WIN32" ) ;
710+ lines . push ( "static void* doStep_thread(void* arg) { doStep_sync((FMUInstance*)arg); return NULL; }" ) ;
711+ lines . push ( "#else" ) ;
712+ lines . push ( "static DWORD WINAPI doStep_thread(LPVOID arg) { doStep_sync((FMUInstance*)arg); return 0; }" ) ;
713+ lines . push ( "#endif" ) ;
701714 lines . push ( "" ) ;
702715
703- // After each step, check for events and process them
704- lines . push ( " /* Event detection after integration step */" ) ;
705- lines . push ( " if (N_EVENT_INDICATORS > 0) {" ) ;
706- lines . push ( " fmi2EventInfo info;" ) ;
707- lines . push ( " fmi2NewDiscreteStates((fmi2Component)inst, &info);" ) ;
716+ // ── Co-Simulation: fmi2DoStep ──
717+ lines . push ( "/* --- Co-Simulation --- */" ) ;
718+ lines . push ( "fmi2Status fmi2DoStep(fmi2Component c, fmi2Real currentCommunicationPoint," ) ;
719+ lines . push ( " fmi2Real communicationStepSize, fmi2Boolean noSetFMUStatePriorToCurrentPoint) {" ) ;
720+ lines . push ( " (void)noSetFMUStatePriorToCurrentPoint;" ) ;
721+ lines . push ( " FMUInstance* inst = (FMUInstance*)c;" ) ;
722+ lines . push ( " inst->asyncCurrentT = currentCommunicationPoint;" ) ;
723+ lines . push ( " inst->asyncTEnd = currentCommunicationPoint + communicationStepSize;" ) ;
724+ lines . push ( " inst->asyncDone = 0;" ) ;
725+ lines . push ( " inst->cancelRequested = 0;" ) ;
726+ lines . push ( " if (inst->asyncMode) {" ) ;
727+ lines . push ( "#ifdef _WIN32" ) ;
728+ lines . push ( " inst->stepThread = CreateThread(NULL, 0, doStep_thread, inst, 0, NULL);" ) ;
729+ lines . push ( " return inst->stepThread ? fmi2Pending : fmi2Error;" ) ;
730+ lines . push ( "#else" ) ;
731+ lines . push ( " if (pthread_create(&inst->stepThread, NULL, doStep_thread, inst) == 0) {" ) ;
732+ lines . push ( " inst->stepThreadActive = 1;" ) ;
733+ lines . push ( " return fmi2Pending;" ) ;
708734 lines . push ( " }" ) ;
709-
735+ lines . push ( " return fmi2Error;" ) ;
736+ lines . push ( "#endif" ) ;
710737 lines . push ( " }" ) ;
711- lines . push ( " inst->model.time = tEnd;" ) ;
712- lines . push ( " return fmi2OK;" ) ;
738+ lines . push ( " /* Synchronous fallback */" ) ;
739+ lines . push ( " doStep_sync(inst);" ) ;
740+ lines . push ( " return inst->asyncResult;" ) ;
713741 lines . push ( "}" ) ;
714742 lines . push ( "" ) ;
715743
@@ -887,10 +915,34 @@ function generateFmi2FunctionsC(
887915 lines . push ( "}" ) ;
888916 lines . push ( "fmi2Status fmi2EnterContinuousTimeMode(fmi2Component c) { (void)c; return fmi2OK; }" ) ;
889917 lines . push ( "fmi2Status fmi2EnterEventMode(fmi2Component c) { (void)c; return fmi2OK; }" ) ;
890- lines . push ( "fmi2Status fmi2CancelStep(fmi2Component c) { (void)c; return fmi2OK; }" ) ;
891- lines . push (
892- "fmi2Status fmi2GetStatus(fmi2Component c, const fmi2StatusKind s, fmi2Status* value) { (void)c; (void)s; *value = fmi2OK; return fmi2OK; }" ,
893- ) ;
918+ lines . push ( "fmi2Status fmi2CancelStep(fmi2Component c) {" ) ;
919+ lines . push ( " FMUInstance* inst = (FMUInstance*)c;" ) ;
920+ lines . push ( " if (!inst->asyncMode || inst->asyncDone) return fmi2OK;" ) ;
921+ lines . push ( " inst->cancelRequested = 1;" ) ;
922+ lines . push ( "#ifdef _WIN32" ) ;
923+ lines . push ( " WaitForSingleObject(inst->stepThread, INFINITE);" ) ;
924+ lines . push ( " CloseHandle(inst->stepThread);" ) ;
925+ lines . push ( "#else" ) ;
926+ lines . push ( " if (inst->stepThreadActive) { pthread_join(inst->stepThread, NULL); inst->stepThreadActive = 0; }" ) ;
927+ lines . push ( "#endif" ) ;
928+ lines . push ( " return fmi2OK;" ) ;
929+ lines . push ( "}" ) ;
930+ lines . push ( "fmi2Status fmi2GetStatus(fmi2Component c, const fmi2StatusKind s, fmi2Status* value) {" ) ;
931+ lines . push ( " FMUInstance* inst = (FMUInstance*)c;" ) ;
932+ lines . push ( " if (s == fmi2DoStepStatus) {" ) ;
933+ lines . push ( " if (inst->asyncDone) {" ) ;
934+ lines . push ( "#ifndef _WIN32" ) ;
935+ lines . push ( " if (inst->stepThreadActive) { pthread_join(inst->stepThread, NULL); inst->stepThreadActive = 0; }" ) ;
936+ lines . push ( "#endif" ) ;
937+ lines . push ( " *value = inst->asyncResult;" ) ;
938+ lines . push ( " } else {" ) ;
939+ lines . push ( " *value = fmi2Pending;" ) ;
940+ lines . push ( " }" ) ;
941+ lines . push ( " } else {" ) ;
942+ lines . push ( " *value = fmi2OK;" ) ;
943+ lines . push ( " }" ) ;
944+ lines . push ( " return fmi2OK;" ) ;
945+ lines . push ( "}" ) ;
894946 lines . push (
895947 "fmi2Status fmi2GetRealStatus(fmi2Component c, const fmi2StatusKind s, fmi2Real* value) { (void)c; (void)s; *value = 0.0; return fmi2OK; }" ,
896948 ) ;
0 commit comments