Click here to Skip to main content
15,885,244 members
Articles / Web Development / HTML

Circuit Engine

Rate me:
Please Sign up or sign in to vote.
4.93/5 (103 votes)
18 Oct 2018GPL355 min read 248.1K   8.6K   212  
A System for Simulation and Analysis of Logic Circuits
/*
This file is part of Circuit Engine.
 
Circuit Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
Circuit Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with Circuit Engine.  If not, see <http://www.gnu.org/licenses/>.
-----------------------------------------------------------------------
	CircuitElement.h :	Holds and handles list of Gates in order
						to constitude and manipulate a circuit element.
*/

/*
  CE::CABLE differencies:
	nof_inputs => Position X2
	nof_outputs => Position Y2
	V.nof_inputs => height
	V.output => Selected Leg
	V.next_gate => points to CE::CABLE (explicitly)
	V.Input[0] => output gate address reported by a plugged leg of cable
	V.leg_no => CableNodeId //connected cables consists one node.

	and the queries: ceqHover1, ceqHover2, ceqHasOd1, ceqHasOd2
	belong to CE::CABLE only.
*/


#pragma once
#include "gate.h" //Gate.h inherits Binary.h
#include "BreadBoard.h"


//CE constant definitions.
#define CE_NOF_TYPES 5
#define CE_NOF_STATE_QUERIES 6

//CE state and type enumerations:
enum CEQuery {ceqHover,ceqOn,  ceqHover1,ceqHover2,ceqHasOd1,ceqHasOd2,};
/*last four queries are for cetCABLE:
	ceqHover1 : is first leg of the cable in hover mode.
	ceqHover2 : is second leg of the cable in hover mode.
	ceqHasOd1 : is there output dublication in first leg's BBNode list of the cable.
	ceqHasOd2 : is there output dublication in second leg's BBNode list of the cable.
*/
//enum CabStats {CabStatINPUT, CabStatOUTPUT};
enum CEtype {cetEmpty,cetLED,cetCHIP,cetCABLE,cetSOURCE,cetBREADBOARD};
char *CEnames[]  = {"Empty","LED","CHIP","CABLE","SOURCE","BREADBOARD"}; //for logging.

unsigned int CurrentBBrow,CurrentBBcol,CurrentBBstride; //are set by Artist for movement restriction of CEs.
unsigned int LastOutputRow, LastOutputCol;	//are filled by BreadBoard. this is the list address to which the last output enters.
BBNode *LastOutputAddres;					//and they are used by the cetCABLE::CalculateCE().


class CircuitElement
{
private:
	Gate *gate;				//The list of gates of the CE.
	CircuitElement *next_ce;//Concequtive CE in a CE list.
	CircuitElement *prev_ce;
	unsigned int id;		//identifier of CE.
	unsigned int nof_gates;	//Number of gates that the CE contains.
	CEtype type;			//Type of the CE: CHIP LED or CABLE.
	static unsigned int ce_id_counter; //identifier counter.


	//GUI related variables for CE positioning over/on BreadBoard.
	unsigned int position_x; //BB(row,col,stride) (the upper left leg position on BB hole array)
					//for cetCABLE, this is first leg position X.
	unsigned int position_y; //these vars. are to check plugability of this CE on breadboard.
					//for cetCABLE, this is first leg position Y.

	//CE Message Functions:
	void GiveError(char *e);
	void GiveMsg(char *msg);

public:
	char name[27];			//in-script name of the CE:CHIP or, "LED" or "CABLE".
	unsigned int
		nof_inputs,  //to check nof_inputs; in-script CHIP header is equal with the declarations in CHIP block.
					//for cetCABLE, this is second leg position X.
		nof_outputs; //to check nof_outputs
					//for cetCABLE, this is second leg position Y.

	Gate V, G;				//the connection numbers for V&G in-script is saved in these.

	Binary CEInfo; //Holds information about CE states.(Inspect CEQuery enums for binary queries.)
	Binary LegPlugAbility;
	CircuitElement();
	~CircuitElement();
	Gate *AddGate(GateType gate_type, unsigned int nof_inputs = 0, unsigned int leg_no = 0); //add to tail of the list.
	void print(void); //Prints the CE for logging purpose.
	void CalculateCE(void);	//Calculation of all gates in the CE.

	//CE Adjustment Functions:
	void SetType(CEtype new_type);
	void SetNext(CircuitElement *new_next_ce);
	void SetPrev(CircuitElement *new_prev_ce);
	void SetName(char *new_name);
	void SetNofInputs(unsigned int new_nof_inputs);
	void SetNofOutputs(unsigned int new_nof_inputs);
	void SetVoltageLegNo(unsigned short voltage_leg_no);
	void SetGroundLegNo(unsigned short ground_leg_no);
	//void SetNofGates(unsigned int new_nof_gates);


