diff --git a/README.md b/README.md index 98ad6cb..b9bd0d6 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,11 @@ To be decided, but at this moment this code is open source and free to use for n ## Changelog +### 0.2.5 +* Fixed clock sync issue when disabled +* Added recursive detection on logic to prevent runaway oscillations +* Fixed click alignment on single input elements + ### 0.2.4 * Brought connections to foreground to make them more obvious in less then ideal layouts * Resized logic elements and positions I/O better diff --git a/js/logicengine.js b/js/logicengine.js index 597a85f..db76b95 100644 --- a/js/logicengine.js +++ b/js/logicengine.js @@ -241,6 +241,7 @@ class Element extends CanvasTools { Delete() { // Just to clean up connections for (let a = 0; a < this.OutputConnections.length;a++) { + this.LogicEngine.RecursionCount = 0; this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input,false); } } @@ -254,8 +255,12 @@ class Element extends CanvasTools { // We need to see if an input is being clicked on to be linked to let foundInput = false; for (let a = 0; a < this.Inputs.length;a++) { + let centerY = this.Y + Math.round(this.Height / 2); + let totalHeight = this.totalInputs() * ((this.inputCircleRadius*2)+4); + let firstY = (centerY - (totalHeight/2)) + 12; + let mouseDist = length2D(this.X+10, - this.Y+(this.inputCircleRadius + 2)+(((a*(4+(this.inputCircleRadius*2))))-2)+(this.inputCircleRadius/2), + firstY+ (a*24), this.MousePosition.x, this.MousePosition.y); if (mouseDist <= (this.inputCircleRadius)) { @@ -283,6 +288,7 @@ class Element extends CanvasTools { addConnection(container, element, input) { let newConnection = new ElementConnection(container,element,input); this.OutputConnections.push(newConnection); + this.LogicEngine.RecursionCount = 0; element.setInput(input,this.getOutput()); } @@ -331,10 +337,15 @@ class Element extends CanvasTools { this.OutputConnections.splice(a,1); a--; } else { + let endCenterY = this.OutputConnections[a].Element.Y + Math.round(this.OutputConnections[a].Element.Height / 2); + let endTotalHeight = this.OutputConnections[a].Element.totalInputs() * ((this.OutputConnections[a].Element.inputCircleRadius*2)+4); + let endFirstY = (endCenterY - (endTotalHeight/2)) + 12; + let startX = this.X + this.Width; let startY = this.Y+(this.Height/2); let endX = this.OutputConnections[a].Element.X; - let endY = this.OutputConnections[a].Element.Y+(this.OutputConnections[a].Element.inputCircleRadius + 2)+(((this.OutputConnections[a].Input*(4+(this.OutputConnections[a].Element.inputCircleRadius*2))))-2)+(this.OutputConnections[a].Element.inputCircleRadius/2); + //let endY = this.OutputConnections[a].Element.Y+(this.OutputConnections[a].Element.inputCircleRadius + 2)+(((this.OutputConnections[a].Input*(4+(this.OutputConnections[a].Element.inputCircleRadius*2))))-2)+(this.OutputConnections[a].Element.inputCircleRadius/2); + let endY = endFirstY + (this.OutputConnections[a].Input*24); let startMidX = startX + ((endX - startX)/2); let startMidY = startY; let midX = startMidX; @@ -366,11 +377,24 @@ class Element extends CanvasTools { } if (Input < this.totalInputs()) { this.Inputs[Input] = Value; + } else { + return; } if (this.getOutput() != oldOutput) { // The output changed, we need to notify connected elements for (let a = 0; a < this.OutputConnections.length;a++) { + //console.log(this.Designator + " sending " + this.getOutput() + " to " + this.OutputConnections[a].Element.Designator + " I" + this.OutputConnections[a].Input); + this.LogicEngine.RecursionCount++; + //console.log("Recursion: " + this.LogicEngine.RecursionCount); + if (this.LogicEngine.RecursionCount > 1000) { + if (!this.LogicEngine.RecursionError) { + console.log("RECURSION ERROR"); + this.LogicEngine.RecursionError = true; + } + return; + } this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input,this.getOutput()); + this.LogicEngine.RecursionCount--; } } } @@ -404,6 +428,7 @@ class ClockElement extends Element { this.Task.Time = this.Period - Math.round(this.Period * this.Duty); } for (let a = 0; a < this.OutputConnections.length; a++) { + this.LogicEngine.RecursionCount = 0; this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input, this.getOutput()); } } @@ -422,9 +447,14 @@ class ClockElement extends Element { super.setInput(Input, Value); if (!this.Inputs[0]) { this.Output = false; + this.Task.LastCall = 0; + this.Task.Enabled = false; for (let a = 0; a < this.OutputConnections.length;a++) { + this.LogicEngine.RecursionCount = 0; this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input,this.getOutput()); } + } else { + this.Task.Enabled = true; } } @@ -497,6 +527,7 @@ class InputSwitch extends inputElement { if ((mousePos.x >= (this.X + 5)) && (mousePos.x <= (this.X + 55)) && (mousePos.y >= (this.Y + 5)) && (mousePos.y <= (this.Y + 55))) { this.Output = ~this.Output; for (let a = 0; a < this.OutputConnections.length; a++) { + this.LogicEngine.RecursionCount = 0; this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input, this.getOutput()); } } @@ -880,7 +911,8 @@ class LogicEngine { this.ActiveContainer = new elementContainer(); this.ActiveLink = false; this.Scheduler = new ScheduleEngine(); - + this.RecursionCount = 0; + this.RecursionError = false; this.Canvas.setAttribute('tabindex','0'); } @@ -902,6 +934,10 @@ class LogicEngine { } DrawLoop() { + if (this.RecursionError) { + this.RecursionError = false; + alert("Recursion Error! Whatever you last did is causing an oscillating loop, please check your connections and try again!"); + } let startLoop = performance.now(); this.Ctx.clearRect(0,0,this.Canvas.width,this.Canvas.height); if (this.ActiveLink) { diff --git a/js/main.js b/js/main.js index 4868d0b..8dc2b2c 100644 --- a/js/main.js +++ b/js/main.js @@ -2,7 +2,7 @@ MatCat BrowserLogic Simulator */ -let Version = "0.2.4"; +let Version = "0.2.5"; let spanVersion = document.getElementById("version"); spanVersion.innerText = Version; // get the canvas and get the engine object going