How to simulate digital logic circuits with feedback loops? - c++

I learning how to simulate digital logic circuits .
I am presenting the source code of my first attempt here.
It is small program for simulating circuits consisting
of AND,OR and NOT gates.
This code works well for circuits without loops.
When circuit loops are introduced it causes a stack overflow because of endless recursion.
Please help me to remove this bug.
Please note that this is a hobby project and any help will be appreciated.
Source code :
#include <cstdlib>
#include <iostream>
using namespace std;
class LogicGate
{
int type;//gate type: 0 for NOT, 1 for OR, 2 for AND
//pins
bool ina;//input a
bool inb;//input b::this pin is not used for NOT gate
bool outc;//output
//fan-in
LogicGate* ga;//gate connected to input a
LogicGate* gb;//gate connected to input b
//fan-out
LogicGate* gc;//gate connected to output
int gctarget;//target input to which the gate "gc" is connected, 0 for input a, 1 for input c
public:
char* name;
LogicGate()
{
ina = inb = outc = false;
ga = gb = gc = (LogicGate*)0;
type = 0;
}
LogicGate(bool a, bool b)
{
ina = a; inb = b; outc = false;
ga = gb = gc = (LogicGate*)0;
type = 0;
}
//set logic
void settype(int t){if(t>=0&&t<3)type=t;else type=0;}
//set input
void seta(bool a){ ina = a; }
void setb(bool b){ inb = b; }
void setab(bool a, bool b){ina = a; inb = b; }
//connect gate
void cona(LogicGate* cga){ ga = cga; }
void conb(LogicGate* cgb){ gb = cgb; }
void conab(LogicGate* cga, LogicGate* cgb){ ga = cga; gb = cgb; }
//connect the output of this gate to another gate's input
void chainc(LogicGate* cgc, int target)
{
gc = cgc;
gctarget = target;
if(target==0) cgc->cona(this); else cgc->conb(this);
}
//calculate output
bool calcout()
{
//if the input is not available make it available by forcing the connected gates to calculate
if(ga){ ina = ga->calcout(); } //BUG:this may cause Stack overflow for circuits with loops
if(gb){ inb = gb->calcout(); }//BUG:this may cause Stack overflow for circuits with loops
//do the logic when inputs are available
switch(type)
{
case 0:
outc = !ina; break;
case 1:
outc = ina || inb; break;
case 2:
outc = ina && inb; break;
}
//if a gate is connected to output pin transfer the output value to the target input pin of the gate
if(gc){
if(gctarget==0){
gc->seta(outc);
}else{
gc->setb(outc);
}
}
//for debugging only
cout<<name<<" outputs "<<outc<<endl;
return outc;
}
};
int main(int argc, char *argv[])
{
LogicGate x,z;
//AND gate
z.settype(2);
z.seta(false);
z.setb(true);
z.name = "ZZZ";
//OR gate
x.settype(1);
x.cona(&z); // take one input from AND gate's output
x.setb(true);
x.name = "XXX";
//z.cona(&x);// take one input from OR gate's output to make a loop:: results in stack overflow
x.chainc(&z,0);//connect the output to AND gate's input "a" to form loop:: results in stack overflow
cout<<"final output"<<x.calcout()<<endl;
return 0;
}

The Problem here is that you are Looping infinitely. A program behaves somehow different than real logic gates. I see two possibilities here:
1) Implement cycles
You can implement it like a cpu works. a call to calcout only calculates to Output of one gate and iterates to the next one. You could create a Container class for your gates:
class GateContainer
{
//Contains all gates of your "circuit"
std::vector<LogicalGate> allGates;
//Contains all current gates to be processed
std::queue<LogicalGate*> currentGates;
void nextStep();
}
The nextStep function could look like this:
void GateContainer::nextStep()
{
//Get first gate from queue
LogicalGate *current = currentGates.front();
currentGates.pop();
//Do all the calculations with th current gate
//Push the gate connected to the Output to the list
currentGates.push(current->gc);
}
Please not that this code is untested and may also Need some error checks
2) Try to catch Loops
You can also try to catch Loops in calcout. You could achieve this by creating a flag in LogicalGate and reset it every time before calling calcout:
class LogicalGate
{
...
bool calculated;
...
}
Now before calling calcout() You Need to set calculated to false for every gate. Then, calcout could look something like this:
bool calcout()
{
calculated = true;
if(ga && !ga->calculated){ ina = ga->calcout(); }
if(gb && !ga->calculated){ inb = gb->calcout(); }
...
}