	//CE Query Functions:
	unsigned int	GetNofGates(void);
	CircuitElement	*GetNext(void);
	CircuitElement	*GetPrev(void);
	Gate			*GetHead(void);
	CEtype			GetType(void);
	char			*GetName(void);
	unsigned int	GetNofLegs(void);
	unsigned int	GetPositionX(void);
	unsigned int	GetPositionY(void);
	Gate			*GetGateAddrOfLeg(unsigned int LegNo);
	bool IsOutputtingLeg(unsigned int LegNo);// may be dublication check it later...
	unsigned int	GetPositionX2(void);
	unsigned int	GetPositionY2(void);
	unsigned int    GetID(void);

	//CE Binary Query Functions:
	void SetStateInfo(CEQuery enumQ);
	void ResetStateInfo(CEQuery enumQ);
	bool GetStateInfo(CEQuery enumQ);

	//Visual
	void MoveTo(unsigned int pos_x, unsigned int pos_y);
	void MoveTo2(unsigned int pos_x2, unsigned int pos_y2);//for cable other leg.
	void MoveUp(void);
	void MoveDown(void);
	void MoveLeft(void);
	void MoveRight(void);
};

unsigned int CircuitElement::ce_id_counter = 0;

CircuitElement::CircuitElement()
{
	strcpy(name,"CE_NONAME");
	id = ce_id_counter++;
	GiveMsg("New circuit element requested. initializing...");

	nof_gates = 0;
	gate = NULL;
	next_ce = NULL;
	prev_ce = NULL;
	type = cetEmpty;

	nof_inputs = 0;
	nof_outputs = 0;

	position_x = 0;
	position_y = 0;

	GiveMsg("Voltage leg is creating...");
	V.SetProperties(gtInput,1);
	GiveMsg("Ground leg is creating...");
	G.SetProperties(gtInput,1);

    CEInfo.CreateBitArray(CE_NOF_STATE_QUERIES);
	CEInfo.SetIndex(ceqHover);
	CEInfo.Clear();
	SetStateInfo(ceqHover); // initially the CE is in hover mode before its birth in GUI.

	//LegPlugAbility is created by CECircuit class after parse.
}

CircuitElement::~CircuitElement()
{
	Gate *pick = gate;
	Gate *prev_gate = NULL;
	for(unsigned int i=0; i<nof_gates; i++)
	{
		prev_gate = pick;
		pick = pick->GetNext();
		delete prev_gate;
	}
	gate = NULL;
}

Gate *CircuitElement::AddGate(GateType gate_type, unsigned int nof_inputs ,unsigned int leg_no )
{//in destructor, place deallocation lines
	Gate *new_gate = new Gate();
	new_gate->SetProperties(gate_type,nof_inputs,leg_no);

	if(nof_gates == 0)
	{
		gate = new_gate;
	}
	else
	{
		Gate *pick = gate;
		for(; pick->GetNext() != NULL; pick = pick->GetNext()) ;//move on last.
		pick->SetNext(new_gate);
	}

	nof_gates ++;
	return new_gate;
}

void CircuitElement::print(void)
{
	unsigned int i=0;
	Gate *pick = gate;
	if(pick == NULL) {printf("\nEmpty CE : %s",name); return;}

	printf("\nGate List CE %s.id_%d [gtType(Addr).no >> nof_inputs (input addr. list)]",name,id);
	printf("\nV = leg_%d (%p), G = leg_%d (%p)",V.GetLegNo(), V.Input[0],G.GetLegNo(),G.Input[0]);
	do
	{
		printf("\n%s(%p)(leg_%d).%d >> %d (",GateNames[pick->GetGateType()],pick,pick->GetLegNo(),++i,pick->GetNofInputs());
		for(unsigned short input_no=0; input_no<pick->GetNofInputs(); input_no++)
			printf(" %p ",pick->Input[input_no]);
		printf(")");
		pick = pick->GetNext();

	}
	while(pick != NULL);

}

void CircuitElement::CalculateCE(void)
{
	switch (type)
	{
	case cetCHIP:
		V.Calculate();
		G.Calculate();
		
		if(V.output && !G.output)//behave normal.
			for(Gate *pick = gate; pick!=NULL; pick->Calculate(),pick=pick->GetNext());
		else
		{//the chip has no power -> take all inputs as 0.
			for(Gate *pick = gate; pick!=NULL; pick=pick->GetNext())
				if(pick->GetGateType() == gtInput)
                    pick->output = false;

			for(Gate *pick = gate; pick!=NULL; pick=pick->GetNext())
				if(pick->GetGateType() != gtInput)
					pick->Calculate();
		}
		

		break;
	case cetLED://if one of the legs of CE:LED is NULL turn off it else both connected to some gate check correctness of poles of the LED, if so turn on it.
		V.Input[0] == NULL || G.Input[0] == NULL ? CEInfo.ResetIndex(ceqOn) : V.Calculate() == true && G.Calculate() == false ? CEInfo.SetIndex(ceqOn) : CEInfo.ResetIndex(ceqOn);
		break;
	case cetCABLE:
		//cable only completes the connections between CEs while it is plugging/unplugging
		//so, no calculation stage occurs.
		break;
	}
}
void CircuitElement::GiveError(char *e)
{
	printf("\n(e)(CircuitElement %s.%d): %s",name,id,e);
	exit(0);
}

