From 33e1945ab4b231df473604b13aa217343f18f3ea Mon Sep 17 00:00:00 2001 From: kevin Date: Wed, 29 Dec 2021 21:52:46 -0500 Subject: [PATCH] cwFlow,cwFlowTypes : Changes to fix problems with communicating between connected variables. Added _set_var_template(), _var_setter() --- cwFlow.cpp | 97 ++++++++++++++++----- cwFlowTypes.cpp | 222 ++++++++++++++++++++++++++++++++++++++---------- cwFlowTypes.h | 5 +- 3 files changed, 261 insertions(+), 63 deletions(-) diff --git a/cwFlow.cpp b/cwFlow.cpp index 56652ac..46414ee 100644 --- a/cwFlow.cpp +++ b/cwFlow.cpp @@ -183,7 +183,17 @@ namespace cw return rc; } - + void _connect_vars( variable_t* src_var, variable_t* in_var ) + { + // connect in_var into src_var's outgoing var chain + in_var->connect_link = src_var->connect_link; + src_var->connect_link = in_var; + + assert( src_var->value != nullptr ); + + in_var->value = src_var->value; + in_var->src_var = src_var; + } rc_t _setup_input( flow_t* p, instance_t* in_inst, const char* in_var_label, const char* src_label_arg ) { @@ -244,14 +254,7 @@ namespace cw goto errLabel; } - - // connect in_var into src_var's outgoing var chain - in_var->connect_link = src_var->connect_link; - src_var->connect_link = in_var; - - - in_var->value = src_var->value; - + _connect_vars( src_var, in_var ); //cwLogInfo("'%s:%s' connected to source '%s:%s' %p.", in_inst->label, in_var_label, src_inst->label, suffix, in_var->value ); @@ -301,8 +304,8 @@ namespace cw if( max_vid == kInvalidId || var->vid > max_vid ) max_vid = var->vid; - if( var->chIdx != kAnyChIdx && var->chIdx > max_chIdx ) - max_chIdx = var->chIdx; + if( var->chIdx != kAnyChIdx && (var->chIdx+1) > max_chIdx ) + max_chIdx = (var->chIdx + 1); } } @@ -332,17 +335,19 @@ namespace cw variable_t* v0 = inst->varMapA[idx]; rc = cwLogError(kInvalidStateRC,"The variable '%s' id:%i ch:%i and '%s' id:%i ch:%i share the same variable map position on instance: %s. This is usually cased by duplicate variable id's.", v0->label,v0->vid,v0->chIdx, var->label,var->vid,var->chIdx,inst->label); + goto errLabel; } // assign this variable to a map position inst->varMapA[ idx ] = var; - if( var->value == nullptr ) + if( var->chIdx != kAnyChIdx && var->value == nullptr ) { rc = cwLogError(kInvalidStateRC,"The value of the variable '%s' ch:%i on instance:'%s' has not been set.",var->label,var->chIdx,inst->label); goto errLabel; } + } } @@ -352,6 +357,49 @@ namespace cw } + void _complete_input_connections( instance_t* inst ) + { + for(variable_t* var=inst->varL; var!=nullptr; var=var->var_link) + if(var->chIdx == kAnyChIdx && is_connected_to_external_proc(var) ) + { + + variable_t* base_src_var = var->src_var; + + // since 'var' is on the 'any' channel the 'src' var must also be on the 'any' channel + assert( base_src_var->chIdx == kAnyChIdx ); + + printf("%s %s\n",inst->label,var->label); + for(variable_t* in_var = var->ch_link; in_var != nullptr; in_var=in_var->ch_link) + { + + + variable_t* svar = base_src_var; + for(; svar!=nullptr; svar=svar->ch_link) + if( svar->chIdx == in_var->chIdx ) + break; + + _connect_vars( svar==nullptr ? base_src_var : svar, in_var); + } + } + } + + rc_t _call_value_func_on_all_variables( instance_t* inst ) + { + rc_t rc = kOkRC; + rc_t rc1 = kOkRC; + + for(unsigned i=0; ivarMapN; ++i) + if( inst->varMapA[i] != nullptr && inst->varMapA[i]->vid != kInvalidId ) + { + variable_t* var = inst->varMapA[i]; + + if((rc = var->inst->class_desc->members->value( var->inst, var )) != kOkRC ) + rc1 = cwLogError(rc,"The proc instance '%s' reported an invalid valid on variable:%s chIdx:%i.", var->inst->label, var->label, var->chIdx ); + } + + return rc1; + } + rc_t _preset_channelize_vars( instance_t* inst, const char* type_src_label, const char* preset_label, const object_t* preset_cfg ) { rc_t rc = kOkRC; @@ -384,12 +432,12 @@ namespace cw if( value->is_list() ) { for(unsigned chIdx=0; chIdxchild_count(); ++chIdx) - if((rc = var_channelize( inst, value_label, chIdx, value->child_ele(chIdx), dummy )) != kOkRC ) + if((rc = var_channelize( inst, value_label, chIdx, value->child_ele(chIdx), kInvalidId, dummy )) != kOkRC ) goto errLabel; } else // otherwise a single value was given { - if((rc = var_channelize( inst, value_label, kAnyChIdx, value, dummy )) != kOkRC ) + if((rc = var_channelize( inst, value_label, kAnyChIdx, value, kInvalidId, dummy )) != kOkRC ) goto errLabel; } @@ -626,7 +674,7 @@ namespace cw // that were expressed with a list have numeric channel indexes assigned. - // TODO: Should the 'all' variable be removed for variables that have numeric channel indexes. + // TODO: Should the 'all' variable be removed for variables that have numeric channel indexes? // connect the variable lists in the instance 'in' dictionary if( pvars.in_dict != nullptr ) @@ -681,6 +729,11 @@ namespace cw if((rc =_create_instance_var_map( inst )) != kOkRC ) goto errLabel; + _complete_input_connections(inst); + + if((rc = _call_value_func_on_all_variables( inst )) != kOkRC ) + goto errLabel; + // insert an instance in the network if( p->network_tail == nullptr ) { @@ -787,7 +840,7 @@ namespace cw variable_t* var = nullptr; // locate the proc instance - if((inst = instance_find(p,inst_label)) != nullptr ) + if((inst = instance_find(p,inst_label)) == nullptr ) { rc = cwLogError(kInvalidIdRC,"Unknown proc instance label '%s'.", cwStringNullGuard(inst_label)); goto errLabel; @@ -886,7 +939,7 @@ cw::rc_t cw::flow::create( handle_t& hRef, // create the instance if( (rc= _create_instance( p, inst_cfg ) ) != kOkRC ) { - rc = cwLogError(rc,"The instantiation at network index %i is invalid.",i); + rc = cwLogError(rc,"The instantiation at proc index %i is invalid.",i); goto errLabel; } @@ -983,6 +1036,7 @@ cw::rc_t cw::flow::apply_preset( handle_t h, const char* presetLabel ) goto errLabel; } + // if the preset value is a string then look it up in the class dictionary if( preset_value_cfg->is_string() ) { const char* class_preset_label; @@ -990,10 +1044,15 @@ cw::rc_t cw::flow::apply_preset( handle_t h, const char* presetLabel ) _class_preset_channelize_vars(inst, class_preset_label ); } else + // if the preset value is a dict then apply it directly if( preset_value_cfg->is_dict() ) { - printf("Not implemented.\n"); - assert(0); + if((rc = _preset_channelize_vars( inst, "network", presetLabel, preset_value_cfg )) != kOkRC ) + { + rc = cwLogError(rc,"The preset '%s' application failed on instance '%s'.", presetLabel, inst_label ); + goto errLabel; + } + } else { diff --git a/cwFlowTypes.cpp b/cwFlowTypes.cpp index 19b29e0..2d34137 100644 --- a/cwFlowTypes.cpp +++ b/cwFlowTypes.cpp @@ -437,29 +437,143 @@ namespace cw rc_t _var_broadcast_new_value( variable_t* var ) { rc_t rc = kOkRC; - + /* // notify each connected var that the value has changed for(variable_t* con_var = var->connect_link; con_var!=nullptr; con_var=con_var->connect_link) if((rc = con_var->inst->class_desc->members->value( con_var->inst, con_var )) != kOkRC ) break; + */ + return rc; + } + + template< typename T > + void _var_setter( variable_t* var, T val ) + { + cwLogError(kAssertFailRC,"Unimplemented variable setter."); + assert(0); + } + + template<> + void _var_setter( variable_t* var, bool val ) + { + var->local_value.u.b = val; + var->local_value.flags = kBoolTFl; + cwLogMod("%s.%s ch:%i %i (bool).",var->inst->label,var->label,var->chIdx,val); + } + + template<> + void _var_setter( variable_t* var, unsigned val ) + { + var->local_value.u.u = val; + var->local_value.flags = kUIntTFl; + cwLogMod("%s.%s ch:%i %i (uint).",var->inst->label,var->label,var->chIdx,val); + } + + template<> + void _var_setter( variable_t* var, int val ) + { + var->local_value.u.i = val; + var->local_value.flags = kIntTFl; + cwLogMod("%s.%s ch:%i %i (int).",var->inst->label,var->label,var->chIdx,val); + } + + template<> + void _var_setter( variable_t* var, float val ) + { + var->local_value.u.f = val; + var->local_value.flags = kFloatTFl; + cwLogMod("%s.%s ch:%i %f (float).",var->inst->label,var->label,var->chIdx,val); + } + + template<> + void _var_setter( variable_t* var, double val ) + { + var->local_value.u.d = val; + var->local_value.flags = kDoubleTFl; + cwLogMod("%s.%s ch:%i %f (double).",var->inst->label,var->label,var->chIdx,val); + } + + template<> + void _var_setter( variable_t* var, const char* val ) + { + var->local_value.u.s = mem::duplStr(val); + var->local_value.flags = kStringTFl; + cwLogMod("%s.%s ch:%i %s (string).",var->inst->label,var->label,var->chIdx,val); + } + + template<> + void _var_setter( variable_t* var, abuf_t* val ) + { + var->local_value.u.abuf = val; + var->local_value.flags = kABufTFl; + cwLogMod("%s.%s ch:%i %s (abuf).",var->inst->label,var->label,var->chIdx,abuf==nullptr ? "null" : "valid"); + } + + template<> + void _var_setter( variable_t* var, fbuf_t* val ) + { + var->local_value.u.fbuf = val; + var->local_value.flags = kFBufTFl; + cwLogMod("%s.%s ch:%i %s (fbuf).",var->inst->label,var->label,var->chIdx,fbuf==nullptr ? "null" : "valid"); + } + + template< typename T > + rc_t _var_set_template( variable_t* var, unsigned typeFlag, T val ) + { + rc_t rc; + + if((rc = _validate_var_assignment( var, typeFlag )) != kOkRC ) + return rc; + + // If the instance is fully initialized ... + if( var->inst->varMapA != nullptr ) + { + // ... then inform the proc. that the value changed + // (we don't want to do call to occur if we are inside or prior to 'proc.create()' + // call because calls' to 'proc.value()' will see the instance in a incomplete state) + rc = var->inst->class_desc->members->value( var->inst, var ); + } + + if( rc == kOkRC ) + { + // release the current value + _value_release(&var->local_value); + + // set the new local value + _var_setter(var,val); + + // make the var point to the local value + var->value = &var->local_value; + + + // send the value to connected downstream proc's + rc = _var_broadcast_new_value( var ); + } return rc; } + rc_t _var_set( variable_t* var, bool val ) { rc_t rc; if((rc = _validate_var_assignment( var, kBoolTFl )) != kOkRC ) return rc; + + if((rc = var->inst->class_desc->members->value( var->inst, var )) == kOkRC ) + { + + _value_release(&var->local_value); + var->local_value.u.b = val; + var->local_value.flags = kBoolTFl; + var->value = &var->local_value; + + cwLogMod("%s.%s ch:%i %i (bool).",var->inst->label,var->label,var->chIdx,val); + + rc = _var_broadcast_new_value( var ); + } - _value_release(&var->local_value); - var->local_value.u.b = val; - var->local_value.flags = kBoolTFl; - var->value = &var->local_value; - - cwLogMod("%s.%s ch:%i %i (bool).",var->inst->label,var->label,var->chIdx,val); - - return _var_broadcast_new_value( var ); + return rc; } rc_t _var_set( variable_t* var, unsigned val ) @@ -467,16 +581,20 @@ namespace cw rc_t rc; if((rc = _validate_var_assignment( var, kUIntTFl )) != kOkRC ) return rc; - - _value_release(&var->local_value); - var->local_value.u.u = val; - var->local_value.flags = kUIntTFl; - var->value = &var->local_value; - cwLogMod("%s.%s ch:%i %i (uint_t).",var->inst->label,var->label,var->chIdx,val); + if((rc = var->inst->class_desc->members->value( var->inst, var )) == kOkRC ) + { + _value_release(&var->local_value); + var->local_value.u.u = val; + var->local_value.flags = kUIntTFl; + var->value = &var->local_value; + + cwLogMod("%s.%s ch:%i %i (uint_t).",var->inst->label,var->label,var->chIdx,val); - return _var_broadcast_new_value( var ); - + _var_broadcast_new_value( var ); + } + + return rc; } rc_t _var_set( variable_t* var, int val ) @@ -576,27 +694,37 @@ namespace cw return _var_broadcast_new_value( var ); } + + bool is_connected_to_external_proc( const variable_t* var ) + { + return var->src_var != nullptr && var->value != nullptr && var->value != &var->local_value; + } + template< typename T > - rc_t _var_set_driver( variable_t* var, T value ) + rc_t _var_set_driver( variable_t* var, unsigned typeFlag, T value ) { rc_t rc; + // if this variable is fed from the output of an external proc - then it's local value cannot be set + if(is_connected_to_external_proc(var) ) + return kOkRC; + + // if this assignment targets a specific channel ... if( var->chIdx != kAnyChIdx ) { - rc = _var_set(var,value); // ... then set it alone + rc = _var_set_template( var, typeFlag, value ); // ... then set it alone } else // ... otherwise set all channels. { for(; var!=nullptr; var=var->ch_link) - if((rc = _var_set(var,value)) != kOkRC ) + if((rc = _var_set_template( var, typeFlag, value )) != kOkRC) break; } return rc; } - rc_t _var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, abuf_t* abuf ) { @@ -606,7 +734,7 @@ namespace cw return rc; if( var != nullptr ) - _var_set_driver( var, abuf ); + _var_set_driver( var, kABufTFl, abuf ); return rc; } @@ -619,7 +747,7 @@ namespace cw return rc; if( var != nullptr ) - _var_set_driver( var, fbuf ); + _var_set_driver( var, kFBufTFl, fbuf ); return rc; } @@ -628,13 +756,15 @@ namespace cw { rc_t rc = kOkRC; - switch( var->varDesc->type & kTypeMask ) + unsigned typeFlag = var->varDesc->type & kTypeMask; + + switch( typeFlag ) { case kBoolTFl: { bool v; if((rc = value->value(v)) == kOkRC ) - rc = _var_set_driver( var, v ); + rc = _var_set_driver( var, typeFlag, v ); } break; @@ -642,7 +772,7 @@ namespace cw { unsigned v; if((rc = value->value(v)) == kOkRC ) - rc = _var_set_driver( var, v ); + rc = _var_set_driver( var, typeFlag, v ); } break; @@ -650,7 +780,7 @@ namespace cw { int v; if((rc = value->value(v)) == kOkRC ) - rc = _var_set_driver( var, v ); + rc = _var_set_driver( var, typeFlag, v ); } break; @@ -658,7 +788,7 @@ namespace cw { float v; if((rc = value->value(v)) == kOkRC ) - rc = _var_set_driver( var, v ); + rc = _var_set_driver( var, typeFlag, v ); } break; @@ -666,7 +796,7 @@ namespace cw { double v; if((rc = value->value(v)) == kOkRC ) - rc = _var_set_driver( var, v ); + rc = _var_set_driver( var, typeFlag, v ); } break; @@ -674,7 +804,7 @@ namespace cw { const char* v; if((rc = value->value(v)) == kOkRC ) - rc = _var_set_driver( var, v ); + rc = _var_set_driver( var, typeFlag, v ); } break; @@ -692,11 +822,11 @@ namespace cw rc_t _var_map_id_to_index( instance_t* inst, unsigned vid, unsigned chIdx, unsigned& idxRef ) { - unsigned idx = vid * inst->varMapChN + (chIdx == kAnyChIdx ? 0 : chIdx); + unsigned idx = vid * inst->varMapChN + (chIdx == kAnyChIdx ? 0 : (chIdx+1)); // verify that the map idx is valid if( idx >= inst->varMapN ) - return cwLogError(kAssertFailRC,"The variable map positioning location %i is out of the range % on instance '%s' vid:%i ch:%i.", idx, inst->varMapN, inst->label,vid,chIdx); + return cwLogError(kAssertFailRC,"The variable map positioning location %i is out of the range %i on instance '%s' vid:%i ch:%i.", idx, inst->varMapN, inst->label,vid,chIdx); idxRef = idx; @@ -820,9 +950,10 @@ namespace cw void _var_print( const variable_t* var ) { - const char* local_label = var->value==nullptr || var->value == &var->local_value ? "local" : " "; + //const char* local_label = var->value==nullptr || var->value == &var->local_value ? "local" : " "; + const char* conn_label = is_connected_to_external_proc(var) ? "extern" : " "; - printf(" %20s id:%4i ch:%3i : %s : ", var->label, var->vid, var->chIdx, local_label ); + printf(" %20s id:%4i ch:%3i : %s : ", var->label, var->vid, var->chIdx, conn_label ); if( var->value == nullptr ) _value_print( &var->local_value ); @@ -1095,7 +1226,7 @@ cw::rc_t cw::flow::var_create( instance_t* inst, const char* var_label, unsigned return rc; } -cw::rc_t cw::flow::var_channelize( instance_t* inst, const char* var_label, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef ) +cw::rc_t cw::flow::var_channelize( instance_t* inst, const char* var_label, unsigned chIdx, const object_t* value_cfg, unsigned vid, variable_t*& varRef ) { rc_t rc = kOkRC; variable_t* var = nullptr; @@ -1124,7 +1255,7 @@ cw::rc_t cw::flow::var_channelize( instance_t* inst, const char* var_label, uns if( var == nullptr && chIdx != kAnyChIdx ) { // create the channelized var - if((rc = _var_create( inst, var_label, kInvalidId, chIdx, value_cfg, var )) != kOkRC ) + if((rc = _var_create( inst, var_label, vid, chIdx, value_cfg, var )) != kOkRC ) goto errLabel; // if no value was set then set the value from the 'any' channel @@ -1247,12 +1378,17 @@ cw::rc_t cw::flow::var_register( instance_t* inst, const char* var_label, unsign } else // an exact match was not found - channelize the variable { - if((rc = var_channelize(inst,var_label,chIdx,value_cfg,var)) != kOkRC ) + if((rc = var_channelize(inst,var_label,chIdx,value_cfg,vid,var)) != kOkRC ) goto errLabel; } var->vid = vid; varRef = var; + + if((var = _var_find_on_label_and_ch(inst,var_label,kAnyChIdx)) != nullptr ) + var->vid = vid; + else + rc = cwLogError(kInvalidStateRC,"The variable '%s' instance '%s' has no base channel.", var_label, inst->label, chIdx); errLabel: if( rc != kOkRC ) @@ -1331,7 +1467,7 @@ cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, bool variable_t* var = nullptr; if((rc = _var_find_to_set(inst, vid, chIdx, kBoolTFl, var )) == kOkRC ) - _var_set_driver( var, val ); + _var_set_driver( var, kBoolTFl, val ); return rc; } @@ -1342,7 +1478,7 @@ cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, uint variable_t* var = nullptr; if((rc = _var_find_to_set(inst, vid, chIdx, kUIntTFl, var )) == kOkRC ) - _var_set_driver( var, val ); + _var_set_driver( var, kUIntTFl, val ); return rc; } @@ -1353,7 +1489,7 @@ cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, int_ variable_t* var = nullptr; if((rc = _var_find_to_set(inst, vid, chIdx, kIntTFl, var )) == kOkRC ) - _var_set_driver( var, val ); + _var_set_driver( var, kIntTFl, val ); return rc; } @@ -1364,7 +1500,7 @@ cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, floa variable_t* var = nullptr; if((rc = _var_find_to_set(inst, vid, chIdx, kFloatTFl, var )) == kOkRC ) - _var_set_driver( var, val ); + _var_set_driver( var, kFloatTFl, val ); return rc; } @@ -1375,7 +1511,7 @@ cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, doub variable_t* var = nullptr; if((rc = _var_find_to_set(inst, vid, chIdx, kDoubleTFl, var )) == kOkRC ) - _var_set_driver( var, val ); + _var_set_driver( var, kDoubleTFl, val ); return rc; } @@ -1386,7 +1522,7 @@ cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, cons variable_t* var = nullptr; if((rc = _var_find_to_set(inst, vid, chIdx, kStringTFl, var )) == kOkRC ) - _var_set_driver( var, val ); + _var_set_driver( var, kStringTFl, val ); return rc; } diff --git a/cwFlowTypes.h b/cwFlowTypes.h index 79f8cec..2834922 100644 --- a/cwFlowTypes.h +++ b/cwFlowTypes.h @@ -165,6 +165,7 @@ namespace cw value_t local_value; // the local value instance (actual value if this is not a 'src' variable) value_t* value; // pointer to the value associated with this variable unsigned chIdx; // channel index + struct variable_str* src_var; // pointer to this input variables source link (or null if it uses the local_value) struct variable_str* var_link; // link to other var's on 'inst' struct variable_str* connect_link; // list of outgoing connections struct variable_str* ch_link; // list of channels that share this variable (rooted on 'any' channel - in order by channel number) @@ -280,11 +281,13 @@ namespace cw // Channelizing creates a new var record with an explicit channel index to replace the // automatically generated variable whose channel index is set to 'all'. - rc_t var_channelize( instance_t* inst, const char* var_label, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef ); + rc_t var_channelize( instance_t* inst, const char* var_label, unsigned chIdx, const object_t* value_cfg, unsigned vid, variable_t*& varRef ); // `value_cfg` is optional. Set it to NULL to ignore rc_t var_register( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef ); + // Returns true if this var is connected to an external proc variable + bool is_connected_to_external_proc( const variable_t* var ); //----------------- //