@@ -49,15 +49,16 @@ export function generateFmuCSources(dae: ModelicaDAE, fmuResult: FmuResult, opti
4949 const vars = fmuResult . scalarVariables ;
5050 const nStates = fmuResult . modelStructure . derivatives . length ;
5151 const nVars = vars . length ;
52+ const nStringVars = vars . filter ( ( v ) => v . type === "String" ) . length ;
5253
5354 // ── model.h ──
54- const modelH = generateModelH ( id , nVars , nStates , fmuResult ) ;
55+ const modelH = generateModelH ( id , nVars , nStates , nStringVars , fmuResult ) ;
5556
5657 // ── model.c ──
5758 const modelC = generateModelC ( id , dae , fmuResult ) ;
5859
5960 // ── fmi2Functions.c ──
60- const fmi2FunctionsC = generateFmi2FunctionsC ( id , nVars , nStates , fmuResult ) ;
61+ const fmi2FunctionsC = generateFmi2FunctionsC ( id , nVars , nStates , nStringVars , fmuResult ) ;
6162
6263 // ── CMakeLists.txt ──
6364 const cmakeLists = generateCMakeLists ( id ) ;
@@ -237,7 +238,7 @@ function escapeCString(s: string): string {
237238
238239// ── File generators ──
239240
240- function generateModelH ( id : string , nVars : number , nStates : number , result : FmuResult ) : string {
241+ function generateModelH ( id : string , nVars : number , nStates : number , nStringVars : number , result : FmuResult ) : string {
241242 const lines : string [ ] = [ ] ;
242243 lines . push ( "/* Auto-generated by ModelScript — do not edit */" ) ;
243244 lines . push ( `#ifndef ${ id . toUpperCase ( ) } _MODEL_H` ) ;
@@ -250,6 +251,7 @@ function generateModelH(id: string, nVars: number, nStates: number, result: FmuR
250251 lines . push ( `#define MODEL_GUID "${ result . guid } "` ) ;
251252 lines . push ( `#define N_VARS ${ nVars } ` ) ;
252253 lines . push ( `#define N_STATES ${ nStates } ` ) ;
254+ lines . push ( `#define N_STRING_VARS ${ nStringVars } ` ) ;
253255 lines . push ( `#define N_EVENT_INDICATORS ${ result . numberOfEventIndicators } ` ) ;
254256 lines . push ( "" ) ;
255257
@@ -265,6 +267,7 @@ function generateModelH(id: string, nVars: number, nStates: number, result: FmuR
265267 lines . push ( " double vars[N_VARS + 1]; /* +1 for safety */" ) ;
266268 lines . push ( " double states[N_STATES + 1];" ) ;
267269 lines . push ( " double derivatives[N_STATES + 1];" ) ;
270+ lines . push ( " char* stringVars[N_STRING_VARS + 1]; /* string variable storage */" ) ;
268271 lines . push ( " double time;" ) ;
269272 lines . push ( " int isDirtyValues;" ) ;
270273 lines . push ( `} ${ id } _Instance;` ) ;
@@ -376,7 +379,13 @@ function generateModelC(id: string, dae: ModelicaDAE, result: FmuResult): string
376379 return lines . join ( "\n" ) ;
377380}
378381
379- function generateFmi2FunctionsC ( id : string , nVars : number , nStates : number , result : FmuResult ) : string {
382+ function generateFmi2FunctionsC (
383+ id : string ,
384+ nVars : number ,
385+ nStates : number ,
386+ nStringVars : number ,
387+ result : FmuResult ,
388+ ) : string {
380389 const lines : string [ ] = [ ] ;
381390 lines . push ( "/* Auto-generated by ModelScript — FMI 2.0 API implementation */" ) ;
382391 lines . push ( `#include "${ id } _model.h"` ) ;
@@ -623,18 +632,74 @@ function generateFmi2FunctionsC(id: string, nVars: number, nStates: number, resu
623632
624633 // ── Terminate / FreeInstance ──
625634 lines . push ( "fmi2Status fmi2Terminate(fmi2Component c) { (void)c; return fmi2OK; }" ) ;
626- lines . push ( "void fmi2FreeInstance(fmi2Component c) { free(c); }" ) ;
635+ lines . push ( "" ) ;
636+ lines . push ( "void fmi2FreeInstance(fmi2Component c) {" ) ;
637+ lines . push ( " if (!c) return;" ) ;
638+ lines . push ( " FMUInstance* inst = (FMUInstance*)c;" ) ;
639+ lines . push ( " /* Free all allocated string variables */" ) ;
640+ lines . push ( " for (int i = 0; i < N_STRING_VARS; i++) {" ) ;
641+ lines . push ( " if (inst->model.stringVars[i]) free(inst->model.stringVars[i]);" ) ;
642+ lines . push ( " }" ) ;
643+ lines . push ( " free(inst);" ) ;
644+ lines . push ( "}" ) ;
627645 lines . push ( "" ) ;
628646
629647 // ── Stubs for remaining FMI 2.0 functions ──
630648 lines . push ( "/* --- Stubs --- */" ) ;
631649 lines . push ( "fmi2Status fmi2Reset(fmi2Component c) { (void)c; return fmi2OK; }" ) ;
632- lines . push (
633- "fmi2Status fmi2SetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]) { (void)c; (void)vr; (void)nvr; (void)value; return fmi2OK; }" ,
634- ) ;
635- lines . push (
636- "fmi2Status fmi2GetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]) { (void)c; (void)vr; (void)nvr; (void)value; return fmi2OK; }" ,
637- ) ;
650+
651+ // ── fmi2SetString / fmi2GetString ──
652+ // Build a value-reference → string-index mapping for string variables
653+ const stringVarIndices = result . scalarVariables
654+ . filter ( ( sv ) => sv . type === "String" )
655+ . map ( ( sv , idx ) => ( { vr : sv . valueReference , idx } ) ) ;
656+
657+ if ( nStringVars > 0 ) {
658+ // Emit a lookup table: VR → string index (-1 if not a string var)
659+ lines . push ( "" ) ;
660+ lines . push ( "/* VR-to-string-index mapping */" ) ;
661+ lines . push ( `static int stringVarIndex(fmi2ValueReference vr) {` ) ;
662+ lines . push ( " switch (vr) {" ) ;
663+ for ( const { vr, idx } of stringVarIndices ) {
664+ lines . push ( ` case ${ vr } : return ${ idx } ;` ) ;
665+ }
666+ lines . push ( " default: return -1;" ) ;
667+ lines . push ( " }" ) ;
668+ lines . push ( "}" ) ;
669+ lines . push ( "" ) ;
670+
671+ lines . push (
672+ "fmi2Status fmi2SetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]) {" ,
673+ ) ;
674+ lines . push ( " FMUInstance* inst = (FMUInstance*)c;" ) ;
675+ lines . push ( " for (size_t i = 0; i < nvr; i++) {" ) ;
676+ lines . push ( " int idx = stringVarIndex(vr[i]);" ) ;
677+ lines . push ( " if (idx >= 0) {" ) ;
678+ lines . push ( " if (inst->model.stringVars[idx]) free(inst->model.stringVars[idx]);" ) ;
679+ lines . push ( ' inst->model.stringVars[idx] = value[i] ? strdup(value[i]) : strdup("");' ) ;
680+ lines . push ( " }" ) ;
681+ lines . push ( " }" ) ;
682+ lines . push ( " return fmi2OK;" ) ;
683+ lines . push ( "}" ) ;
684+ lines . push ( "" ) ;
685+ lines . push (
686+ "fmi2Status fmi2GetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]) {" ,
687+ ) ;
688+ lines . push ( " FMUInstance* inst = (FMUInstance*)c;" ) ;
689+ lines . push ( " for (size_t i = 0; i < nvr; i++) {" ) ;
690+ lines . push ( " int idx = stringVarIndex(vr[i]);" ) ;
691+ lines . push ( ' value[i] = (idx >= 0 && inst->model.stringVars[idx]) ? inst->model.stringVars[idx] : "";' ) ;
692+ lines . push ( " }" ) ;
693+ lines . push ( " return fmi2OK;" ) ;
694+ lines . push ( "}" ) ;
695+ } else {
696+ lines . push (
697+ "fmi2Status fmi2SetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]) { (void)c; (void)vr; (void)nvr; (void)value; return fmi2OK; }" ,
698+ ) ;
699+ lines . push (
700+ "fmi2Status fmi2GetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]) { (void)c; (void)vr; (void)nvr; (void)value; return fmi2OK; }" ,
701+ ) ;
702+ }
638703 lines . push (
639704 "fmi2Status fmi2GetNominalsOfContinuousStates(fmi2Component c, fmi2Real nominals[], size_t nx) { for (size_t i = 0; i < nx; i++) nominals[i] = 1.0; (void)c; return fmi2OK; }" ,
640705 ) ;
0 commit comments