void CircuitElement::GiveMsg(char *msg)
{
	printf("\n(i)(CircuitElement %s.%d): %s",name,id,msg);
}

unsigned int CircuitElement::GetNofGates(void)
{
	return nof_gates;
}

void CircuitElement::SetName(char *new_name)
{
	GiveMsg("Renaming...");
	strncpy(name,new_name,sizeof(name));
	name[sizeof(name)-1] = '\0';
	GiveMsg("New name is OK.");
}

void CircuitElement::SetType(CEtype new_type)
{
	type = new_type;
}

void CircuitElement::SetNext(CircuitElement *new_next_ce)
{
	next_ce = new_next_ce;
}
void CircuitElement::SetPrev(CircuitElement *new_prev_ce)
{
    prev_ce = new_prev_ce;
}

void CircuitElement::SetNofInputs(unsigned int new_nof_inputs)
{
	nof_inputs = new_nof_inputs;
}
void CircuitElement::SetNofOutputs(unsigned int new_nof_outputs)
{
	nof_outputs = new_nof_outputs;
}
void CircuitElement::SetVoltageLegNo(unsigned short voltage_leg_no)
{
	GiveMsg("Setting Voltage Leg Association");
	V.SetProperties(gtInput,1,voltage_leg_no);
}
void CircuitElement::SetGroundLegNo(unsigned short ground_leg_no)
{
	GiveMsg("Setting Ground Leg Association");
	G.SetProperties(gtInput,1,ground_leg_no);
}
//void CircuitElement::SetNofGates(unsigned int new_nof_gates)
//{
//	nof_gates = new_nof_gates;
//}
CircuitElement *CircuitElement::GetNext(void)
{
	return next_ce;
}
CircuitElement *CircuitElement::GetPrev(void)
{
	return prev_ce;
}

Gate *CircuitElement::GetHead(void)
{
 return gate;
}

CEtype CircuitElement::GetType(void)
{
	return type;
}
char *CircuitElement::GetName(void)
{
	return name;
}

