#include "brick_composite.h" PIVector BrickComposite::baseBricks; BrickComposite::BrickComposite(): BrickCompositeBase(0, 0, 1) { type = "Composite"; setName(type); paramNames[0] = "Scheme file"; note_ = "\"Scheme\" is path to *.mbs file, described this brick"; parameters[0].setValue(""); parameters[0].setType(BrickBase::File); setComposite(true); mode_ = Asynchronous; bi = 0; bo = 0; bp = 0; inf = 0; } void BrickComposite::clear() { for (uint i = 0; i < bricks.size(); ++i) delete bricks[i]; bricks.clear(); } void BrickComposite::proceedConnections(bool compositeToo) { if (compositeToo) { if (bi != 0) { for (int i = 0; i < inputsCount(); ++i) bi->setOutputValue(i, inputs[i]); bi->proceedConnections(); } if (bp != 0) { for (int i = 1; i < parametersCount(); ++i) bp->setOutputValue(i - 1, parameters[i].toFloat()); bp->proceedConnections(); } switch (mode_) { case BrickBase::Synchronous: for (uint i = 0; i < bricks.size(); ++i) bricks[i]->proceedConnections(); break; case BrickBase::Asynchronous: default: for (uint i = 0; i < tree.size(); ++i) { tl = &tree[i]; for (uint j = 0; j < tl->size(); ++j) (*tl)[j]->proceedConnections(); } break; } if (bo != 0) for (int i = 0; i < outputsCount(); ++i) outputs[i] = bo->input(i); } BrickBase::proceedConnections(compositeToo); } void BrickComposite::parameterChanged(int index) { fillBaseBricks(); if (index != 0) return; PIConfig sr(parameters[0].toString()); PIString prefix, cname; BrickBase * b; int pcnt; clear(); setMode((Mode)(int)sr.getValue("Mode", 1)); PIStringList names = sr.getValue("Bricks", PIStringList()); for (uint i = 0; i < names.size(); ++i) { prefix = names[i] + " "; cname = sr.getValue(prefix + "codeName", ""); b = findBaseBrick(cname)->copy(); BrickComposite::loadBrick(sr, prefix, b); bricks.push_back(b); } uint cnt = sr.getValue("Connections count", 0); //cout << endl; for (uint i = 0; i < cnt; ++i) { prefix = "Connection " + PIString::fromNumber(i) + " "; BrickBase::connect(findBrick(sr.getValue(prefix + "from Name", "")), sr.getValue(prefix + "from Port", 0), findBrick(sr.getValue(prefix + "to Name", "")), sr.getValue(prefix + "to Port", 0)); } bi = 0; for (uint i = 0; i < bricks.size(); ++i) if (bricks[i]->codeName() == "BrickCompositeInput") {bi = (BrickCompositeInput * )bricks[i]; break;} if (bi != 0) { setInputsCount(bi->outputsCount()); for (int i = 0; i < inputsCount(); ++i) inNames[i] = bi->parameter(i).toString(); } else setInputsCount(0); bo = 0; for (uint i = 0; i < bricks.size(); ++i) if (bricks[i]->codeName() == "BrickCompositeOutput") {bo = (BrickCompositeOutput * )bricks[i]; break;} if (bo != 0) { setOutputsCount(bo->inputsCount()); for (int i = 0; i < outputsCount(); ++i) outNames[i] = bo->parameter(i).toString(); } else setOutputsCount(0); bp = 0; for (uint i = 0; i < bricks.size(); ++i) if (bricks[i]->codeName() == "BrickCompositeParameters") {bp = (BrickCompositeParameters * )bricks[i]; break;} if (bp != 0) { pcnt = parametersCount(); setParametersCount(bp->parametersCount() + 1); for (int i = 1; i < parametersCount(); ++i) { cname = bp->parameter(i - 1).toString(); int j = cname.toLowerCase().find(':'); if (j < 0) paramNames[i] = cname; else { paramNames[i] = cname.left(j).trim(); if (i >= pcnt) parameters[i].setValue(cname.cutLeft(j + 1).toDouble()); } } } else setParametersCount(1); inf = 0; for (uint i = 0; i < bricks.size(); ++i) if (bricks[i]->codeName() == "BrickCompositeInformation") {inf = (BrickCompositeInformation * )bricks[i]; break;} if (inf != 0) { type = inf->parameter(0).toString(); note_ = inf->parameter(1).toString(); } else { type = "Composite"; note_ = "\"Scheme\" is path to *.mbs file, described this brick"; } buildBrickTree(); //cout << name_ << " load " << bricks.size() << " bricks" << endl; } void BrickComposite::loadBrick(PIConfig & sr, const PIString & prefix, BrickBase * b, BrickManager * m) { b->setName(sr.getValue(prefix + "name", b->name())); b->setInitial(sr.getValue(prefix + "initial", false)); b->setFrequencyDivider(sr.getValue(prefix + "freqDiv", 1)); b->setOutputsCount(sr.getValue(prefix + "outCount", b->outputsCount())); b->setInputsCount(sr.getValue(prefix + "inCount", b->inputsCount())); for (int i = 0; i < b->inputsCount(); ++i) b->setInputValue(i, sr.getValue(prefix + "in " + PIString::fromNumber(i), b->input(i))); b->setParametersCount(sr.getValue(prefix + "paramCount", b->parametersCount())); for (int i = 0; i < b->parametersCount(); ++i) b->setParameterValue(i, PIVariant::fromValue(sr.getValue(prefix + "param " + PIString::fromNumber(i), b->parameter(i).toString())), false); b->setManager(m); } BrickBase * BrickComposite::findBrick(const PIString & name) { for (uint i = 0; i < bricks.size(); ++i) if (bricks[i]->name() == name) return bricks[i]; return 0; } BrickBase * BrickComposite::findBaseBrick(const PIString & code_name) { for (uint i = 0; i < baseBricks.size(); ++i) if (baseBricks[i]->codeName() == code_name) return baseBricks[i]; return 0; } bool BrickComposite::tick_body(double time) { if (bi != 0) { for (int i = 0; i < inputsCount(); ++i) bi->setOutputValue(i, inputs[i]); bi->proceedConnections(); } if (bp != 0) { for (int i = 1; i < parametersCount(); ++i) bp->setOutputValue(i - 1, parameters[i].toFloat()); bp->proceedConnections(); } switch (mode_) { case BrickBase::Synchronous: for (uint i = 0; i < bricks.size(); ++i) bricks[i]->tick(time); for (uint i = 0; i < bricks.size(); ++i) bricks[i]->proceedConnections(); break; case BrickBase::Asynchronous: default: for (uint i = 0; i < tree.size(); ++i) { tl = &tree[i]; for (uint j = 0; j < tl->size(); ++j) (*tl)[j]->tick(time); for (uint j = 0; j < tl->size(); ++j) (*tl)[j]->proceedConnections(); } break; } if (bo != 0) for (int i = 0; i < outputsCount(); ++i) outputs[i] = bo->input(i); return true; } void BrickComposite::fillBaseBricks() { if (!baseBricks.isEmpty()) return; PIStringList libs = PICollection::groups(); piForeachC (PIString & l, libs) { PIVector group = PICollection::groupElements(l); piForeachC (PIObject * o, group) baseBricks << (BrickBase * )o; } /*baseBricks.push_back(new BrickEmitConst()); baseBricks.push_back(new BrickEmitLinear()); baseBricks.push_back(new BrickEmitSin()); baseBricks.push_back(new BrickEmitDelta()); baseBricks.push_back(new BrickEmitStep()); baseBricks.push_back(new BrickEmitPulse()); baseBricks.push_back(new BrickEmitStrobe()); baseBricks.push_back(new BrickEmitTime()); baseBricks.push_back(new BrickEmitFrequency()); baseBricks.push_back(new BrickEmitNoiseRandom()); baseBricks.push_back(new BrickEmitNoiseNormal()); baseBricks.push_back(new BrickMathAbsolute()); baseBricks.push_back(new BrickMathSign()); baseBricks.push_back(new BrickMathAmplifier()); baseBricks.push_back(new BrickMathSum()); baseBricks.push_back(new BrickMathMultiply()); baseBricks.push_back(new BrickMathDivide()); baseBricks.push_back(new BrickMathPower()); baseBricks.push_back(new BrickMathDeadZone()); baseBricks.push_back(new BrickMathSaturation()); baseBricks.push_back(new BrickMathDelayTicks()); baseBricks.push_back(new BrickMathDelaySeconds()); baseBricks.push_back(new BrickMathRelay()); baseBricks.push_back(new BrickMathDerivate()); baseBricks.push_back(new BrickMathIntegral()); baseBricks.push_back(new BrickMathIntegralSaturated()); baseBricks.push_back(new BrickMathQuantize()); baseBricks.push_back(new BrickMathThreshold()); baseBricks.push_back(new BrickMathFunction()); baseBricks.push_back(new BrickMathFFT()); baseBricks.push_back(new BrickMathCopy()); baseBricks.push_back(new BrickMathBessel()); baseBricks.push_back(new BrickLogicNot()); baseBricks.push_back(new BrickLogicAnd()); baseBricks.push_back(new BrickLogicOr()); baseBricks.push_back(new BrickLogicXor()); baseBricks.push_back(new BrickLogicNAnd()); baseBricks.push_back(new BrickLogicNOr()); baseBricks.push_back(new BrickLogicNXor()); baseBricks.push_back(new BrickLogicMemory()); baseBricks.push_back(new BrickLogicCompare()); baseBricks.push_back(new BrickDigitalTriggerRS()); baseBricks.push_back(new BrickDigitalTriggerD()); baseBricks.push_back(new BrickDigitalTriggerJK()); baseBricks.push_back(new BrickDigitalCounter2()); baseBricks.push_back(new BrickDigitalCounter4()); baseBricks.push_back(new BrickDigitalCounter8()); baseBricks.push_back(new BrickDigitalCoder1()); baseBricks.push_back(new BrickDigitalCoder2()); baseBricks.push_back(new BrickDigitalCoder3()); baseBricks.push_back(new BrickDigitalCoder4()); baseBricks.push_back(new BrickDigitalDecoder1()); baseBricks.push_back(new BrickDigitalDecoder2()); baseBricks.push_back(new BrickDigitalDecoder3()); baseBricks.push_back(new BrickDigitalDecoder4()); baseBricks.push_back(new BrickDigitalMux1()); baseBricks.push_back(new BrickDigitalMux2()); baseBricks.push_back(new BrickDigitalMux3()); baseBricks.push_back(new BrickDigitalMux4()); baseBricks.push_back(new BrickDigitalDemux1()); baseBricks.push_back(new BrickDigitalDemux2()); baseBricks.push_back(new BrickDigitalDemux3()); baseBricks.push_back(new BrickDigitalDemux4()); baseBricks.push_back(new BrickDigitalDigitalToAnalog2()); baseBricks.push_back(new BrickDigitalDigitalToAnalog4()); baseBricks.push_back(new BrickDigitalDigitalToAnalog8()); baseBricks.push_back(new BrickDigitalAnalogToDigital2()); baseBricks.push_back(new BrickDigitalAnalogToDigital4()); baseBricks.push_back(new BrickDigitalAnalogToDigital8()); baseBricks.push_back(new BrickLinkTransferFunction()); baseBricks.push_back(new BrickLinkFilter1Degree()); baseBricks.push_back(new BrickLinkFilterBandpass()); baseBricks.push_back(new BrickInterfaceSerialIn()); baseBricks.push_back(new BrickInterfaceSerialOut()); baseBricks.push_back(new BrickInterfaceUDPIn()); baseBricks.push_back(new BrickInterfaceUDPOut()); baseBricks.push_back(new BrickInterfaceBinFileOut()); baseBricks.push_back(new BrickStatisticMinMaxI()); baseBricks.push_back(new BrickStatisticMinMaxF()); baseBricks.push_back(new BrickStatisticExpectation()); baseBricks.push_back(new BrickStatisticVariance()); baseBricks.push_back(new BrickComposite()); baseBricks.push_back(new BrickCompositeInput()); baseBricks.push_back(new BrickCompositeOutput()); baseBricks.push_back(new BrickCompositeParameters()); baseBricks.push_back(new BrickCompositeInformation());*/ } void sumTrees(PIVector > & ft, PIVector > & st) { uint mi = piMin(ft.size(), st.size()); for (uint i = 0; i < mi; ++i) for (uint j = 0; j < st[i].size(); ++j) ft[i].push_back(st[i][j]); if (st.size() > ft.size()) for (uint i = mi; i < st.size(); ++i) ft.push_back(st[i]); } void buildTree(PIVector & bricks, PIVector > & tree) { PIVector > ct; BrickBase * b; tree.clear(); if (bricks.size() == 0) return; for (uint i = 0; i < bricks.size(); ++i) { b = bricks[i]; b->ticked = false; b->level_ = -666; b->tmp_ = 0; } ct = buildSubtree(bricks, tree); //cout << "--------" << endl; while (ct.size() > 0) { //cout << "subtree " << ct.size() << endl; sumTrees(tree, ct); ct = buildSubtree(bricks, tree); } //cout << "subtrees built" << endl; uint tcnt = 0; for (uint i = 0; i < tree.size(); ++i) tcnt += tree[i].size(); //cout << "built for " << tcnt << " from " << bricks.size() << endl; if (tcnt < bricks.size()) { for (uint i = 0; i < bricks.size(); ++i) { b = bricks[i]; for (uint j = 0; j < tree.size(); ++j) for (uint k = 0; k < tree[j].size(); ++k) if (tree[j][k] == b) goto next; //cout << "add " << b->name().stdString() << " in level (" << b->level_ << ") ... " << flush; if (b->level_ < 0) b->level_ = 0; if ((uint)b->level_ < tree.size() && b->level_ >= 0) tree[b->level_].push_back(b); else { tree.resize(b->level_ + 1); tree[b->level_].push_back(b); } //cout << "ok" << endl; next: ; } } int mlev = bricks[0]->level_; for (uint i = 1; i < bricks.size(); ++i) if (mlev > bricks[i]->level_) mlev = bricks[i]->level_; if (mlev >= 0) return; piCout << "minimum level =" << mlev << ", so rebuild tree manually"; tree.clear(); int clev = 0; uint cnt = 0; PIVector level; for (uint i = 0; i < bricks.size(); ++i) bricks[i]->level_ -= mlev; mlev = 0; while (bricks.size() > cnt) { level.clear(); for (uint i = 0; i < bricks.size(); ++i) { b = bricks[i]; if (b->level_ != clev) continue; level.push_back(b); ++cnt; } if (level.size() > 0) tree.push_back(level); ++clev; } } PIVector > buildSubtree(PIVector & bricks, PIVector > & tree) { PIVector bbs, tbs, level; PIVector > ttree; BrickBase * b, * sb; int minlev, clev; if (bricks.size() == 0) return ttree; //cout << "initial stage" << endl; /// Initial stage: first level - initialize bricks for (uint i = 0; i < bricks.size(); ++i) { b = bricks[i]; if (b->level_ >= 0) continue; bbs.push_back(b); if (!b->isInitial()) { tbs.push_back(b); continue; } b->level_ = 0; level.push_back(b); } if (level.size() == 0 && tbs.size() == 0) return ttree; if (level.size() == 0) { level.push_back(tbs[0]); level.back()->level_ = 0; tbs.pop_front(); } ttree.clear(); ttree.push_back(level); //cout << "first stage" << endl; /// First pass: direct bricks bypass while (tbs.size() > 0) { level.clear(); for (uint i = 0; i < ttree.back().size(); ++i) { b = ttree.back()[i]; b->tmp_++; for (uint j = 0; j < b->connections.size(); ++j) { sb = b->connections[j].brick_to; if (sb->ticked) continue; level.push_back(sb); sb->level_ = ttree.size(); for (uint k = 0; k < tbs.size(); ++k) { if (tbs[k] == sb) { tbs.remove(k); break; } } } if (b->tmp_ >= b->inputs_count) b->ticked = true; } if (level.size() == 0) break; ttree.push_back(level); } minlev = ttree[0][0]->level_; if (tbs.size() == 0) goto third; for (uint i = 0; i < ttree.size(); ++i) for (uint j = 0; j < ttree[i].size(); ++j) ttree[i][j]->ticked = true; //cout << "second stage" << endl; /// Second pass: ttree complement with invert bypass while (tbs.size() > 0) { level.clear(); for (uint i = 0; i < tbs.size(); ++i) { b = tbs[i]; for (uint j = 0; j < b->connections.size(); ++j) { sb = b->connections[j].brick_to; if (!sb->ticked) continue; level.push_back(b); b->level_ = sb->level_ - 1; if (minlev > b->level_) minlev = b->level_; b->ticked = true; for (uint k = 0; k < tbs.size(); ++k) { if (tbs[k] == b) { tbs.remove(k); break; } } i = 0; } } if (level.size() == 0) break; } //cout << "third stage" << endl; third: /// Third pass: rebuild ttree ttree.clear(); clev = minlev; level.push_back(0); while (level.size() > 0) { level.clear(); for (uint i = 0; i < bbs.size(); ++i) { b = bbs[i]; if (b->level_ == clev) level.push_back(b); } if (level.size() > 0) ttree.push_back(level); ++clev; } //cout << "final stage" << endl << endl; /// Final stage: normalize levels for (uint i = 0; i < ttree.size(); ++i) for (uint j = 0; j < ttree[i].size(); ++j) ttree[i][j]->level_ = i; return ttree; } BrickCompositeInput::BrickCompositeInput(int inputs_num): BrickCompositeBase(0, inputs_num, inputs_num) { type = "Input"; setName(type); io_Type = BrickBase::VariableOutputs; outNames[0] = "0"; note_ += "\"Parameters\" are labels for inputs that will be shown in parent composite brick"; parameters[0].setValue(""); } BrickCompositeOutput::BrickCompositeOutput(int outputs_num): BrickCompositeBase(outputs_num, 0, outputs_num) { type = "Output"; setName(type); io_Type = BrickBase::VariableInputs; inNames[0] = "0"; note_ += "\"Parameters\" are labels for outputs that will be shown in parent composite brick"; parameters[0].setValue(""); } BrickCompositeParameters::BrickCompositeParameters(): BrickCompositeBase(0, 1, 1) { type = "Parameters"; setName(type); io_Type = BrickBase::VariableOutputs; note_ = "There are parameters you can set from parent brick\nEach parameter is float and should be typed in format: \"name[:default]\""; parameters[0].setValue("p"); outNames[0] = "p"; } void BrickCompositeParameters::parameterChanged(int index) { PIString s = parameters[index].toString(); int i = s.toLowerCase().find(':'); if (i < 0) outNames[index] = s; else outNames[index] = s.left(i).trim(); } BrickCompositeInformation::BrickCompositeInformation(): BrickCompositeBase(0, 0, 2) { type = "Information"; setName(type); parametersName_ = "Information"; paramNames[0] = "Type name"; paramNames[1] = "Promt"; note_ = "There are information fields about parent composite brick"; parameters[0].setValue(""); parameters[1].setValue(""); }