Related

Global variable doesn't update prior to next loop

I'm trying to build a tachometer in C++ for my ESP32. When I uncomment Serial.printf("outside rev: %d \n", rev); outside of the conditional it works, but when I comment it I get values that are orders of magnitude greater than they should be (700 revolutions without, vs 7 revolutions with). My best guess is that the print statement is slowing the loop() down just enough for incrementRevolutions() to toggle the global variable passedMagnet from true to false before the next loop. That would make sense, since a delay in updating passedMagnet would allow newRevCount++; to be triggered multiple times. But this is obviously something I can't debug with either print statements or step-through debugging given the time-sensitive nature of the race condition.
bool passedMagnet = true;
int incrementRevolutions(int runningRevCount, bool passingMagnet)
{
// Serial.printf("passedMagnet: %d , passingMagnet %d , runningRevCount: %d \n", passedMagnet, passingMagnet, runningRevCount);
int newRevCount = runningRevCount;
if (passedMagnet && passingMagnet)
{ //Started a new pass of the magnet
passedMagnet = false;
newRevCount++;
}
else if (!passedMagnet && !passingMagnet)
{ //The new pass of the magnet is complete
passedMagnet = true;
}
return newRevCount;
}
unsigned long elapsedTime = 0;
unsigned long intervalTime = 0;
int rev = 0;
void loop()
{
intervalTime = millis() - elapsedTime;
rev = incrementRevolutions(rev, digitalRead(digitalPin));
// Serial.printf("outside rev: %d \n", rev);
if (intervalTime > 1000)
{
Serial.printf("rev: %d \n", rev);
rev = 0;
elapsedTime = millis();
}
}
Is this a known gotcha with Arduino or C++ programming? What should I do to fix it?
I think the test is to blame. I had to rename and move things a bit to visualize the logic, sorry about that.
bool magStateOld = false; // initialize to digitalRead(digitalPin) in setup()
int incrementRevolutions(int runningRevCount, bool magState)
{
int newRevCount = runningRevCount;
// detect positive edge.
if (magState && !magStateOld) // <- was eq. to if (magState && magStateOld)
// the large counts came from here.
{
newRevCount++;
}
magStateOld = magState; // record last state unconditionally
return newRevCount;
}
You could also write it as...
int incrementRevolutions(int n, bool magState)
{
n += (magState && !magStateOld);
magStateOld = magState;
return n;
}
But the most economical (and fastest) way of doing what you want would be:
bool magStateOld;
inline bool positiveEdge(bool state, bool& oldState)
{
bool result = (state && !oldState);
oldState = state;
return result;
}
void setup()
{
// ...
magStateOld = digitalRead(digitalPin);
}
void loop()
{
// ...
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
// ...
}
It's reusable, and saves both stack space and unnecessary assignments.
If you cannot get clean transitions from your sensor (noise on positive and negative edges, you'll need to debounce the signal a bit, using a timer.
Example:
constexpr byte debounce_delay = 50; // ms, you may want to play with
// this value, smaller is better.
// but must be high enough to
// avoid issues on expected
// RPM range.
// 50 ms is on the high side.
byte debounce_timestamp; // byte is large enough for delays
// up to 255ms.
// ...
void loop()
{
// ...
byte now = (byte)millis();
if (now - debounce_timestamp >= debounce_delay)
{
debounce_timestamp = now;
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
}
// ...
}

c/c++ get large size data like 180 array from another class in stm32

I have an 32-bit ARM Cortex M4 (the processor in Pixhawk) to write two classes, each one is one threading in Pixhawk codebase setting.
The first one is LidarScanner, which dealing with incoming serial data and generates "obstacle situation". The second one is Algorithm, which handle "obstacle situation" and take some planning strategy. Here are my solution right now, use the reference function LidarScanner::updateObstacle(uint8_t (&array)[181]) to update "obstacle situation" which is 181 size array.
LidarScanner.cpp:
class LidarScanner{
private:
struct{
bool available = false;
int AngleArr[181];
int RangeArr[181];
bool isObstacle[181] = {}; //1: unsafe; 0:safe;
}scan;
......
public:
LidarScanner();
//main function
void update()
{
while(hal.uartE->available()) //incoming serial data is available
{
decode_data(); //decode serial data into three kind data: Range, Angle and Period_flag
if(complete_scan()) //determine if the lidarscanner one period is completed
{
scan.available = false;
checkObstacle(); //check obstacle situation and store safety in isObstacle[181]
scan.available = true;
}
}
}
//for another API recall
void updateObstacle(uint8_t (&array)[181])
{
for(int i=0; i<=181; i++)
{
array[i]=scan.isObstacle[i];
}
}
//for another API recall
bool ScanAvailable() const { return scan.available; }
......
}
Algorithm.cpp:
class Algorithm{
private:
uint8_t Obatcle_Value[181] = {};
class LidarScanner& _lidarscanner;
......
public:
Algorithm(class LidarScanner& _lidarscanner);
//main funcation
void update()
{
if (hal.uartE->available() && _lidarscanner.ScanAvailable())
{
//Update obstacle situation into Algorithm phase and do more planning strategy
_lidarscanner.updateObstacle(Obatcle_Value);
}
}
......
}`
Usually, it works fine. But I want to improve the performances so that I want to know what's the most effective way to do that. thanks!!!!
The most efficient way to copy data is to use the DMA.
DMAx_Channelx->CNDTR = size;
DMAx_Channelx->CPAR = (uint32_t)&source;
DMAx_Channelx->CMAR = (uint32_t)&destination;
DMAx_Channelx->CCR = (0<<DMA_CCR_MSIZE_Pos) | (0<<DMA_CCR_PSIZE_Pos)
| DMA_CCR_MINC | DMA_CCR_PINC | DMA_CCR_MEM2MEM ;
while(!(DMAx->ISR & DMA_ISR_TCIFx ));
AN4031 Using the DMA controller.

std::map pass by reference Pointer to Object

I'm coding a plugin for XPLANE10 which gets a MSG from ROS.
My IDE is QTcreator 4.1.0 based QT 5.7.0 for Ubuntu 64 Bit. I would like to use C++11 Standards
My code explained
The main initializes ROS and creates a map -> container.
ROS spins in a loop till my GUI sends a MSG where my AirPlane should fly.
The MSG contains 3 floats(phi, theta, psi) where "phi" is the AirPlane ID, theta contains the ID for my ETA(Estimated Time of Arrival)
and psi contains the ID for my pose All of the IDs are saved in the ParameterServer(lookuptable).
So at the beginning i look up the activeAirplanes which returns a vector . I would like to store them in a map where the key is the AirCraft ID and the second param is an instance of the Object.
So i have initialized the for example(looked in container while debugging):
[0] first = 1 // Airplane ID1
[0] second = new CObject(freq)
[1] first = 2 // Airplane ID2
[1] second = new CObject(freq)
If i get a MSG from GUI
phi = 1
theta=2
psi=3
,
ROS will callback
MSG(....std::map<i32, CObject> &container)
// if phi is 1 so use the mapkey 1 and trigger the method do_stuff from CObject
do_stuff(phi, theta, psi,freq)
I would like to call the in a function from main
int getPlanes(std::map<i32,CObject>& container)
{
...
getActiveAirplanesFromServer(activePlanes);
}
First Question:
How do i pass the container to my callback?
Second Question:
How do i parallelize do_stuff() so my callback will return to main and i'm able to command more aircrafts while the others are calculated?
Third Question:
How would be the correct syntax for getPlanes to pass the container by reference so getPlanes() can edit it?
Fourth Question:
Is there a difference between
std::map<i32,CObject*> map
std::map<i32,CObject>* map
and
std::map<i32,CObject*>::iterator it=container->begin();
std::map<i32,CObject*>::iterator* it=container->begin();
If yes, what do i want ? #4Solved
// I have to edit stuff 'cause of some restrictions in my company.
#include "Header.h"
int main()
{
f64 freq = 10;
std::map<i32, CObject>* container;
std::map<i32,CObject>::iterator* it=container->begin();
// ROS
if(!ros::isInitialized())
{
int rosargc = 0;
char** rosargv = NULL;
ros::init(rosargc, rosargv, "MainNode");//), ros::init_options::AnonymousName);
}
else
{
printf("Ros has already been initialized.....\n");
}
ros::NodeHandle* mainNodeHandle=new ros::NodeHandle;
ros::AsyncSpinner spinner(2);
ParameterServer * ptrParam= new ParameterServer(mainNodeHandle);
ros::Subscriber airSub=mainNodeHandle->subscribe<own_msgs::ownStruct>("/MSG",
1000,
boost::bind(MSG,
_1,
freq,
container));
std::vector<i32> activePlanes;
i32 retVal=0;
retVal += ptrParam-> ParameterServer::getActiveAirplanesFromServer(activePlanes);
if (retVal == 0 && activePlanes.size()>0)
{
for (u32 j =0; j <activePlanes.size(); j++)
{
container->insert (std::pair<i32,CObject> (activePlanes[j] , new CObject(freq)));
}
}
while (ros::ok())
{
spinner.start(); //spinnt sehr viel :-)
ros::waitForShutdown ();
}
std::cout<<"ENDE"<<std::endl;
int retval = 1;
return retval;
}
void MSG(const own_msgs::ownStruct<std::allocator<void> >::ConstPtr &guiMSG,
f64 freq,
std::map<i32, CObject> &container)
{
if ((guiMSG->phi != 0) && (guiMSG->theta != 0) && (guiMSG->psi != 0))
{
std::string alpha = std::to_string(guiMSG->phi)+std::to_string(guiMSG->theta)+to_string(guiMSG->psi);
container.at(guiMSG->phi) -> do_stuff(guiMSG->phi,guiMSG->theta,guiMSG->psi, freq);
}
else
{
std::cout<<" Did not receive anything\n"<<endl;
}
}
void do_stuff(...)
{
//copy the IDs to private Member of this single Object
//setROS() for this single Object
//callback the current AC pose via ID from XPLANE
//callback the wished AC pose via ID from ParamServer
// do some calculations for optimum flight path
// publish the Route to XPlane
}
EDIT::
Problem is i get it to compile now and if debug it and set a breakpoint at :
void MSG(const own_msgs::ownStruct<std::allocator<void> >::ConstPtr &guiMSG,f64 freq,std::map<i32, CObject*> &container)
{
..
/*->*/ container.at(guiMSG->)...
}
The Container remains empty.
So i read some stuff about pointers and i saw my errors..
I confused * and &
if i want to pass the adress of a variable i have to write like
int main()
{
int a = 0;
AddTwo(&a)
cout<<a<<endl; // Output: 2
}
void AddTwo(int* a)
{
a+=2;
}

Creating new objects in C++ function causes program to crash

I have a program which allows the user to play Dominoes against 3 CPU players, with varying difficulty. Each CPU player can be either Beginner, Intermediate or Expert, and each difficulty has it's own class. If I initiate my 3 CPU players at the beginning of my 'Window' class (below), the program runs fine.
In Window.h
public:
Window(QWidget *parent = 0);
Intermediate *cpu1;
Beginner *cpu2;
Intermediate *cpu3;
In Window.cpp
Window::Window(QWidget *parent):QDialog(parent) {
cpu1 = new Intermediate;
cpu2 = new Beginner;
cpu3 = new Intermediate;
}
However I want the user to be able to select the CPU difficulties at the beginning of the game, so I now have a function within 'Window' that creates the objects. As soon as I call this function the game freezes and I get an error message pop up saying telling me the program has ended unexpectedly.
void Window:: startGame(){
cpu1 = new Intermediate;
cpu2 = new Beginner;
cpu3 = new Intermediate;
}
If anyone would be able to explain to me what is going on and what I can do to get around this that would be great.
Intermediate.cpp (Beginner.cpp is almost identical)
#include "intermediate.h"
Intermediate::Intermediate()
{
tilePlaced = false;
skipGo = false;
}
void Intermediate::findDoubles(int a[7][2]){
for(int i = 0; i < 7; i++){ // Creates new doubles list after each go.
doublesList[i] = 0;
}
for(int i = 0; i < 7; i++){ // Creates a list of doubles
if ((a[i][0] == a[i][1]) && (a[i][0] != 7)){
doublesList[a[i][0]] = 1;
}
}
}
bool Intermediate::addDomino(){} // Function that finds best domino to replace and returns bool
if(tilePlaced == false){
pass++;
text += "\nPassed turn";
return false;
}
else{
pass = 0;
text += QString("\nPlaced [%1 : %2]").arg(a).arg(b);
return true;
}
}
One way to start would be to narrow down which class is causing the fault. Does it work if they are all Beginner, or if they are all Intermediate? If so then the other one is causing the problem.

Threads C++, Access Violation reading location x error

Platform : Windows 7
I'm developing a project for known text cipher attack in which;
Main process creates n child processes
Child processes decrypt an encrypted string, key subspace is partitioned according to number of child processes
Communication between child processes are by a static variable
for(int i = 0; i<info.totalNumberOfChildren; i++)
{
startChild( &info.childInfoList[i]);
//_beginthread(startChild, 0, &info.childInfoList[i]);
}
Above code works fine since:
First child starts execution, the key is set as a number such as 8 for testing purposes which is within the first child's partition, so first child finds the key, reports and sets true the killSwitch.
All the other children that are created are closed even before checking the first key as the killSwitch is true.
When I however do this :
for(int i = 0; i<info.totalNumberOfChildren; i++)
{
//startChild( &info.childInfoList[i]);
_beginthread(startChild, 0, &info.childInfoList[i]);
}
I get an access violation error. What could possibly be my source of error ?
Edit: I will try to share as relevant code as I can
startChild does the following:
void startChild( void* pParams)
{
ChildInfo *ci = (ChildInfo*)pParams;
// cout<<"buraya geldi"<<endl;
ChildProcess cp(*ci);
// write to log
cp.completeNextJob();
}
childInfo holds the following :
// header file
class ChildInfo
{
public:
ChildInfo();
ChildInfo(char * encrypted, char * original, static bool killSwitch, int totalNumOfChildren, int idNum, int orjLen);
void getNextJob();
bool keyIsFound();
Des des;
void printTest();
bool stopExecution;
bool allIsChecked;
char * encyptedString;
char * originalString;
int id;
int orjStrLen;
private:
int lastJobCompleted;
int totalNumberOfChildren;
int jobDistBits;
};
completeNextJob() does the following :
void ChildProcess::completeNextJob()
{
cout<<"Child Id : "<<info.id<<endl;
// cout<<"Trying : "<<info.encyptedString<<endl; // here I got an error
char * newtrial = info.encyptedString;
char * cand = info.des.Decrypt(newtrial); // here I also get an error if I comment out
/*
cout<<"Resultant : "<<cand<<endl;
cout<<"Comparing with : "<<info.originalString<<endl;
*/
bool match = true;
for(int i = 0; i<info.orjStrLen; i++)
{
if(!(cand[i] == info.originalString[i]))
match = false;
}
if(match)
{
cout<<"It has been acknowledged "<<endl;
info.stopExecution = true;
return;
}
else
{
if(!info.keyIsFound())
{
if(!info.allIsChecked)
{
info.getNextJob();
completeNextJob();
}
else
{
}
}
else
{
}
}
}
decrypt() method does the following :
char * Des::Decrypt(char *Text1)
{
int i,a1,j,nB,m,iB,k,K,B[8],n,t,d,round;
char *Text=new char[1000];
unsigned char ch;
strcpy(Text,Text1); // this is where I get the error
i=strlen(Text);
keygen();
int mc=0;
for(iB=0,nB=0,m=0;m<(strlen(Text)/8);m++) //Repeat for TextLenth/8 times.
{
for(iB=0,i=0;i<8;i++,nB++)
{
ch=Text[nB];
n=(int)ch;//(int)Text[nB];
for(K=7;n>=1;K--)
{
B[K]=n%2; //Converting 8-Bytes to 64-bit Binary Format
n/=2;
} for(;K>=0;K--) B[K]=0;
for(K=0;K<8;K++,iB++) total[iB]=B[K]; //Now `total' contains the 64-Bit binary format of 8-Bytes
}
IP(); //Performing initial permutation on `total[64]'
for(i=0;i<64;i++) total[i]=ip[i]; //Store values of ip[64] into total[64]
for(i=0;i<32;i++) left[i]=total[i]; // +--> left[32]
// total[64]--|
for(;i<64;i++) right[i-32]=total[i];// +--> right[32]
for(round=1;round<=16;round++)
{
Expansion(); //Performing expansion on `right[32]' to get `expansion[48]'
xor_oneD(round);
substitution();//Perform substitution on xor1[48] to get sub[32]
permutation(); //Performing Permutation on sub[32] to get p[32]
xor_two(); //Performing XOR operation on left[32],p[32] to get xor2[32]
for(i=0;i<32;i++) left[i]=right[i]; //Dumping right[32] into left[32]
for(i=0;i<32;i++) right[i]=xor2[i]; //Dumping xor2[32] into right[32]
} //rounds end here
for(i=0;i<32;i++) temp[i]=right[i]; // Dumping -->[ swap32bit ]
for(;i<64;i++) temp[i]=left[i-32]; // left[32],right[32] into temp[64]
inverse(); //Inversing the bits of temp[64] to get inv[8][8]
/* Obtaining the Cypher-Text into final[1000]*/
k=128; d=0;
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
{
d=d+inv[i][j]*k;
k=k/2;
}
final[mc++]=(char)d;
k=128; d=0;
}
} //for loop ends here
final[mc]='\0';
char *final1=new char[1000];
for(i=0,j=strlen(Text);i<strlen(Text);i++,j++)
final1[i]=final[j]; final1[i]='\0';
return(final);
}
Windows is trying to tell you why your program crashed. Please use a debugger to see what Windows is talking about. Location X is important: it should tell you whether your program is dereferencing NULL, overflowing a buffer, or doing something else. The call stack at the time of the crash is also very important.
Debugger is your best friend, try to use it and check step by step what could cause this access violation.
I think that info.encyptedString is not initialized correctly and pointing to not allocated memory, but I cant be sure because you didn't show this part of code.
And of course you must protect your shared resources (info) using some synchronization objects like critical section or mutex or semaphore.
I don't know, the basic issue seems pretty straightforward to me. You have multiple threads executing simultaneously, which access the same information via *pParams, which presumably is of type ChildInfo since that's what you cast it to. That info must be getting accessed elsewhere in the program, perhaps in the main thread. This is corrupting something, which may or may not have to do with Text1 or info.id, these errors can often be 'non-local' and hard to debug for this reason. So start mutex-protecting the entire thread (within your initial loop), and then zero in on the critical sections by trial and error, i.e. mutex-protect as small a region of code as you can get away with without producing errors.