void CircuitElement::SetStateInfo(CEQuery enumQ)
{
    CEInfo.SetIndex(enumQ);
}
bool CircuitElement::GetStateInfo(CEQuery enumQ)
{
    return CEInfo[enumQ];
}
void CircuitElement::ResetStateInfo(CEQuery enumQ)
{
    CEInfo.ResetIndex(enumQ);
}
unsigned int CircuitElement::GetNofLegs(void)
{
    return (nof_inputs+nof_outputs) + (nof_inputs+nof_outputs)%2 + 2;
}
unsigned int CircuitElement::GetPositionX(void)
{
	return position_x;
}
unsigned int CircuitElement::GetPositionY(void)
{
	return position_y;
}
void CircuitElement::MoveTo(unsigned int pos_x, unsigned int pos_y)
{
    position_x = pos_x;
	position_y = pos_y;
}
void CircuitElement::MoveTo2(unsigned int pos_x2, unsigned int pos_y2)
{//!a cetCABLE specific function!
    nof_inputs = pos_x2;
	nof_outputs = pos_y2;
}
void CircuitElement::MoveUp(void)
{
	if(type == cetCABLE)
	{
		if(!V.output)//if the selected leg is the first one
		{
            if(position_y != 0) position_y -= 1;
		}
		else//if the selected leg is the second one
		{
			if(nof_outputs != 0) nof_outputs -= 1;
		}
		return;
	}
	if(position_y != 0) position_y -= 1;
}
void CircuitElement::MoveDown(void)
{
	switch(type)
	{
	case cetCHIP: if( position_y < CurrentBBrow - (GetNofLegs()/2) ) position_y += 1;
		break;
	case cetLED: if(position_y < CurrentBBrow-2) position_y += 1;
		break;
	case cetCABLE:
		if(!V.output)//if the selected leg is the first one
		{
            if(position_y < CurrentBBrow-1) position_y += 1;
		}
		else//if the selected leg is the second one
		{
			if(nof_outputs < CurrentBBrow-1) nof_outputs += 1;
		}
		break;
	default:;// if(position_y > CurrentBBrow-1)position_y += 1;
	}
}
void CircuitElement::MoveLeft(void)
{
	switch(type)
	{
	case cetCHIP:
		if(position_x != CurrentBBstride-1) //if not on the left most hollow
			position_x -= CurrentBBstride +  2;// 2 is the x length of a hollow.
		break;
	case cetLED:
        if( position_x!=0 && (position_x)%(CurrentBBstride+2) == 0 ) position_x -= 2; //jump over stride.
		if(position_x > 0) position_x -= 1;
		break;
	case cetCABLE:
		if(!V.output)//if the selected leg is the first one
		{
            if( position_x!=0 && (position_x)%(CurrentBBstride+2) == 0 ) position_x -= 2; //jump over stride.
			if(position_x > 0) position_x -= 1;
		}
		else//if the selected leg is the second one
		{
            if( nof_inputs!=0 && (nof_inputs)%(CurrentBBstride+2) == 0 ) nof_inputs -= 2; //jump over stride.
			if(nof_inputs > 0) nof_inputs -= 1;
		}
		break;
	default: ;//if(position_x > 0) position_x -= 1;
	}

}
void CircuitElement::MoveRight(void)
{
	switch(type)
	{
	case cetCHIP:
		if(position_x != (CurrentBBstride-1) + (CurrentBBcol-2)*(CurrentBBstride+2))
			//if not on the right most hollow move right.
			position_x += CurrentBBstride +  2;// 2 is the width of a hollow.
		break;
	case cetLED://if one right is hollow add 2 more (as hollow width) to the default case(no break!)
        if((position_x+1)!= CurrentBBcol*(CurrentBBstride+2)-2 && (position_x+3) % (CurrentBBstride+2) == 0 )position_x+=2;//jump over stride.
		if(position_x < (CurrentBBcol*CurrentBBstride) + (CurrentBBcol-1)*2 - 1) position_x += 1;
		break;
	case cetCABLE:
		if(!V.output)//if the selected leg is the first one
		{
			if((position_x+1)!= CurrentBBcol*(CurrentBBstride+2)-2 && (position_x+3) % (CurrentBBstride+2) == 0 )position_x+=2;//jump over stride.
			if(position_x < (CurrentBBcol*CurrentBBstride) + (CurrentBBcol-1)*2 - 1) position_x += 1;
		}
		else//if the selected leg is the second one
		{
			if((nof_inputs+1)!= CurrentBBcol*(CurrentBBstride+2)-2 && (nof_inputs+3) % (CurrentBBstride+2) == 0 )nof_inputs+=2;//jump over stride.
			if(nof_inputs < (CurrentBBcol*CurrentBBstride) + (CurrentBBcol-1)*2 - 1) nof_inputs += 1;
		}
		break;
	}
}
bool CircuitElement::IsOutputtingLeg(unsigned int LegNo)
{
    for(Gate *pick_G = gate; pick_G != NULL; pick_G = pick_G->GetNext())
		if(pick_G->GetLegNo() == LegNo+1) //leg numbers in gate starts from 1 inst. of 0
			return pick_G->GetGateType() == gtInput ? false : true;
	return false;
}
Gate *CircuitElement::GetGateAddrOfLeg(unsigned int LegNo)
{
	if(V.GetLegNo() == (LegNo+1)) return &V;
	if(G.GetLegNo() == (LegNo+1)) return &G;
	for(Gate *pick_G = gate; pick_G != NULL; pick_G = pick_G->GetNext())
		if(pick_G->GetLegNo() == (LegNo + 1))
			return pick_G;
	return NULL;
}
unsigned int CircuitElement::GetPositionX2(void)
{
	return nof_inputs; //for second leg X position of CE::cetCABLE.
}

unsigned int CircuitElement::GetPositionY2(void)
{
    return nof_outputs; //for second leg Y position of CE::cetCABLE.
}
unsigned int CircuitElement::GetID(void)
{
	return id;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Engineer Siemens
Turkey Turkey
I've graduated from computer engineering department in 2004 July, and developed the Circuit Engine as my graduation project at Eastern Mediterranean University (EMU). I've also graduated from MBA, Istanbul University in 2008 February. From 2004 until now, I've developed many web sites (B2B, B2C). Currently work for Siemens AG (http://siemens.com/ingenuityforlife) as a R&D Engineer (IoT) and I still continue to develop my personal projects about encryption algorithms, maths, OpenGL, Stock Exchange Market Analyses and Real-time Systems, MultiThreaded Applications and Web Solutions (mostly ASP.NET C#, JQuery/JS, MVC, WinForms, Win/Web Services, T-SQL and less PHP, ASP, MySQL and some possible other methods about problem solving if necessary). Also personal profession of photography : https://www.instagram.com/egldgn/


Circuit Engine base URL : https://sites.google.com/view/circuitengine


Comments and Discussions