Skip to content

Instantly share code, notes, and snippets.

@Alexanderallenbrown
Created August 11, 2017 12:04
Show Gist options
  • Save Alexanderallenbrown/1d13a8a392ea2c7263b1bb7fe42fbb71 to your computer and use it in GitHub Desktop.
Save Alexanderallenbrown/1d13a8a392ea2c7263b1bb7fe42fbb71 to your computer and use it in GitHub Desktop.
p5.js Boolean Algebra Program Simulator w/Timers, Counters
<div id='sketch-holder'></div>
<textarea id=inputcode rows=20 cols=195>
//This demo code shows latching, rising edge detection for a 3-state program.
//To see this program work, push button X1!!
//To See some other functionality, play with inputs 4, 5, and 6!
//Block 1: Handle Inputs, Timers, Counters
V2 = X1&&!V1 //V2 is press
T0_EN = X4&&!T1; //have timer count repeatedly and reset itself
T1_EN = X4&&T0;//same
CT0_UP = X5;
CT0_DOWN = X6;
CT0_RST = CTA0>10;
CT1_UP = T1;
CT1_RST = CT1;
//Block 2: State Transition Algebra (all ways into each state sans latches)
V7 = (Y3&&V2)||SP0;
V14 = (Y1&&V2);
V21 = (Y2&&V2);
//Block 3: Set States based on Transition variables (with latches)
//NOTE: Here, states are the outputs themselves. This is not always the case.
Y1 = V7||(Y1&&!V2);
Y2 = V14||(Y2&&!V2);
Y3 = V21||(Y3&&!V2);
//Block 4: write any outputs that are not states themselves & "old" variables that need to be remembered next loop
V1 = X1;
//That's it! This is the Boolean Algebra Program that will run over and over!!
</textarea>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.2.22/p5.js"></script>
<script type="text/javascript" src="https://rawgit.com/lmccart/p5.js/master/lib/addons/p5.dom.js"></script>
-->
var in1_button;
var in2_button;
var run_button;
var Y1light;
var Y2light;
var Y3light;
//inputs
var X1=false;
var X2=false;
var X3=false;
//outputs
var Y1=false;
var Y2=false;;
var Y3=false;
var Y4 = false;
var Y5 = false;
var Y6 = false;
//internal "coils"
var V1=false;
var V2=false;
var V3=false;
var V4=false;
var V5=false;
var V6=false;
var V7=false;
var V8=false;
var V9=false;
var V10=false;
var V11 = false;
var V12 = false;
var V13 = false;
var V14 = false;
var V15 = false;
var V16 = false;
var V17 = false;
var V18 = false;
var V19 = false;
var V20 = false;
var V21 = false;
//timer 1 variables
var T0_DUR = 1000;
var T0_EN = false;
var T0_RST = false;
var T0 = false;
//counter variables
var CT0_EN = false;
var CT0 = false;
var CTA0 = 0;
var CTO_RST = false;
//timer variables
var T0 = false;
var T0_EN = false;
var TA0 = 0;
var T1 = false;
var T1_EN = false;
var TA1 = 0;
//var TO_RST = false;
//counter variables
var CT0 = false;
var CT0_UP = false;
var CT0_DOWN = false;
var CTA0 = 0;
var CT0_RST = false;
var CT1 = false;
var CT1_UP = false;
var CT1_DOWN = false;
var CTA1 = 0;
var CT1_RST = false;
var SP0 = true;
var canv_w = 1200;
var canv_h = 650;
var inputCode;//this is the string that we will execute as code
var savedInputCode;
function setup(){
var canvas = createCanvas(canv_w,canv_h);
canvas.parent('sketch-holder');
frameRate(30);
stroke(0);
fill(0);
background(220);
textAlign(CENTER);
//textFont('Arial',32);
in1_button = new MomentaryButton(100,200,50,'X1',12);
in2_button = new MomentaryButton(100,300,50,'X2',12);
in3_button = new MomentaryButton(100,400,50,'X3',12);
in4_button = new RadioButton(175,200,50,'X4');
in5_button = new RadioButton(175,300,50,'X5');
in6_button = new RadioButton(175,400,50,'X6');
run_button = new MomentaryButton(75,550,25,'Update',18);
//output lights
Y1light = new outputLight(canv_w-150,200,50,color(128,0,0),color(255,0,0),'Y1',12);
Y2light = new outputLight(canv_w-150,300,50,color(128,128,0),color(255,255,0),'Y2',12);
Y3light = new outputLight(canv_w-150,400,50,color(0,128,0),color(0,255,0),'Y3',12);
Y4light = new outputLight(canv_w-50,200,50,color(128,0,0),color(255,0,0),'Y4',12);
Y5light = new outputLight(canv_w-50,300,50,color(128,128,0),color(255,255,0),'Y5',12);
Y6light = new outputLight(canv_w-50,400,50,color(0,128,0),color(0,255,0),'Y6',12);
//intermediate lights
V1light = new outputLight(canv_w/2-300,200,50,color(0,0,128),color(0,0,255),'V1',12);
V2light = new outputLight(canv_w/2-200,200,50,color(0,0,128),color(0,0,255),'V2',12);
V3light = new outputLight(canv_w/2-100,200,50,color(0,0,128),color(0,0,255),'V3',12);
V4light = new outputLight(canv_w/2,200,50,color(0,0,128),color(0,0,255),'V4',12);
V5light = new outputLight(canv_w/2+100,200,50,color(0,0,128),color(0,0,255),'V5',12);
V6light = new outputLight(canv_w/2+200,200,50,color(0,0,128),color(0,0,255),'V6',12);
V7light = new outputLight(canv_w/2+300,200,50,color(0,0,128),color(0,0,255),'V7',12);
V8light = new outputLight(canv_w/2-300,300,50,color(0,0,128),color(0,0,255),'V8',12);
V9light = new outputLight(canv_w/2-200,300,50,color(0,0,128),color(0,0,255),'V9',12);
V10light = new outputLight(canv_w/2-100,300,50,color(0,0,128),color(0,0,255),'V10',12);
V11light = new outputLight(canv_w/2,300,50,color(0,0,128),color(0,0,255),'V11',12);
V12light = new outputLight(canv_w/2+100,300,50,color(0,0,128),color(0,0,255),'V12',12);
V13light = new outputLight(canv_w/2+200,300,50,color(0,0,128),color(0,0,255),'V13',12);
V14light = new outputLight(canv_w/2+300,300,50,color(0,0,128),color(0,0,255),'V14',12);
V15light = new outputLight(canv_w/2-300,400,50,color(0,0,128),color(0,0,255),'V15',12);
V16light = new outputLight(canv_w/2-200,400,50,color(0,0,128),color(0,0,255),'V16',12);
V17light = new outputLight(canv_w/2-100,400,50,color(0,0,128),color(0,0,255),'V17',12);
V18light = new outputLight(canv_w/2,400,50,color(0,0,128),color(0,0,255),'V8',12);
V19light = new outputLight(canv_w/2+100,400,50,color(0,0,128),color(0,0,255),'V19',12);
V20light = new outputLight(canv_w/2+200,400,50,color(0,0,128),color(0,0,255),'V20',12);
V21light = new outputLight(canv_w/2+300,400,50,color(0,0,128),color(0,0,255),'V21',12);
//set up the timers
TA0box = new Timer(canv_w/2-300,500,150,75,"T0",color(0,0,128),color(0,0,255));
TA1box = new Timer(canv_w/2-100,500,150,75,"T1",color(0,0,128),color(0,0,255));
//set up the counters
CTA0box = new Counter(canv_w/2+100,512,150,100,"CT0",color(0,0,128),color(0,0,255));
CTA1box = new Counter(canv_w/2+300,512,150,100,"CT1",color(0,0,128),color(0,0,255));
//run the BAP once to get into a state.
runCallback();
}
function draw(){
background(220);
fill(0);
stroke(0);
rectMode(CENTER);
fill(220);
rect(140,canv_h/2-20,150,385);
rect(canv_w-100,canv_h/2-20,175,385);
fill(0);
//greet the user
textSize(32);
text("Boolean Algebra Program Simulator",canv_w/2,50);
textSize(12);
text("Type your Boolean Algebra code in javascript in the input box below the simulator. Hit update to see the effects of your Boolean Algebra program on the outputs/variables.",canv_w/2,75);
text("You can use any of the momentary inputs (X1-X3), latching inputs (X4-X6), outputs (Yx) or intermediate variables (Vx) shown on the screen in your program.",canv_w/2,95);
text("You can also assign timer inputs Tx_EN, and counter inputs CTx_UP/CTx_DOWN to use timers and counters in your program. ",canv_w/2,115);
textSize(32);
text("Inputs",140,160);
text("Outputs",canv_w-100,160);
text("Internal Variables",canv_w/2,160);
textSize(32);
text("Your Code Goes Below Here. Use only variable names you see in the simulator",canv_w/2,640);
//process inputs
in1_button.updateButton();
in2_button.updateButton();
in3_button.updateButton();
in4_button.updateRadio();
in5_button.updateRadio();
in6_button.updateRadio();
run_button.updateButton();
//hook timers up to global boolean vars
TA1box.en = T1_EN;
TA0box.update();
TA1box.update();
TA0 = TA0box.elapsed;
T0 = TA0box.state;
TA0box.en = T0_EN;
TA1 = TA1box.elapsed;
T1 = TA1box.state;
//hook timers up to global boolean vars
CTA0box.down = CT0_DOWN;
CTA0box.up = CT0_UP;
CTA1box.down = CT1_DOWN;
CTA1box.up = CT1_UP;
CTA0box.RST = CT0_RST;
CTA1box.RST = CT1_RST;
CTA0box.update();
CTA1box.update();
CTA0 = CTA0box.count;
CTA1 = CTA1box.count;
CT0 = CTA0box.state;
CT1 = CTA1box.state;
//update boolean code from text area with callback
//console.log(run_button.newtouch);
//boolean algebra block 3
X1 = in1_button.state;
X2 = in2_button.state;
X3 = in3_button.state;
X4 = in4_button.state;
X5 = in5_button.state;
X6 = in6_button.state;
if(run_button.newtouch){
runCallback();
}
try{
eval(inputCode);
}
catch(e){
inputCode = savedInputCode;
eval(inputCode);
alert(e+". Fix Error and Update To Continue!");
}
//boolean algebra block 4
Y1light.state = Y1;
Y2light.state = Y2;
Y3light.state = Y3;
Y4light.state = Y4;
Y5light.state = Y5;
Y6light.state = Y6;
V1light.state = V1;
V2light.state = V2;
V3light.state = V3;
V4light.state = V4;
V5light.state = V5;
V6light.state = V6;
V7light.state = V7;
V8light.state = V8;
V9light.state = V9;
V10light.state = V10;
V11light.state = V11;
V12light.state = V12;
V13light.state = V13;
V14light.state = V14;
V15light.state = V15;
V16light.state = V16;
V17light.state = V17;
V18light.state = V18;
V19light.state = V19;
V20light.state = V20;
V21light.state = V21;
//set light states to Y variables;
//light up outputs
Y1light.drawLight();
Y2light.drawLight();
Y3light.drawLight();
Y4light.drawLight();
Y5light.drawLight();
Y6light.drawLight();
V1light.drawLight();
V2light.drawLight();
V3light.drawLight();
V4light.drawLight();
V5light.drawLight();
V6light.drawLight();
V7light.drawLight();
V8light.drawLight();
V9light.drawLight();
V10light.drawLight();
V11light.drawLight();
V12light.drawLight();
V13light.drawLight();
V14light.drawLight();
V15light.drawLight();
V16light.drawLight();
V17light.drawLight();
V18light.drawLight();
V19light.drawLight();
V20light.drawLight();
V21light.drawLight();
console.log(SP0);
//kill SP0 if it's true
if(SP0==true){
SP0=false;
}
}
function runCallback(){
console.log("got into run callback");
var text = document.getElementById("inputcode");
console.log(text.value);
savedInputCode = inputCode;
inputCode = text.value;
X1=false;
X2=false;
X3=false;
V1=false;
V2=false;
V3=false;
V4=false;
V5=false;
V6=false;
V7=false;
V8=false;
V9=false;
Y1=false;
Y2=false;
Y3=false;
SP0=true;
}
function outputLight(ix,iy,id,icolorFalse,icolorTrue,ilabel,itextSize){
this.x =ix;
this.y = iy;
this.d = id;
this.label = ilabel;
this.colorFalse = icolorFalse;
this.colorTrue = icolorTrue;
this.state = false;
this.textSize = itextSize;
this.update = function(val){
this.state = val;
}
this.drawLight=function(){
if(this.state==false){
fill(this.colorFalse);
stroke(0);
}
else{
fill(this.colorTrue);
stroke(0);
}
//draw the radio button
ellipse(this.x,this.y,this.d,this.d,2);
fill(0);
stroke(0);
textSize(this.textSize);
text(this.label, this.x, this.y+this.d);
}
}
function Counter(ix,iy,iw,ih,ilabel,ifalseColor,itrueColor){
this.thresh = 3;//global variable
this.up = false;
this.oldup = false;
this.down = false;
this.olddown = false;
this.state = false;
this.RST = false;
this.count = 0;
this.x = ix;
this.y = iy;
this.w = iw;
this.h = ih;
this.label = ilabel;
this.falseColor = ifalseColor;
this.trueColor = itrueColor;
//variables for duration up/down control
this.upbtnx = this.x+0.75*this.w/2;
this.upbtny = this.y-0.5*this.h/2;
this.dnbtny = this.y+0.5*this.h/2;
this.upbtn_d = this.w*0.1;//diameter of the button circle
this.uplightx = this.x-0.75*this.w/2;
this.uplighty = this.y-0.5*this.h/2;
this.downlightx = this.uplightx;
this.downlighty = this.y;
this.rstlightx = this.uplightx;
this.rstlighty = this.y+this.h/4;
this.lightd = 0.1*this.w;
//lights for showing when inputs go high
this.uplight = new outputLight(this.uplightx,this.uplighty,this.lightd,color(0,128,128),color(0,255,255),"UP",8);
this.downlight = new outputLight(this.downlightx,this.downlighty,this.lightd,color(0,128,128),color(0,255,255),"DOWN",8);
this.rstlight = new outputLight(this.rstlightx,this.rstlighty,this.lightd,color(0,128,128),color(0,255,255),"RST",8);
//now create a momentary button for the up and down buttons
this.upbtn = new MomentaryButton(this.upbtnx,this.upbtny,this.upbtn_d,"CNT+",8);
this.dnbtn = new MomentaryButton(this.upbtnx,this.dnbtny,this.upbtn_d,"CNT-",8);
this.update = function (){
//draw timer box
this.drawCounter();
//update class-owned variables based on buttons on timer
if (this.upbtn.newtouch==true){
this.thresh=this.thresh+1;//increase the timer duration by 10.
}
if ((this.dnbtn.newtouch==true)&&(this.thresh>0)){
this.thresh=this.thresh-1;//decrease
}
this.uplight.state = this.up;
this.downlight.state = this.down;
this.rstlight.state = this.RST;
//actually update timer variables
if (this.up&&!this.oldup){
this.count = this.count+1;
}
if(this.down&&!this.olddown&&this.count>=0){
this.count = this.count-1;
}
if(this.RST){
this.count=0;
}
//reset old enable to detect rising edge
this.oldup=this.up;
this.olddown = this.down;
this.state = this.count>=this.thresh;
}
this.drawCounter = function(){
rectMode(CENTER);
if(this.state==false){
fill(this.falseColor);
}
else{
fill(this.trueColor);
}
stroke(0);
//draw box for timer
rect(this.x,this.y,this.w,this.h);
this.uplight.drawLight();
this.downlight.drawLight();
this.rstlight.drawLight();
//draw buttons
this.dnbtn.updateButton();
this.upbtn.updateButton();
//draw some text
textSize(8);
fill(0);
text(this.label+" (out)",this.x,this.y-0.25*this.h);
text("CNT: "+str(int(this.thresh)),this.x,this.y);
text(this.label[0]+this.label[1]+"A"+this.label[2]+": "+str(int(this.count))+" (out)",this.x,this.y+this.h*.25);
text(this.label[0]+this.label[1]+"A"+this.label[2]+" counts up on "+str(this.label)+"_UP rising edge",this.x,this.y+1.3*this.h/2);
text(this.label[0]+this.label[2]+"A"+this.label[2]+" counts down on "+str(this.label)+"_DOWN rising edge",this.x,this.y+1.6*this.h/2);
text(str(this.label)+" is true when "+str(this.label[0]+this.label[1])+"A"+str(this.label[2])+">CNT",this.x,this.y+1.9*this.h/2);
text(str(this.label[0]+this.label[1])+"A"+str(this.label[2])+" resets when "+str(this.label)+"_RST is true")
}
}
function Timer(ix,iy,iw,ih,ilabel,ifalseColor,itrueColor){
this.duration = 1000;//global variable
this.en = false;
this.olden = false;
this.state = false;
this.RST = false;
this.tstart = millis();
this.elapsed = 0;
this.x = ix;
this.y = iy;
this.w = iw;
this.h = ih;
this.label = ilabel;
this.falseColor = ifalseColor;
this.trueColor = itrueColor;
//variables for duration up/down control
this.upbtnx = this.x+0.75*this.w/2;
this.upbtny = this.y-0.5*this.h/2;
this.dnbtny = this.y+0.5*this.h/2;
this.upbtn_d = this.w*0.1;//diameter of the button circle
this.enlightx = this.x-0.75*this.w/2;
this.enlighty = this.y;
this.enlightd = this.w*0.1;
this.enlight = new outputLight(this.enlightx,this.enlighty,this.enlightd,color(0,128,128),color(0,255,255),"EN",8);
//now create a momentary button for the up and down buttons
this.upbtn = new MomentaryButton(this.upbtnx,this.upbtny,this.upbtn_d,"dur+",8);
this.dnbtn = new MomentaryButton(this.upbtnx,this.dnbtny,this.upbtn_d,"dur-",8);
this.update = function (){
this.enlight.state = this.en;
//draw timer box
this.drawTimer();
//update class-owned variables based on buttons on timer
if (this.upbtn.newtouch==true){
this.duration=this.duration+100;//increase the timer duration by 10.
}
if (this.dnbtn.newtouch==true){
this.duration=this.duration-100;//decrease
}
//actually update timer variables
if (this.en){
this.elapsed = millis()-this.tstart;
}
else{
this.elapsed=0;
this.tstart = millis();
}
//reset old enable to detect rising edge
this.olden=this.en;
this.state = this.elapsed>=this.duration;
}
this.drawTimer = function(){
rectMode(CENTER);
if(this.state==false){
fill(this.falseColor);
}
else{
fill(this.trueColor);
}
stroke(0);
//draw box for timer
rect(this.x,this.y,this.w,this.h);
//draw light
this.enlight.drawLight();
//draw buttons
this.dnbtn.updateButton();
this.upbtn.updateButton();
//draw some text
textSize(8);
fill(0);
text(this.label+" (out)",this.x,this.y-0.25*this.h);
text("Duration: "+str(int(this.duration)),this.x,this.y);
text(this.label[0]+"A"+this.label[1]+": "+str(int(this.elapsed))+" (out)",this.x,this.y+this.h*.25);
text(this.label+" counts when "+str(this.label)+"_EN is true",this.x,this.y+1.3*this.h/2);
text(str(this.label)+" is true when "+str(this.label[0])+"A"+str(this.label[1])+">Duration",this.x,this.y+1.6*this.h/2);
}
}
function MomentaryButton(ix,iy,id,ilabel,itextSize){
this.x = ix;
this.y = iy;
this.d = id;
this.state = false;
this.touched = false;
this.wastouched = false;
this.newtouch = false;
this.label = ilabel;
this.textSize = itextSize;
this.updateButton=function(){
//detect whether the radio button is
if (mouseIsPressed==true){
if (sqrt(pow(mouseX-this.x,2)+pow(mouseY-this.y,2))<=this.d/2){
this.touched=true;
}
}
else{
this.touched=false;
}
this.newtouch = this.touched&!this.wastouched;
this.state = this.touched;
//update value of touched
this.wastouched = this.touched;
//draw the button
this.drawButton();
}
this.drawButton=function(){
if(this.state==false){
fill(255);
}
else{
fill(0);
}
stroke(0);
//draw the radio button
ellipse(this.x,this.y,this.d,this.d,2);
fill(0);
stroke(0);
textSize(this.textSize);
text(this.label, this.x, this.y+this.d);
}
}
function RadioButton(ix,iy,id,ilabel){
this.x = ix;
this.y = iy;
this.d = id;
this.state = false;
this.touched = false;
this.wastouched = false;
this.newtouch = false;
this.label = ilabel;
this.updateRadio=function(){
//detect whether the radio button is
if (mouseIsPressed==true){
if (sqrt(pow(mouseX-this.x,2)+pow(mouseY-this.y,2))<=this.d/2){
this.touched=true;
}
}
else{
this.touched=false;
}
if(this.touched==true & this.wastouched==false){
this.state = !this.state;
}
//update value of touched
this.wastouched = this.touched;
//draw the button
this.drawRadio();
}
this.drawRadio=function(){
if(this.state==false){
fill(255);
}
else{
fill(0);
}
stroke(0);
//draw the radio button
ellipse(this.x,this.y,this.d,this.d,2);
fill(0);
stroke(0);
textSize(12);
text(this.label, this.x, this.y+this.d);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment