Initial board SVG and basic simulator
This commit is contained in:
		
							
								
								
									
										99
									
								
								libs/base/_locales/base-jsdoc-strings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								libs/base/_locales/base-jsdoc-strings.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "Math.abs": "Returns the absolute value of a number (the value without regard to whether it is positive or negative).\nFor example, the absolute value of -5 is the same as the absolute value of 5.",
 | 
				
			||||||
 | 
					  "Math.abs|param|x": "A numeric expression for which the absolute value is needed.",
 | 
				
			||||||
 | 
					  "Math.acos": "Returns the arccosine (in radians) of a number",
 | 
				
			||||||
 | 
					  "Math.acos|param|x": "A number",
 | 
				
			||||||
 | 
					  "Math.asin": "Returns the arcsine (in radians) of a number",
 | 
				
			||||||
 | 
					  "Math.asin|param|x": "A number",
 | 
				
			||||||
 | 
					  "Math.atan": "Returns the arctangent (in radians) of a number",
 | 
				
			||||||
 | 
					  "Math.atan2": "Returns the arctangent of the quotient of its arguments.",
 | 
				
			||||||
 | 
					  "Math.atan2|param|x": "A number",
 | 
				
			||||||
 | 
					  "Math.atan2|param|y": "A number",
 | 
				
			||||||
 | 
					  "Math.atan|param|x": "A number",
 | 
				
			||||||
 | 
					  "Math.ceil": "Returns the smallest number greater than or equal to its numeric argument.",
 | 
				
			||||||
 | 
					  "Math.ceil|param|x": "A numeric expression.",
 | 
				
			||||||
 | 
					  "Math.constrain": "Constrains a number to be within a range",
 | 
				
			||||||
 | 
					  "Math.cos": "Returns the cosine of a number.",
 | 
				
			||||||
 | 
					  "Math.cos|param|x": "An angle in radians",
 | 
				
			||||||
 | 
					  "Math.exp": "Returns returns ``e^x``.",
 | 
				
			||||||
 | 
					  "Math.exp|param|x": "A number",
 | 
				
			||||||
 | 
					  "Math.floor": "Returns the greatest number less than or equal to its numeric argument.",
 | 
				
			||||||
 | 
					  "Math.floor|param|x": "A numeric expression.",
 | 
				
			||||||
 | 
					  "Math.icos": "Returns the cosine of an input angle. This is an 8-bit approximation.",
 | 
				
			||||||
 | 
					  "Math.icos|param|theta": "input angle from 0-255",
 | 
				
			||||||
 | 
					  "Math.idiv": "Returns the value of integer signed 32 bit division of two numbers.",
 | 
				
			||||||
 | 
					  "Math.idiv|param|x": "The first number",
 | 
				
			||||||
 | 
					  "Math.idiv|param|y": "The second number",
 | 
				
			||||||
 | 
					  "Math.imul": "Returns the value of integer signed 32 bit multiplication of two numbers.",
 | 
				
			||||||
 | 
					  "Math.imul|param|x": "The first number",
 | 
				
			||||||
 | 
					  "Math.imul|param|y": "The second number",
 | 
				
			||||||
 | 
					  "Math.isin": "Returns the sine of an input angle. This is an 8-bit approximation.",
 | 
				
			||||||
 | 
					  "Math.isin|param|theta": "input angle from 0-255",
 | 
				
			||||||
 | 
					  "Math.log": "Returns the natural logarithm (base e) of a number.",
 | 
				
			||||||
 | 
					  "Math.log|param|x": "A number",
 | 
				
			||||||
 | 
					  "Math.map": "Re-maps a number from one range to another. That is, a value of ``from low`` would get mapped to ``to low``, a value of ``from high`` to ``to high``, values in-between to values in-between, etc.",
 | 
				
			||||||
 | 
					  "Math.map|param|fromHigh": "the upper bound of the value's current range, eg: 1023",
 | 
				
			||||||
 | 
					  "Math.map|param|fromLow": "the lower bound of the value's current range",
 | 
				
			||||||
 | 
					  "Math.map|param|toHigh": "the upper bound of the value's target range, eg: 4",
 | 
				
			||||||
 | 
					  "Math.map|param|toLow": "the lower bound of the value's target range",
 | 
				
			||||||
 | 
					  "Math.map|param|value": "value to map in ranges",
 | 
				
			||||||
 | 
					  "Math.max": "Returns the larger of two supplied numeric expressions.",
 | 
				
			||||||
 | 
					  "Math.min": "Returns the smaller of two supplied numeric expressions.",
 | 
				
			||||||
 | 
					  "Math.pow": "Returns the value of a base expression taken to a specified power.",
 | 
				
			||||||
 | 
					  "Math.pow|param|x": "The base value of the expression.",
 | 
				
			||||||
 | 
					  "Math.pow|param|y": "The exponent value of the expression.",
 | 
				
			||||||
 | 
					  "Math.random": "Returns a pseudorandom number between 0 and 1.",
 | 
				
			||||||
 | 
					  "Math.randomRange": "Returns a pseudorandom number between min and max included. \nIf both numbers are integral, the result is integral.",
 | 
				
			||||||
 | 
					  "Math.randomRange|param|max": "the upper inclusive bound, eg: 10",
 | 
				
			||||||
 | 
					  "Math.randomRange|param|min": "the lower inclusive bound, eg: 0",
 | 
				
			||||||
 | 
					  "Math.round": "Returns a supplied numeric expression rounded to the nearest number.",
 | 
				
			||||||
 | 
					  "Math.round|param|x": "The value to be rounded to the nearest number.",
 | 
				
			||||||
 | 
					  "Math.sign": "Returns the sign of the x, indicating whether x is positive, negative or zero.",
 | 
				
			||||||
 | 
					  "Math.sign|param|x": "The numeric expression to test",
 | 
				
			||||||
 | 
					  "Math.sin": "Returns the sine of a number.",
 | 
				
			||||||
 | 
					  "Math.sin|param|x": "An angle in radians",
 | 
				
			||||||
 | 
					  "Math.sqrt": "Returns the square root of a number.",
 | 
				
			||||||
 | 
					  "Math.sqrt|param|x": "A numeric expression.",
 | 
				
			||||||
 | 
					  "Math.tan": "Returns the tangent of a number.",
 | 
				
			||||||
 | 
					  "Math.tan|param|x": "An angle in radians",
 | 
				
			||||||
 | 
					  "Math.trunc": "Returns the number with the decimal part truncated.",
 | 
				
			||||||
 | 
					  "Math.trunc|param|x": "A numeric expression.",
 | 
				
			||||||
 | 
					  "String.charAt": "Returns the character at the specified index.",
 | 
				
			||||||
 | 
					  "String.charAt|param|index": "The zero-based index of the desired character.",
 | 
				
			||||||
 | 
					  "String.charCodeAt": "Returns the Unicode value of the character at the specified location.",
 | 
				
			||||||
 | 
					  "String.charCodeAt|param|index": "The zero-based index of the desired character. If there is no character at the specified index, NaN is returned.",
 | 
				
			||||||
 | 
					  "String.compare": "Determines whether relative order of two strings (in ASCII encoding).",
 | 
				
			||||||
 | 
					  "String.compare|param|that": "String to compare to target string",
 | 
				
			||||||
 | 
					  "String.concat": "Returns a string that contains the concatenation of two or more strings.",
 | 
				
			||||||
 | 
					  "String.concat|param|other": "The string to append to the end of the string.",
 | 
				
			||||||
 | 
					  "String.fromCharCode": "Make a string from the given ASCII character code.",
 | 
				
			||||||
 | 
					  "String.isEmpty": "Returns a value indicating if the string is empty",
 | 
				
			||||||
 | 
					  "String.length": "Returns the length of a String object.",
 | 
				
			||||||
 | 
					  "String.substr": "Return substring of the current string.",
 | 
				
			||||||
 | 
					  "String.substr|param|length": "number of characters to extract",
 | 
				
			||||||
 | 
					  "String.substr|param|start": "first character index; can be negative from counting from the end, eg:0",
 | 
				
			||||||
 | 
					  "control": "Program controls and events.",
 | 
				
			||||||
 | 
					  "control.assert": "Display specified error code and stop the program.",
 | 
				
			||||||
 | 
					  "control.deviceSerialNumber": "Derive a unique, consistent serial number of this device from internal data.",
 | 
				
			||||||
 | 
					  "control.millis": "Gets the number of milliseconds elapsed since power on.",
 | 
				
			||||||
 | 
					  "control.onEvent": "Run code when a registered event happens.",
 | 
				
			||||||
 | 
					  "control.onEvent|param|value": "the event value to match",
 | 
				
			||||||
 | 
					  "control.panic": "Display an error code and stop the program.",
 | 
				
			||||||
 | 
					  "control.panic|param|code": "an error number to display. eg: 5",
 | 
				
			||||||
 | 
					  "control.reset": "Reset the device.",
 | 
				
			||||||
 | 
					  "control.runInBackground": "Run other code in the background.",
 | 
				
			||||||
 | 
					  "control.waitForEvent": "Blocks the calling thread until the specified event is raised.",
 | 
				
			||||||
 | 
					  "control.waitMicros": "Block the current fiber for the given microseconds",
 | 
				
			||||||
 | 
					  "control.waitMicros|param|micros": "number of micro-seconds to wait. eg: 4",
 | 
				
			||||||
 | 
					  "loops.forever": "Repeats the code forever in the background. On each iteration, allows other codes to run.",
 | 
				
			||||||
 | 
					  "loops.pause": "Pause for the specified time in milliseconds",
 | 
				
			||||||
 | 
					  "loops.pause|param|ms": "how long to pause for, eg: 100, 200, 500, 1000, 2000",
 | 
				
			||||||
 | 
					  "serial": "Reading and writing data over a serial connection.",
 | 
				
			||||||
 | 
					  "serial.writeBuffer": "Send a buffer across the serial connection.",
 | 
				
			||||||
 | 
					  "serial.writeLine": "Write a line of text to the serial port.",
 | 
				
			||||||
 | 
					  "serial.writeNumber": "Write a number to the serial port.",
 | 
				
			||||||
 | 
					  "serial.writeString": "Write some text to the serial port.",
 | 
				
			||||||
 | 
					  "serial.writeValue": "Write a name:value pair as a line of text to the serial port.",
 | 
				
			||||||
 | 
					  "serial.writeValue|param|name": "name of the value stream, eg: x",
 | 
				
			||||||
 | 
					  "serial.writeValue|param|value": "to write"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										36
									
								
								libs/base/_locales/base-strings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								libs/base/_locales/base-strings.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "Math.constrain|block": "constrain %value|between %low|and %high",
 | 
				
			||||||
 | 
					  "Math.map|block": "map %value|from low %fromLow|from high %fromHigh|to low %toLow|to high %toHigh",
 | 
				
			||||||
 | 
					  "Math.randomRange|block": "pick random %min|to %limit",
 | 
				
			||||||
 | 
					  "Math|block": "Math",
 | 
				
			||||||
 | 
					  "String.charAt|block": "char from %this=text|at %pos",
 | 
				
			||||||
 | 
					  "String.compare|block": "compare %this=text| to %that",
 | 
				
			||||||
 | 
					  "String.fromCharCode|block": "text from char code %code",
 | 
				
			||||||
 | 
					  "String.length|block": "length of %VALUE",
 | 
				
			||||||
 | 
					  "String.substr|block": "substring of %this=text|from %start|of length %length",
 | 
				
			||||||
 | 
					  "String|block": "String",
 | 
				
			||||||
 | 
					  "control.deviceSerialNumber|block": "device serial number",
 | 
				
			||||||
 | 
					  "control.millis|block": "millis (ms)",
 | 
				
			||||||
 | 
					  "control.onEvent|block": "on event|from %src|with value %value",
 | 
				
			||||||
 | 
					  "control.panic|block": "panic %code",
 | 
				
			||||||
 | 
					  "control.reset|block": "reset",
 | 
				
			||||||
 | 
					  "control.runInBackground|block": "run in background",
 | 
				
			||||||
 | 
					  "control.waitForEvent|block": "wait for event|from %src|with value %value",
 | 
				
			||||||
 | 
					  "control.waitMicros|block": "wait (µs)%micros",
 | 
				
			||||||
 | 
					  "control|block": "control",
 | 
				
			||||||
 | 
					  "loops.forever|block": "forever",
 | 
				
			||||||
 | 
					  "loops.pause|block": "pause (ms) %pause",
 | 
				
			||||||
 | 
					  "loops|block": "loops",
 | 
				
			||||||
 | 
					  "serial.writeBuffer|block": "serial|write buffer %buffer",
 | 
				
			||||||
 | 
					  "serial.writeLine|block": "serial|write line %text",
 | 
				
			||||||
 | 
					  "serial.writeNumber|block": "serial|write number %value",
 | 
				
			||||||
 | 
					  "serial.writeString|block": "serial|write string %text",
 | 
				
			||||||
 | 
					  "serial.writeValue|block": "serial|write value %name|= %value",
 | 
				
			||||||
 | 
					  "serial|block": "serial",
 | 
				
			||||||
 | 
					  "{id:category}Control": "Control",
 | 
				
			||||||
 | 
					  "{id:category}Loops": "Loops",
 | 
				
			||||||
 | 
					  "{id:category}Math": "Math",
 | 
				
			||||||
 | 
					  "{id:category}Serial": "Serial",
 | 
				
			||||||
 | 
					  "{id:category}String": "String",
 | 
				
			||||||
 | 
					  "{id:category}Text": "Text"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								libs/core/_locales/core-jsdoc-strings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								libs/core/_locales/core-jsdoc-strings.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "control": "Program controls and events.",
 | 
				
			||||||
 | 
					  "control.allocateNotifyEvent": "Allocates the next user notification event",
 | 
				
			||||||
 | 
					  "control.deviceFirmwareVersion": "Determine the version of system software currently running.",
 | 
				
			||||||
 | 
					  "control.dmesg": "Write data to DMESG debugging buffer.",
 | 
				
			||||||
 | 
					  "control.mmap": "Create new file mapping in memory",
 | 
				
			||||||
 | 
					  "control.raiseEvent": "Announce that an event happened to registered handlers.",
 | 
				
			||||||
 | 
					  "control.raiseEvent|param|src": "ID of the Component that generated the event",
 | 
				
			||||||
 | 
					  "control.raiseEvent|param|value": "Component specific code indicating the cause of the event.",
 | 
				
			||||||
 | 
					  "input.Button": "Generic button class, for device buttons and sensors.",
 | 
				
			||||||
 | 
					  "input.buttonDown": "Down button.",
 | 
				
			||||||
 | 
					  "input.buttonEnter": "Enter button.",
 | 
				
			||||||
 | 
					  "input.buttonLeft": "Left button.",
 | 
				
			||||||
 | 
					  "input.buttonRight": "Right button.",
 | 
				
			||||||
 | 
					  "input.buttonUp": "Up button.",
 | 
				
			||||||
 | 
					  "input.remoteBottomLeft": "Remote bottom-left button.",
 | 
				
			||||||
 | 
					  "input.remoteBottomRight": "Remote bottom-right button.",
 | 
				
			||||||
 | 
					  "input.remoteCenter": "Remote beacon (center) button.",
 | 
				
			||||||
 | 
					  "input.remoteTopLeft": "Remote top-left button.",
 | 
				
			||||||
 | 
					  "input.remoteTopRight": "Remote top-right button.",
 | 
				
			||||||
 | 
					  "output.createBuffer": "Create a new zero-initialized buffer.",
 | 
				
			||||||
 | 
					  "output.createBuffer|param|size": "number of bytes in the buffer",
 | 
				
			||||||
 | 
					  "output.setLights": "Set lights.",
 | 
				
			||||||
 | 
					  "screen.clear": "Clear screen and reset font to normal.",
 | 
				
			||||||
 | 
					  "screen.drawText": "Draw text.",
 | 
				
			||||||
 | 
					  "screen.scroll": "Scroll screen vertically.",
 | 
				
			||||||
 | 
					  "screen.setFont": "Set font for drawText()",
 | 
				
			||||||
 | 
					  "serial": "Reading and writing data over a serial connection.",
 | 
				
			||||||
 | 
					  "serial.writeDmesg": "Send DMESG debug buffer over serial."
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										28
									
								
								libs/core/_locales/core-strings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								libs/core/_locales/core-strings.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "ButtonEvent.Click|block": "click",
 | 
				
			||||||
 | 
					  "ButtonEvent.Down|block": "down",
 | 
				
			||||||
 | 
					  "ButtonEvent.LongClick|block": "long click",
 | 
				
			||||||
 | 
					  "ButtonEvent.Up|block": "up",
 | 
				
			||||||
 | 
					  "control.raiseEvent|block": "raise event|from %src|with value value",
 | 
				
			||||||
 | 
					  "control|block": "control",
 | 
				
			||||||
 | 
					  "input.buttonDown|block": "button down",
 | 
				
			||||||
 | 
					  "input.buttonEnter|block": "button enter",
 | 
				
			||||||
 | 
					  "input.buttonLeft|block": "button left",
 | 
				
			||||||
 | 
					  "input.buttonRight|block": "button right",
 | 
				
			||||||
 | 
					  "input.buttonUp|block": "button up",
 | 
				
			||||||
 | 
					  "input.remoteBottomLeft|block": "remote bottom-left",
 | 
				
			||||||
 | 
					  "input.remoteBottomRight|block": "remote bottom-right",
 | 
				
			||||||
 | 
					  "input.remoteCenter|block": "remote center",
 | 
				
			||||||
 | 
					  "input.remoteTopLeft|block": "remote top-left",
 | 
				
			||||||
 | 
					  "input.remoteTopRight|block": "remote top-right",
 | 
				
			||||||
 | 
					  "input|block": "input",
 | 
				
			||||||
 | 
					  "output.setLights|block": "set lights %pattern",
 | 
				
			||||||
 | 
					  "output|block": "output",
 | 
				
			||||||
 | 
					  "screen|block": "screen",
 | 
				
			||||||
 | 
					  "serial|block": "serial",
 | 
				
			||||||
 | 
					  "{id:category}Control": "Control",
 | 
				
			||||||
 | 
					  "{id:category}Input": "Input",
 | 
				
			||||||
 | 
					  "{id:category}Output": "Output",
 | 
				
			||||||
 | 
					  "{id:category}Screen": "Screen",
 | 
				
			||||||
 | 
					  "{id:category}Serial": "Serial"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										81
									
								
								libs/core/sim/analogSensor.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								libs/core/sim/analogSensor.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
				
			|||||||
 | 
					namespace pxsim {
 | 
				
			||||||
 | 
					    enum ThresholdState {
 | 
				
			||||||
 | 
					        High,
 | 
				
			||||||
 | 
					        Low,
 | 
				
			||||||
 | 
					        Normal
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export class AnalogSensorState {
 | 
				
			||||||
 | 
					        public sensorUsed: boolean = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private level: number;
 | 
				
			||||||
 | 
					        private state = ThresholdState.Normal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        constructor(public id: number, private min = 0, private max = 255, private lowThreshold = 64, private highThreshold = 192) {
 | 
				
			||||||
 | 
					            this.level = Math.ceil((max - min) / 2);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public setUsed() {
 | 
				
			||||||
 | 
					            if (!this.sensorUsed) {
 | 
				
			||||||
 | 
					                this.sensorUsed = true;
 | 
				
			||||||
 | 
					                runtime.queueDisplayUpdate();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public setLevel(level: number) {
 | 
				
			||||||
 | 
					            this.level = this.clampValue(level);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (this.level >= this.highThreshold) {
 | 
				
			||||||
 | 
					                this.setState(ThresholdState.High);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (this.level <= this.lowThreshold) {
 | 
				
			||||||
 | 
					                this.setState(ThresholdState.Low);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                this.setState(ThresholdState.Normal);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public getLevel(): number {
 | 
				
			||||||
 | 
					            return this.level;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public setLowThreshold(value: number) {
 | 
				
			||||||
 | 
					            this.lowThreshold = this.clampValue(value);
 | 
				
			||||||
 | 
					            this.highThreshold = Math.max(this.lowThreshold + 1, this.highThreshold);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public setHighThreshold(value: number) {
 | 
				
			||||||
 | 
					            this.highThreshold = this.clampValue(value);
 | 
				
			||||||
 | 
					            this.lowThreshold = Math.min(this.highThreshold - 1, this.lowThreshold);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private clampValue(value: number) {
 | 
				
			||||||
 | 
					            if (value < this.min) {
 | 
				
			||||||
 | 
					                return this.min;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (value > this.max) {
 | 
				
			||||||
 | 
					                return this.max;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private setState(state: ThresholdState) {
 | 
				
			||||||
 | 
					            if (this.state === state) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.state = state;
 | 
				
			||||||
 | 
					            switch (state) {
 | 
				
			||||||
 | 
					                case ThresholdState.High:
 | 
				
			||||||
 | 
					                    board().bus.queue(this.id, DAL.ANALOG_THRESHOLD_HIGH);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case ThresholdState.Low:
 | 
				
			||||||
 | 
					                    board().bus.queue(this.id, DAL.ANALOG_THRESHOLD_LOW);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case ThresholdState.Normal:
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										177
									
								
								libs/core/sim/pins.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								libs/core/sim/pins.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,177 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					namespace pxsim.pins {
 | 
				
			||||||
 | 
					    export class CommonPin extends Pin {
 | 
				
			||||||
 | 
					        used: boolean;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export class DigitalPin extends CommonPin {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export class AnalogPin extends CommonPin {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export function markUsed(name: CommonPin) {
 | 
				
			||||||
 | 
					        if (!name.used) {
 | 
				
			||||||
 | 
					            name.used = true;
 | 
				
			||||||
 | 
					            runtime.queueDisplayUpdate();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace pxsim.DigitalPinMethods {
 | 
				
			||||||
 | 
					    export function digitalRead(name: pins.DigitalPin): number {
 | 
				
			||||||
 | 
					        return name.digitalReadPin();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    * Set a pin or connector value to either 0 or 1.
 | 
				
			||||||
 | 
					    * @param value value to set on the pin, 1 eg,0
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    export function digitalWrite(name: pins.DigitalPin, value: number): void {
 | 
				
			||||||
 | 
					        name.digitalWritePin(value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    * Configures this pin to a digital input, and generates events where the timestamp is the duration
 | 
				
			||||||
 | 
					    * that this pin was either ``high`` or ``low``.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    export function onPulsed(name: pins.DigitalPin, pulse: number, body: RefAction): void {
 | 
				
			||||||
 | 
					        // TODO
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    * Returns the duration of a pulse in microseconds
 | 
				
			||||||
 | 
					    * @param value the value of the pulse (default high)
 | 
				
			||||||
 | 
					    * @param maximum duration in micro-seconds
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    export function pulseIn(name: pins.DigitalPin, pulse: number, maxDuration = 2000000): number {
 | 
				
			||||||
 | 
					        // TODO
 | 
				
			||||||
 | 
					        return 500;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    * Configures the pull of this pin.
 | 
				
			||||||
 | 
					    * @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    export function setPull(name: pins.DigitalPin, pull: number): void {
 | 
				
			||||||
 | 
					        name.setPull(pull);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    * Do something when a pin is pressed.
 | 
				
			||||||
 | 
					    * @param body the code to run when the pin is pressed
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    export function onPressed(name: pins.DigitalPin, body: RefAction): void {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Do something when a pin is released.
 | 
				
			||||||
 | 
					     * @param body the code to run when the pin is released
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    export function onReleased(name: pins.DigitalPin, body: RefAction): void {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the pin state (pressed or not). Requires to hold the ground to close the circuit.
 | 
				
			||||||
 | 
					     * @param name pin used to detect the touch
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    export function isPressed(name: pins.DigitalPin): boolean {
 | 
				
			||||||
 | 
					        return name.isTouched();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace pxsim.AnalogPinMethods {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Read the connector value as analog, that is, as a value comprised between 0 and 1023.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    export function analogRead(name: pins.AnalogPin): number {
 | 
				
			||||||
 | 
					        pins.markUsed(name);
 | 
				
			||||||
 | 
					        return name.analogReadPin();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set the connector value as analog. Value must be comprised between 0 and 1023.
 | 
				
			||||||
 | 
					     * @param value value to write to the pin between ``0`` and ``1023``. eg:1023,0
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    export function analogWrite(name: pins.AnalogPin, value: number): void {
 | 
				
			||||||
 | 
					        pins.markUsed(name);
 | 
				
			||||||
 | 
					        name.analogWritePin(value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Configures the Pulse-width modulation (PWM) of the analog output to the given value in
 | 
				
			||||||
 | 
					     * **microseconds** or `1/1000` milliseconds.
 | 
				
			||||||
 | 
					     * If this pin is not configured as an analog output (using `analog write pin`), the operation has
 | 
				
			||||||
 | 
					     * no effect.
 | 
				
			||||||
 | 
					     * @param micros period in micro seconds. eg:20000
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    export function analogSetPeriod(name: pins.AnalogPin, micros: number): void {
 | 
				
			||||||
 | 
					        pins.markUsed(name);
 | 
				
			||||||
 | 
					        name.analogSetPeriod(micros);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Writes a value to the servo, controlling the shaft accordingly. On a standard servo, this will
 | 
				
			||||||
 | 
					     * set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous
 | 
				
			||||||
 | 
					     * rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one
 | 
				
			||||||
 | 
					     * direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).
 | 
				
			||||||
 | 
					     * @param value angle or rotation speed, eg:180,90,0
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    export function servoWrite(name: pins.AnalogPin, value: number): void {
 | 
				
			||||||
 | 
					        pins.markUsed(name);
 | 
				
			||||||
 | 
					        name.servoWritePin(value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Configures this IO pin as an analog/pwm output, configures the period to be 20 ms, and sets the
 | 
				
			||||||
 | 
					     * pulse width, based on the value it is given **microseconds** or `1/1000` milliseconds.
 | 
				
			||||||
 | 
					     * @param micros pulse duration in micro seconds, eg:1500
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    export function servoSetPulse(name: pins.AnalogPin, micros: number): void {
 | 
				
			||||||
 | 
					        pins.markUsed(name);
 | 
				
			||||||
 | 
					        // TODO fix pxt
 | 
				
			||||||
 | 
					        // name.servoSetPulse(micros);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace pxsim.PwmPinMethods {
 | 
				
			||||||
 | 
					    export function analogSetPeriod(name: pins.AnalogPin, micros: number): void {
 | 
				
			||||||
 | 
					        name.analogSetPeriod(micros);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export function servoWrite(name: pins.AnalogPin, value: number): void {
 | 
				
			||||||
 | 
					        name.servoWritePin(value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export function servoSetPulse(name: pins.AnalogPin, micros: number): void {
 | 
				
			||||||
 | 
					        name.servoSetPulse(name.id, micros);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace pxsim.pins {
 | 
				
			||||||
 | 
					    export function pulseDuration(): number {
 | 
				
			||||||
 | 
					        // bus last event timestamp
 | 
				
			||||||
 | 
					        return 500;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export function createBuffer(sz: number) {
 | 
				
			||||||
 | 
					        return pxsim.BufferMethods.createBuffer(sz)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export function spiWrite(value: number): number {
 | 
				
			||||||
 | 
					        // TODO
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export function i2cReadBuffer(address: number, size: number, repeat?: boolean): RefBuffer {
 | 
				
			||||||
 | 
					        // fake reading zeros
 | 
				
			||||||
 | 
					        return createBuffer(size)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export function i2cWriteBuffer(address: number, buf: RefBuffer, repeat?: boolean): void {
 | 
				
			||||||
 | 
					        // fake - noop
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								libs/ev3/_locales/ev3-jsdoc-strings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								libs/ev3/_locales/ev3-jsdoc-strings.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					{}
 | 
				
			||||||
							
								
								
									
										1
									
								
								libs/ev3/_locales/ev3-strings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								libs/ev3/_locales/ev3-strings.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					{}
 | 
				
			||||||
							
								
								
									
										28
									
								
								libs/music/_locales/music-jsdoc-strings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								libs/music/_locales/music-jsdoc-strings.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "music": "Generation of music tones.",
 | 
				
			||||||
 | 
					  "music.beat": "Return the duration of a beat in milliseconds (the beat fraction).",
 | 
				
			||||||
 | 
					  "music.beat|param|fraction": "the fraction of the current whole note, eg: BeatFraction.Half",
 | 
				
			||||||
 | 
					  "music.changeTempoBy": "Change the tempo up or down by some amount of beats per minute (bpm).",
 | 
				
			||||||
 | 
					  "music.changeTempoBy|param|bpm": "The change in beats per minute to the tempo, eg: 20",
 | 
				
			||||||
 | 
					  "music.noteFrequency": "Get the frequency of a note.",
 | 
				
			||||||
 | 
					  "music.noteFrequency|param|name": "the note name, eg: Note.C",
 | 
				
			||||||
 | 
					  "music.playSound": "Start playing a sound and don't wait for it to finish.\nNotes are expressed as a string of characters with this format: NOTE[octave][:duration]",
 | 
				
			||||||
 | 
					  "music.playSoundUntilDone": "Play a sound and wait until the sound is done.\nNotes are expressed as a string of characters with this format: NOTE[octave][:duration]",
 | 
				
			||||||
 | 
					  "music.playSoundUntilDone|param|sound": "the melody to play, eg: 'g5:1'",
 | 
				
			||||||
 | 
					  "music.playSound|param|sound": "the melody to play, eg: 'g5:1'",
 | 
				
			||||||
 | 
					  "music.playTone": "Play a tone through the speaker for some amount of time.",
 | 
				
			||||||
 | 
					  "music.playTone|param|frequency": "pitch of the tone to play in Hertz (Hz)",
 | 
				
			||||||
 | 
					  "music.playTone|param|ms": "tone duration in milliseconds (ms)",
 | 
				
			||||||
 | 
					  "music.rest": "Rest, or play silence, for some time (in milleseconds).",
 | 
				
			||||||
 | 
					  "music.rest|param|ms": "rest duration in milliseconds (ms)",
 | 
				
			||||||
 | 
					  "music.ringTone": "Play a tone.",
 | 
				
			||||||
 | 
					  "music.ringTone|param|frequency": "pitch of the tone to play in Hertz (Hz)",
 | 
				
			||||||
 | 
					  "music.setTempo": "Set the tempo a number of beats per minute (bpm).",
 | 
				
			||||||
 | 
					  "music.setTempo|param|bpm": "The new tempo in beats per minute, eg: 120",
 | 
				
			||||||
 | 
					  "music.setVolume": "Set the output volume of the sound synthesizer.",
 | 
				
			||||||
 | 
					  "music.setVolume|param|volume": "the volume 0...256, eg: 128",
 | 
				
			||||||
 | 
					  "music.sounds": "Get the melody string for a built-in melody.",
 | 
				
			||||||
 | 
					  "music.sounds|param|name": "the note name, eg: Note.C",
 | 
				
			||||||
 | 
					  "music.stopAllSounds": "Stop all sounds from playing.",
 | 
				
			||||||
 | 
					  "music.tempo": "Return the tempo in beats per minute (bpm).\nTempo is the speed (bpm = beats per minute) at which notes play. The larger the tempo value, the faster the notes will play."
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										46
									
								
								libs/music/_locales/music-strings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								libs/music/_locales/music-strings.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "BeatFraction.Breve|block": "4",
 | 
				
			||||||
 | 
					  "BeatFraction.Double|block": "2",
 | 
				
			||||||
 | 
					  "BeatFraction.Eighth|block": "1/8",
 | 
				
			||||||
 | 
					  "BeatFraction.Half|block": "1/2",
 | 
				
			||||||
 | 
					  "BeatFraction.Quarter|block": "1/4",
 | 
				
			||||||
 | 
					  "BeatFraction.Sixteenth|block": "1/16",
 | 
				
			||||||
 | 
					  "BeatFraction.Whole|block": "1",
 | 
				
			||||||
 | 
					  "Note.CSharp3|block": "C#3",
 | 
				
			||||||
 | 
					  "Note.CSharp4|block": "C#4",
 | 
				
			||||||
 | 
					  "Note.CSharp5|block": "C#5",
 | 
				
			||||||
 | 
					  "Note.CSharp|block": "C#",
 | 
				
			||||||
 | 
					  "Note.FSharp3|block": "F#3",
 | 
				
			||||||
 | 
					  "Note.FSharp4|block": "F#4",
 | 
				
			||||||
 | 
					  "Note.FSharp5|block": "F#5",
 | 
				
			||||||
 | 
					  "Note.FSharp|block": "F#",
 | 
				
			||||||
 | 
					  "Note.GSharp3|block": "G#3",
 | 
				
			||||||
 | 
					  "Note.GSharp4|block": "G#4",
 | 
				
			||||||
 | 
					  "Note.GSharp5|block": "G#5",
 | 
				
			||||||
 | 
					  "Note.GSharp|block": "G#",
 | 
				
			||||||
 | 
					  "SoundOutputDestination.Pin|block": "pin",
 | 
				
			||||||
 | 
					  "SoundOutputDestination.Speaker|block": "speaker",
 | 
				
			||||||
 | 
					  "Sounds.BaDing|block": "ba ding",
 | 
				
			||||||
 | 
					  "Sounds.JumpDown|block": "jump down",
 | 
				
			||||||
 | 
					  "Sounds.JumpUp|block": "jump up",
 | 
				
			||||||
 | 
					  "Sounds.MagicWand|block": "magic wand",
 | 
				
			||||||
 | 
					  "Sounds.PowerDown|block": "power down",
 | 
				
			||||||
 | 
					  "Sounds.PowerUp|block": "power up",
 | 
				
			||||||
 | 
					  "Sounds.Siren|block": "siren",
 | 
				
			||||||
 | 
					  "Sounds.Wawawawaa|block": "wawawawaa",
 | 
				
			||||||
 | 
					  "music.beat|block": "%fraction|beat",
 | 
				
			||||||
 | 
					  "music.changeTempoBy|block": "change tempo by (bpm)|%value",
 | 
				
			||||||
 | 
					  "music.noteFrequency|block": "%note",
 | 
				
			||||||
 | 
					  "music.playSoundUntilDone|block": "play sound %sound=music_sounds|until done",
 | 
				
			||||||
 | 
					  "music.playSound|block": "play sound %sound=music_sounds",
 | 
				
			||||||
 | 
					  "music.playTone|block": "play tone|at %note=device_note|for %duration=device_beat",
 | 
				
			||||||
 | 
					  "music.rest|block": "rest|for %duration=device_beat",
 | 
				
			||||||
 | 
					  "music.ringTone|block": "ring tone|at %note=device_note",
 | 
				
			||||||
 | 
					  "music.setTempo|block": "set tempo to (bpm)|%value",
 | 
				
			||||||
 | 
					  "music.setVolume|block": "set volume %volume",
 | 
				
			||||||
 | 
					  "music.sounds|block": "%name",
 | 
				
			||||||
 | 
					  "music.stopAllSounds|block": "stop all sounds",
 | 
				
			||||||
 | 
					  "music.tempo|block": "tempo (bpm)",
 | 
				
			||||||
 | 
					  "music|block": "music",
 | 
				
			||||||
 | 
					  "{id:category}Music": "Music"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -13,14 +13,14 @@
 | 
				
			|||||||
        "libs/ev3"
 | 
					        "libs/ev3"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "simulator": {
 | 
					    "simulator": {
 | 
				
			||||||
      "headless": true
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "DISABLED-simulator": {
 | 
					 | 
				
			||||||
        "autoRun": true,
 | 
					        "autoRun": true,
 | 
				
			||||||
        "streams": true,
 | 
					        "streams": true,
 | 
				
			||||||
        "aspectRatio": 1.0,
 | 
					        "aspectRatio": 0.67,
 | 
				
			||||||
        "parts": false,
 | 
					        "parts": false,
 | 
				
			||||||
        "enableTrace": true
 | 
					        "enableTrace": true,
 | 
				
			||||||
 | 
					        "boardDefinition": {
 | 
				
			||||||
 | 
					            "visual": "ev3"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "cloud": {
 | 
					    "cloud": {
 | 
				
			||||||
        "workspace": false,
 | 
					        "workspace": false,
 | 
				
			||||||
@@ -118,8 +118,6 @@
 | 
				
			|||||||
        "invertedMonaco": false,
 | 
					        "invertedMonaco": false,
 | 
				
			||||||
        "monacoToolbox": true,
 | 
					        "monacoToolbox": true,
 | 
				
			||||||
        "invertedToolbox": true,
 | 
					        "invertedToolbox": true,
 | 
				
			||||||
        "simAnimationEnter": "roll in",
 | 
					 | 
				
			||||||
        "simAnimationExit": "roll out",
 | 
					 | 
				
			||||||
        "exampleGallery": "examples",
 | 
					        "exampleGallery": "examples",
 | 
				
			||||||
        "hasAudio": true,
 | 
					        "hasAudio": true,
 | 
				
			||||||
        "usbHelp": [],
 | 
					        "usbHelp": [],
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										197
									
								
								sim/dalboard.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								sim/dalboard.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,197 @@
 | 
				
			|||||||
 | 
					/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
 | 
				
			||||||
 | 
					/// <reference path="../node_modules/pxt-core/localtypings/pxtarget.d.ts"/>
 | 
				
			||||||
 | 
					/// <reference path="../built/common-sim.d.ts"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace pxsim {
 | 
				
			||||||
 | 
					    export enum CPlayPinName {
 | 
				
			||||||
 | 
					        A0,
 | 
				
			||||||
 | 
					        A1,
 | 
				
			||||||
 | 
					        A2,
 | 
				
			||||||
 | 
					        A3,
 | 
				
			||||||
 | 
					        A4,
 | 
				
			||||||
 | 
					        A5,
 | 
				
			||||||
 | 
					        A6,
 | 
				
			||||||
 | 
					        A7,
 | 
				
			||||||
 | 
					        A8,
 | 
				
			||||||
 | 
					        A9,
 | 
				
			||||||
 | 
					        D4,
 | 
				
			||||||
 | 
					        D5,
 | 
				
			||||||
 | 
					        D6,
 | 
				
			||||||
 | 
					        D7,
 | 
				
			||||||
 | 
					        D8,
 | 
				
			||||||
 | 
					        D13
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export class DalBoard extends CoreBoard implements
 | 
				
			||||||
 | 
					        AccelerometerBoard,
 | 
				
			||||||
 | 
					        CommonBoard,
 | 
				
			||||||
 | 
					        LightBoard,
 | 
				
			||||||
 | 
					        LightSensorBoard,
 | 
				
			||||||
 | 
					        MicrophoneBoard,
 | 
				
			||||||
 | 
					        MusicBoard,
 | 
				
			||||||
 | 
					        SlideSwitchBoard,
 | 
				
			||||||
 | 
					        TemperatureBoard,
 | 
				
			||||||
 | 
					        InfraredBoard,
 | 
				
			||||||
 | 
					        CapTouchBoard {
 | 
				
			||||||
 | 
					        // state & update logic for component services
 | 
				
			||||||
 | 
					        neopixelState: CommonNeoPixelState;
 | 
				
			||||||
 | 
					        buttonState: EV3ButtonState;
 | 
				
			||||||
 | 
					        slideSwitchState: SlideSwitchState;
 | 
				
			||||||
 | 
					        lightSensorState: AnalogSensorState;
 | 
				
			||||||
 | 
					        thermometerState: AnalogSensorState;
 | 
				
			||||||
 | 
					        thermometerUnitState: number;
 | 
				
			||||||
 | 
					        microphoneState: AnalogSensorState;
 | 
				
			||||||
 | 
					        edgeConnectorState: EdgeConnectorState;
 | 
				
			||||||
 | 
					        capacitiveSensorState: CapacitiveSensorState;
 | 
				
			||||||
 | 
					        accelerometerState: AccelerometerState;
 | 
				
			||||||
 | 
					        audioState: AudioState;
 | 
				
			||||||
 | 
					        touchButtonState: TouchButtonState;
 | 
				
			||||||
 | 
					        irState: InfraredState;
 | 
				
			||||||
 | 
					        lightState: EV3LightState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        view: SVGSVGElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        constructor() {
 | 
				
			||||||
 | 
					            super()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.bus.setNotify(DAL.DEVICE_ID_NOTIFY, DAL.DEVICE_ID_NOTIFY_ONE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //components
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.builtinParts["buttons"] = this.buttonState = new EV3ButtonState();
 | 
				
			||||||
 | 
					            this.builtinParts["light"] = this.lightState = new EV3LightState();
 | 
				
			||||||
 | 
					            /*this.builtinParts["neopixel"] = this.neopixelState = new CommonNeoPixelState();
 | 
				
			||||||
 | 
					            this.builtinParts["buttonpair"] = this.buttonState = new CommonButtonState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.builtinParts["switch"] = this.slideSwitchState = new SlideSwitchState();
 | 
				
			||||||
 | 
					            this.builtinParts["audio"] = this.audioState = new AudioState();
 | 
				
			||||||
 | 
					            this.builtinParts["lightsensor"] = this.lightSensorState = new AnalogSensorState(DAL.DEVICE_ID_LIGHT_SENSOR, 0, 255);
 | 
				
			||||||
 | 
					            this.builtinParts["thermometer"] = this.thermometerState = new AnalogSensorState(DAL.DEVICE_ID_THERMOMETER, -5, 50);
 | 
				
			||||||
 | 
					            this.builtinParts["soundsensor"] = this.microphoneState = new AnalogSensorState(DAL.DEVICE_ID_TOUCH_SENSOR + 1, 0, 255);
 | 
				
			||||||
 | 
					            this.builtinParts["capacitivesensor"] = this.capacitiveSensorState = new CapacitiveSensorState({
 | 
				
			||||||
 | 
					                0: 0,
 | 
				
			||||||
 | 
					                1: 1,
 | 
				
			||||||
 | 
					                2: 2,
 | 
				
			||||||
 | 
					                3: 3,
 | 
				
			||||||
 | 
					                6: 4,
 | 
				
			||||||
 | 
					                9: 5,
 | 
				
			||||||
 | 
					                10: 6,
 | 
				
			||||||
 | 
					                12: 7
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.builtinParts["accelerometer"] = this.accelerometerState = new AccelerometerState(runtime);
 | 
				
			||||||
 | 
					            this.builtinParts["edgeconnector"] = this.edgeConnectorState = new EdgeConnectorState({
 | 
				
			||||||
 | 
					                pins: [
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.A0,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.A1,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.A2,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.A3,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.A4,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.A5,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.A6,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.A7,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.A8,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.A9,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.D4,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.D5,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.D6,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.D7,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.D8,
 | 
				
			||||||
 | 
					                    pxsim.CPlayPinName.D13
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            this.builtinParts["microservo"] = this.edgeConnectorState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.builtinVisuals["microservo"] = () => new visuals.MicroServoView();
 | 
				
			||||||
 | 
					            this.builtinPartVisuals["microservo"] = (xy: visuals.Coord) => visuals.mkMicroServoPart(xy);
 | 
				
			||||||
 | 
					            this.touchButtonState = new TouchButtonState([
 | 
				
			||||||
 | 
					                pxsim.CPlayPinName.A1,
 | 
				
			||||||
 | 
					                pxsim.CPlayPinName.A2,
 | 
				
			||||||
 | 
					                pxsim.CPlayPinName.A3,
 | 
				
			||||||
 | 
					                pxsim.CPlayPinName.A4,
 | 
				
			||||||
 | 
					                pxsim.CPlayPinName.A5,
 | 
				
			||||||
 | 
					                pxsim.CPlayPinName.A6,
 | 
				
			||||||
 | 
					                pxsim.CPlayPinName.A7
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.builtinParts["ir"] = this.irState = new InfraredState();*/
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        receiveMessage(msg: SimulatorMessage) {
 | 
				
			||||||
 | 
					            if (!runtime || runtime.dead) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            switch (msg.type || "") {
 | 
				
			||||||
 | 
					                case "eventbus": {
 | 
				
			||||||
 | 
					                    let ev = <SimulatorEventBusMessage>msg;
 | 
				
			||||||
 | 
					                    this.bus.queue(ev.id, ev.eventid, ev.value);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                case "serial": {
 | 
				
			||||||
 | 
					                    let data = (<SimulatorSerialMessage>msg).data || "";
 | 
				
			||||||
 | 
					                    // TODO
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                case "irpacket": {
 | 
				
			||||||
 | 
					                    let ev = <SimulatorInfraredPacketMessage>msg;
 | 
				
			||||||
 | 
					                    this.irState.receive(new RefBuffer(ev.packet));
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        initAsync(msg: SimulatorRunMessage): Promise<void> {
 | 
				
			||||||
 | 
					            super.initAsync(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const options = (msg.options || {}) as pxt.RuntimeOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const boardDef = msg.boardDefinition;
 | 
				
			||||||
 | 
					            const cmpsList = msg.parts;
 | 
				
			||||||
 | 
					            const cmpDefs = msg.partDefinitions || {};
 | 
				
			||||||
 | 
					            const fnArgs = msg.fnArgs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const opts: visuals.BoardHostOpts = {
 | 
				
			||||||
 | 
					                state: this,
 | 
				
			||||||
 | 
					                boardDef: boardDef,
 | 
				
			||||||
 | 
					                partsList: cmpsList,
 | 
				
			||||||
 | 
					                partDefs: cmpDefs,
 | 
				
			||||||
 | 
					                fnArgs: fnArgs,
 | 
				
			||||||
 | 
					                maxWidth: "100%",
 | 
				
			||||||
 | 
					                maxHeight: "100%",
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            const viewHost = new visuals.BoardHost(pxsim.visuals.mkBoardView({
 | 
				
			||||||
 | 
					                visual: boardDef.visual
 | 
				
			||||||
 | 
					            }), opts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            document.body.innerHTML = ""; // clear children
 | 
				
			||||||
 | 
					            document.body.appendChild(this.view = viewHost.getView() as SVGSVGElement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return Promise.resolve();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        screenshot(): string {
 | 
				
			||||||
 | 
					            return svg.toDataUri(new XMLSerializer().serializeToString(this.view));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        defaultNeopixelPin() {
 | 
				
			||||||
 | 
					            return this.edgeConnectorState.getPin(CPlayPinName.D8);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        getDefaultPitchPin() {
 | 
				
			||||||
 | 
					            return this.edgeConnectorState.getPin(CPlayPinName.D6);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export function initRuntimeWithDalBoard() {
 | 
				
			||||||
 | 
					        U.assert(!runtime.board);
 | 
				
			||||||
 | 
					        let b = new DalBoard();
 | 
				
			||||||
 | 
					        runtime.board = b;
 | 
				
			||||||
 | 
					        runtime.postError = (e) => {
 | 
				
			||||||
 | 
					            // TODO
 | 
				
			||||||
 | 
					            runtime.updateDisplay();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!pxsim.initCurrentRuntime) {
 | 
				
			||||||
 | 
					        pxsim.initCurrentRuntime = initRuntimeWithDalBoard;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										92
									
								
								sim/instructions.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								sim/instructions.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
				
			|||||||
 | 
					/// <reference path="../node_modules/pxt-core/typings/globals/bluebird/index.d.ts"/>
 | 
				
			||||||
 | 
					/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
 | 
				
			||||||
 | 
					/// <reference path="../node_modules/pxt-core/built/pxtrunner.d.ts"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//HACK: allows instructions.html to access pxtblocks without requiring simulator.html to import blocks as well
 | 
				
			||||||
 | 
					if (!(<any>window).pxt) (<any>window).pxt = {};
 | 
				
			||||||
 | 
					import pxtrunner = pxt.runner;
 | 
				
			||||||
 | 
					import pxtdocs = pxt.docs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace pxsim.instructions {
 | 
				
			||||||
 | 
					    export function drawInstructions() {
 | 
				
			||||||
 | 
					        pxsim.visuals.mkBoardView = (opts: pxsim.visuals.BoardViewOptions): pxsim.visuals.BoardView => {
 | 
				
			||||||
 | 
					            return new visuals.EV3BoardSvg({
 | 
				
			||||||
 | 
					                runtime: runtime,
 | 
				
			||||||
 | 
					                theme: visuals.randomTheme(),
 | 
				
			||||||
 | 
					                disableTilt: false,
 | 
				
			||||||
 | 
					                wireframe: opts.wireframe,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let getQsVal = parseQueryString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //project name
 | 
				
			||||||
 | 
					        let name = getQsVal("name") || "Untitled";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // board def
 | 
				
			||||||
 | 
					        const boardDef = JSON.parse(getQsVal("board")) as pxsim.BoardDefinition;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //parts list
 | 
				
			||||||
 | 
					        let parts = (getQsVal("parts") || "").split(" ");
 | 
				
			||||||
 | 
					        parts.sort();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // parts definitions
 | 
				
			||||||
 | 
					        let partDefinitions = JSON.parse(getQsVal("partdefs") || "{}") as pxsim.Map<PartDefinition>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //fn args
 | 
				
			||||||
 | 
					        let fnArgs = JSON.parse((getQsVal("fnArgs") || "{}"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //project code
 | 
				
			||||||
 | 
					        let tsCode = getQsVal("code");
 | 
				
			||||||
 | 
					        let tsPackage = getQsVal("package") || "";
 | 
				
			||||||
 | 
					        let codeSpinnerDiv = document.getElementById("proj-code-spinner");
 | 
				
			||||||
 | 
					        let codeContainerDiv = document.getElementById("proj-code-container");
 | 
				
			||||||
 | 
					        if (tsCode) {
 | 
				
			||||||
 | 
					            //we use the docs renderer to decompile the code to blocks and render it
 | 
				
			||||||
 | 
					            //TODO: render the blocks code directly
 | 
				
			||||||
 | 
					            let md =
 | 
				
			||||||
 | 
					                `\`\`\`blocks
 | 
				
			||||||
 | 
					${tsCode}
 | 
				
			||||||
 | 
					\`\`\`
 | 
				
			||||||
 | 
					\`\`\`package
 | 
				
			||||||
 | 
					${tsPackage}
 | 
				
			||||||
 | 
					\`\`\`
 | 
				
			||||||
 | 
					`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            pxtdocs.requireMarked = function () { return (<any>window).marked; }
 | 
				
			||||||
 | 
					            pxtrunner.renderMarkdownAsync(codeContainerDiv, md)
 | 
				
			||||||
 | 
					                .done(function () {
 | 
				
			||||||
 | 
					                    let codeSvg = $("#proj-code-container svg");
 | 
				
			||||||
 | 
					                    if (codeSvg.length > 0) {
 | 
				
			||||||
 | 
					                        //code rendered successfully as blocks
 | 
				
			||||||
 | 
					                        codeSvg.css("width", "inherit");
 | 
				
			||||||
 | 
					                        codeSvg.css("height", "inherit");
 | 
				
			||||||
 | 
					                        //takes the svg out of the wrapper markdown
 | 
				
			||||||
 | 
					                        codeContainerDiv.innerHTML = "";
 | 
				
			||||||
 | 
					                        codeContainerDiv.appendChild(codeSvg[0]);
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        //code failed to convert to blocks, display as typescript instead
 | 
				
			||||||
 | 
					                        codeContainerDiv.innerText = tsCode;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    $(codeContainerDiv).show();
 | 
				
			||||||
 | 
					                    $(codeSpinnerDiv).hide();
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (name)
 | 
				
			||||||
 | 
					            $("#proj-title").text(name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //init runtime
 | 
				
			||||||
 | 
					        if (!pxsim.initCurrentRuntime)
 | 
				
			||||||
 | 
					            pxsim.initCurrentRuntime = initRuntimeWithDalBoard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        renderParts({
 | 
				
			||||||
 | 
					            name,
 | 
				
			||||||
 | 
					            boardDef,
 | 
				
			||||||
 | 
					            parts,
 | 
				
			||||||
 | 
					            partDefinitions,
 | 
				
			||||||
 | 
					            fnArgs
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								sim/public/parts/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								sim/public/parts/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					# don't check in until OSS request is approved
 | 
				
			||||||
 | 
					sparkfun-*
 | 
				
			||||||
 | 
					raspberrypi-*
 | 
				
			||||||
 | 
					arduino-*
 | 
				
			||||||
 | 
					max6675*
 | 
				
			||||||
							
								
								
									
										10
									
								
								sim/public/sim.manifest
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								sim/public/sim.manifest
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					CACHE MANIFEST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CACHE:
 | 
				
			||||||
 | 
					/cdn/bluebird.min.js
 | 
				
			||||||
 | 
					/cdn/pxtsim.js
 | 
				
			||||||
 | 
					/sim/common-sim.js
 | 
				
			||||||
 | 
					/sim/sim.js
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NETWORK:
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
							
								
								
									
										201
									
								
								sim/public/siminstructions.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								sim/public/siminstructions.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,201 @@
 | 
				
			|||||||
 | 
					<!doctype html>
 | 
				
			||||||
 | 
					<html lang="en" data-framework="typescript">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					    <meta charset="utf-8">
 | 
				
			||||||
 | 
					    <title>Assembly Instructions</title>
 | 
				
			||||||
 | 
					    <style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        svg {
 | 
				
			||||||
 | 
					            max-width: 100%;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .blocklyText, .ace_editor {
 | 
				
			||||||
 | 
					            font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace !important;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .blocklyText, .ace_editor {
 | 
				
			||||||
 | 
					            font-size: 1rem !important;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .blocklyTreeLabel {
 | 
				
			||||||
 | 
					            font-size: 1.25rem !important;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .blocklyCheckbox {
 | 
				
			||||||
 | 
					            fill: #ff3030 !important;
 | 
				
			||||||
 | 
					            text-shadow: 0px 0px 6px #f00;
 | 
				
			||||||
 | 
					            font-size: 17pt !important;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .ui.card .blocklyPreview {
 | 
				
			||||||
 | 
					            position: absolute;
 | 
				
			||||||
 | 
					            top: 50%;
 | 
				
			||||||
 | 
					            left: 50%;
 | 
				
			||||||
 | 
					            transform: translate(-50%, -50%);
 | 
				
			||||||
 | 
					            width: calc(100% - 1em);
 | 
				
			||||||
 | 
					            max-height: calc(100% - 1em);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        code {
 | 
				
			||||||
 | 
					            white-space: pre-wrap;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        code.lang-config, code.lang-package { display:none; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        code.lang-blocks::before,
 | 
				
			||||||
 | 
					        code.lang-sig::before,
 | 
				
			||||||
 | 
					        code.lang-block::before,
 | 
				
			||||||
 | 
					        code.lang-shuffle::before,
 | 
				
			||||||
 | 
					        code.lang-sim::before,
 | 
				
			||||||
 | 
					        code.lang-cards::before,
 | 
				
			||||||
 | 
					        code.lang-namespaces::before,
 | 
				
			||||||
 | 
					        code.lang-codecard::before {
 | 
				
			||||||
 | 
					            content: "...";
 | 
				
			||||||
 | 
					            position: absolute;
 | 
				
			||||||
 | 
					            top: calc(50% - 0.5em);
 | 
				
			||||||
 | 
					            left: calc(50% - 5em);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        code.lang-blocks,
 | 
				
			||||||
 | 
					        code.lang-sig,
 | 
				
			||||||
 | 
					        code.lang-block,
 | 
				
			||||||
 | 
					        code.lang-shuffle,
 | 
				
			||||||
 | 
					        code.lang-sim,
 | 
				
			||||||
 | 
					        code.lang-cards,
 | 
				
			||||||
 | 
					        code.lang-namespaces,
 | 
				
			||||||
 | 
					        code.lang-codecard {
 | 
				
			||||||
 | 
					            color: transparent;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					    <style type="text/css">
 | 
				
			||||||
 | 
					        @import "/cdn/semantic.css";
 | 
				
			||||||
 | 
					        @import "/cdn/icons.css";
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					    <style>
 | 
				
			||||||
 | 
					        html {
 | 
				
			||||||
 | 
					            padding: 0;
 | 
				
			||||||
 | 
					            margin: 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        body {
 | 
				
			||||||
 | 
					            padding: 0;
 | 
				
			||||||
 | 
					            margin: 0;
 | 
				
			||||||
 | 
					            font-family: "Lucida Console", Monaco, monospace;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        div {
 | 
				
			||||||
 | 
					            /*undo semantic UI*/
 | 
				
			||||||
 | 
					            box-sizing: content-box;
 | 
				
			||||||
 | 
					            line-height: normal;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        img {
 | 
				
			||||||
 | 
					            border: 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /*TODO: Share CSS with main webpage*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .organization {
 | 
				
			||||||
 | 
					            position: absolute;
 | 
				
			||||||
 | 
					            bottom: 2rem;
 | 
				
			||||||
 | 
					            right: 2rem;
 | 
				
			||||||
 | 
					            height: 4rem;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        h1 {
 | 
				
			||||||
 | 
					            font-size: 2em;
 | 
				
			||||||
 | 
					            font-weight: normal;
 | 
				
			||||||
 | 
					            color: rgba(0, 0, 0, 0.87);
 | 
				
			||||||
 | 
					            font-family: 'Segoe UI', 'Helvetica Neue', Arial, Helvetica, sans-serif;
 | 
				
			||||||
 | 
					            display: block;
 | 
				
			||||||
 | 
					            text-align: center;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #front-panel .board-svg {
 | 
				
			||||||
 | 
					            position: absolute;
 | 
				
			||||||
 | 
					            left: 2rem;
 | 
				
			||||||
 | 
					            width: 300px;
 | 
				
			||||||
 | 
					            top: 16rem;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #proj-title {
 | 
				
			||||||
 | 
					            width: 100%;
 | 
				
			||||||
 | 
					            font-size: 70px;
 | 
				
			||||||
 | 
					            margin-top: 20px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #proj-code {
 | 
				
			||||||
 | 
					            width: 300px;
 | 
				
			||||||
 | 
					            height: 400px;
 | 
				
			||||||
 | 
					            position: absolute;
 | 
				
			||||||
 | 
					            right: 2rem;
 | 
				
			||||||
 | 
					            top: 16rem;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        #proj-code-container {
 | 
				
			||||||
 | 
					            width: 100%;
 | 
				
			||||||
 | 
					            height: 100%;
 | 
				
			||||||
 | 
					            font-size: 4px;
 | 
				
			||||||
 | 
					            overflow: hidden;
 | 
				
			||||||
 | 
					            display: none;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        #proj-code-spinner {
 | 
				
			||||||
 | 
					            width: 100%;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .back-panel svg {
 | 
				
			||||||
 | 
					            position: relative;
 | 
				
			||||||
 | 
					            margin: 0 auto;
 | 
				
			||||||
 | 
					            left: inherit;
 | 
				
			||||||
 | 
					            bottom: -7px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					    <div id='loading' class="ui active inverted dimmer">
 | 
				
			||||||
 | 
					        <div class="ui large loader"></div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <script>
 | 
				
			||||||
 | 
					        // This line gets patched up by the cloud
 | 
				
			||||||
 | 
					        var pxtConfig = null;
 | 
				
			||||||
 | 
					    </script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/cdn/lzma/lzma_worker-min.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/cdn/marked/marked.min.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/cdn/jquery.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/cdn/typescript.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/cdn/blockly/blockly_compressed.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/cdn/blockly/blocks_compressed.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/cdn/blockly/msg/js/en.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/cdn/pxtlib.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/cdn/pxtblocks.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/cdn/pxtsim.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/cdn/pxtrunner.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/cdn/semantic.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/embed.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/sim/common-sim.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="/sim/sim.js"></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript">
 | 
				
			||||||
 | 
					        (function () {
 | 
				
			||||||
 | 
					        ksRunnerReady(function() {
 | 
				
			||||||
 | 
					            var orgLogo = pxt.appTarget.appTheme.organizationLogo;
 | 
				
			||||||
 | 
					            if (orgLogo)
 | 
				
			||||||
 | 
					                $('#front-panel').append(
 | 
				
			||||||
 | 
					                    $('<img/>').attr('class', 'organization').attr('src', orgLogo)
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            var loading = document.getElementById('loading');
 | 
				
			||||||
 | 
					            pxsim.instructions.drawInstructions();
 | 
				
			||||||
 | 
					            $(loading).hide();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        })();
 | 
				
			||||||
 | 
					    </script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div id="front-panel" class="instr-panel">
 | 
				
			||||||
 | 
					        <h1 id="proj-title"></h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!--TODO: extract real code snapshot from PXT -->
 | 
				
			||||||
 | 
					        <div id="proj-code">
 | 
				
			||||||
 | 
					            <i id="proj-code-spinner" class="spinner loading icon"></i>
 | 
				
			||||||
 | 
					            <div id="proj-code-container">
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										29
									
								
								sim/public/simulator.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								sim/public/simulator.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					<!doctype html>
 | 
				
			||||||
 | 
					<html lang="en" data-manifest="" data-framework="typescript">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					    <meta charset="utf-8">
 | 
				
			||||||
 | 
					    <title>EV3 Simulator</title>
 | 
				
			||||||
 | 
					    <style>
 | 
				
			||||||
 | 
					html {
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					body {
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  width:100%;
 | 
				
			||||||
 | 
					  padding: 0;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					    <script src="/cdn/bluebird.min.js"></script>
 | 
				
			||||||
 | 
					    <script src="/cdn/pxtsim.js"></script>
 | 
				
			||||||
 | 
					    <script src="/sim/common-sim.js"></script>
 | 
				
			||||||
 | 
					    <script src="/sim/sim.js"></script>
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
							
								
								
									
										18
									
								
								sim/state/buttons.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								sim/state/buttons.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					namespace pxsim {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export class EV3ButtonState extends CommonButtonState{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        constructor() {
 | 
				
			||||||
 | 
					            super();
 | 
				
			||||||
 | 
					            this.buttons = [
 | 
				
			||||||
 | 
					                new CommonButton(DAL.BUTTON_ID_UP),
 | 
				
			||||||
 | 
					                new CommonButton(DAL.BUTTON_ID_ENTER),
 | 
				
			||||||
 | 
					                new CommonButton(DAL.BUTTON_ID_DOWN),
 | 
				
			||||||
 | 
					                new CommonButton(DAL.BUTTON_ID_RIGHT),
 | 
				
			||||||
 | 
					                new CommonButton(DAL.BUTTON_ID_LEFT),
 | 
				
			||||||
 | 
					                new CommonButton(DAL.BUTTON_ID_ESCAPE),
 | 
				
			||||||
 | 
					                new CommonButton(DAL.BUTTON_ID_ALL)
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								sim/state/control.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								sim/state/control.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/// <reference path="../../libs/core/enums.d.ts"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace pxsim.control {
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    export function mmap(filename: string, size: number, offset: number): void {
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								sim/state/light.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								sim/state/light.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					namespace pxsim {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export class EV3LightState {
 | 
				
			||||||
 | 
					        lightPattern: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        constructor() {
 | 
				
			||||||
 | 
					            this.lightPattern = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace pxsim.output {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export function setLights(pattern: number){
 | 
				
			||||||
 | 
					        const lightState = (board() as DalBoard).lightState;
 | 
				
			||||||
 | 
					        lightState.lightPattern = pattern;
 | 
				
			||||||
 | 
					        runtime.queueDisplayUpdate();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								sim/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								sim/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "compilerOptions": {
 | 
				
			||||||
 | 
					        "target": "es5",
 | 
				
			||||||
 | 
					        "noImplicitAny": true,
 | 
				
			||||||
 | 
					        "noImplicitReturns": true,
 | 
				
			||||||
 | 
					        "declaration": true,
 | 
				
			||||||
 | 
					        "out": "../built/sim.js",
 | 
				
			||||||
 | 
					        "rootDir": ".",
 | 
				
			||||||
 | 
					        "newLine": "LF",
 | 
				
			||||||
 | 
					        "sourceMap": false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1178
									
								
								sim/visuals/board.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1178
									
								
								sim/visuals/board.svg
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
		 After Width: | Height: | Size: 74 KiB  | 
							
								
								
									
										803
									
								
								sim/visuals/board.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										803
									
								
								sim/visuals/board.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,803 @@
 | 
				
			|||||||
 | 
					namespace pxsim.visuals {
 | 
				
			||||||
 | 
					    const MB_STYLE = `
 | 
				
			||||||
 | 
					        svg.sim {
 | 
				
			||||||
 | 
					            margin-bottom:1em;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        svg.sim.grayscale {
 | 
				
			||||||
 | 
					            -moz-filter: grayscale(1);
 | 
				
			||||||
 | 
					            -webkit-filter: grayscale(1);
 | 
				
			||||||
 | 
					            filter: grayscale(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .sim-button {
 | 
				
			||||||
 | 
					            cursor: pointer;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .sim-button:hover {
 | 
				
			||||||
 | 
					            stroke-width: 2px !important;
 | 
				
			||||||
 | 
					            stroke: white !important;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .sim-systemled {
 | 
				
			||||||
 | 
					            fill:#333;
 | 
				
			||||||
 | 
					            stroke:#555;
 | 
				
			||||||
 | 
					            stroke-width: 1px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .sim-light-level-button {
 | 
				
			||||||
 | 
					            stroke:#f1c40f;
 | 
				
			||||||
 | 
					            stroke-width: 1px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .sim-pin-level-button {
 | 
				
			||||||
 | 
					            stroke:darkorange;
 | 
				
			||||||
 | 
					            stroke-width: 1px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .sim-sound-level-button {
 | 
				
			||||||
 | 
					            stroke:#7f8c8d;
 | 
				
			||||||
 | 
					            stroke-width: 1px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .sim-antenna {
 | 
				
			||||||
 | 
					            stroke:#555;
 | 
				
			||||||
 | 
					            stroke-width: 2px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .sim-text {
 | 
				
			||||||
 | 
					            font-family:"Lucida Console", Monaco, monospace;
 | 
				
			||||||
 | 
					            font-size:8px;
 | 
				
			||||||
 | 
					            fill:#fff;
 | 
				
			||||||
 | 
					            pointer-events: none; user-select: none;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .sim-text.small {
 | 
				
			||||||
 | 
					            font-size:6px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .sim-text.inverted {
 | 
				
			||||||
 | 
					            fill:#000;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .sim-text-pin {
 | 
				
			||||||
 | 
					            font-family:"Lucida Console", Monaco, monospace;
 | 
				
			||||||
 | 
					            font-size:5px;
 | 
				
			||||||
 | 
					            fill:#fff;
 | 
				
			||||||
 | 
					            pointer-events: none;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .sim-thermometer {
 | 
				
			||||||
 | 
					            stroke:#aaa;
 | 
				
			||||||
 | 
					            stroke-width: 1px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #rgbledcircle:hover {
 | 
				
			||||||
 | 
					            r:8px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #SLIDE_HOVER {
 | 
				
			||||||
 | 
					            cursor: pointer;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .sim-slide-switch:hover #SLIDE_HOVER {
 | 
				
			||||||
 | 
					            stroke:orange !important;
 | 
				
			||||||
 | 
					            stroke-width: 1px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .sim-slide-switch-inner.on {
 | 
				
			||||||
 | 
					            fill:#ff0000 !important;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* animations */
 | 
				
			||||||
 | 
					        .sim-theme-glow {
 | 
				
			||||||
 | 
					            animation-name: sim-theme-glow-animation;
 | 
				
			||||||
 | 
					            animation-timing-function: ease-in-out;
 | 
				
			||||||
 | 
					            animation-direction: alternate;
 | 
				
			||||||
 | 
					            animation-iteration-count: infinite;
 | 
				
			||||||
 | 
					            animation-duration: 1.25s;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        @keyframes sim-theme-glow-animation {
 | 
				
			||||||
 | 
					            from { opacity: 1; }
 | 
				
			||||||
 | 
					            to   { opacity: 0.75; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .sim-flash {
 | 
				
			||||||
 | 
					            animation-name: sim-flash-animation;
 | 
				
			||||||
 | 
					            animation-duration: 0.1s;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @keyframes sim-flash-animation {
 | 
				
			||||||
 | 
					            from { fill: yellow; }
 | 
				
			||||||
 | 
					            to   { fill: default; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .sim-flash-stroke {
 | 
				
			||||||
 | 
					            z-index: 0;
 | 
				
			||||||
 | 
					            animation-name: sim-flash-stroke-animation;
 | 
				
			||||||
 | 
					            animation-duration: 0.4s;
 | 
				
			||||||
 | 
					            animation-timing-function: ease-in;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @keyframes sim-flash-stroke-animation {
 | 
				
			||||||
 | 
					            from { stroke: yellow; }
 | 
				
			||||||
 | 
					            to   { stroke: default; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .sim-sound-stroke {
 | 
				
			||||||
 | 
					            animation-name: sim-sound-stroke-animation;
 | 
				
			||||||
 | 
					            animation-duration: 0.4s;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @keyframes sim-sound-stroke-animation {
 | 
				
			||||||
 | 
					            from { stroke: yellow; }
 | 
				
			||||||
 | 
					            to   { stroke: default; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* wireframe */
 | 
				
			||||||
 | 
					        .sim-wireframe * {
 | 
				
			||||||
 | 
					            fill: none;
 | 
				
			||||||
 | 
					            stroke: black;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .sim-wireframe .sim-display,
 | 
				
			||||||
 | 
					        .sim-wireframe .sim-led,
 | 
				
			||||||
 | 
					        .sim-wireframe .sim-led-back,
 | 
				
			||||||
 | 
					        .sim-wireframe .sim-head,
 | 
				
			||||||
 | 
					        .sim-wireframe .sim-theme,
 | 
				
			||||||
 | 
					        .sim-wireframe .sim-button-group,
 | 
				
			||||||
 | 
					        .sim-wireframe .sim-button-label,
 | 
				
			||||||
 | 
					        .sim-wireframe .sim-button,
 | 
				
			||||||
 | 
					        .sim-wireframe .sim-text-pin
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            visibility: hidden;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .sim-wireframe .sim-label
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            stroke: none;
 | 
				
			||||||
 | 
					            fill: #777;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .sim-wireframe .sim-board {
 | 
				
			||||||
 | 
					            stroke-width: 2px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    `;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const pinNames: { 'name': string, 'touch': number, 'text': any, 'id'?: number, tooltip?: string }[] = [
 | 
				
			||||||
 | 
					        { 'name': "PIN_A0", 'touch': 0, 'text': null, 'id': pxsim.CPlayPinName.A0, tooltip: "A0 - Speaker" },
 | 
				
			||||||
 | 
					        { 'name': "PIN_A1", 'touch': 1, 'text': null, 'id': pxsim.CPlayPinName.A1, tooltip: "~A1" },
 | 
				
			||||||
 | 
					        { 'name': "PIN_A2", 'touch': 1, 'text': null, 'id': pxsim.CPlayPinName.A2, tooltip: "~A2" },
 | 
				
			||||||
 | 
					        { 'name': "PIN_A3", 'touch': 1, 'text': null, 'id': pxsim.CPlayPinName.A3, tooltip: "~A3" },
 | 
				
			||||||
 | 
					        { 'name': "PIN_A4", 'touch': 1, 'text': null, 'id': pxsim.CPlayPinName.A4, tooltip: "A4 - SCL" },
 | 
				
			||||||
 | 
					        { 'name': "PIN_A5", 'touch': 1, 'text': null, 'id': pxsim.CPlayPinName.A5, tooltip: "A5 - SDA" },
 | 
				
			||||||
 | 
					        { 'name': "PIN_A6", 'touch': 1, 'text': null, 'id': pxsim.CPlayPinName.A6, tooltip: "A6 - RX" },
 | 
				
			||||||
 | 
					        { 'name': "PIN_A7", 'touch': 1, 'text': null, 'id': pxsim.CPlayPinName.A7, tooltip: "A7 - TX" },
 | 
				
			||||||
 | 
					        { 'name': "GND_0", 'touch': 0, 'text': null, tooltip: "Ground" },
 | 
				
			||||||
 | 
					        { 'name': "GND_1", 'touch': 0, 'text': null, tooltip: "Ground" },
 | 
				
			||||||
 | 
					        { 'name': "GND_2", 'touch': 0, 'text': null, tooltip: "Ground" },
 | 
				
			||||||
 | 
					        { 'name': "VBATT", 'touch': 0, 'text': null, tooltip: "Battery power" },
 | 
				
			||||||
 | 
					        { 'name': "PWR_0", 'touch': 0, 'text': null, tooltip: "+3.3V" },
 | 
				
			||||||
 | 
					        { 'name': "PWR_1", 'touch': 0, 'text': null, tooltip: "+3.3V" },
 | 
				
			||||||
 | 
					        { 'name': "PWR_2", 'touch': 0, 'text': null, tooltip: "+3.3V" }
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					    const MB_WIDTH = 169.82979;
 | 
				
			||||||
 | 
					    const MB_HEIGHT = 259.11862;
 | 
				
			||||||
 | 
					    export interface IBoardTheme {
 | 
				
			||||||
 | 
					        accent?: string;
 | 
				
			||||||
 | 
					        display?: string;
 | 
				
			||||||
 | 
					        pin?: string;
 | 
				
			||||||
 | 
					        pinTouched?: string;
 | 
				
			||||||
 | 
					        pinActive?: string;
 | 
				
			||||||
 | 
					        ledOn?: string;
 | 
				
			||||||
 | 
					        ledOff?: string;
 | 
				
			||||||
 | 
					        buttonOuter?: string;
 | 
				
			||||||
 | 
					        buttonUps: string[];
 | 
				
			||||||
 | 
					        buttonDown?: string;
 | 
				
			||||||
 | 
					        virtualButtonOuter?: string;
 | 
				
			||||||
 | 
					        virtualButtonUp?: string;
 | 
				
			||||||
 | 
					        virtualButtonDown?: string;
 | 
				
			||||||
 | 
					        lightLevelOn?: string;
 | 
				
			||||||
 | 
					        lightLevelOff?: string;
 | 
				
			||||||
 | 
					        soundLevelOn?: string;
 | 
				
			||||||
 | 
					        soundLevelOff?: string;
 | 
				
			||||||
 | 
					        gestureButtonOn?: string;
 | 
				
			||||||
 | 
					        gestureButtonOff?: string;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export var themes: IBoardTheme[] = ["#3ADCFE"].map(accent => {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            accent: accent,
 | 
				
			||||||
 | 
					            pin: "#D4AF37",
 | 
				
			||||||
 | 
					            pinTouched: "#FFA500",
 | 
				
			||||||
 | 
					            pinActive: "#FF5500",
 | 
				
			||||||
 | 
					            ledOn: "#ff7777",
 | 
				
			||||||
 | 
					            ledOff: "#fff",
 | 
				
			||||||
 | 
					            buttonOuter: "#979797",
 | 
				
			||||||
 | 
					            buttonUps: ["#FFF", "#4D4D4D", "#FFF", "#FFF", "#FFF", "#FFF", '#FFF'],
 | 
				
			||||||
 | 
					            buttonDown: "#000",
 | 
				
			||||||
 | 
					            virtualButtonDown: "#FFA500",
 | 
				
			||||||
 | 
					            virtualButtonOuter: "#333",
 | 
				
			||||||
 | 
					            virtualButtonUp: "#FFF",
 | 
				
			||||||
 | 
					            lightLevelOn: "yellow",
 | 
				
			||||||
 | 
					            lightLevelOff: "#555",
 | 
				
			||||||
 | 
					            soundLevelOn: "#7f8c8d",
 | 
				
			||||||
 | 
					            soundLevelOff: "#555",
 | 
				
			||||||
 | 
					            gestureButtonOn: "#FFA500",
 | 
				
			||||||
 | 
					            gestureButtonOff: "#B4009E"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export function randomTheme(): IBoardTheme {
 | 
				
			||||||
 | 
					        return themes[Math.floor(Math.random() * themes.length)];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export interface IBoardProps {
 | 
				
			||||||
 | 
					        runtime?: pxsim.Runtime;
 | 
				
			||||||
 | 
					        theme?: IBoardTheme;
 | 
				
			||||||
 | 
					        disableTilt?: boolean;
 | 
				
			||||||
 | 
					        wireframe?: boolean;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export class EV3BoardSvg implements BoardView {
 | 
				
			||||||
 | 
					        public element: SVGSVGElement;
 | 
				
			||||||
 | 
					        private style: SVGStyleElement;
 | 
				
			||||||
 | 
					        private defs: SVGDefsElement;
 | 
				
			||||||
 | 
					        private g: SVGGElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private buttons: SVGElement[];
 | 
				
			||||||
 | 
					        private buttonABText: SVGTextElement;
 | 
				
			||||||
 | 
					        private light: SVGElement;
 | 
				
			||||||
 | 
					        private pins: SVGElement[];
 | 
				
			||||||
 | 
					        private pinControls: { [index: number]: AnalogPinControl };
 | 
				
			||||||
 | 
					        private systemLed: SVGCircleElement;
 | 
				
			||||||
 | 
					        private irReceiver: SVGElement;
 | 
				
			||||||
 | 
					        private irTransmitter: SVGElement;
 | 
				
			||||||
 | 
					        private redLED: SVGRectElement;
 | 
				
			||||||
 | 
					        private slideSwitch: SVGGElement;
 | 
				
			||||||
 | 
					        private lightLevelButton: SVGCircleElement;
 | 
				
			||||||
 | 
					        private lightLevelGradient: SVGLinearGradientElement;
 | 
				
			||||||
 | 
					        private lightLevelText: SVGTextElement;
 | 
				
			||||||
 | 
					        private soundLevelButton: SVGCircleElement;
 | 
				
			||||||
 | 
					        private soundLevelGradient: SVGLinearGradientElement;
 | 
				
			||||||
 | 
					        private soundLevelText: SVGTextElement;
 | 
				
			||||||
 | 
					        private thermometerGradient: SVGLinearGradientElement;
 | 
				
			||||||
 | 
					        private thermometer: SVGRectElement;
 | 
				
			||||||
 | 
					        private thermometerText: SVGTextElement;
 | 
				
			||||||
 | 
					        private antenna: SVGPolylineElement;
 | 
				
			||||||
 | 
					        private shakeButtonGroup: SVGElement;
 | 
				
			||||||
 | 
					        private shakeText: SVGTextElement;
 | 
				
			||||||
 | 
					        public board: pxsim.DalBoard;
 | 
				
			||||||
 | 
					        private pinNmToCoord: Map<Coord> = {
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        constructor(public props: IBoardProps) {
 | 
				
			||||||
 | 
					            this.buildDom();
 | 
				
			||||||
 | 
					            if (props && props.wireframe)
 | 
				
			||||||
 | 
					                svg.addClass(this.element, "sim-wireframe");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /*
 | 
				
			||||||
 | 
					            if (props && props.theme)
 | 
				
			||||||
 | 
					                this.updateTheme();
 | 
				
			||||||
 | 
					            */
 | 
				
			||||||
 | 
					            if (props && props.runtime) {
 | 
				
			||||||
 | 
					                this.board = this.props.runtime.board as pxsim.DalBoard;
 | 
				
			||||||
 | 
					                this.board.updateSubscribers.push(() => this.updateState());
 | 
				
			||||||
 | 
					                this.updateState();
 | 
				
			||||||
 | 
					                this.attachEvents();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public getView(): SVGAndSize<SVGSVGElement> {
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                el: this.element,
 | 
				
			||||||
 | 
					                y: 0,
 | 
				
			||||||
 | 
					                x: 0,
 | 
				
			||||||
 | 
					                w: MB_WIDTH,
 | 
				
			||||||
 | 
					                h: MB_HEIGHT
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public getCoord(pinNm: string): Coord {
 | 
				
			||||||
 | 
					            return this.pinNmToCoord[pinNm];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public highlightPin(pinNm: string): void {
 | 
				
			||||||
 | 
					            //TODO: for instructions
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public getPinDist(): number {
 | 
				
			||||||
 | 
					            return 10;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private recordPinCoords() {
 | 
				
			||||||
 | 
					            pinNames.forEach((pin, i) => {
 | 
				
			||||||
 | 
					                const nm = pin.name;
 | 
				
			||||||
 | 
					                const p = this.pins[i];
 | 
				
			||||||
 | 
					                const r = p.getBoundingClientRect();
 | 
				
			||||||
 | 
					                this.pinNmToCoord[nm] = [r.left + r.width / 2, r.top + r.height / 2];
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            console.log(JSON.stringify(this.pinNmToCoord, null, 2))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private updateTheme() {
 | 
				
			||||||
 | 
					            let theme = this.props.theme;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            svg.fill(this.buttons[0], theme.buttonUps[0]);
 | 
				
			||||||
 | 
					            svg.fill(this.buttons[1], theme.buttonUps[1]);
 | 
				
			||||||
 | 
					            svg.fill(this.buttons[2], theme.buttonUps[2]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (this.shakeButtonGroup) {
 | 
				
			||||||
 | 
					                svg.fill(this.shakeButtonGroup, this.props.theme.gestureButtonOff);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            svg.setGradientColors(this.lightLevelGradient, theme.lightLevelOn, theme.lightLevelOff);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            svg.setGradientColors(this.thermometerGradient, theme.ledOff, theme.ledOn);
 | 
				
			||||||
 | 
					            svg.setGradientColors(this.soundLevelGradient, theme.soundLevelOn, theme.soundLevelOff);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (const id in this.pinControls) {
 | 
				
			||||||
 | 
					                this.pinControls[id].updateTheme();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public updateState() {
 | 
				
			||||||
 | 
					            let state = this.board;
 | 
				
			||||||
 | 
					            if (!state) return;
 | 
				
			||||||
 | 
					            let theme = this.props.theme;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let bpState = state.buttonState;
 | 
				
			||||||
 | 
					            let buttons = bpState.buttons;
 | 
				
			||||||
 | 
					            this.buttons.forEach((button, i) => {
 | 
				
			||||||
 | 
					                svg.fill(button, buttons[i].pressed ? theme.buttonDown : theme.buttonUps[i]);
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.updateLight();
 | 
				
			||||||
 | 
					            /*
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            this.updatePins();
 | 
				
			||||||
 | 
					            this.updateTilt();
 | 
				
			||||||
 | 
					            this.updateNeoPixels();
 | 
				
			||||||
 | 
					            this.updateSwitch();
 | 
				
			||||||
 | 
					            this.updateSound();
 | 
				
			||||||
 | 
					            this.updateLightLevel();
 | 
				
			||||||
 | 
					            this.updateSoundLevel();
 | 
				
			||||||
 | 
					            this.updateButtonAB();
 | 
				
			||||||
 | 
					            this.updateGestures();
 | 
				
			||||||
 | 
					            this.updateTemperature();
 | 
				
			||||||
 | 
					            this.updateInfrared();
 | 
				
			||||||
 | 
					            */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!runtime || runtime.dead) svg.addClass(this.element, "grayscale");
 | 
				
			||||||
 | 
					            else svg.removeClass(this.element, "grayscale");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private lastFlashTime: number = 0;
 | 
				
			||||||
 | 
					        private flashSystemLed() {
 | 
				
			||||||
 | 
					            /*
 | 
				
			||||||
 | 
					            if (!this.systemLed)
 | 
				
			||||||
 | 
					                this.systemLed = <SVGCircleElement>svg.child(this.g, "circle", { class: "sim-systemled", cx: 75, cy: MB_HEIGHT - 171, r: 2 })
 | 
				
			||||||
 | 
					            let now = Date.now();
 | 
				
			||||||
 | 
					            if (now - this.lastFlashTime > 150) {
 | 
				
			||||||
 | 
					                this.lastFlashTime = now;
 | 
				
			||||||
 | 
					                svg.animate(this.systemLed, "sim-flash")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            */
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private lastIrReceiverFlash: number = 0;
 | 
				
			||||||
 | 
					        public flashIrReceiver() {
 | 
				
			||||||
 | 
					            /*
 | 
				
			||||||
 | 
					            if (!this.irReceiver)
 | 
				
			||||||
 | 
					                this.irReceiver = this.element.getElementById("path2054") as SVGElement;
 | 
				
			||||||
 | 
					            let now = Date.now();
 | 
				
			||||||
 | 
					            if (now - this.lastIrReceiverFlash > 200) {
 | 
				
			||||||
 | 
					                this.lastIrReceiverFlash = now;
 | 
				
			||||||
 | 
					                svg.animate(this.irReceiver, 'sim-flash-stroke')
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            */
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private lastIrTransmitterFlash: number = 0;
 | 
				
			||||||
 | 
					        public flashIrTransmitter() {
 | 
				
			||||||
 | 
					            /*
 | 
				
			||||||
 | 
					            if (!this.irTransmitter)
 | 
				
			||||||
 | 
					                this.irTransmitter = this.element.getElementById("path2062") as SVGElement;
 | 
				
			||||||
 | 
					            let now = Date.now();
 | 
				
			||||||
 | 
					            if (now - this.lastIrTransmitterFlash > 200) {
 | 
				
			||||||
 | 
					                this.lastIrTransmitterFlash = now;
 | 
				
			||||||
 | 
					                svg.animate(this.irTransmitter, 'sim-flash-stroke')
 | 
				
			||||||
 | 
					            }*/
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private updateInfrared() {
 | 
				
			||||||
 | 
					            const state = this.board;
 | 
				
			||||||
 | 
					            if (!state) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (state.irState.packetReceived) {
 | 
				
			||||||
 | 
					                state.irState.packetReceived = false;
 | 
				
			||||||
 | 
					                this.flashIrReceiver();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private lastLightPattern: number = -1;
 | 
				
			||||||
 | 
					        private updateLight() {
 | 
				
			||||||
 | 
					            let state = this.board;
 | 
				
			||||||
 | 
					            if (!state || !state.lightState) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const lightPattern = state.lightState.lightPattern;
 | 
				
			||||||
 | 
					            if (lightPattern == this.lastLightPattern) return;
 | 
				
			||||||
 | 
					            this.lastLightPattern = lightPattern;
 | 
				
			||||||
 | 
					            switch(lightPattern) {
 | 
				
			||||||
 | 
					                case 0:  // LED_BLACK
 | 
				
			||||||
 | 
					                    svg.fill(this.light, "#FFF");
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 1:  // LED_GREEN
 | 
				
			||||||
 | 
					                    svg.fill(this.light, "#00ff00");
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 2:  // LED_RED
 | 
				
			||||||
 | 
					                    svg.fill(this.light, "#ff0000");
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 3:  // LED_ORANGE
 | 
				
			||||||
 | 
					                    svg.fill(this.light, "#ffff00");
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 4:  // LED_GREEN_FLASH
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 5:  // LED_RED_FLASH
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 6:  // LED_ORANGE_FLASH
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 7:  // LED_GREEN_PULSE
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 8:  // LED_RED_PULSE
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 9:  // LED_ORANGE_PULSE
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private updateNeoPixels() {
 | 
				
			||||||
 | 
					            let state = this.board;
 | 
				
			||||||
 | 
					            if (!state || !state.neopixelState) return;
 | 
				
			||||||
 | 
					            let neopixels = state.neopixelState.getNeoPixels();
 | 
				
			||||||
 | 
					            for (let i = 0; i < state.neopixelState.NUM_PIXELS; i++) {
 | 
				
			||||||
 | 
					                let rgb = neopixels[i];
 | 
				
			||||||
 | 
					                let p_inner = this.element.getElementById(`LED${i}`) as SVGPathElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!rgb || (rgb.length == 3 && rgb[0] == 0 && rgb[1] == 0 && rgb[2] == 0)) {
 | 
				
			||||||
 | 
					                    // Clear the pixel
 | 
				
			||||||
 | 
					                    svg.fill(p_inner, `rgb(200,200,200)`);
 | 
				
			||||||
 | 
					                    svg.filter(p_inner, null);
 | 
				
			||||||
 | 
					                    p_inner.style.stroke = `none`
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let hsl = visuals.rgbToHsl(rgb);
 | 
				
			||||||
 | 
					                let [h, s, l] = hsl;
 | 
				
			||||||
 | 
					                let lx = Math.max(l * 1.3, 85);
 | 
				
			||||||
 | 
					                // at least 10% luminosity
 | 
				
			||||||
 | 
					                l = l * 90 / 100 + 10;
 | 
				
			||||||
 | 
					                if (p_inner) {
 | 
				
			||||||
 | 
					                    p_inner.style.stroke = `hsl(${h}, ${s}%, ${Math.min(l * 3, 75)}%)`
 | 
				
			||||||
 | 
					                    p_inner.style.strokeWidth = "1.5";
 | 
				
			||||||
 | 
					                    svg.fill(p_inner, `hsl(${h}, ${s}%, ${lx}%)`)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (p_inner) svg.filter(p_inner, `url(#neopixelglow)`);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private updateSound() {
 | 
				
			||||||
 | 
					            let state = this.board;
 | 
				
			||||||
 | 
					            if (!state || !state.audioState) return;
 | 
				
			||||||
 | 
					            let audioState = state.audioState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // FIXME
 | 
				
			||||||
 | 
					            // let soundBoard = this.element.getElementById('g4656') as SVGGElement;
 | 
				
			||||||
 | 
					            // if (audioState.isPlaying()) {
 | 
				
			||||||
 | 
					            //     svg.addClass(soundBoard, "sim-sound-stroke");
 | 
				
			||||||
 | 
					            // } else {
 | 
				
			||||||
 | 
					            //     svg.removeClass(soundBoard, "sim-sound-stroke");
 | 
				
			||||||
 | 
					            // }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private updatePins() {
 | 
				
			||||||
 | 
					            let state = this.board;
 | 
				
			||||||
 | 
					            if (!state || !state.edgeConnectorState || !state.capacitiveSensorState) return;
 | 
				
			||||||
 | 
					            state.edgeConnectorState.pins.forEach((pin, i) => this.updatePin(pin, i));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private updatePin(pin: Pin, index: number) {
 | 
				
			||||||
 | 
					            if (!pin || !this.pins[index]) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ((pin as pins.CommonPin).used) {
 | 
				
			||||||
 | 
					                if (this.pinControls[pin.id] === undefined) {
 | 
				
			||||||
 | 
					                    const pinName = pinNames.filter((a) => a.id === pin.id)[0];
 | 
				
			||||||
 | 
					                    if (pinName) {
 | 
				
			||||||
 | 
					                        this.pinControls[pin.id] = new AnalogPinControl(this, this.defs, pin.id, pinName.name);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else {
 | 
				
			||||||
 | 
					                        // TODO: Surface pin controls for sensor pins in some way?
 | 
				
			||||||
 | 
					                        this.pinControls[pin.id] = null;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (this.pinControls[pin.id]) {
 | 
				
			||||||
 | 
					                    this.pinControls[pin.id].updateValue();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private updateLightLevel() {
 | 
				
			||||||
 | 
					            let state = this.board;
 | 
				
			||||||
 | 
					            if (!state || !state.lightSensorState.sensorUsed) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!this.lightLevelButton) {
 | 
				
			||||||
 | 
					                let gid = "gradient-light-level";
 | 
				
			||||||
 | 
					                this.lightLevelGradient = svg.linearGradient(this.defs, gid)
 | 
				
			||||||
 | 
					                let cy = 15;
 | 
				
			||||||
 | 
					                let r = 10;
 | 
				
			||||||
 | 
					                this.lightLevelButton = svg.child(this.g, "circle", {
 | 
				
			||||||
 | 
					                    cx: `12px`, cy: `${cy}px`, r: `${r}px`,
 | 
				
			||||||
 | 
					                    class: 'sim-light-level-button',
 | 
				
			||||||
 | 
					                    fill: `url(#${gid})`
 | 
				
			||||||
 | 
					                }) as SVGCircleElement;
 | 
				
			||||||
 | 
					                let pt = this.element.createSVGPoint();
 | 
				
			||||||
 | 
					                svg.buttonEvents(this.lightLevelButton,
 | 
				
			||||||
 | 
					                    (ev) => {
 | 
				
			||||||
 | 
					                        let pos = svg.cursorPoint(pt, this.element, ev);
 | 
				
			||||||
 | 
					                        let rs = r / 2;
 | 
				
			||||||
 | 
					                        let level = Math.max(0, Math.min(255, Math.floor((pos.y - (cy - rs)) / (2 * rs) * 255)));
 | 
				
			||||||
 | 
					                        if (level != this.board.lightSensorState.getLevel()) {
 | 
				
			||||||
 | 
					                            this.board.lightSensorState.setLevel(level);
 | 
				
			||||||
 | 
					                            this.applyLightLevel();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }, ev => { },
 | 
				
			||||||
 | 
					                    ev => { })
 | 
				
			||||||
 | 
					                this.lightLevelText = svg.child(this.g, "text", { x: 23, y: cy + r - 15, text: '', class: 'sim-text' }) as SVGTextElement;
 | 
				
			||||||
 | 
					                this.updateTheme();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            svg.setGradientValue(this.lightLevelGradient, Math.min(100, Math.max(0, Math.floor(state.lightSensorState.getLevel() * 100 / 255))) + '%')
 | 
				
			||||||
 | 
					            this.lightLevelText.textContent = state.lightSensorState.getLevel().toString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private applyLightLevel() {
 | 
				
			||||||
 | 
					            let lv = this.board.lightSensorState.getLevel();
 | 
				
			||||||
 | 
					            svg.setGradientValue(this.lightLevelGradient, Math.min(100, Math.max(0, Math.floor(lv * 100 / 255))) + '%')
 | 
				
			||||||
 | 
					            this.lightLevelText.textContent = lv.toString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private updateSoundLevel() {
 | 
				
			||||||
 | 
					            let state = this.board;
 | 
				
			||||||
 | 
					            if (!state || !state.microphoneState.sensorUsed) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!this.soundLevelButton) {
 | 
				
			||||||
 | 
					                let gid = "gradient-sound-level";
 | 
				
			||||||
 | 
					                this.soundLevelGradient = svg.linearGradient(this.defs, gid)
 | 
				
			||||||
 | 
					                let cy = 165;
 | 
				
			||||||
 | 
					                let r = 10;
 | 
				
			||||||
 | 
					                this.soundLevelButton = svg.child(this.g, "circle", {
 | 
				
			||||||
 | 
					                    cx: `12px`, cy: `${cy}px`, r: `${r}px`,
 | 
				
			||||||
 | 
					                    class: 'sim-sound-level-button',
 | 
				
			||||||
 | 
					                    fill: `url(#${gid})`
 | 
				
			||||||
 | 
					                }) as SVGCircleElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let pt = this.element.createSVGPoint();
 | 
				
			||||||
 | 
					                svg.buttonEvents(this.soundLevelButton,
 | 
				
			||||||
 | 
					                    (ev) => {
 | 
				
			||||||
 | 
					                        let pos = svg.cursorPoint(pt, this.element, ev);
 | 
				
			||||||
 | 
					                        let rs = r / 2;
 | 
				
			||||||
 | 
					                        let level = Math.max(0, Math.min(255, Math.floor((pos.y - (cy - rs)) / (2 * rs) * 255)));
 | 
				
			||||||
 | 
					                        if (level != this.board.microphoneState.getLevel()) {
 | 
				
			||||||
 | 
					                            this.board.microphoneState.setLevel(255 - level);
 | 
				
			||||||
 | 
					                            this.applySoundLevel();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }, ev => { },
 | 
				
			||||||
 | 
					                    ev => { })
 | 
				
			||||||
 | 
					                this.soundLevelText = svg.child(this.g, "text", { x: 23, y: cy + r - 3, text: '', class: 'sim-text' }) as SVGTextElement;
 | 
				
			||||||
 | 
					                this.updateTheme();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            svg.setGradientValue(this.soundLevelGradient, Math.min(100, Math.max(0, Math.floor((255 - state.microphoneState.getLevel()) * 100 / 255))) + '%')
 | 
				
			||||||
 | 
					            this.soundLevelText.textContent = state.microphoneState.getLevel().toString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private applySoundLevel() {
 | 
				
			||||||
 | 
					            let lv = this.board.microphoneState.getLevel();
 | 
				
			||||||
 | 
					            svg.setGradientValue(this.soundLevelGradient, Math.min(100, Math.max(0, Math.floor((255 - lv) * 100 / 255))) + '%')
 | 
				
			||||||
 | 
					            this.soundLevelText.textContent = lv.toString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private updateTemperature() {
 | 
				
			||||||
 | 
					            let state = this.board;
 | 
				
			||||||
 | 
					            if (!state || !state.thermometerState || !state.thermometerState.sensorUsed) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Celsius
 | 
				
			||||||
 | 
					            let tmin = -5;
 | 
				
			||||||
 | 
					            let tmax = 50;
 | 
				
			||||||
 | 
					            if (!this.thermometer) {
 | 
				
			||||||
 | 
					                let gid = "gradient-thermometer";
 | 
				
			||||||
 | 
					                this.thermometerGradient = svg.linearGradient(this.defs, gid);
 | 
				
			||||||
 | 
					                this.thermometer = <SVGRectElement>svg.child(this.g, "rect", {
 | 
				
			||||||
 | 
					                    class: "sim-thermometer",
 | 
				
			||||||
 | 
					                    x: 170,
 | 
				
			||||||
 | 
					                    y: 3,
 | 
				
			||||||
 | 
					                    width: 7,
 | 
				
			||||||
 | 
					                    height: 32,
 | 
				
			||||||
 | 
					                    rx: 2, ry: 2,
 | 
				
			||||||
 | 
					                    fill: `url(#${gid})`
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                this.thermometerText = svg.child(this.g, "text", { class: 'sim-text', x: 148, y: 10 }) as SVGTextElement;
 | 
				
			||||||
 | 
					                this.updateTheme();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let pt = this.element.createSVGPoint();
 | 
				
			||||||
 | 
					                svg.buttonEvents(this.thermometer,
 | 
				
			||||||
 | 
					                    (ev) => {
 | 
				
			||||||
 | 
					                        let cur = svg.cursorPoint(pt, this.element, ev);
 | 
				
			||||||
 | 
					                        let t = Math.max(0, Math.min(1, (35 - cur.y) / 30))
 | 
				
			||||||
 | 
					                        state.thermometerState.setLevel(Math.floor(tmin + t * (tmax - tmin)));
 | 
				
			||||||
 | 
					                        this.updateTemperature();
 | 
				
			||||||
 | 
					                    }, ev => { }, ev => { })
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let t = Math.max(tmin, Math.min(tmax, state.thermometerState.getLevel()))
 | 
				
			||||||
 | 
					            let per = Math.floor((state.thermometerState.getLevel() - tmin) / (tmax - tmin) * 100)
 | 
				
			||||||
 | 
					            svg.setGradientValue(this.thermometerGradient, 100 - per + "%");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let unit = "°C";
 | 
				
			||||||
 | 
					            if (state.thermometerUnitState == pxsim.TemperatureUnit.Fahrenheit) {
 | 
				
			||||||
 | 
					                unit = "°F";
 | 
				
			||||||
 | 
					                t = ((t * 18) / 10 + 32) >> 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            this.thermometerText.textContent = t + unit;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private updateButtonAB() {
 | 
				
			||||||
 | 
					            let state = this.board;
 | 
				
			||||||
 | 
					            if (state.buttonState.usesButtonAB) {
 | 
				
			||||||
 | 
					                (<any>this.buttons[2]).style.visibility = "visible";
 | 
				
			||||||
 | 
					                this.updateTheme();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private updateGestures() {
 | 
				
			||||||
 | 
					            let state = this.board;
 | 
				
			||||||
 | 
					            if (state.accelerometerState.useShake && !this.shakeButtonGroup) {
 | 
				
			||||||
 | 
					                const btnr = 2;
 | 
				
			||||||
 | 
					                const width = 22;
 | 
				
			||||||
 | 
					                const height = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let btng = svg.child(this.g, "g", { class: "sim-button-group" });
 | 
				
			||||||
 | 
					                this.shakeButtonGroup = btng;
 | 
				
			||||||
 | 
					                this.shakeText = svg.child(this.g, "text", { x: 81, y: 32, class: "sim-text small" }) as SVGTextElement;
 | 
				
			||||||
 | 
					                this.shakeText.textContent = "SHAKE"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                svg.child(btng, "rect", { class: "sim-button", x: 79, y: 25, rx: btnr, ry: btnr, width, height });
 | 
				
			||||||
 | 
					                svg.fill(btng, this.props.theme.gestureButtonOff);
 | 
				
			||||||
 | 
					                this.shakeButtonGroup.addEventListener(pointerEvents.down, ev => {
 | 
				
			||||||
 | 
					                    let state = this.board;
 | 
				
			||||||
 | 
					                    svg.fill(btng, this.props.theme.gestureButtonOn);
 | 
				
			||||||
 | 
					                    svg.addClass(this.shakeText, "inverted");
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                this.shakeButtonGroup.addEventListener(pointerEvents.leave, ev => {
 | 
				
			||||||
 | 
					                    let state = this.board;
 | 
				
			||||||
 | 
					                    svg.fill(btng, this.props.theme.gestureButtonOff);
 | 
				
			||||||
 | 
					                    svg.removeClass(this.shakeText, "inverted");
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                this.shakeButtonGroup.addEventListener(pointerEvents.up, ev => {
 | 
				
			||||||
 | 
					                    let state = this.board;
 | 
				
			||||||
 | 
					                    svg.fill(btng, this.props.theme.gestureButtonOff);
 | 
				
			||||||
 | 
					                    //this.board.bus.queue(DAL.DEVICE_ID_GESTURE, 11); // GESTURE_SHAKE
 | 
				
			||||||
 | 
					                    svg.removeClass(this.shakeText, "inverted");
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private updateTilt() {
 | 
				
			||||||
 | 
					            if (this.props.disableTilt) return;
 | 
				
			||||||
 | 
					            let state = this.board;
 | 
				
			||||||
 | 
					            if (!state || !state.accelerometerState.accelerometer.isActive) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const x = state.accelerometerState.accelerometer.getX();
 | 
				
			||||||
 | 
					            const y = state.accelerometerState.accelerometer.getY();
 | 
				
			||||||
 | 
					            const af = 8 / 1023;
 | 
				
			||||||
 | 
					            const s = 1 - Math.min(0.1, Math.pow(Math.max(Math.abs(x), Math.abs(y)) / 1023, 2) / 35);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.element.style.transform = `perspective(30em) rotateX(${y * af}deg) rotateY(${x * af}deg) scale(${s}, ${s})`
 | 
				
			||||||
 | 
					            this.element.style.perspectiveOrigin = "50% 50% 50%";
 | 
				
			||||||
 | 
					            this.element.style.perspective = "30em";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private buildDom() {
 | 
				
			||||||
 | 
					            this.element = new DOMParser().parseFromString(BOARD_SVG, "image/svg+xml").querySelector("svg") as SVGSVGElement;
 | 
				
			||||||
 | 
					            svg.hydrate(this.element, {
 | 
				
			||||||
 | 
					                "version": "1.0",
 | 
				
			||||||
 | 
					                "viewBox": `0 0 ${MB_WIDTH} ${MB_HEIGHT}`,
 | 
				
			||||||
 | 
					                "class": "sim",
 | 
				
			||||||
 | 
					                "x": "0px",
 | 
				
			||||||
 | 
					                "y": "0px",
 | 
				
			||||||
 | 
					                "width": MB_WIDTH + "px",
 | 
				
			||||||
 | 
					                "height": MB_HEIGHT + "px",
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            this.style = <SVGStyleElement>svg.child(this.element, "style", {});
 | 
				
			||||||
 | 
					            this.style.textContent = MB_STYLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.defs = <SVGDefsElement>svg.child(this.element, "defs", {});
 | 
				
			||||||
 | 
					            this.g = <SVGGElement>svg.elt("g");
 | 
				
			||||||
 | 
					            this.element.appendChild(this.g);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const btnids = ["BTN_1", "BTN_2", "BTN_3", "BTN_4", "BTN_5", "BTN_BACK"];
 | 
				
			||||||
 | 
					            this.buttons = btnids.map(n => this.element.getElementById(n) as SVGElement);
 | 
				
			||||||
 | 
					            this.buttons.forEach(b => svg.addClass(b, "sim-button"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.light = this.element.getElementById("BOARD_Light") as SVGElement;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private attachEvents() {
 | 
				
			||||||
 | 
					            Runtime.messagePosted = (msg) => {
 | 
				
			||||||
 | 
					                switch (msg.type || "") {
 | 
				
			||||||
 | 
					                    case "serial": this.flashSystemLed(); break;
 | 
				
			||||||
 | 
					                    case "irpacket": this.flashIrTransmitter(); break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /*
 | 
				
			||||||
 | 
					            let tiltDecayer = 0;
 | 
				
			||||||
 | 
					            this.element.addEventListener(pointerEvents.move, (ev: MouseEvent) => {
 | 
				
			||||||
 | 
					                let state = this.board;
 | 
				
			||||||
 | 
					                if (!state.accelerometerState.accelerometer.isActive) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (tiltDecayer) {
 | 
				
			||||||
 | 
					                    clearInterval(tiltDecayer);
 | 
				
			||||||
 | 
					                    tiltDecayer = 0;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let bbox = this.element.getBoundingClientRect();
 | 
				
			||||||
 | 
					                let ax = (ev.clientX - bbox.width / 2) / (bbox.width / 3);
 | 
				
			||||||
 | 
					                let ay = (ev.clientY - bbox.height / 2) / (bbox.height / 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let x = - Math.max(- 1023, Math.min(1023, Math.floor(ax * 1023)));
 | 
				
			||||||
 | 
					                let y = Math.max(- 1023, Math.min(1023, Math.floor(ay * 1023)));
 | 
				
			||||||
 | 
					                let z2 = 1023 * 1023 - x * x - y * y;
 | 
				
			||||||
 | 
					                let z = Math.floor((z2 > 0 ? -1 : 1) * Math.sqrt(Math.abs(z2)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                state.accelerometerState.accelerometer.update(x, y, z);
 | 
				
			||||||
 | 
					                this.updateTilt();
 | 
				
			||||||
 | 
					            }, false);
 | 
				
			||||||
 | 
					            this.element.addEventListener(pointerEvents.leave, (ev: MouseEvent) => {
 | 
				
			||||||
 | 
					                let state = this.board;
 | 
				
			||||||
 | 
					                if (!state.accelerometerState.accelerometer.isActive) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!tiltDecayer) {
 | 
				
			||||||
 | 
					                    tiltDecayer = setInterval(() => {
 | 
				
			||||||
 | 
					                        let accx = state.accelerometerState.accelerometer.getX(MicroBitCoordinateSystem.RAW);
 | 
				
			||||||
 | 
					                        accx = Math.floor(Math.abs(accx) * 0.85) * (accx > 0 ? 1 : -1);
 | 
				
			||||||
 | 
					                        let accy = state.accelerometerState.accelerometer.getY(MicroBitCoordinateSystem.RAW);
 | 
				
			||||||
 | 
					                        accy = Math.floor(Math.abs(accy) * 0.85) * (accy > 0 ? 1 : -1);
 | 
				
			||||||
 | 
					                        let accz = -Math.sqrt(Math.max(0, 1023 * 1023 - accx * accx - accy * accy));
 | 
				
			||||||
 | 
					                        if (Math.abs(accx) <= 24 && Math.abs(accy) <= 24) {
 | 
				
			||||||
 | 
					                            clearInterval(tiltDecayer);
 | 
				
			||||||
 | 
					                            tiltDecayer = 0;
 | 
				
			||||||
 | 
					                            accx = 0;
 | 
				
			||||||
 | 
					                            accy = 0;
 | 
				
			||||||
 | 
					                            accz = -1023;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        state.accelerometerState.accelerometer.update(accx, accy, accz);
 | 
				
			||||||
 | 
					                        this.updateTilt();
 | 
				
			||||||
 | 
					                    }, 50)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }, false);
 | 
				
			||||||
 | 
					            */
 | 
				
			||||||
 | 
					            let bpState = this.board.buttonState;
 | 
				
			||||||
 | 
					            let stateButtons = bpState.buttons;
 | 
				
			||||||
 | 
					            this.buttons.forEach((btn, index) => {
 | 
				
			||||||
 | 
					                let button = stateButtons[index];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                btn.addEventListener(pointerEvents.down, ev => {
 | 
				
			||||||
 | 
					                    button.setPressed(true);
 | 
				
			||||||
 | 
					                    svg.fill(this.buttons[index], this.props.theme.buttonDown);
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                btn.addEventListener(pointerEvents.leave, ev => {
 | 
				
			||||||
 | 
					                    button.setPressed(false);
 | 
				
			||||||
 | 
					                    svg.fill(this.buttons[index], this.props.theme.buttonUps[index]);
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                btn.addEventListener(pointerEvents.up, ev => {
 | 
				
			||||||
 | 
					                    button.setPressed(false);
 | 
				
			||||||
 | 
					                    svg.fill(this.buttons[index], this.props.theme.buttonUps[index]);
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1178
									
								
								sim/visuals/boardsvg.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1178
									
								
								sim/visuals/boardsvg.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										10
									
								
								sim/visuals/boardview.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								sim/visuals/boardview.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					namespace pxsim.visuals {
 | 
				
			||||||
 | 
					    mkBoardView = (opts: BoardViewOptions): BoardView => {
 | 
				
			||||||
 | 
					        return new visuals.EV3BoardSvg({
 | 
				
			||||||
 | 
					            runtime: runtime,
 | 
				
			||||||
 | 
					            theme: visuals.randomTheme(),
 | 
				
			||||||
 | 
					            disableTilt: false,
 | 
				
			||||||
 | 
					            wireframe: opts.wireframe,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										92
									
								
								sim/visuals/pincontrol.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								sim/visuals/pincontrol.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
				
			|||||||
 | 
					namespace pxsim.visuals {
 | 
				
			||||||
 | 
					    export class AnalogPinControl {
 | 
				
			||||||
 | 
					        private outerElement: SVGElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private innerCircle: SVGCircleElement;
 | 
				
			||||||
 | 
					        private gradient: SVGLinearGradientElement;
 | 
				
			||||||
 | 
					        private currentValue: number;
 | 
				
			||||||
 | 
					        private pin: Pin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        constructor(private parent: EV3BoardSvg, private defs: SVGDefsElement, private id: CPlayPinName, name: string) {
 | 
				
			||||||
 | 
					            this.pin = board().edgeConnectorState.getPin(this.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Init the button events
 | 
				
			||||||
 | 
					            this.outerElement = parent.element.getElementById(name) as SVGElement;
 | 
				
			||||||
 | 
					            svg.addClass(this.outerElement, "sim-pin-touch");
 | 
				
			||||||
 | 
					            this.addButtonEvents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Init the gradient controls
 | 
				
			||||||
 | 
					            // const gid = `gradient-${CPlayPinName[id]}-level`;
 | 
				
			||||||
 | 
					            // this.innerCircle = parent.element.getElementById("PIN_CONNECTOR_" + CPlayPinName[id]) as SVGCircleElement;
 | 
				
			||||||
 | 
					            // this.gradient = svg.linearGradient(this.defs, gid);
 | 
				
			||||||
 | 
					            // this.innerCircle.setAttribute("fill", `url(#${gid})`);
 | 
				
			||||||
 | 
					            // this.innerCircle.setAttribute("class", "sim-light-level-button")
 | 
				
			||||||
 | 
					            // this.addLevelControlEvents()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.updateTheme();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public updateTheme() {
 | 
				
			||||||
 | 
					            const theme = this.parent.props.theme;
 | 
				
			||||||
 | 
					            svg.setGradientColors(this.gradient, theme.lightLevelOff, 'darkorange');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public updateValue() {
 | 
				
			||||||
 | 
					            const value = this.pin.value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (value === this.currentValue) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.currentValue = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // svg.setGradientValue(this.gradient, 100 - Math.min(100, Math.max(0, Math.floor(value * 100 / 1023))) + '%')
 | 
				
			||||||
 | 
					            // if (this.innerCircle.childNodes.length) {
 | 
				
			||||||
 | 
					            //    this.innerCircle.removeChild(this.innerCircle.childNodes[0])
 | 
				
			||||||
 | 
					            // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            svg.title(this.outerElement, value.toString());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private addButtonEvents() {
 | 
				
			||||||
 | 
					            this.outerElement.addEventListener(pointerEvents.down, ev => {
 | 
				
			||||||
 | 
					                this.pin.touched = true;
 | 
				
			||||||
 | 
					                svg.addClass(this.outerElement, "touched");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                (pxtcore.getTouchButton(this.id - 1) as CommonButton).setPressed(true);
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.outerElement.addEventListener(pointerEvents.leave, ev => {
 | 
				
			||||||
 | 
					                this.pin.touched = false;
 | 
				
			||||||
 | 
					                svg.removeClass(this.outerElement, "touched");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                (pxtcore.getTouchButton(this.id - 1) as CommonButton).setPressed(false);
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.outerElement.addEventListener(pointerEvents.up, ev => {
 | 
				
			||||||
 | 
					                this.pin.touched = false;
 | 
				
			||||||
 | 
					                svg.removeClass(this.outerElement, "touched");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                (pxtcore.getTouchButton(this.id - 1) as CommonButton).setPressed(false);
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private addLevelControlEvents() {
 | 
				
			||||||
 | 
					            const cy = parseFloat(this.innerCircle.getAttribute("cy"));
 | 
				
			||||||
 | 
					            const r = parseFloat(this.innerCircle.getAttribute("r"));
 | 
				
			||||||
 | 
					            const pt = this.parent.element.createSVGPoint();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            svg.buttonEvents(this.innerCircle,
 | 
				
			||||||
 | 
					                (ev) => {
 | 
				
			||||||
 | 
					                    const pos = svg.cursorPoint(pt, this.parent.element, ev);
 | 
				
			||||||
 | 
					                    const rs = r / 2;
 | 
				
			||||||
 | 
					                    const level = Math.max(0, Math.min(1023, Math.floor((1 - (pos.y - (cy - rs)) / (2 * rs)) * 1023)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (level != this.pin.value) {
 | 
				
			||||||
 | 
					                        this.pin.value = level;
 | 
				
			||||||
 | 
					                        this.updateValue();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }, ev => { },
 | 
				
			||||||
 | 
					                ev => { });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -121,7 +121,7 @@
 | 
				
			|||||||
   Full screen
 | 
					   Full screen
 | 
				
			||||||
--------------------*/
 | 
					--------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@fullscreenBackgroundGradientStart: @mainMenuInvertedBackground;
 | 
					@fullscreenBackgroundGradientStart: @blue;
 | 
				
			||||||
@fullscreenBackgroundGradientEnd: #fff;
 | 
					@fullscreenBackgroundGradientEnd: #fff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*-------------------
 | 
					/*-------------------
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,6 +46,10 @@
 | 
				
			|||||||
#menubar .ui.item {
 | 
					#menubar .ui.item {
 | 
				
			||||||
    color: @red;
 | 
					    color: @red;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					.fullscreensim #menubar .ui.menu {
 | 
				
			||||||
 | 
					    box-shadow: none !important;
 | 
				
			||||||
 | 
					    border-bottom: 0 !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* logo */
 | 
					/* logo */
 | 
				
			||||||
#logo a.ui.image .ui.logo {
 | 
					#logo a.ui.image .ui.logo {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user